From fcd2239eb2849432269ba4456718b657fdff3972 Mon Sep 17 00:00:00 2001 From: Leo C Date: Tue, 21 Jun 2016 13:18:19 +0200 Subject: [PATCH] Enable expression evaluation for numeric command line args --- avr/Tupfile | 3 +- avr/cmd_mem.c | 66 +++++++++++-------- avr/command.c | 9 ++- avr/command_tbl.c | 9 ++- avr/eval_arg.c | 161 +++++++++++++++++++++++++++++++++++++++++++++ include/command.h | 3 + include/eval_arg.h | 19 ++++++ 7 files changed, 238 insertions(+), 32 deletions(-) create mode 100644 avr/eval_arg.c create mode 100644 include/eval_arg.h diff --git a/avr/Tupfile b/avr/Tupfile index 0eb910a..d41de25 100644 --- a/avr/Tupfile +++ b/avr/Tupfile @@ -9,7 +9,8 @@ SRC += cli.c cli_readline.c command.c command_tbl.c SRC += cmd_help.c cmd_run.c cmd_boot.c cmd_misc.c SRC += cmd_date.c cmd_mem.c cmd_gpio.c cmd_attach.c SRC += cmd_loadihex.c cmd_loadcpm3.c cmd_sd.c cmd_fat.c -SRC += env.c xmalloc.c con-utils.c print-utils.c getopt-min.c +SRC += env.c xmalloc.c con-utils.c print-utils.c +SRC += getopt-min.c eval_arg.c SRC += timer.c serial.c i2c.c bcd.c pcf8583.c mmc.c SRC += background.c z180-serv.c z80-if.c gpio.c SRC += $(FATFS) $(TOP)/fatfs/src/option/unicode.c diff --git a/avr/cmd_mem.c b/avr/cmd_mem.c index 4fe9415..2ddeab7 100644 --- a/avr/cmd_mem.c +++ b/avr/cmd_mem.c @@ -14,7 +14,6 @@ */ #include "common.h" -#include #include #include @@ -23,6 +22,7 @@ #include "print-utils.h" #include "con-utils.h" #include "getopt-min.h" +#include "eval_arg.h" #include "timer.h" #include "z80-if.h" #include "debug.h" @@ -85,12 +85,12 @@ command_ret_t do_mem_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ if ((flag & CMD_FLAG_REPEAT) == 0) { /* Address is specified since argc > 1 */ - addr = strtoul(argv[1], NULL, 16); + addr = eval_arg(argv[1], NULL); addr += base_address; /* If another parameter, it is the length to display. */ if (argc > 2) - length = strtoul(argv[2], NULL, 16); + length = eval_arg(argv[2], NULL); } /* Print the lines. */ @@ -136,7 +136,7 @@ mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[]) /* Address is specified since argc > 1 */ - addr = strtoul(argv[1], NULL, 16); + addr = eval_arg(argv[1], NULL); addr += base_address; } @@ -163,7 +163,7 @@ mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[]) } else { char *endp; - data = strtoul(console_buffer, &endp, 16); + data = eval_arg(console_buffer, &endp); nbytes = endp - console_buffer; if (nbytes) { if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) { @@ -227,13 +227,13 @@ command_ret_t do_mem_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ return CMD_RET_USAGE; /* Address and value are specified since (adjusted) argc >= 2 */ - addr = strtoul(argv[optind++], NULL, 16); + addr = eval_arg(argv[optind++], NULL); addr += base_address; - writeval = strtoul(argv[optind++], NULL, 16); + writeval = eval_arg(argv[optind++], NULL); /* Count ? */ if (argc == 3) - count = strtoul(argv[optind], NULL, 16); + count = eval_arg(argv[optind], NULL); if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) { my_puts_P(PSTR("Bus timeout\n")); @@ -262,18 +262,30 @@ command_ret_t do_mem_mdc ( cmd_tbl_t *cmdtp, int flag, int argc, char * const ar (void) cmdtp; (void) flag; - if (argc < 4) + optind = 0; + if (argv[0][1] != 'd') { + int opt; + while ((opt = getopt(argc, argv, PSTR("bwl"))) != -1) + if (opt == '?') + return CMD_RET_USAGE; + --optind; + } + + printf_P(PSTR("# argc: %d, optind: %d, argv[optind+3]: '%s'\n"), + argc, optind, argv[optind+3]); + + if (argc-optind != 4) return CMD_RET_USAGE; - count = strtoul(argv[3], NULL, 10); + count = eval_arg(argv[optind + 3], NULL); clear_ctrlc(); /* forget any previous Control C */ for (;;) { if (argv[0][1] == 'd') - do_mem_md (NULL, 0, 3, argv); + do_mem_md (NULL, 0, argc-1, argv); /* memory display */ else - do_mem_mw (NULL, 0, 3, argv); + do_mem_mw (NULL, 0, argc-1, argv); /* memory write */ /* delay for ms... */ @@ -304,11 +316,11 @@ command_ret_t do_mem_cmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv return CMD_RET_USAGE; - addr1 = strtoul(argv[1], NULL, 16); + addr1 = eval_arg(argv[1], NULL); addr1 += base_address; - addr2 = strtoul(argv[2], NULL, 16); + addr2 = eval_arg(argv[2], NULL); addr2 += base_address; - count = strtoul(argv[3], NULL, 16); + count = eval_arg(argv[3], NULL); for (ngood = 0; ngood < count; ++ngood) { if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) { @@ -351,11 +363,11 @@ command_ret_t do_mem_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ if (argc != 4) return CMD_RET_USAGE; - src = strtoul(argv[1], NULL, 16); + src = eval_arg(argv[1], NULL); src += base_address; - dest = strtoul(argv[2], NULL, 16); + dest = eval_arg(argv[2], NULL); dest += base_address; - count = strtoul(argv[3], NULL, 16); + count = eval_arg(argv[3], NULL); if (count == 0) { my_puts_P(PSTR("Zero length?\n")); @@ -398,7 +410,7 @@ command_ret_t do_mem_base(cmd_tbl_t *cmdtp, int flag, int argc, if (argc > 1) { /* Set new base address. */ - base_address = strtoul(argv[1], NULL, 16); + base_address = eval_arg(argv[1], NULL); } /* Print the current base address. */ printf_P(PSTR("Base Address: 0x%05lx\n"), base_address); @@ -417,10 +429,10 @@ command_ret_t do_mem_loop(cmd_tbl_t *cmdtp, int flag, int argc, return CMD_RET_USAGE; /* Address is always specified. */ - addr = strtoul(argv[1], NULL, 16); + addr = eval_arg(argv[1], NULL); /* Length is the number of bytes. */ - length = strtoul(argv[2], NULL, 16); + length = eval_arg(argv[2], NULL); /* We want to optimize the loops to run as fast as possible. @@ -463,12 +475,12 @@ command_ret_t do_mem_loopw (cmd_tbl_t *cmdtp, int flag, int argc, char * const a return CMD_RET_USAGE; /* Address is always specified. */ - addr = strtoul(argv[1], NULL, 16); + addr = eval_arg(argv[1], NULL); /* Length is the number of bytes. */ - length = strtoul(argv[2], NULL, 16); + length = eval_arg(argv[2], NULL); - data = strtoul(argv[3], NULL, 16); + data = eval_arg(argv[3], NULL); /* * We want to optimize the loops to run as fast as possible. @@ -739,15 +751,15 @@ command_ret_t do_mem_mtest(cmd_tbl_t *cmdtp, int flag, int argc, (void) flag; if (argc > 1) - start = strtoul(argv[1], NULL, 16); + start = eval_arg(argv[1], NULL); if (argc > 2) - end = strtoul(argv[2], NULL, 16); + end = eval_arg(argv[2], NULL); else end = CONFIG_SYS_RAMSIZE_MAX - 1; if (argc > 3) - iteration_limit = (unsigned int) strtoul(argv[3], NULL, 16); + iteration_limit = (unsigned int) eval_arg(argv[3], NULL); printf_P(PSTR("Testing %05lx ... %05lx:\n"), start, end); // debug("## %s:%d: start %#05lx end %#05lx\n", __func__, __LINE__, start, end); diff --git a/avr/command.c b/avr/command.c index 5499b9d..cd2ee39 100644 --- a/avr/command.c +++ b/avr/command.c @@ -11,17 +11,21 @@ * Command Processor Table */ +#include "command.h" #include "common.h" #include #include #include +#include #include "config.h" #include "print-utils.h" #include "con-utils.h" #include "env.h" #include "debug.h" -#include "command.h" + + +jmp_buf cmd_jbuf; static void print_usage_line(const FLASH char *name, int width, @@ -521,6 +525,9 @@ command_ret_t cmd_process(int flag, int argc, char * const argv[], } #endif + if (setjmp(cmd_jbuf) != 0) + return CMD_RET_FAILURE; + /* If OK so far, then do the command */ if (!rc) { rc = cmd_call(cmdtp, flag, argc, argv); diff --git a/avr/command_tbl.c b/avr/command_tbl.c index 8c3fb76..ed14db9 100644 --- a/avr/command_tbl.c +++ b/avr/command_tbl.c @@ -284,7 +284,7 @@ CMD_TBL_ITEM( "[-bwl] address value [count]\n" " -b write value as byte (8 bit, default)\n" " -w write value as word (16 bit)\n" - " -l write value as long (32 bit)\n" + " -l write value as long (32 bit)" ), CMD_TBL_ITEM( cp, 4, 1, do_mem_cp, @@ -330,9 +330,12 @@ CMD_TBL_ITEM( "address count delay(ms)" ), CMD_TBL_ITEM( - mwc, 4, 1, do_mem_mdc, + mwc, CONFIG_SYS_MAXARGS, 1, do_mem_mdc, "memory write cyclic", - "address value delay(ms)" + "[-bwl] address value delay(ms)\n" + " -b write value as byte (8 bit, default)\n" + " -w write value as word (16 bit)\n" + " -l write value as long (32 bit)" ), #endif /* CONFIG_MX_CYCLIC */ diff --git a/avr/eval_arg.c b/avr/eval_arg.c new file mode 100644 index 0000000..020dd98 --- /dev/null +++ b/avr/eval_arg.c @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2016 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "eval_arg.h" +#include "common.h" +#include +#include +#include +#include "print-utils.h" +#include "command.h" /* jump_buf */ + +static jmp_buf eval_jbuf; +static char ch; +static char *start_p; +static char *bp; + + +static long expr(void); + +static void print_error_pos(void) +{ + printf_P(PSTR("Arg: '%s'\n" + " "), start_p); + print_blanks(bp - start_p); + my_puts_P(PSTR("^syntax error!\n")); +} + +static void error (void) +{ + --bp; + longjmp (eval_jbuf, 1); +} + +static void next(void) +{ + do + ch = *bp++; + while (ch == ' ' || ch == '\n'); +} + +static long number (void) +{ + int base = 16; + char *end_p; + long n; + + if (ch == '$') { /* FIXME: should be '#' */ + next(); + base = 10; + } + if (!isdigit(ch) && !(base == 16 && isxdigit(ch))) + error (); + + n = strtoul(bp - 1, &end_p, base); + + if (end_p == bp - 1) + error(); + bp = end_p; + next(); + + return n; +} + +static long factor (void) +{ + long f; + + if (ch == '(') + { + next(); + f = expr(); + if (ch == ')') + next(); + else + error (); + } + else + f = number (); + + return f; +} + +static long term (void) +{ + long t = factor(); + + for (;;) + switch (ch) { + case '*': + next(); + t *= factor(); + break; + case '/': + next(); + t /= factor(); + break; + case '%': + next(); + t %= factor(); + break; + default: + return t; + } +} + + +static long expr(void) +{ + long e; + + if (ch == '+') { + next(); + e = term (); + } else if (ch == '-') { + next(); + e = - term (); + } else + e = term (); + + while (ch == '+' || ch == '-') { + char op = ch; + next(); + if (op == '-') + e -= term (); + else + e += term (); + } + return e; +} + +long eval_arg(char *arg, char **end_ptr) +{ + long val; + + start_p = arg; + bp = arg; + next(); + if (setjmp (eval_jbuf) != 0) { + if (!end_ptr) { + print_error_pos(); + longjmp(cmd_jbuf, 1); + } + val = -1; + } else { + val = expr (); + --bp; + } + + if (!end_ptr) { + if (*bp != '\0') { + print_error_pos(); + longjmp(cmd_jbuf, 1); + } + } else + *end_ptr = bp; + + return val; +} diff --git a/include/command.h b/include/command.h index db469e3..9ca460d 100644 --- a/include/command.h +++ b/include/command.h @@ -15,6 +15,7 @@ #include "common.h" #include "config.h" +#include #ifndef NULL #define NULL 0 @@ -160,5 +161,7 @@ typedef command_ret_t (*do_cmd_t)(cmd_tbl_t *, int, int, char * const []); extern cmd_tbl_t cmd_tbl[]; +extern jmp_buf cmd_jbuf; + #endif /* __COMMAND_H */ diff --git a/include/eval_arg.h b/include/eval_arg.h new file mode 100644 index 0000000..a86b0d5 --- /dev/null +++ b/include/eval_arg.h @@ -0,0 +1,19 @@ +/* + * (C) Copyright 2016 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef EVAL_ARG_H +#define EVAL_ARG_H + +/** + * eval_arg() - evaluate a command argument expression + * + * @arg: pointer to argument (usually argv[i]) + * @end_ptr: pointer to position, where evaluation stopped. Points to '\0' if no error. + * @return evaluated argument + */ +long eval_arg(char *arg, char **end_ptr); + +#endif /* EVAL_ARG_H */ -- 2.39.2