Skip to content

Commit

Permalink
Add handling of formula byte in list names. Fixes #489
Browse files Browse the repository at this point in the history
  • Loading branch information
calc84maniac committed Aug 12, 2024
1 parent 1f06da3 commit 76da0fe
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 19 deletions.
4 changes: 4 additions & 0 deletions core/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
58 changes: 46 additions & 12 deletions core/vat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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';
Expand All @@ -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;
}
Expand Down Expand Up @@ -275,14 +303,15 @@ 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--);
var->address |= mem_peek_byte(var->vat--) << 8;
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 {
Expand All @@ -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:
Expand Down Expand Up @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions core/vat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 *);
Expand Down
2 changes: 1 addition & 1 deletion gui/qt/basicdebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t*>(&name[1]), true));
QString var_name = QString(calc_var_name_to_utf8(reinterpret_cast<uint8_t*>(&name[1]), strlen(&name[1]), true));

// lookup in map to see if we've already parsed this file
if (m_basicPrgmsMap.contains(var_name)) {
Expand Down
2 changes: 1 addition & 1 deletion gui/qt/debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 7 additions & 3 deletions gui/qt/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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<calc_var_t>();
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) {
Expand Down

0 comments on commit 76da0fe

Please sign in to comment.