diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2023-10-02 15:24:06 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2023-10-02 15:24:06 +0200 |
commit | 92ab29fcf04bc3ff3d3ad897f1c2463d8b8d1410 (patch) | |
tree | e55cbae26eec69ff6bc05ac73ed892f14c71a8f0 /editors/awk.c | |
parent | 6d22c9abc29d43e919e819ff004fcd84a90de60b (diff) | |
download | busybox-w32-92ab29fcf04bc3ff3d3ad897f1c2463d8b8d1410.tar.gz busybox-w32-92ab29fcf04bc3ff3d3ad897f1c2463d8b8d1410.tar.bz2 busybox-w32-92ab29fcf04bc3ff3d3ad897f1c2463d8b8d1410.zip |
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>
Diffstat (limited to '')
-rw-r--r-- | editors/awk.c | 113 |
1 files 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 @@ | |||
40 | //usage:#define awk_full_usage "\n\n" | 40 | //usage:#define awk_full_usage "\n\n" |
41 | //usage: " -v VAR=VAL Set variable" | 41 | //usage: " -v VAR=VAL Set variable" |
42 | //usage: "\n -F SEP Use SEP as field separator" | 42 | //usage: "\n -F SEP Use SEP as field separator" |
43 | //usage: "\n -f FILE Read program from FILE" | 43 | //usage: "\n -f/-E FILE Read program from FILE" |
44 | //usage: IF_FEATURE_AWK_GNU_EXTENSIONS( | 44 | //usage: IF_FEATURE_AWK_GNU_EXTENSIONS( |
45 | //usage: "\n -e AWK_PROGRAM" | 45 | //usage: "\n -e AWK_PROGRAM" |
46 | //usage: ) | 46 | //usage: ) |
@@ -76,8 +76,8 @@ | |||
76 | * 1: -argz | 76 | * 1: -argz |
77 | */ | 77 | */ |
78 | #define OPTSTR_AWK "+" \ | 78 | #define OPTSTR_AWK "+" \ |
79 | "F:v:*f:*" \ | 79 | "F:v:f:" \ |
80 | IF_FEATURE_AWK_GNU_EXTENSIONS("e:*") \ | 80 | IF_FEATURE_AWK_GNU_EXTENSIONS("e:E:") \ |
81 | "W:" | 81 | "W:" |
82 | enum { | 82 | enum { |
83 | OPTBIT_F, /* define field separator */ | 83 | OPTBIT_F, /* define field separator */ |
@@ -560,6 +560,7 @@ struct globals { | |||
560 | var *Fields; | 560 | var *Fields; |
561 | char *g_pos; | 561 | char *g_pos; |
562 | char g_saved_ch; | 562 | char g_saved_ch; |
563 | smallint got_program; | ||
563 | smallint icase; | 564 | smallint icase; |
564 | smallint exiting; | 565 | smallint exiting; |
565 | smallint nextrec; | 566 | smallint nextrec; |
@@ -635,6 +636,7 @@ struct globals2 { | |||
635 | #define Fields (G1.Fields ) | 636 | #define Fields (G1.Fields ) |
636 | #define g_pos (G1.g_pos ) | 637 | #define g_pos (G1.g_pos ) |
637 | #define g_saved_ch (G1.g_saved_ch ) | 638 | #define g_saved_ch (G1.g_saved_ch ) |
639 | #define got_program (G1.got_program ) | ||
638 | #define icase (G1.icase ) | 640 | #define icase (G1.icase ) |
639 | #define exiting (G1.exiting ) | 641 | #define exiting (G1.exiting ) |
640 | #define nextrec (G1.nextrec ) | 642 | #define nextrec (G1.nextrec ) |
@@ -2899,11 +2901,13 @@ static int next_input_file(void) | |||
2899 | } | 2901 | } |
2900 | fname = getvar_s(findvar(iamarray(intvar[ARGV]), utoa(argind))); | 2902 | fname = getvar_s(findvar(iamarray(intvar[ARGV]), utoa(argind))); |
2901 | if (fname && *fname) { | 2903 | if (fname && *fname) { |
2902 | /* "If a filename on the command line has the form | 2904 | if (got_program != 2) { /* there was no -E option */ |
2903 | * var=val it is treated as a variable assignment" | 2905 | /* "If a filename on the command line has the form |
2904 | */ | 2906 | * var=val it is treated as a variable assignment" |
2905 | if (try_to_assign(fname)) | 2907 | */ |
2906 | continue; | 2908 | if (try_to_assign(fname)) |
2909 | continue; | ||
2910 | } | ||
2907 | iF.F = xfopen_stdin(fname); | 2911 | iF.F = xfopen_stdin(fname); |
2908 | setvar_i(intvar[ARGIND], argind); | 2912 | setvar_i(intvar[ARGIND], argind); |
2909 | break; | 2913 | break; |
@@ -3659,13 +3663,7 @@ static int awk_exit(void) | |||
3659 | int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 3663 | int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
3660 | int awk_main(int argc UNUSED_PARAM, char **argv) | 3664 | int awk_main(int argc UNUSED_PARAM, char **argv) |
3661 | { | 3665 | { |
3662 | unsigned opt; | 3666 | int ch; |
3663 | char *opt_F; | ||
3664 | llist_t *list_v = NULL; | ||
3665 | llist_t *list_f = NULL; | ||
3666 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS | ||
3667 | llist_t *list_e = NULL; | ||
3668 | #endif | ||
3669 | int i; | 3667 | int i; |
3670 | 3668 | ||
3671 | INIT_G(); | 3669 | INIT_G(); |
@@ -3714,49 +3712,68 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3714 | } | 3712 | } |
3715 | } | 3713 | } |
3716 | } | 3714 | } |
3717 | opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL); | ||
3718 | argv += optind; | ||
3719 | //argc -= optind; | ||
3720 | if (opt & OPT_W) | ||
3721 | bb_simple_error_msg("warning: option -W is ignored"); | ||
3722 | if (opt & OPT_F) { | ||
3723 | unescape_string_in_place(opt_F); | ||
3724 | setvar_s(intvar[FS], opt_F); | ||
3725 | } | ||
3726 | while (list_v) { | ||
3727 | if (!try_to_assign(llist_pop(&list_v))) | ||
3728 | bb_show_usage(); | ||
3729 | } | ||
3730 | 3715 | ||
3731 | /* Parse all supplied programs */ | ||
3732 | fnhash = hash_init(); | 3716 | fnhash = hash_init(); |
3733 | ahash = hash_init(); | 3717 | ahash = hash_init(); |
3734 | while (list_f) { | ||
3735 | int fd; | ||
3736 | char *s; | ||
3737 | 3718 | ||
3738 | g_progname = llist_pop(&list_f); | 3719 | /* Cannot use getopt32: need to preserve order of -e / -f / -E / -i */ |
3739 | fd = xopen_stdin(g_progname); | 3720 | while ((ch = getopt(argc, argv, OPTSTR_AWK)) >= 0) { |
3740 | s = xmalloc_read(fd, NULL); /* it's NUL-terminated */ | 3721 | switch (ch) { |
3741 | if (!s) | 3722 | case 'F': |
3742 | bb_perror_msg_and_die("read error from '%s'", g_progname); | 3723 | unescape_string_in_place(optarg); |
3743 | close(fd); | 3724 | setvar_s(intvar[FS], optarg); |
3744 | parse_program(s); | 3725 | break; |
3745 | free(s); | 3726 | case 'v': |
3746 | } | 3727 | if (!try_to_assign(optarg)) |
3747 | g_progname = "cmd. line"; | 3728 | bb_show_usage(); |
3729 | break; | ||
3730 | //TODO: implement -i LIBRARY, it is easy-ish | ||
3731 | case 'E': | ||
3732 | case 'f': { | ||
3733 | int fd; | ||
3734 | char *s; | ||
3735 | g_progname = optarg; | ||
3736 | fd = xopen_stdin(g_progname); | ||
3737 | s = xmalloc_read(fd, NULL); /* it's NUL-terminated */ | ||
3738 | if (!s) | ||
3739 | bb_perror_msg_and_die("read error from '%s'", g_progname); | ||
3740 | close(fd); | ||
3741 | parse_program(s); | ||
3742 | free(s); | ||
3743 | got_program = 1; | ||
3744 | if (ch == 'E') { | ||
3745 | got_program = 2; | ||
3746 | goto stop_option_parsing; | ||
3747 | } | ||
3748 | break; | ||
3749 | } | ||
3748 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS | 3750 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS |
3749 | while (list_e) { | 3751 | case 'e': |
3750 | parse_program(llist_pop(&list_e)); | 3752 | g_progname = "cmd. line"; |
3751 | } | 3753 | parse_program(optarg); |
3754 | got_program = 1; | ||
3755 | break; | ||
3752 | #endif | 3756 | #endif |
3753 | //FIXME: preserve order of -e and -f | 3757 | case 'W': |
3754 | //TODO: implement -i LIBRARY and -E FILE too, they are easy-ish | 3758 | bb_simple_error_msg("warning: option -W is ignored"); |
3755 | if (!(opt & (OPT_f | OPT_e))) { | 3759 | break; |
3760 | default: | ||
3761 | //bb_error_msg("ch:%d", ch); | ||
3762 | bb_show_usage(); | ||
3763 | } | ||
3764 | } | ||
3765 | stop_option_parsing: | ||
3766 | |||
3767 | argv += optind; | ||
3768 | //argc -= optind; | ||
3769 | |||
3770 | if (!got_program) { | ||
3756 | if (!*argv) | 3771 | if (!*argv) |
3757 | bb_show_usage(); | 3772 | bb_show_usage(); |
3773 | g_progname = "cmd. line"; | ||
3758 | parse_program(*argv++); | 3774 | parse_program(*argv++); |
3759 | } | 3775 | } |
3776 | |||
3760 | /* Free unused parse structures */ | 3777 | /* Free unused parse structures */ |
3761 | //hash_free(fnhash); // ~250 bytes when empty, used only for function names | 3778 | //hash_free(fnhash); // ~250 bytes when empty, used only for function names |
3762 | //^^^^^^^^^^^^^^^^^ does not work, hash_clear() inside SEGVs | 3779 | //^^^^^^^^^^^^^^^^^ does not work, hash_clear() inside SEGVs |