On Thu, 20 Aug 2026 at 22:55, Rob Landley via busybox <[email protected]> wrote: > > On 8/6/26 21:30, G. Branden Robinson via busybox wrote: > > [looping in busybox mailing list; Bruno found a sed portability problem] > > > > Background: > > https://savannah.gnu.org/bugs/?68601 > > > > Hi Bruno, > > > > At 2026-08-06T18:07:55+0200, Bruno Haible wrote: > >> I wrote: > >>> The reason is that the 'sed' program on this platform (from BusyBox) > >>> ignores '-e' options when a '-f' option is present, regardless > >>> whether the '-e' options come before or after the '-f' option. > > Which apparently nobody noticed for 20 years.
Or nobody cared about it for 20 years, which is apparently the same thing but it isn't. sed.c: POSIX compliance fix about '-f' with '-e' ordered options v3 https://github.com/robang74/busybox/commit/825b8f85af52adfe14bc07eb3aaff5fcc50a7070 sed.c: POSIX compliance fix about '-f' with '-e' ordered options v2 https://github.com/robang74/busybox/commit/d1f50a14db96968d4ecc1cb042dfb83bd2cd6a01 Are these two solving the problem? Best regards, -- Roberto A. Foglietta +49.176.274.75.661 +39.349.33.30.697
From 825b8f85af52adfe14bc07eb3aaff5fcc50a7070 Mon Sep 17 00:00:00 2001 From: "Roberto A. Foglietta" <[email protected]> Date: Mon, 17 Aug 2026 08:57:33 +0200 Subject: [PATCH 2/9] sed.c: POSIX compliance fix about '-f' with '-e' ordered options v3 goal: Processing '-e' and '-f' options in command line order for achieving the POSIX compliance as expected by the command line. how: The getopt32long stores them in separate lists, losing their relative order. We determine which appeared first by finding which argv[] element each optarg points into. bug: - https://savannah.gnu.org/bugs/?68601 fix: text data bss dec hex filename 7352 0 0 7352 1cb8 editors/sed.o 7441 0 0 7441 1d11 editors/sed.o v1 7465 0 0 7465 1d29 editors/sed.o v2 7508 0 0 7508 1d54 editors/sed.o v3 +156 v1 --> v2: - from string comparison to a more compatct options check v2 --> v3: - what about -nre? or -nve? uncommon but lecit and broken, fixed requires: - sed.c: POSIX compliance fix about '-f' with '-e' ordered options v2 todo: - test in testsuite - footprint reduction Signed-off-by: Roberto A. Foglietta <[email protected]> --- editors/sed.c | 57 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/editors/sed.c b/editors/sed.c index 9d14294fb..4dd89fa8d 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -1528,7 +1528,7 @@ static void add_cmd_block(char *cmdstr) int sed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sed_main(int argc UNUSED_PARAM, char **argv) { - unsigned opt, i; + unsigned opt; llist_t *opt_e, *opt_f; char *opt_i; @@ -1568,36 +1568,51 @@ int sed_main(int argc UNUSED_PARAM, char **argv) sed_longopts, &opt_i, &opt_e, &opt_f, &G.be_quiet); /* counter for -n */ - - - /* Process -e and -f options in command line order. - * getopt32long stores them in separate lists, losing - * their relative order. We re-scan argv to preserve it. + /* + * RAF: process -e and -f options in command line order. + * The getopt32long stores them in separate lists, losing + * their relative order. We determine which appeared first + * by finding which argv[] element each optarg points into. */ - for (i = 1; i < optind; i++) - { - char *p = argv[i], c = *p; - if (c != '-' || !*++p) //'-' - continue; - if (*p == '-' && !*++p) //'--' - continue; - c = *p; - if (c == 'e' && opt_e) { - add_cmd_block(llist_pop(&opt_e)); + while (opt_e || opt_f) { + int use_e = 1; + if (opt_e && opt_f) { + int i, idx_e = optind, idx_f = optind; + for (i = 1; i < optind; i++) { + char *end = argv[i] + strlen(argv[i]); + if (idx_e == optind + && opt_e->data >= argv[i] + && opt_e->data <= end + ){ + idx_e = i; + } + if (idx_f == optind + && opt_f->data >= argv[i] + && opt_f->data <= end + ){ + idx_f = i; + } + } + if (idx_f < idx_e) { + use_e = 0; + } } else - if (c == 'f' && opt_f) { + if (!opt_e) { + use_e = 0; + } + if (use_e) { + add_cmd_block(llist_pop(&opt_e)); + } else { char *line; FILE *cmdfile = xfopen_stdin(llist_pop(&opt_f)); - while ( (line = xmalloc_fgetline(cmdfile)) ) { + while ((line = xmalloc_fgetline(cmdfile)) != NULL) { add_cmd(line); free(line); } fclose_if_not_stdin(cmdfile); - } + } } - llist_free(opt_e, free); - llist_free(opt_f, free); //argc -= optind; argv += optind; -- 2.34.1
From d1f50a14db96968d4ecc1cb042dfb83bd2cd6a01 Mon Sep 17 00:00:00 2001 From: "Roberto A. Foglietta" <[email protected]> Date: Mon, 17 Aug 2026 07:38:13 +0200 Subject: [PATCH 1/9] sed.c: POSIX compliance fix about '-f' with '-e' ordered options v2 bug found: - https://savannah.gnu.org/bugs/?68601 fix size: text data bss dec hex filename 7352 0 0 7352 1cb8 editors/sed.o 7441 0 0 7441 1d11 editors/sed.o v1 7465 0 0 7465 1d29 editors/sed.o v2 +113 regression: - what about -nre? or -nve? uncommon but lecit and broken Signed-off-by: Roberto A. Foglietta <[email protected]> --- editors/sed.c | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/editors/sed.c b/editors/sed.c index 029e9b8e7..9d14294fb 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -1528,7 +1528,7 @@ static void add_cmd_block(char *cmdstr) int sed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sed_main(int argc UNUSED_PARAM, char **argv) { - unsigned opt; + unsigned opt, i; llist_t *opt_e, *opt_f; char *opt_i; @@ -1568,6 +1568,37 @@ int sed_main(int argc UNUSED_PARAM, char **argv) sed_longopts, &opt_i, &opt_e, &opt_f, &G.be_quiet); /* counter for -n */ + + + /* Process -e and -f options in command line order. + * getopt32long stores them in separate lists, losing + * their relative order. We re-scan argv to preserve it. + */ + for (i = 1; i < optind; i++) + { + char *p = argv[i], c = *p; + if (c != '-' || !*++p) //'-' + continue; + if (*p == '-' && !*++p) //'--' + continue; + c = *p; + if (c == 'e' && opt_e) { + add_cmd_block(llist_pop(&opt_e)); + } + else + if (c == 'f' && opt_f) { + char *line; + FILE *cmdfile = xfopen_stdin(llist_pop(&opt_f)); + while ( (line = xmalloc_fgetline(cmdfile)) ) { + add_cmd(line); + free(line); + } + fclose_if_not_stdin(cmdfile); + } + } + llist_free(opt_e, free); + llist_free(opt_f, free); + //argc -= optind; argv += optind; if (opt & OPT_in_place) { // -i @@ -1577,19 +1608,7 @@ int sed_main(int argc UNUSED_PARAM, char **argv) G.regex_type |= REG_EXTENDED; // -r or -E //if (opt & 8) // G.be_quiet++; // -n (implemented with a counter instead) - while (opt_e) { // -e - add_cmd_block(llist_pop(&opt_e)); - } - while (opt_f) { // -f - char *line; - FILE *cmdfile; - cmdfile = xfopen_stdin(llist_pop(&opt_f)); - while ((line = xmalloc_fgetline(cmdfile)) != NULL) { - add_cmd(line); - free(line); - } - fclose_if_not_stdin(cmdfile); - } + /* if we didn't get a pattern from -e or -f, use argv[0] */ if (!(opt & 0x30)) { if (!*argv) -- 2.34.1
