aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/qreg-commands.c
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2025-04-13 00:40:37 +0300
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2025-04-13 01:33:43 +0300
commit628c73d984fd7663607cc3fd9368f809855906fd (patch)
treebf9922ec94bbce2df19ef146724bbfe124138998 /src/qreg-commands.c
parent3b06b44fc22cd5c936dd3ce677290e3f65f7f8ce (diff)
downloadsciteco-628c73d984fd7663607cc3fd9368f809855906fd.tar.gz
fixed undoing bitfields on Windows
* It turns out that `bool` (_Bool) in bitfields may cause padding to the next 32-bit word. This was only observed on MinGW. I am not entirely sure why, although the C standard does not guarantee much with regard to bitfield memory layout and there are 64-bit available due to passing anyway. Actually, they could also be layed out in a different order. * I am now consistently using guint instead of `bool` in bitfields to prevent any potential surprises. * The way that guint was aliased with bitfield structs for undoing teco_machine_main_t and teco_machine_qregspec_t flags was therefore insecure. It was not guaranteed that the __flags field really "captures" all of the bit field. Even with `guint v : 1` fields, this was not guaranteed. We would have required a static assertion for robustness. Alternatively, we could have declared a `gsize __flags` variable as well. This __should__ be safe since gsize should always be pointer sized and correspond to the platform's alignment. However, it's also not 100% guaranteed. Using classic ANSI C enums with bit operations to encode multiple fields and flags into a single integer also doesn't look very attractive. * Instead, we now define scalar types with their own teco_undo_push() shortcuts for the bitfield structs. This is in one way simpler and much more robust, but on the other hand complicates access to the flag variables. * It's a good question whether a `struct __attribute__((packed))` bitfield with guint fields would be a reliable replacement for flag enums, that are communicated with the "outside" (TECO) world. I am not going to risk it until GCC gives any guarantees, though. For the time being, bitfields are only used internally where the concrete memory layout (bit positions) is not crucial. * This fixes the test suite and therefore probably CI and nightly builds on Windows. * Test case: Rub out `@I//` or `@Xq` until before the `@`. The parser doesn't know that `@` is still set and allows all sorts of commands where `@` should be forbidden. * It's unknown how long this has been broken on Windows - quite possibly since v2.0.
Diffstat (limited to 'src/qreg-commands.c')
-rw-r--r--src/qreg-commands.c30
1 files changed, 15 insertions, 15 deletions
diff --git a/src/qreg-commands.c b/src/qreg-commands.c
index 3da9c46..a4019a0 100644
--- a/src/qreg-commands.c
+++ b/src/qreg-commands.c
@@ -58,7 +58,7 @@ teco_state_expectqreg_input(teco_machine_main_t *ctx, gunichar chr, GError **err
teco_qreg_table_t *table;
switch (teco_machine_qregspec_input(ctx->expectqreg, chr,
- ctx->mode == TECO_MODE_NORMAL ? &qreg : NULL, &table, error)) {
+ ctx->flags.mode == TECO_MODE_NORMAL ? &qreg : NULL, &table, error)) {
case TECO_MACHINE_QREGSPEC_ERROR:
return NULL;
case TECO_MACHINE_QREGSPEC_MORE:
@@ -81,7 +81,7 @@ teco_state_pushqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
{
teco_state_expectqreg_reset(ctx);
- return ctx->mode == TECO_MODE_NORMAL &&
+ return ctx->flags.mode == TECO_MODE_NORMAL &&
!teco_qreg_stack_push(qreg, error) ? NULL : &teco_state_start;
}
@@ -99,7 +99,7 @@ teco_state_popqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
{
teco_state_expectqreg_reset(ctx);
- return ctx->mode == TECO_MODE_NORMAL &&
+ return ctx->flags.mode == TECO_MODE_NORMAL &&
!teco_qreg_stack_pop(qreg, error) ? NULL : &teco_state_start;
}
@@ -143,7 +143,7 @@ teco_state_loadqreg_done(teco_machine_main_t *ctx, const teco_string_t *str, GEr
teco_machine_qregspec_get_results(ctx->expectqreg, &qreg, &table);
teco_state_expectqreg_reset(ctx);
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
if (str->len > 0) {
@@ -198,7 +198,7 @@ teco_state_saveqreg_done(teco_machine_main_t *ctx, const teco_string_t *str, GEr
teco_machine_qregspec_get_results(ctx->expectqreg, &qreg, NULL);
teco_state_expectqreg_reset(ctx);
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
g_autofree gchar *filename = teco_file_expand_path(str->data);
@@ -231,7 +231,7 @@ teco_state_queryqreg_initial(teco_machine_main_t *ctx, GError **error)
* required Q-Registers.
* In parse-only mode, the type does not matter.
*/
- teco_qreg_type_t type = ctx->modifier_colon ? TECO_QREG_OPTIONAL : TECO_QREG_REQUIRED;
+ teco_qreg_type_t type = ctx->flags.modifier_colon ? TECO_QREG_OPTIONAL : TECO_QREG_REQUIRED;
/*
* NOTE: We have to allocate a new instance always since `expectqreg`
@@ -250,7 +250,7 @@ teco_state_queryqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
{
teco_state_expectqreg_reset(ctx);
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
if (!teco_expressions_eval(FALSE, error))
@@ -363,7 +363,7 @@ teco_state_setqregstring_nobuilding_done(teco_machine_main_t *ctx,
teco_machine_qregspec_get_results(ctx->expectqreg, &qreg, NULL);
teco_state_expectqreg_reset(ctx);
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
gboolean colon_modified = teco_machine_main_eval_colon(ctx) > 0;
@@ -482,7 +482,7 @@ TECO_DEFINE_STATE_EXPECTQREG(teco_state_eucommand,
static gboolean
teco_state_setqregstring_building_initial(teco_machine_main_t *ctx, GError **error)
{
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return TRUE;
teco_qreg_t *qreg;
@@ -526,7 +526,7 @@ teco_state_getqregstring_got_register(teco_machine_main_t *ctx, teco_qreg_t *qre
{
teco_state_expectqreg_reset(ctx);
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
g_auto(teco_string_t) str = {NULL, 0};
@@ -566,7 +566,7 @@ teco_state_setqreginteger_got_register(teco_machine_main_t *ctx, teco_qreg_t *qr
{
teco_state_expectqreg_reset(ctx);
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
if (!teco_expressions_eval(FALSE, error))
@@ -616,7 +616,7 @@ teco_state_increaseqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg
{
teco_state_expectqreg_reset(ctx);
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
teco_int_t value, add;
@@ -650,7 +650,7 @@ teco_state_macro_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
{
teco_state_expectqreg_reset(ctx);
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
if (teco_machine_main_eval_colon(ctx) > 0) {
@@ -705,7 +705,7 @@ TECO_DEFINE_STATE_EXPECTQREG(teco_state_macro);
static teco_state_t *
teco_state_macrofile_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
{
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
g_autofree gchar *filename = teco_file_expand_path(str->data);
@@ -754,7 +754,7 @@ teco_state_copytoqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
*/
gboolean modifier_at = teco_machine_main_eval_at(ctx);
- if (ctx->mode > TECO_MODE_NORMAL)
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
gssize from, len; /* in bytes */