aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2025-07-18 00:34:56 +0300
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2025-07-18 00:34:56 +0300
commit3a2583e918bcc805fe860252f8a520fc2f9b26ce (patch)
treecfe2b7846df4e8c2d1572c6b7b961225a8e87487 /src
parent4794367ce0c31f820bf2bd72d44c886984e3f7ed (diff)
downloadsciteco-3a2583e918bcc805fe860252f8a520fc2f9b26ce.tar.gz
fixed minor memory leaks of per-state data in teco_machine_main_t
* These were leaked e.g. in case of end-of-macro errors, but also in case of syntax highlighting (teco_lexer_style()). I considered to solve this by overwriting more of the end_of_macro_cb, but it didn't turn out to be trivial always. * Considering that the union in teco_machine_main_t saved only 3 machine words of memory, I decided to sacrifice those for more robust memory management. * teco_machine_qregspec_t cannot be directly embedded into teco_machine_main_t due to recursive dependencies with teco_machine_stringbuilding_t. It could now and should perhaps be allocated only once in teco_machine_main_init(), but it would require more refactoring.
Diffstat (limited to 'src')
-rw-r--r--src/goto-commands.c8
-rw-r--r--src/lexer.c4
-rw-r--r--src/parser.c8
-rw-r--r--src/parser.h22
-rw-r--r--src/qreg-commands.c6
-rw-r--r--src/view.c2
6 files changed, 23 insertions, 27 deletions
diff --git a/src/goto-commands.c b/src/goto-commands.c
index a0e6634..72be48e 100644
--- a/src/goto-commands.c
+++ b/src/goto-commands.c
@@ -39,13 +39,6 @@ TECO_DECLARE_STATE(teco_state_eolcomment);
teco_string_t teco_goto_skip_label = {NULL, 0};
-static gboolean
-teco_state_label_initial(teco_machine_main_t *ctx, GError **error)
-{
- memset(&ctx->goto_label, 0, sizeof(ctx->goto_label));
- return TRUE;
-}
-
/*
* NOTE: The comma is theoretically not allowed in a label
* (see <O> syntax), but is accepted anyway since labels
@@ -108,7 +101,6 @@ teco_state_label_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
}
TECO_DEFINE_STATE(teco_state_label,
- .initial_cb = (teco_state_initial_cb_t)teco_state_label_initial,
.style = SCE_SCITECO_LABEL
);
diff --git a/src/lexer.c b/src/lexer.c
index 6bc696f..2f43b76 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -157,7 +157,9 @@ teco_lexer_step(teco_view_t *view, teco_machine_main_t *machine,
* The curly braces will be styled like regular commands.
*
* FIXME: This works only for top-level macro definitions,
- * not for embedded definitions.
+ * not for nested definitions.
+ * FIXME: The macrodef_machine's end-of-macro callback could be used
+ * to detect and highlight an error on the closing `}`.
* FIXME: This cannot currently be disabled, not even with SCI_SETPROPERTY.
* We could only map it to an ED flag or
* rewrite the lexer against the ILexer5 interface, which requires C++.
diff --git a/src/parser.c b/src/parser.c
index ee705a0..33d2e7f 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -81,7 +81,7 @@ teco_machine_input(teco_machine_t *ctx, gunichar chr, GError **error)
gboolean
teco_state_end_of_macro(teco_machine_t *ctx, GError **error)
{
- g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED,
+ g_set_error_literal(error, TECO_ERROR, TECO_ERROR_SYNTAX,
"Unterminated command");
return FALSE;
}
@@ -386,7 +386,8 @@ teco_machine_main_clear(teco_machine_main_t *ctx)
teco_goto_table_clear(&ctx->goto_table);
teco_string_clear(&ctx->expectstring.string);
teco_machine_stringbuilding_clear(&ctx->expectstring.machine);
- // FIXME: Could leak ctx->goto_label, but it's in an union
+ teco_string_clear(&ctx->goto_label);
+ teco_machine_qregspec_free(ctx->expectqreg);
}
/** Append string to result with case folding. */
@@ -1012,8 +1013,7 @@ teco_machine_stringbuilding_escape(teco_machine_stringbuilding_t *ctx, const gch
void
teco_machine_stringbuilding_clear(teco_machine_stringbuilding_t *ctx)
{
- if (ctx->machine_qregspec)
- teco_machine_qregspec_free(ctx->machine_qregspec);
+ teco_machine_qregspec_free(ctx->machine_qregspec);
teco_string_clear(&ctx->code);
}
diff --git a/src/parser.h b/src/parser.h
index 36a0302..a1583d2 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -514,17 +514,19 @@ struct teco_machine_main_t {
/*
* teco_state_t-dependent state.
*
- * Some of these cannot be used concurrently and are therefore
- * grouped into unions.
- * We could further optimize memory usage by dynamically allocating
- * some of these structures on demand.
+ * Some cannot theoretically be used at the same time
+ * but it's hard to prevent memory leaks if putting them into
+ * a common union.
*/
- teco_machine_expectstring_t expectstring;
- union {
- teco_string_t goto_label;
- teco_machine_qregspec_t *expectqreg;
- teco_machine_scintilla_t scintilla;
- };
+ teco_machine_expectstring_t expectstring;
+ /**
+ * State machine for parsing Q-reg specifications.
+ * This could theoretically be inlined, but it would introduce
+ * a recursive dependency between qreg.h and parser.h.
+ */
+ teco_machine_qregspec_t *expectqreg;
+ teco_string_t goto_label;
+ teco_machine_scintilla_t scintilla;
};
typedef struct teco_machine_main_flags_t teco_machine_main_flags_t;
diff --git a/src/qreg-commands.c b/src/qreg-commands.c
index 7189771..9407e6c 100644
--- a/src/qreg-commands.c
+++ b/src/qreg-commands.c
@@ -39,8 +39,8 @@ teco_state_expectqreg_initial(teco_machine_main_t *ctx, GError **error)
teco_state_t *current = ctx->parent.current;
/*
- * NOTE: We have to allocate a new instance always since `expectqreg`
- * is part of an union.
+ * NOTE: This could theoretically be allocated once in
+ * teco_machine_main_init(), but we'd have to set the type here anyway.
*/
ctx->expectqreg = teco_machine_qregspec_new(current->expectqreg.type, ctx->qreg_table_locals,
ctx->parent.must_undo);
@@ -69,7 +69,7 @@ teco_state_expectqreg_input(teco_machine_main_t *ctx, gunichar chr, GError **err
/*
* NOTE: ctx->expectqreg is preserved since we may want to query it from follow-up
- * states. This means, it must usually be stored manually in got_register_cb() via:
+ * states. This means, it must usually be reset manually in got_register_cb() via:
* teco_state_expectqreg_reset(ctx);
*/
return current->expectqreg.got_register_cb(ctx, qreg, table, error);
diff --git a/src/view.c b/src/view.c
index d08728d..972828a 100644
--- a/src/view.c
+++ b/src/view.c
@@ -315,7 +315,7 @@ cleanup:
/**
* Load file into view's document.
- *
+ *
* @param ctx The view to load.
* @param filename File name to read
* @param clear Whether to completely replace document