aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2024-09-18 12:32:16 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2024-09-18 12:32:16 +0200
commitb7b98405089e69dfae0fc11e2a423860f50756e9 (patch)
treeb789182370dc4493d040dafb0bc932f69fbbd3c4
parentdc417a890ad48e28e573770f2ae980af002e93cb (diff)
downloadsciteco-b7b98405089e69dfae0fc11e2a423860f50756e9.tar.gz
check that local register is not edited at the end of macro calls
* This was unsafe and could easily result in crashes, since teco_qreg_current would afterwards point to an already freed Q-Register. * Since automatically editing another register or buffer is not easy to do right, we throw an error instead.
-rw-r--r--TODO3
-rw-r--r--src/error.h9
-rw-r--r--src/qreg-commands.c7
-rw-r--r--src/qreg.c6
-rw-r--r--tests/testsuite.at5
5 files changed, 27 insertions, 3 deletions
diff --git a/TODO b/TODO
index c3bbac5..e1d93d7 100644
--- a/TODO
+++ b/TODO
@@ -4,9 +4,6 @@ Tasks:
"edit" hook.
Known Bugs:
- * A local Q-Register can be left as the edited document
- even after invoking a macro via <M>.
- This is probably not safe and we should throw an error instead.
* E%$...$ broken.
Similarily EQ$file$ won't do what you would expect it to.
* <23(1;)> leaves values on the stack and the internal hidden
diff --git a/src/error.h b/src/error.h
index b12ec80..03af66c 100644
--- a/src/error.h
+++ b/src/error.h
@@ -47,6 +47,7 @@ typedef enum {
TECO_ERROR_INVALIDQREG,
TECO_ERROR_QREGOPUNSUPPORTED,
TECO_ERROR_QREGCONTAINSNULL,
+ TECO_ERROR_EDITINGLOCALQREG,
TECO_ERROR_MEMLIMIT,
/** Interrupt current operation */
@@ -127,6 +128,14 @@ teco_error_qregcontainsnull_set(GError **error, const gchar *name, gsize len, gb
}
static inline void
+teco_error_editinglocalqreg_set(GError **error, const gchar *name, gsize len)
+{
+ g_autofree gchar *name_printable = teco_string_echo(name, len);
+ g_set_error(error, TECO_ERROR, TECO_ERROR_EDITINGLOCALQREG,
+ "Editing local Q-Register \"%s\" at end of macro call", name_printable);
+}
+
+static inline void
teco_error_interrupted_set(GError **error)
{
g_set_error_literal(error, TECO_ERROR, TECO_ERROR_INTERRUPTED, "Interrupted");
diff --git a/src/qreg-commands.c b/src/qreg-commands.c
index 8d28e7d..a96eb5f 100644
--- a/src/qreg-commands.c
+++ b/src/qreg-commands.c
@@ -652,8 +652,15 @@ teco_state_macro_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
} else {
g_auto(teco_qreg_table_t) table;
teco_qreg_table_init(&table, FALSE);
+
if (!teco_qreg_execute(qreg, &table, error))
return NULL;
+ if (teco_qreg_current && !teco_qreg_current->must_undo) {
+ /* currently editing local Q-Register */
+ teco_error_editinglocalqreg_set(error, teco_qreg_current->head.name.data,
+ teco_qreg_current->head.name.len);
+ return NULL;
+ }
}
return &teco_state_start;
diff --git a/src/qreg.c b/src/qreg.c
index cac2d12..17b4830 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -1160,6 +1160,12 @@ teco_ed_hook(teco_ed_hook_t type, GError **error)
if (!teco_qreg_execute(qreg, &locals, error))
goto error_add_frame;
+ if (teco_qreg_current && !teco_qreg_current->must_undo) {
+ /* currently editing local Q-Register */
+ teco_error_editinglocalqreg_set(error, teco_qreg_current->head.name.data,
+ teco_qreg_current->head.name.len);
+ goto error_add_frame;
+ }
return teco_expressions_discard_args(error) &&
teco_expressions_brace_close(error);
diff --git a/tests/testsuite.at b/tests/testsuite.at
index e33a2c4..648e76c 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -79,6 +79,11 @@ AT_CHECK([$SCITECO -e "[[a 23Ub ]]b Qb\"N(0/0)'"], 0, ignore, ignore)
AT_CHECK([$SCITECO -e "[[\$ @FG'..' ]]\$ :Q\$-1Q\$-^^r\"=(0/0)'"], 0, ignore, ignore)
AT_CLEANUP
+AT_SETUP([Editing local registers in macro calls])
+AT_CHECK([$SCITECO -e '@^Ua{@EQ.x//} :Ma @^U.x/FOO/'], 0, ignore, ignore)
+AT_CHECK([$SCITECO -e '@^Ua{@EQ.x//} Ma @^U.x/FOO/'], 1, ignore, ignore)
+AT_CLEANUP
+
AT_SETUP([8-bit cleanliness])
AT_CHECK([$SCITECO -e "0@I//J 0A\"N(0/0)' :@S/^@/\"F(0/0)'"], 0, ignore, ignore)
AT_CHECK([$SCITECO -e "@EQa//0EE 1U*0EE 0:@EUa/f^@^@/ :Qa-4\"N(0/0)' Ga Z-4\"N(0/0)'"], 0, ignore, ignore)