aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core-commands.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core-commands.c')
-rw-r--r--src/core-commands.c106
1 files changed, 85 insertions, 21 deletions
diff --git a/src/core-commands.c b/src/core-commands.c
index 6362d95..f80cd59 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -55,6 +55,89 @@ static teco_state_t *teco_state_control_input(teco_machine_main_t *ctx, gunichar
static teco_state_t *teco_state_ctlc_control_input(teco_machine_main_t *ctx, gunichar chr, GError **error);
static teco_state_t *teco_state_endcond(teco_machine_main_t *ctx, const gchar *cmd, GError **error);
+static teco_state_t teco_state_number;
+
+static gboolean
+teco_state_number_end_of_macro(teco_machine_main_t *ctx, GError **error)
+{
+ teco_undo_guint(ctx->number.radix) = 0; /* default */
+
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
+ return TRUE;
+
+ teco_expressions_push(ctx->number.value);
+ teco_undo_int(ctx->number.value) = 0;
+ return TRUE;
+}
+
+static teco_state_t *
+teco_state_number_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
+{
+ /*
+ * Hexadecimal constants (@[0-9][0-9a-zA-Z]*) are terminated by any non-hexadecimal character.
+ * This means you may have to append a space or braces to stop parsing if the next
+ * command would begin with such a letter (e.g. `@0ff D`).
+ */
+ gboolean end_of_number = chr <= 0xFF && (ctx->number.radix == 16 ? !g_ascii_isxdigit(chr)
+ : !g_ascii_isdigit(chr));
+ if (end_of_number) {
+ teco_state_number_end_of_macro(ctx, error);
+ return teco_state_start_input(ctx, chr, error);
+ }
+
+ if (!ctx->number.radix) {
+ if (teco_machine_main_eval_at(ctx))
+ /* @[0-9] starts a hexadecimal constant */
+ teco_undo_guint(ctx->number.radix) = 16;
+ else if (!ctx->number.value && chr == '0')
+ /* a leading zero starts an octal constant */
+ teco_undo_guint(ctx->number.radix) = 8;
+ }
+
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
+ return &teco_state_number;
+
+ teco_int_t radix = ctx->number.radix;
+ if (!radix) {
+ /*
+ * The ^R radix is only considered if we do not
+ * syntactically signify the radix (octal or hex constants).
+ *
+ * FIXME: We could just access qreg->integer here since
+ * we can assume that "^R" is a plain register.
+ */
+ teco_qreg_t *qreg = ctx->qreg_table_locals->radix;
+ qreg->vtable->get_integer(qreg, &radix, NULL);
+ }
+
+ chr = teco_ascii_toupper(chr);
+ guint digit = 'A' <= chr && chr <= 'F' ? chr-'A'+10 : chr-'0';
+ if (digit >= radix) {
+ g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED,
+ "Digit \"%c\" not allowed in radix %" TECO_INT_FORMAT,
+ (gchar)chr, radix);
+ return NULL;
+ }
+
+ teco_undo_int(ctx->number.value) = ctx->number.value*radix + digit;
+
+ return &teco_state_number;
+}
+
+/*
+ * FIXME: This has to be a "command" since we chain to teco_state_start_input()
+ * and want case-folding to work properly.
+ * On the downside, this will also case-fold the hexadecimal constants (A-F).
+ * There would be cumbersome workarounds with custom process_edit_cmd callbacks,
+ * though.
+ */
+static TECO_DEFINE_STATE_START(teco_state_number,
+ .input_cb = (teco_state_input_cb_t)teco_state_number_input,
+ .end_of_macro_cb = (teco_state_end_of_macro_cb_t)teco_state_number_end_of_macro,
+ .style = SCE_SCITECO_NUMBER,
+ .is_start = FALSE
+);
+
/**
* Translate buffer range arguments from the expression stack to
* a from-position and length in bytes.
@@ -760,32 +843,13 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
}
switch (chr) {
- /*$ 0 1 2 3 4 5 6 7 8 9 digit number
- * [n]0|1|2|3|4|5|6|7|8|9 -> n*Radix+X -- Append digit
- *
- * Integer constants in \*(ST may be thought of and are
- * technically sequences of single-digit commands.
- * These commands take one argument from the stack
- * (0 is implied), multiply it with the current radix
- * (2, 8, 10, 16, ...), add the digit's value and
- * return the resultant integer.
- *
- * The command-like semantics of digits may be abused
- * in macros, for instance to append digits to computed
- * integers.
- * It is not an error to append a digit greater than the
- * current radix - this may be changed in the future.
- */
case '0' ... '9':
- if (ctx->flags.modifier_at ||
- (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) {
+ if (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon) {
gchar cmd[] = {chr, '\0'};
teco_error_modifier_set(error, cmd);
return NULL;
}
- if (ctx->flags.mode == TECO_MODE_NORMAL)
- teco_expressions_add_digit(chr, ctx->qreg_table_locals->radix);
- return &teco_state_start;
+ return teco_state_number_input(ctx, chr, error);
case '*':
/*