diff --git a/core/link.c b/core/link.c index 8f0557c31..efac834f1 100644 --- a/core/link.c +++ b/core/link.c @@ -87,6 +87,10 @@ int emu_receive_variable(const char *file, const calc_var_t *vars, int count) { if (fseek(fd, FILE_DATA_START, SEEK_SET)) goto w_err; while (count--) { if (!vat_search_find(vars++, &var)) goto w_err; + if (calc_var_is_list(&var)) { + /* Remove any linked formula from var name */ + var.name[var.namelen - 1] = 0; + } if (write_le16(header_size, fd) != 1) goto w_err; if (write_le16(var.size, fd) != 1) goto w_err; if (fputc(var.type, fd) == EOF) goto w_err; diff --git a/core/vat.c b/core/vat.c index d5d71aa06..f2caef2c0 100644 --- a/core/vat.c +++ b/core/vat.c @@ -81,18 +81,19 @@ static void hex_byte(char **dest, uint8_t byte) { *(*dest)++ = hex_char(byte >> 0); } -const char *calc_var_name_to_utf8(uint8_t name[8], bool named) { - static char buffer[20]; +const char *calc_var_name_to_utf8(uint8_t name[8], uint8_t namelen, bool named) { + static char buffer[26]; char *dest = buffer; uint8_t i = 0; if (name[0] == 0x5D) { *dest++ = '\xCA'; *dest++ = '\x9F'; i++; + namelen--; /* Ignore formula byte when parsing name */ } - for (; i < 8 && ((name[i] >= 'A' && name[i] <= 'Z' + 1) || - (i && name[i] >= 'a' && name[i] <= 'z') || - (i && name[i] >= '0' && name[i] <= '9')); i++) { + for (; i < namelen && ((name[i] >= 'A' && name[i] <= 'Z' + 1) || + (i && name[i] >= 'a' && name[i] <= 'z') || + (i && name[i] >= '0' && name[i] <= '9')); i++) { if (name[i] == 'Z' + 1) { *dest++ = '\xCE'; *dest++ = '\xB8'; @@ -122,6 +123,18 @@ const char *calc_var_name_to_utf8(uint8_t name[8], bool named) { *dest++ = 'e'; *dest++ = '0' + (name[1] + 1) % 10; break; + case 0x3F: + *dest++ = 'F'; + *dest++ = 'o'; + *dest++ = 'r'; + *dest++ = 'm'; + *dest++ = 'u'; + *dest++ = 'l'; + *dest++ = 'a'; + *dest++ = '0' + name[1] / 100; + *dest++ = '0' + (name[1] / 10) % 10; + *dest++ = '0' + name[1] % 10; + break; case 0x5C: *dest++ = '['; *dest++ = 'A' + name[1]; @@ -189,9 +202,9 @@ const char *calc_var_name_to_utf8(uint8_t name[8], bool named) { } fallthrough; default: - for (i = 0; i < 8 && ((name[i] >= 'A' && name[i] <= 'Z' + 1) || - (name[i] >= 'a' && name[i] <= 'z') || - (name[i] >= '0' && name[i] <= '9')); i++) { + for (i = 0; i < namelen && ((name[i] >= 'A' && name[i] <= 'Z' + 1) || + (name[i] >= 'a' && name[i] <= 'z') || + (name[i] >= '0' && name[i] <= '9')); i++) { if (name[i] == 'Z' + 1) { *dest++ = '\xCE'; *dest++ = '\xB8'; @@ -200,13 +213,28 @@ const char *calc_var_name_to_utf8(uint8_t name[8], bool named) { } } if (!i) { - for (; i < 8 && name[i]; i++) { + for (; i < namelen; i++) { hex_byte(&dest, name[i]); } } break; } } + if (name[0] == 0x5D && name[namelen] != 0) { + *dest++ = ' '; + *dest++ = '('; + *dest++ = 'F'; + *dest++ = 'o'; + *dest++ = 'r'; + *dest++ = 'm'; + *dest++ = 'u'; + *dest++ = 'l'; + *dest++ = 'a'; + *dest++ = '0' + name[namelen] / 100; + *dest++ = '0' + (name[namelen] / 10) % 10; + *dest++ = '0' + name[namelen] % 10; + *dest++ = ')'; + } *dest = '\0'; return buffer; } @@ -275,6 +303,7 @@ bool vat_search_next(calc_var_t *var) { return false; /* some sanity check failed */ } var->type1 = mem_peek_byte(var->vat--); + var->type = (calc_var_type_t)(var->type1 & 0x3F); var->type2 = mem_peek_byte(var->vat--); var->version = mem_peek_byte(var->vat--); var->address = mem_peek_byte(var->vat--); @@ -282,7 +311,7 @@ bool vat_search_next(calc_var_t *var) { var->address |= mem_peek_byte(var->vat--) << 16; if ((var->named = var->vat > pTemp && var->vat <= progPtr)) { var->namelen = mem_peek_byte(var->vat--); - if (!var->namelen || var->namelen > 8) { + if (!var->namelen || var->namelen > 8 - calc_var_is_list(var)) { return false; /* invalid name length */ } } else { @@ -294,7 +323,6 @@ bool vat_search_next(calc_var_t *var) { } else if (var->address < 0xD1A881 || var->address >= 0xD40000) { return false; } - var->type = (calc_var_type_t)(var->type1 & 0x3F); switch (var->type) { case CALC_VAR_TYPE_REAL: case CALC_VAR_TYPE_REAL_FRAC: @@ -398,17 +426,23 @@ bool vat_search_next(calc_var_t *var) { } bool vat_search_find(const calc_var_t *target, calc_var_t *result) { + /* Ignore linked formula when comparing list names */ + bool isList = calc_var_is_list(target); vat_search_init(result); while (vat_search_next(result)) { if (result->type == target->type && result->namelen == target->namelen && - !memcmp(result->name, target->name, target->namelen)) { + !memcmp(result->name, target->name, target->namelen - isList)) { return true; } } return false; } +bool calc_var_is_list(const calc_var_t *var) { + return var && (var->type == CALC_VAR_TYPE_REAL_LIST || var->type == CALC_VAR_TYPE_CPLX_LIST); +} + bool calc_var_is_prog(const calc_var_t *var) { return var && (var->type == CALC_VAR_TYPE_PROG || var->type == CALC_VAR_TYPE_PROT_PROG); } diff --git a/core/vat.h b/core/vat.h index 66dfb40f4..d1d03ca2e 100644 --- a/core/vat.h +++ b/core/vat.h @@ -54,8 +54,7 @@ typedef enum calc_var_type { } calc_var_type_t; extern const char *calc_var_type_names[0x40]; -const char *calc_var_name_to_utf8(uint8_t name[8], bool named); -const char *calc_var_name_to_ascii(uint8_t name[8]); +const char *calc_var_name_to_utf8(uint8_t name[8], uint8_t namelen, bool named); typedef struct calc_var { uint32_t vat, address; @@ -69,6 +68,7 @@ void vat_search_init(calc_var_t *); bool vat_search_next(calc_var_t *); bool vat_search_find(const calc_var_t *, calc_var_t *); +bool calc_var_is_list(const calc_var_t *); bool calc_var_is_prog(const calc_var_t *); bool calc_var_is_asmprog(const calc_var_t *); bool calc_var_is_internal(const calc_var_t *); diff --git a/gui/qt/basicdebugger.cpp b/gui/qt/basicdebugger.cpp index 40b6b9ad5..f09b6299e 100644 --- a/gui/qt/basicdebugger.cpp +++ b/gui/qt/basicdebugger.cpp @@ -178,7 +178,7 @@ MainWindow::debug_basic_status_t MainWindow::debugBasicPgrmLookup(bool allowSwit ui->basicTempEdit->clear(); return DBG_BASIC_NO_EXECUTING_PRGM; } else { - QString var_name = QString(calc_var_name_to_utf8(reinterpret_cast(&name[1]), true)); + QString var_name = QString(calc_var_name_to_utf8(reinterpret_cast(&name[1]), strlen(&name[1]), true)); // lookup in map to see if we've already parsed this file if (m_basicPrgmsMap.contains(var_name)) { diff --git a/gui/qt/debugger.cpp b/gui/qt/debugger.cpp index 6df71ee5f..0d82d9172 100644 --- a/gui/qt/debugger.cpp +++ b/gui/qt/debugger.cpp @@ -2371,7 +2371,7 @@ void MainWindow::osUpdate() { QTableWidgetItem *varAddr = new QTableWidgetItem(int2hex(var.address, 6)); QTableWidgetItem *varVatAddr = new QTableWidgetItem(int2hex(var.vat, 6)); QTableWidgetItem *varSize = new QTableWidgetItem(int2hex(var.size, 4)); - QTableWidgetItem *varName = new QTableWidgetItem(QString(calc_var_name_to_utf8(var.name, var.named))); + QTableWidgetItem *varName = new QTableWidgetItem(QString(calc_var_name_to_utf8(var.name, var.namelen, var.named))); QTableWidgetItem *varType = new QTableWidgetItem(QString(calc_var_type_names[var.type])); varAddr->setFont(monospace); diff --git a/gui/qt/mainwindow.cpp b/gui/qt/mainwindow.cpp index d5e7d84a8..7765c7d73 100644 --- a/gui/qt/mainwindow.cpp +++ b/gui/qt/mainwindow.cpp @@ -1993,7 +1993,7 @@ void MainWindow::varShow() { var_type_str += QStringLiteral(" (ASM)"); } - QTableWidgetItem *var_name = new QTableWidgetItem(calc_var_name_to_utf8(var.name, var.named)); + QTableWidgetItem *var_name = new QTableWidgetItem(calc_var_name_to_utf8(var.name, var.namelen, var.named)); QTableWidgetItem *var_location = new QTableWidgetItem(var.archived ? tr("Archive") : QStringLiteral("RAM")); QTableWidgetItem *var_type = new QTableWidgetItem(var_type_str); QTableWidgetItem *var_preview = new QTableWidgetItem(var_value); @@ -2039,7 +2039,7 @@ void MainWindow::varSaveSelected() { if (selectedVars.size() < 2) { QMessageBox::warning(this, MSG_WARNING, tr("Select at least two files to group")); } else { - fileNames = varDialog(QFileDialog::AcceptSave, tr("TI Group (*.8cg);;All Files (*.*)"), QStringLiteral("8cg")); + fileNames = varDialog(QFileDialog::AcceptSave, tr("TI Group (*.8cg);;All Files (*.*)"), QStringLiteral("8cg")); if (fileNames.size() == 1) { if (emu_receive_variable(fileNames.first().toUtf8(), selectedVars.constData(), selectedVars.size()) != LINK_GOOD) { QMessageBox::critical(this, MSG_ERROR, tr("Transfer error, see console for information:\nFile: ") + fileNames.first()); @@ -2083,8 +2083,12 @@ void MainWindow::varSaveSelectedFiles() { for (int currRow = 0; currRow < ui->emuVarView->rowCount(); currRow++) { if (ui->emuVarView->item(currRow, VAR_NAME_COL)->checkState() == Qt::Checked) { calc_var_t var = ui->emuVarView->item(currRow, VAR_NAME_COL)->data(Qt::UserRole).value(); + if (calc_var_is_list(&var)) { + // Remove any linked formula before generating filename + var.name[var.namelen - 1] = 0; + } - name = QString(calc_var_name_to_utf8(var.name, var.named)); + name = QString(calc_var_name_to_utf8(var.name, var.namelen, var.named)); filename = dialog.directory().absolutePath() + "/" + name + "." + m_varExtensions[var.type1]; if (emu_receive_variable(filename.toStdString().c_str(), &var, 1) != LINK_GOOD) {