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 <vda.linux@googlemail.com>
master
Denys Vlasenko 2023-10-02 15:24:06 +02:00
parent 6d22c9abc2
commit 92ab29fcf0
1 changed files with 65 additions and 48 deletions

View File

@ -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