[git commit] awk: implement -E; do not reorder -f and -e

Denys Vlasenko vda.linux at googlemail.com
Mon Oct 2 13:24:06 UTC 2023


commit: https://git.busybox.net/busybox/commit/?id=92ab29fcf04bc3ff3d3ad897f1c2463d8b8d1410
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at googlemail.com>
---
 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


More information about the busybox-cvs mailing list