From 92ab29fcf04bc3ff3d3ad897f1c2463d8b8d1410 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 2 Oct 2023 15:24:06 +0200 Subject: awk: implement -E; do not reorder -f and -e function old new delta awk_main 843 891 +48 next_input_file 243 261 +18 packed_usage 34631 34638 +7 .rodata 105391 105390 -1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/1 up/down: 73/-1) Total: 72 bytes Signed-off-by: Denys Vlasenko --- editors/awk.c | 113 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 65 insertions(+), 48 deletions(-) diff --git a/editors/awk.c b/editors/awk.c index efdff2778..bc95c4155 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -40,7 +40,7 @@ //usage:#define awk_full_usage "\n\n" //usage: " -v VAR=VAL Set variable" //usage: "\n -F SEP Use SEP as field separator" -//usage: "\n -f FILE Read program from FILE" +//usage: "\n -f/-E FILE Read program from FILE" //usage: IF_FEATURE_AWK_GNU_EXTENSIONS( //usage: "\n -e AWK_PROGRAM" //usage: ) @@ -76,8 +76,8 @@ * 1: -argz */ #define OPTSTR_AWK "+" \ - "F:v:*f:*" \ - IF_FEATURE_AWK_GNU_EXTENSIONS("e:*") \ + "F:v:f:" \ + IF_FEATURE_AWK_GNU_EXTENSIONS("e:E:") \ "W:" enum { OPTBIT_F, /* define field separator */ @@ -560,6 +560,7 @@ struct globals { var *Fields; char *g_pos; char g_saved_ch; + smallint got_program; smallint icase; smallint exiting; smallint nextrec; @@ -635,6 +636,7 @@ struct globals2 { #define Fields (G1.Fields ) #define g_pos (G1.g_pos ) #define g_saved_ch (G1.g_saved_ch ) +#define got_program (G1.got_program ) #define icase (G1.icase ) #define exiting (G1.exiting ) #define nextrec (G1.nextrec ) @@ -2899,11 +2901,13 @@ static int next_input_file(void) } fname = getvar_s(findvar(iamarray(intvar[ARGV]), utoa(argind))); if (fname && *fname) { - /* "If a filename on the command line has the form - * var=val it is treated as a variable assignment" - */ - if (try_to_assign(fname)) - continue; + if (got_program != 2) { /* there was no -E option */ + /* "If a filename on the command line has the form + * var=val it is treated as a variable assignment" + */ + if (try_to_assign(fname)) + continue; + } iF.F = xfopen_stdin(fname); setvar_i(intvar[ARGIND], argind); break; @@ -3659,13 +3663,7 @@ static int awk_exit(void) int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int awk_main(int argc UNUSED_PARAM, char **argv) { - unsigned opt; - char *opt_F; - llist_t *list_v = NULL; - llist_t *list_f = NULL; -#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS - llist_t *list_e = NULL; -#endif + int ch; int i; INIT_G(); @@ -3714,49 +3712,68 @@ int awk_main(int argc UNUSED_PARAM, char **argv) } } } - opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL); - argv += optind; - //argc -= optind; - if (opt & OPT_W) - bb_simple_error_msg("warning: option -W is ignored"); - if (opt & OPT_F) { - unescape_string_in_place(opt_F); - setvar_s(intvar[FS], opt_F); - } - while (list_v) { - if (!try_to_assign(llist_pop(&list_v))) - bb_show_usage(); - } - /* Parse all supplied programs */ fnhash = hash_init(); ahash = hash_init(); - while (list_f) { - int fd; - char *s; - g_progname = llist_pop(&list_f); - fd = xopen_stdin(g_progname); - s = xmalloc_read(fd, NULL); /* it's NUL-terminated */ - if (!s) - bb_perror_msg_and_die("read error from '%s'", g_progname); - close(fd); - parse_program(s); - free(s); - } - g_progname = "cmd. line"; + /* Cannot use getopt32: need to preserve order of -e / -f / -E / -i */ + while ((ch = getopt(argc, argv, OPTSTR_AWK)) >= 0) { + switch (ch) { + case 'F': + unescape_string_in_place(optarg); + setvar_s(intvar[FS], optarg); + break; + case 'v': + if (!try_to_assign(optarg)) + bb_show_usage(); + break; +//TODO: implement -i LIBRARY, it is easy-ish + case 'E': + case 'f': { + int fd; + char *s; + g_progname = optarg; + fd = xopen_stdin(g_progname); + s = xmalloc_read(fd, NULL); /* it's NUL-terminated */ + if (!s) + bb_perror_msg_and_die("read error from '%s'", g_progname); + close(fd); + parse_program(s); + free(s); + got_program = 1; + if (ch == 'E') { + got_program = 2; + goto stop_option_parsing; + } + break; + } #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS - while (list_e) { - parse_program(llist_pop(&list_e)); - } + case 'e': + g_progname = "cmd. line"; + parse_program(optarg); + got_program = 1; + break; #endif -//FIXME: preserve order of -e and -f -//TODO: implement -i LIBRARY and -E FILE too, they are easy-ish - if (!(opt & (OPT_f | OPT_e))) { + case 'W': + bb_simple_error_msg("warning: option -W is ignored"); + break; + default: +//bb_error_msg("ch:%d", ch); + bb_show_usage(); + } + } + stop_option_parsing: + + argv += optind; + //argc -= optind; + + if (!got_program) { if (!*argv) bb_show_usage(); + g_progname = "cmd. line"; parse_program(*argv++); } + /* Free unused parse structures */ //hash_free(fnhash); // ~250 bytes when empty, used only for function names //^^^^^^^^^^^^^^^^^ does not work, hash_clear() inside SEGVs -- cgit v1.2.3