diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-09 19:16:15 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-09 19:16:15 +0000 |
commit | 05d3b7cc0de2283f149b07196f1ca0557c062323 (patch) | |
tree | 4bd8a4d447086c3aebc675400d3925806adf2520 | |
parent | 1943aec2ec390d9fda159aa0412362780ec83f09 (diff) | |
download | busybox-w32-05d3b7cc0de2283f149b07196f1ca0557c062323.tar.gz busybox-w32-05d3b7cc0de2283f149b07196f1ca0557c062323.tar.bz2 busybox-w32-05d3b7cc0de2283f149b07196f1ca0557c062323.zip |
hush: deal with some easier TODOs
function old new delta
is_well_formed_var_name - 87 +87
builtin_read 49 86 +37
die_if_script - 31 +31
syntax_error_unterminated - 28 +28
syntax_error 26 51 +25
done_word 768 788 +20
syntax_error_at - 12 +12
parse_stream_dquoted 320 328 +8
expand_variables 2064 2063 -1
run_list 1225 1220 -5
add_till_closing_paren 308 303 -5
add_till_backquote 111 106 -5
handle_dollar 812 803 -9
parse_stream 2378 2356 -22
parse_redirect 408 372 -36
maybe_die 44 - -44
is_assignment 215 134 -81
------------------------------------------------------------------------------
(add/remove: 4/1 grow/shrink: 4/8 up/down: 248/-208) Total: 40 bytes
-rw-r--r-- | shell/hush.c | 289 | ||||
-rw-r--r-- | shell/hush_test/hush-arith/arith.right | 54 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/param_expand_assign.right | 8 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/param_expand_indicate_error.right | 10 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/param_expand_indicate_error.tests | 10 |
5 files changed, 214 insertions, 157 deletions
diff --git a/shell/hush.c b/shell/hush.c index 4c2716ddd..41d65ff69 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -65,8 +65,6 @@ | |||
65 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. | 65 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. |
66 | */ | 66 | */ |
67 | #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ | 67 | #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ |
68 | //TODO: pull in some .h and find out whether we have SINGLE_APPLET_MAIN? | ||
69 | //#include "applet_tables.h" doesn't work | ||
70 | #include <glob.h> | 68 | #include <glob.h> |
71 | /* #include <dmalloc.h> */ | 69 | /* #include <dmalloc.h> */ |
72 | #if ENABLE_HUSH_CASE | 70 | #if ENABLE_HUSH_CASE |
@@ -80,11 +78,18 @@ | |||
80 | 78 | ||
81 | 79 | ||
82 | /* Debug build knobs */ | 80 | /* Debug build knobs */ |
83 | //#define LEAK_HUNTING 1 | 81 | #define LEAK_HUNTING 0 |
84 | //#define WANT_TO_TEST_NOMMU 1 | 82 | #define BUILD_AS_NOMMU 0 |
83 | /* Enable/disable sanity checks. Ok to enable in production, | ||
84 | * only adds a bit of bloat. Set to >1 to get non-production level verbosity. | ||
85 | * Keeping 1 for now even in released versions. | ||
86 | */ | ||
87 | #define HUSH_DEBUG 1 | ||
88 | /* In progress... */ | ||
89 | #define ENABLE_HUSH_FUNCTIONS 0 | ||
85 | 90 | ||
86 | 91 | ||
87 | #ifdef WANT_TO_TEST_NOMMU | 92 | #if BUILD_AS_NOMMU |
88 | # undef BB_MMU | 93 | # undef BB_MMU |
89 | # undef USE_FOR_NOMMU | 94 | # undef USE_FOR_NOMMU |
90 | # undef USE_FOR_MMU | 95 | # undef USE_FOR_MMU |
@@ -122,15 +127,6 @@ | |||
122 | #define IF_HAS_NO_KEYWORDS(...) __VA_ARGS__ | 127 | #define IF_HAS_NO_KEYWORDS(...) __VA_ARGS__ |
123 | #endif | 128 | #endif |
124 | 129 | ||
125 | /* Enable/disable sanity checks. Ok to enable in production, | ||
126 | * only adds a bit of bloat. | ||
127 | * Keeping unconditionally on for now. | ||
128 | */ | ||
129 | #define HUSH_DEBUG 1 | ||
130 | /* In progress... */ | ||
131 | #define ENABLE_HUSH_FUNCTIONS 0 | ||
132 | |||
133 | |||
134 | /* If you comment out one of these below, it will be #defined later | 130 | /* If you comment out one of these below, it will be #defined later |
135 | * to perform debug printfs to stderr: */ | 131 | * to perform debug printfs to stderr: */ |
136 | #define debug_printf(...) do {} while (0) | 132 | #define debug_printf(...) do {} while (0) |
@@ -216,40 +212,6 @@ static void debug_print_strings(const char *prefix, char **vv) | |||
216 | #define debug_print_strings(prefix, vv) ((void)0) | 212 | #define debug_print_strings(prefix, vv) ((void)0) |
217 | #endif | 213 | #endif |
218 | 214 | ||
219 | /* | ||
220 | * Leak hunting. Use hush_leaktool.sh for post-processing. | ||
221 | */ | ||
222 | #ifdef LEAK_HUNTING | ||
223 | static void *xxmalloc(int lineno, size_t size) | ||
224 | { | ||
225 | void *ptr = xmalloc((size + 0xff) & ~0xff); | ||
226 | fdprintf(2, "line %d: malloc %p\n", lineno, ptr); | ||
227 | return ptr; | ||
228 | } | ||
229 | static void *xxrealloc(int lineno, void *ptr, size_t size) | ||
230 | { | ||
231 | ptr = xrealloc(ptr, (size + 0xff) & ~0xff); | ||
232 | fdprintf(2, "line %d: realloc %p\n", lineno, ptr); | ||
233 | return ptr; | ||
234 | } | ||
235 | static char *xxstrdup(int lineno, const char *str) | ||
236 | { | ||
237 | char *ptr = xstrdup(str); | ||
238 | fdprintf(2, "line %d: strdup %p\n", lineno, ptr); | ||
239 | return ptr; | ||
240 | } | ||
241 | static void xxfree(void *ptr) | ||
242 | { | ||
243 | fdprintf(2, "free %p\n", ptr); | ||
244 | free(ptr); | ||
245 | } | ||
246 | #define xmalloc(s) xxmalloc(__LINE__, s) | ||
247 | #define xrealloc(p, s) xxrealloc(__LINE__, p, s) | ||
248 | #define xstrdup(s) xxstrdup(__LINE__, s) | ||
249 | #define free(p) xxfree(p) | ||
250 | #endif | ||
251 | |||
252 | |||
253 | #define ERR_PTR ((void*)(long)1) | 215 | #define ERR_PTR ((void*)(long)1) |
254 | 216 | ||
255 | #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" | 217 | #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" |
@@ -662,28 +624,100 @@ static const struct built_in_command bltins[] = { | |||
662 | }; | 624 | }; |
663 | 625 | ||
664 | 626 | ||
665 | static void maybe_die(const char *notice, const char *msg) | 627 | /* Leak hunting. Use hush_leaktool.sh for post-processing. |
628 | */ | ||
629 | #if LEAK_HUNTING | ||
630 | static void *xxmalloc(int lineno, size_t size) | ||
631 | { | ||
632 | void *ptr = xmalloc((size + 0xff) & ~0xff); | ||
633 | fdprintf(2, "line %d: malloc %p\n", lineno, ptr); | ||
634 | return ptr; | ||
635 | } | ||
636 | static void *xxrealloc(int lineno, void *ptr, size_t size) | ||
637 | { | ||
638 | ptr = xrealloc(ptr, (size + 0xff) & ~0xff); | ||
639 | fdprintf(2, "line %d: realloc %p\n", lineno, ptr); | ||
640 | return ptr; | ||
641 | } | ||
642 | static char *xxstrdup(int lineno, const char *str) | ||
643 | { | ||
644 | char *ptr = xstrdup(str); | ||
645 | fdprintf(2, "line %d: strdup %p\n", lineno, ptr); | ||
646 | return ptr; | ||
647 | } | ||
648 | static void xxfree(void *ptr) | ||
649 | { | ||
650 | fdprintf(2, "free %p\n", ptr); | ||
651 | free(ptr); | ||
652 | } | ||
653 | #define xmalloc(s) xxmalloc(__LINE__, s) | ||
654 | #define xrealloc(p, s) xxrealloc(__LINE__, p, s) | ||
655 | #define xstrdup(s) xxstrdup(__LINE__, s) | ||
656 | #define free(p) xxfree(p) | ||
657 | #endif | ||
658 | |||
659 | |||
660 | /* Syntax and runtime errors. They always abort scripts. | ||
661 | * In interactive use they usually discard unparsed and/or unexecuted commands | ||
662 | * and return to the prompt. | ||
663 | * HUSH_DEBUG >= 2 prints line number in this file where it was detected. | ||
664 | */ | ||
665 | #if HUSH_DEBUG < 2 | ||
666 | # define die_if_script(lineno, fmt, msg) die_if_script(fmt, msg) | ||
667 | # define syntax_error(lineno, msg) syntax_error(msg) | ||
668 | # define syntax_error_at(lineno, msg) syntax_error_at(msg) | ||
669 | # define syntax_error_unterminated(lineno, ch) syntax_error_unterminated(ch) | ||
670 | #endif | ||
671 | |||
672 | static void die_if_script(unsigned lineno, const char *fmt, const char *msg) | ||
666 | { | 673 | { |
667 | /* Was using fancy stuff: | ||
668 | * (G_interactive_fd ? bb_error_msg : bb_error_msg_and_die)(...params...) | ||
669 | * but it SEGVs. ?! Oh well... explicit temp ptr works around that */ | ||
670 | void FAST_FUNC (*fp)(const char *s, ...) = bb_error_msg_and_die; | 674 | void FAST_FUNC (*fp)(const char *s, ...) = bb_error_msg_and_die; |
671 | #if ENABLE_HUSH_INTERACTIVE | 675 | #if ENABLE_HUSH_INTERACTIVE |
672 | if (G_interactive_fd) | 676 | if (G_interactive_fd) |
673 | fp = bb_error_msg; | 677 | fp = bb_error_msg; |
674 | #endif | 678 | #endif |
675 | fp(msg ? "%s: %s" : notice, notice, msg); | 679 | #if HUSH_DEBUG >= 2 |
680 | bb_error_msg("hush.c:%u", lineno); | ||
681 | #endif | ||
682 | fp(fmt, msg); | ||
683 | } | ||
684 | |||
685 | static void syntax_error(unsigned lineno, const char *msg) | ||
686 | { | ||
687 | if (msg) | ||
688 | die_if_script(lineno, "syntax error: %s", msg); | ||
689 | else | ||
690 | die_if_script(lineno, "syntax error", NULL); | ||
691 | } | ||
692 | |||
693 | static void syntax_error_at(unsigned lineno, const char *msg) | ||
694 | { | ||
695 | die_if_script(lineno, "syntax error at '%s'", msg); | ||
696 | } | ||
697 | |||
698 | static void syntax_error_unterminated(unsigned lineno, char ch) | ||
699 | { | ||
700 | char msg[2]; | ||
701 | msg[0] = ch; | ||
702 | msg[1] = '\0'; | ||
703 | die_if_script(lineno, "syntax error: unterminated %s", msg); | ||
676 | } | 704 | } |
677 | #if 1 | 705 | |
678 | #define syntax(msg) maybe_die("syntax error", msg); | 706 | #if HUSH_DEBUG < 2 |
707 | # undef die_if_script | ||
708 | # undef syntax_error | ||
709 | # undef syntax_error_at | ||
710 | # undef syntax_error_unterminated | ||
679 | #else | 711 | #else |
680 | /* Debug -- trick gcc to expand __LINE__ and convert to string */ | 712 | # define die_if_script(fmt, msg) die_if_script(__LINE__, fmt, msg) |
681 | #define __syntax(msg, line) maybe_die("syntax error hush.c:" # line, msg) | 713 | # define syntax_error(msg) syntax_error(__LINE__, msg) |
682 | #define _syntax(msg, line) __syntax(msg, line) | 714 | # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) |
683 | #define syntax(msg) _syntax(msg, __LINE__) | 715 | # define syntax_error_unterminated(ch) syntax_error_unterminated(__LINE__, ch) |
684 | #endif | 716 | #endif |
685 | 717 | ||
686 | 718 | ||
719 | /* Utility functions | ||
720 | */ | ||
687 | static int glob_needed(const char *s) | 721 | static int glob_needed(const char *s) |
688 | { | 722 | { |
689 | while (*s) { | 723 | while (*s) { |
@@ -696,14 +730,14 @@ static int glob_needed(const char *s) | |||
696 | return 0; | 730 | return 0; |
697 | } | 731 | } |
698 | 732 | ||
699 | static int is_assignment(const char *s) | 733 | static int is_well_formed_var_name(const char *s, char terminator) |
700 | { | 734 | { |
701 | if (!s || !(isalpha(*s) || *s == '_')) | 735 | if (!s || !(isalpha(*s) || *s == '_')) |
702 | return 0; | 736 | return 0; |
703 | s++; | 737 | s++; |
704 | while (isalnum(*s) || *s == '_') | 738 | while (isalnum(*s) || *s == '_') |
705 | s++; | 739 | s++; |
706 | return *s == '='; | 740 | return *s == terminator; |
707 | } | 741 | } |
708 | 742 | ||
709 | /* Replace each \x with x in place, return ptr past NUL. */ | 743 | /* Replace each \x with x in place, return ptr past NUL. */ |
@@ -747,7 +781,7 @@ static char **add_strings_to_strings(char **strings, char **add, int need_to_dup | |||
747 | v[count1 + i] = (need_to_dup ? xstrdup(add[i]) : add[i]); | 781 | v[count1 + i] = (need_to_dup ? xstrdup(add[i]) : add[i]); |
748 | return v; | 782 | return v; |
749 | } | 783 | } |
750 | #ifdef LEAK_HUNTING | 784 | #if LEAK_HUNTING |
751 | static char **xx_add_strings_to_strings(int lineno, char **strings, char **add, int need_to_dup) | 785 | static char **xx_add_strings_to_strings(int lineno, char **strings, char **add, int need_to_dup) |
752 | { | 786 | { |
753 | char **ptr = add_strings_to_strings(strings, add, need_to_dup); | 787 | char **ptr = add_strings_to_strings(strings, add, need_to_dup); |
@@ -765,7 +799,7 @@ static char **add_string_to_strings(char **strings, char *add) | |||
765 | v[1] = NULL; | 799 | v[1] = NULL; |
766 | return add_strings_to_strings(strings, v, /*dup:*/ 0); | 800 | return add_strings_to_strings(strings, v, /*dup:*/ 0); |
767 | } | 801 | } |
768 | #ifdef LEAK_HUNTING | 802 | #if LEAK_HUNTING |
769 | static char **xx_add_string_to_strings(int lineno, char **strings, char *add) | 803 | static char **xx_add_string_to_strings(int lineno, char **strings, char *add) |
770 | { | 804 | { |
771 | char **ptr = add_string_to_strings(strings, add); | 805 | char **ptr = add_string_to_strings(strings, add); |
@@ -1911,12 +1945,19 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1911 | free(exp_str); | 1945 | free(exp_str); |
1912 | 1946 | ||
1913 | if (errcode < 0) { | 1947 | if (errcode < 0) { |
1948 | const char *msg = "error in arithmetic"; | ||
1914 | switch (errcode) { | 1949 | switch (errcode) { |
1915 | case -3: maybe_die("arith", "exponent less than 0"); break; | 1950 | case -3: |
1916 | case -2: maybe_die("arith", "divide by zero"); break; | 1951 | msg = "exponent less than 0"; |
1917 | case -5: maybe_die("arith", "expression recursion loop detected"); break; | 1952 | break; |
1918 | default: maybe_die("arith", "syntax error"); break; | 1953 | case -2: |
1954 | msg = "divide by 0"; | ||
1955 | break; | ||
1956 | case -5: | ||
1957 | msg = "expression recursion loop detected"; | ||
1958 | break; | ||
1919 | } | 1959 | } |
1960 | die_if_script(msg, NULL); | ||
1920 | } | 1961 | } |
1921 | debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res); | 1962 | debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res); |
1922 | sprintf(arith_buf, arith_t_fmt, res); | 1963 | sprintf(arith_buf, arith_t_fmt, res); |
@@ -1951,7 +1992,8 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1951 | exp_save = var[exp_off]; | 1992 | exp_save = var[exp_off]; |
1952 | exp_null = exp_save == ':'; | 1993 | exp_null = exp_save == ':'; |
1953 | exp_word = var + exp_off; | 1994 | exp_word = var + exp_off; |
1954 | if (exp_null) ++exp_word; | 1995 | if (exp_null) |
1996 | ++exp_word; | ||
1955 | exp_op = *exp_word++; | 1997 | exp_op = *exp_word++; |
1956 | var[exp_off] = '\0'; | 1998 | var[exp_off] = '\0'; |
1957 | } | 1999 | } |
@@ -1995,17 +2037,28 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1995 | exp_null ? "true" : "false", exp_test); | 2037 | exp_null ? "true" : "false", exp_test); |
1996 | if (exp_test) { | 2038 | if (exp_test) { |
1997 | if (exp_op == '?') | 2039 | if (exp_op == '?') |
1998 | maybe_die(var, *exp_word ? exp_word : "parameter null or not set"); | 2040 | //TODO: what does interactive bash |
2041 | /* ${var?[error_msg_if_unset]} */ | ||
2042 | /* ${var:?[error_msg_if_unset_or_null]} */ | ||
2043 | /* mimic bash message */ | ||
2044 | if (*exp_word) { | ||
2045 | char *msg = xasprintf("%s: %s", var, exp_word); | ||
2046 | die_if_script("%s", msg); | ||
2047 | free(msg); | ||
2048 | } else { | ||
2049 | die_if_script("%s: parameter null or not set", var); | ||
2050 | } | ||
1999 | else | 2051 | else |
2000 | val = exp_word; | 2052 | val = exp_word; |
2001 | 2053 | ||
2002 | if (exp_op == '=') { | 2054 | if (exp_op == '=') { |
2055 | /* ${var=[word]} or ${var:=[word]} */ | ||
2003 | if (isdigit(var[0]) || var[0] == '#') { | 2056 | if (isdigit(var[0]) || var[0] == '#') { |
2004 | maybe_die(var, "special vars cannot assign in this way"); | 2057 | /* mimic bash message */ |
2058 | die_if_script("$%s: cannot assign in this way", var); | ||
2005 | val = NULL; | 2059 | val = NULL; |
2006 | } else { | 2060 | } else { |
2007 | char *new_var = xmalloc(strlen(var) + strlen(val) + 2); | 2061 | char *new_var = xasprintf("%s=%s", var, val); |
2008 | sprintf(new_var, "%s=%s", var, val); | ||
2009 | set_local_var(new_var, -1, 0); | 2062 | set_local_var(new_var, -1, 0); |
2010 | } | 2063 | } |
2011 | } | 2064 | } |
@@ -3280,7 +3333,7 @@ static int run_list(struct pipe *pi) | |||
3280 | continue; | 3333 | continue; |
3281 | /* current word is FOR or IN (BOLD in comments below) */ | 3334 | /* current word is FOR or IN (BOLD in comments below) */ |
3282 | if (cpipe->next == NULL) { | 3335 | if (cpipe->next == NULL) { |
3283 | syntax("malformed for"); | 3336 | syntax_error("malformed for"); |
3284 | debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); | 3337 | debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); |
3285 | return 1; | 3338 | return 1; |
3286 | } | 3339 | } |
@@ -3291,7 +3344,7 @@ static int run_list(struct pipe *pi) | |||
3291 | if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */ | 3344 | if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */ |
3292 | || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */ | 3345 | || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */ |
3293 | ) { | 3346 | ) { |
3294 | syntax("malformed for"); | 3347 | syntax_error("malformed for"); |
3295 | debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); | 3348 | debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); |
3296 | return 1; | 3349 | return 1; |
3297 | } | 3350 | } |
@@ -3443,7 +3496,7 @@ static int run_list(struct pipe *pi) | |||
3443 | break; | 3496 | break; |
3444 | } | 3497 | } |
3445 | /* Insert next value from for_lcur */ | 3498 | /* Insert next value from for_lcur */ |
3446 | //TODO: does it need escaping? | 3499 | /* note: *for_lcur already has quotes removed, $var expanded, etc */ |
3447 | pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); | 3500 | pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); |
3448 | pi->cmds[0].assignment_cnt = 1; | 3501 | pi->cmds[0].assignment_cnt = 1; |
3449 | } | 3502 | } |
@@ -3846,7 +3899,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
3846 | #endif | 3899 | #endif |
3847 | if (r->flag == 0) { /* '!' */ | 3900 | if (r->flag == 0) { /* '!' */ |
3848 | if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ | 3901 | if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ |
3849 | syntax("! ! command"); | 3902 | syntax_error("! ! command"); |
3850 | IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;) | 3903 | IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;) |
3851 | } | 3904 | } |
3852 | ctx->ctx_inverted = 1; | 3905 | ctx->ctx_inverted = 1; |
@@ -3860,7 +3913,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
3860 | initialize_context(ctx); | 3913 | initialize_context(ctx); |
3861 | ctx->stack = old; | 3914 | ctx->stack = old; |
3862 | } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { | 3915 | } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { |
3863 | syntax(word->data); | 3916 | syntax_error_at(word->data); |
3864 | ctx->ctx_res_w = RES_SNTX; | 3917 | ctx->ctx_res_w = RES_SNTX; |
3865 | return 1; | 3918 | return 1; |
3866 | } | 3919 | } |
@@ -3943,7 +3996,7 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3943 | * while if false; then false; fi; do; break; done | 3996 | * while if false; then false; fi; do; break; done |
3944 | * TODO? */ | 3997 | * TODO? */ |
3945 | if (command->group) { | 3998 | if (command->group) { |
3946 | syntax(word->data); | 3999 | syntax_error_at(word->data); |
3947 | debug_printf_parse("done_word return 1: syntax error, " | 4000 | debug_printf_parse("done_word return 1: syntax error, " |
3948 | "groups and arglists don't mix\n"); | 4001 | "groups and arglists don't mix\n"); |
3949 | return 1; | 4002 | return 1; |
@@ -4008,7 +4061,10 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
4008 | * as it is "for v; in ...". FOR and IN become two pipe structs | 4061 | * as it is "for v; in ...". FOR and IN become two pipe structs |
4009 | * in parse tree. */ | 4062 | * in parse tree. */ |
4010 | if (ctx->ctx_res_w == RES_FOR) { | 4063 | if (ctx->ctx_res_w == RES_FOR) { |
4011 | //TODO: check that command->argv[0] is a valid variable name! | 4064 | if (!is_well_formed_var_name(command->argv[0], '\0')) { |
4065 | syntax_error("malformed variable name in for"); | ||
4066 | return 1; | ||
4067 | } | ||
4012 | done_pipe(ctx, PIPE_SEQ); | 4068 | done_pipe(ctx, PIPE_SEQ); |
4013 | } | 4069 | } |
4014 | #endif | 4070 | #endif |
@@ -4091,12 +4147,6 @@ static int parse_redirect(struct parse_context *ctx, | |||
4091 | nommu_addchr(&ctx->as_string, ch); | 4147 | nommu_addchr(&ctx->as_string, ch); |
4092 | ch = i_peek(input); | 4148 | ch = i_peek(input); |
4093 | } | 4149 | } |
4094 | /* <<[-] word is the same as <<[-]word */ | ||
4095 | while (ch == ' ' || ch == '\t') { | ||
4096 | ch = i_getch(input); | ||
4097 | nommu_addchr(&ctx->as_string, ch); | ||
4098 | ch = i_peek(input); | ||
4099 | } | ||
4100 | } | 4150 | } |
4101 | 4151 | ||
4102 | if (style == REDIRECT_OVERWRITE && dup_num == -1) { | 4152 | if (style == REDIRECT_OVERWRITE && dup_num == -1) { |
@@ -4222,7 +4272,7 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_ | |||
4222 | { | 4272 | { |
4223 | struct pipe *pi = ctx->list_head; | 4273 | struct pipe *pi = ctx->list_head; |
4224 | 4274 | ||
4225 | while (pi) { | 4275 | while (pi && heredoc_cnt) { |
4226 | int i; | 4276 | int i; |
4227 | struct command *cmd = pi->cmds; | 4277 | struct command *cmd = pi->cmds; |
4228 | 4278 | ||
@@ -4238,16 +4288,12 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_ | |||
4238 | if (redir->rd_type == REDIRECT_HEREDOC) { | 4288 | if (redir->rd_type == REDIRECT_HEREDOC) { |
4239 | char *p; | 4289 | char *p; |
4240 | 4290 | ||
4241 | if (heredoc_cnt <= 0) { | ||
4242 | syntax("heredoc BUG 1"); | ||
4243 | return 1; /* error */ | ||
4244 | } | ||
4245 | redir->rd_type = REDIRECT_HEREDOC2; | 4291 | redir->rd_type = REDIRECT_HEREDOC2; |
4246 | /* redir->dup is (ab)used to indicate <<- */ | 4292 | /* redir->dup is (ab)used to indicate <<- */ |
4247 | p = fetch_till_str(&ctx->as_string, input, | 4293 | p = fetch_till_str(&ctx->as_string, input, |
4248 | redir->rd_filename, redir->rd_dup & HEREDOC_SKIPTABS); | 4294 | redir->rd_filename, redir->rd_dup & HEREDOC_SKIPTABS); |
4249 | if (!p) { | 4295 | if (!p) { |
4250 | syntax("unexpected EOF in here document"); | 4296 | syntax_error("unexpected EOF in here document"); |
4251 | return 1; | 4297 | return 1; |
4252 | } | 4298 | } |
4253 | free(redir->rd_filename); | 4299 | free(redir->rd_filename); |
@@ -4260,10 +4306,12 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_ | |||
4260 | } | 4306 | } |
4261 | pi = pi->next; | 4307 | pi = pi->next; |
4262 | } | 4308 | } |
4309 | #if 0 | ||
4263 | /* Should be 0. If it isn't, it's a parse error */ | 4310 | /* Should be 0. If it isn't, it's a parse error */ |
4264 | if (heredoc_cnt) | 4311 | if (heredoc_cnt) |
4265 | syntax("heredoc BUG 2"); | 4312 | bb_error_msg_and_die("heredoc BUG 2"); |
4266 | return heredoc_cnt; | 4313 | #endif |
4314 | return 0; | ||
4267 | } | 4315 | } |
4268 | 4316 | ||
4269 | 4317 | ||
@@ -4388,7 +4436,7 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
4388 | || dest->length /* word(... */ | 4436 | || dest->length /* word(... */ |
4389 | || dest->o_quoted /* ""(... */ | 4437 | || dest->o_quoted /* ""(... */ |
4390 | ) { | 4438 | ) { |
4391 | syntax(NULL); | 4439 | syntax_error(NULL); |
4392 | debug_printf_parse("parse_group return 1: " | 4440 | debug_printf_parse("parse_group return 1: " |
4393 | "syntax error, groups and arglists don't mix\n"); | 4441 | "syntax error, groups and arglists don't mix\n"); |
4394 | return 1; | 4442 | return 1; |
@@ -4412,7 +4460,7 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
4412 | #if !BB_MMU | 4460 | #if !BB_MMU |
4413 | free(as_string); | 4461 | free(as_string); |
4414 | #endif | 4462 | #endif |
4415 | syntax(NULL); | 4463 | syntax_error(NULL); |
4416 | debug_printf_parse("parse_group return 1: " | 4464 | debug_printf_parse("parse_group return 1: " |
4417 | "parse_stream returned %p\n", pipe_list); | 4465 | "parse_stream returned %p\n", pipe_list); |
4418 | return 1; | 4466 | return 1; |
@@ -4439,7 +4487,7 @@ static int add_till_single_quote(o_string *dest, struct in_str *input) | |||
4439 | while (1) { | 4487 | while (1) { |
4440 | int ch = i_getch(input); | 4488 | int ch = i_getch(input); |
4441 | if (ch == EOF) { | 4489 | if (ch == EOF) { |
4442 | syntax("unterminated '"); | 4490 | syntax_error_unterminated('\''); |
4443 | return 1; | 4491 | return 1; |
4444 | } | 4492 | } |
4445 | if (ch == '\'') | 4493 | if (ch == '\'') |
@@ -4453,7 +4501,7 @@ static int add_till_double_quote(o_string *dest, struct in_str *input) | |||
4453 | while (1) { | 4501 | while (1) { |
4454 | int ch = i_getch(input); | 4502 | int ch = i_getch(input); |
4455 | if (ch == EOF) { | 4503 | if (ch == EOF) { |
4456 | syntax("unterminated \""); | 4504 | syntax_error_unterminated('"'); |
4457 | return 1; | 4505 | return 1; |
4458 | } | 4506 | } |
4459 | if (ch == '"') | 4507 | if (ch == '"') |
@@ -4491,7 +4539,7 @@ static int add_till_backquote(o_string *dest, struct in_str *input) | |||
4491 | while (1) { | 4539 | while (1) { |
4492 | int ch = i_getch(input); | 4540 | int ch = i_getch(input); |
4493 | if (ch == EOF) { | 4541 | if (ch == EOF) { |
4494 | syntax("unterminated `"); | 4542 | syntax_error_unterminated('`'); |
4495 | return 1; | 4543 | return 1; |
4496 | } | 4544 | } |
4497 | if (ch == '`') | 4545 | if (ch == '`') |
@@ -4500,7 +4548,7 @@ static int add_till_backquote(o_string *dest, struct in_str *input) | |||
4500 | /* \x. Copy both chars unless it is \` */ | 4548 | /* \x. Copy both chars unless it is \` */ |
4501 | int ch2 = i_getch(input); | 4549 | int ch2 = i_getch(input); |
4502 | if (ch2 == EOF) { | 4550 | if (ch2 == EOF) { |
4503 | syntax("unterminated `"); | 4551 | syntax_error_unterminated('`'); |
4504 | return 1; | 4552 | return 1; |
4505 | } | 4553 | } |
4506 | if (ch2 != '`' && ch2 != '$' && ch2 != '\\') | 4554 | if (ch2 != '`' && ch2 != '$' && ch2 != '\\') |
@@ -4528,7 +4576,7 @@ static int add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl | |||
4528 | while (1) { | 4576 | while (1) { |
4529 | int ch = i_getch(input); | 4577 | int ch = i_getch(input); |
4530 | if (ch == EOF) { | 4578 | if (ch == EOF) { |
4531 | syntax("unterminated )"); | 4579 | syntax_error_unterminated(')'); |
4532 | return 1; | 4580 | return 1; |
4533 | } | 4581 | } |
4534 | if (ch == '(') | 4582 | if (ch == '(') |
@@ -4560,7 +4608,7 @@ static int add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl | |||
4560 | /* \x. Copy verbatim. Important for \(, \) */ | 4608 | /* \x. Copy verbatim. Important for \(, \) */ |
4561 | ch = i_getch(input); | 4609 | ch = i_getch(input); |
4562 | if (ch == EOF) { | 4610 | if (ch == EOF) { |
4563 | syntax("unterminated )"); | 4611 | syntax_error_unterminated(')'); |
4564 | return 1; | 4612 | return 1; |
4565 | } | 4613 | } |
4566 | o_addchr(dest, ch); | 4614 | o_addchr(dest, ch); |
@@ -4678,7 +4726,7 @@ static int handle_dollar(o_string *as_string, | |||
4678 | break; | 4726 | break; |
4679 | default: | 4727 | default: |
4680 | case_default: | 4728 | case_default: |
4681 | syntax("unterminated ${name}"); | 4729 | syntax_error("unterminated ${name}"); |
4682 | debug_printf_parse("handle_dollar return 1: unterminated ${name}\n"); | 4730 | debug_printf_parse("handle_dollar return 1: unterminated ${name}\n"); |
4683 | return 1; | 4731 | return 1; |
4684 | } | 4732 | } |
@@ -4783,7 +4831,7 @@ static int parse_stream_dquoted(o_string *as_string, | |||
4783 | } | 4831 | } |
4784 | /* note: can't move it above ch == dquote_end check! */ | 4832 | /* note: can't move it above ch == dquote_end check! */ |
4785 | if (ch == EOF) { | 4833 | if (ch == EOF) { |
4786 | syntax("unterminated \""); | 4834 | syntax_error_unterminated('"'); |
4787 | debug_printf_parse("parse_stream_dquoted return 1: unterminated \"\n"); | 4835 | debug_printf_parse("parse_stream_dquoted return 1: unterminated \"\n"); |
4788 | return 1; | 4836 | return 1; |
4789 | } | 4837 | } |
@@ -4794,8 +4842,9 @@ static int parse_stream_dquoted(o_string *as_string, | |||
4794 | debug_printf_parse(": ch=%c (%d) escape=%d\n", | 4842 | debug_printf_parse(": ch=%c (%d) escape=%d\n", |
4795 | ch, ch, dest->o_escape); | 4843 | ch, ch, dest->o_escape); |
4796 | if (ch == '\\') { | 4844 | if (ch == '\\') { |
4845 | //TODO: check interactive behavior | ||
4797 | if (next == EOF) { | 4846 | if (next == EOF) { |
4798 | syntax("\\<eof>"); | 4847 | syntax_error("\\<eof>"); |
4799 | debug_printf_parse("parse_stream_dquoted return 1: \\<eof>\n"); | 4848 | debug_printf_parse("parse_stream_dquoted return 1: \\<eof>\n"); |
4800 | return 1; | 4849 | return 1; |
4801 | } | 4850 | } |
@@ -4839,7 +4888,7 @@ static int parse_stream_dquoted(o_string *as_string, | |||
4839 | if (ch == '=' | 4888 | if (ch == '=' |
4840 | && (dest->o_assignment == MAYBE_ASSIGNMENT | 4889 | && (dest->o_assignment == MAYBE_ASSIGNMENT |
4841 | || dest->o_assignment == WORD_IS_KEYWORD) | 4890 | || dest->o_assignment == WORD_IS_KEYWORD) |
4842 | && is_assignment(dest->data) | 4891 | && is_well_formed_var_name(dest->data, '=') |
4843 | ) { | 4892 | ) { |
4844 | dest->o_assignment = DEFINITELY_ASSIGNMENT; | 4893 | dest->o_assignment = DEFINITELY_ASSIGNMENT; |
4845 | } | 4894 | } |
@@ -4905,7 +4954,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4905 | struct pipe *pi; | 4954 | struct pipe *pi; |
4906 | 4955 | ||
4907 | if (heredoc_cnt) { | 4956 | if (heredoc_cnt) { |
4908 | syntax("unterminated here document"); | 4957 | syntax_error("unterminated here document"); |
4909 | goto parse_error; | 4958 | goto parse_error; |
4910 | } | 4959 | } |
4911 | if (done_word(&dest, &ctx)) { | 4960 | if (done_word(&dest, &ctx)) { |
@@ -4943,7 +4992,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4943 | if ((dest.o_assignment == MAYBE_ASSIGNMENT | 4992 | if ((dest.o_assignment == MAYBE_ASSIGNMENT |
4944 | || dest.o_assignment == WORD_IS_KEYWORD) | 4993 | || dest.o_assignment == WORD_IS_KEYWORD) |
4945 | && ch == '=' | 4994 | && ch == '=' |
4946 | && is_assignment(dest.data) | 4995 | && is_well_formed_var_name(dest.data, '=') |
4947 | ) { | 4996 | ) { |
4948 | dest.o_assignment = DEFINITELY_ASSIGNMENT; | 4997 | dest.o_assignment = DEFINITELY_ASSIGNMENT; |
4949 | } | 4998 | } |
@@ -4994,7 +5043,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4994 | * We require heredoc to be in enclosing {}/(), | 5043 | * We require heredoc to be in enclosing {}/(), |
4995 | * if any. | 5044 | * if any. |
4996 | */ | 5045 | */ |
4997 | syntax("unterminated here document"); | 5046 | syntax_error("unterminated here document"); |
4998 | goto parse_error; | 5047 | goto parse_error; |
4999 | } | 5048 | } |
5000 | if (done_word(&dest, &ctx)) { | 5049 | if (done_word(&dest, &ctx)) { |
@@ -5051,7 +5100,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5051 | break; | 5100 | break; |
5052 | case '\\': | 5101 | case '\\': |
5053 | if (next == EOF) { | 5102 | if (next == EOF) { |
5054 | syntax("\\<eof>"); | 5103 | syntax_error("\\<eof>"); |
5055 | goto parse_error; | 5104 | goto parse_error; |
5056 | } | 5105 | } |
5057 | o_addchr(&dest, '\\'); | 5106 | o_addchr(&dest, '\\'); |
@@ -5074,7 +5123,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5074 | while (1) { | 5123 | while (1) { |
5075 | ch = i_getch(input); | 5124 | ch = i_getch(input); |
5076 | if (ch == EOF) { | 5125 | if (ch == EOF) { |
5077 | syntax("unterminated '"); | 5126 | syntax_error_unterminated('\''); |
5078 | goto parse_error; | 5127 | goto parse_error; |
5079 | } | 5128 | } |
5080 | nommu_addchr(&ctx.as_string, ch); | 5129 | nommu_addchr(&ctx.as_string, ch); |
@@ -5126,7 +5175,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5126 | } | 5175 | } |
5127 | #if 0 | 5176 | #if 0 |
5128 | else if (next == '(') { | 5177 | else if (next == '(') { |
5129 | syntax(">(process) not supported"); | 5178 | syntax_error(">(process) not supported"); |
5130 | goto parse_error; | 5179 | goto parse_error; |
5131 | } | 5180 | } |
5132 | #endif | 5181 | #endif |
@@ -5152,7 +5201,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5152 | } | 5201 | } |
5153 | #if 0 | 5202 | #if 0 |
5154 | else if (next == '(') { | 5203 | else if (next == '(') { |
5155 | syntax("<(process) not supported"); | 5204 | syntax_error("<(process) not supported"); |
5156 | goto parse_error; | 5205 | goto parse_error; |
5157 | } | 5206 | } |
5158 | #endif | 5207 | #endif |
@@ -5246,7 +5295,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5246 | ch = i_getch(input); | 5295 | ch = i_getch(input); |
5247 | } while (ch == ' ' || ch == '\n'); | 5296 | } while (ch == ' ' || ch == '\n'); |
5248 | if (ch != '{') { | 5297 | if (ch != '{') { |
5249 | syntax("was expecting {"); | 5298 | syntax_error("was expecting {"); |
5250 | goto parse_error; | 5299 | goto parse_error; |
5251 | } | 5300 | } |
5252 | ch = 'F'; /* magic value */ | 5301 | ch = 'F'; /* magic value */ |
@@ -5266,7 +5315,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5266 | /* proper use of this character is caught by end_trigger: | 5315 | /* proper use of this character is caught by end_trigger: |
5267 | * if we see {, we call parse_group(..., end_trigger='}') | 5316 | * if we see {, we call parse_group(..., end_trigger='}') |
5268 | * and it will match } earlier (not here). */ | 5317 | * and it will match } earlier (not here). */ |
5269 | syntax("unexpected } or )"); | 5318 | syntax_error("unexpected } or )"); |
5270 | goto parse_error; | 5319 | goto parse_error; |
5271 | default: | 5320 | default: |
5272 | if (HUSH_DEBUG) | 5321 | if (HUSH_DEBUG) |
@@ -6111,8 +6160,16 @@ static int builtin_pwd(char **argv UNUSED_PARAM) | |||
6111 | static int builtin_read(char **argv) | 6160 | static int builtin_read(char **argv) |
6112 | { | 6161 | { |
6113 | char *string; | 6162 | char *string; |
6114 | const char *name = argv[1] ? argv[1] : "REPLY"; | 6163 | const char *name = "REPLY"; |
6115 | //TODO: check that argv[1] is a valid variable name | 6164 | |
6165 | if (argv[1]) { | ||
6166 | name = argv[1]; | ||
6167 | if (!is_well_formed_var_name(name, '\0')) { | ||
6168 | /* Mimic bash message */ | ||
6169 | bb_error_msg("read: '%s': not a valid identifier", name); | ||
6170 | return 1; | ||
6171 | } | ||
6172 | } | ||
6116 | 6173 | ||
6117 | string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name), NULL); | 6174 | string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name), NULL); |
6118 | return set_local_var(string, 0, 0); | 6175 | return set_local_var(string, 0, 0); |
diff --git a/shell/hush_test/hush-arith/arith.right b/shell/hush_test/hush-arith/arith.right index a35fe893f..8cde0ee53 100644 --- a/shell/hush_test/hush-arith/arith.right +++ b/shell/hush_test/hush-arith/arith.right | |||
@@ -55,28 +55,28 @@ Format: 'expected actual' | |||
55 | 30 30 | 55 | 30 30 |
56 | 20 20 | 56 | 20 20 |
57 | 30 30 | 57 | 30 30 |
58 | hush: arith: syntax error | 58 | hush: error in arithmetic |
59 | 6 6 | 59 | 6 6 |
60 | 6,5,3 6,5,3 | 60 | 6,5,3 6,5,3 |
61 | 263 263 | 61 | 263 263 |
62 | 255 255 | 62 | 255 255 |
63 | 40 40 | 63 | 40 40 |
64 | hush: arith: syntax error | 64 | hush: error in arithmetic |
65 | hush: arith: divide by zero | 65 | hush: divide by 0 |
66 | hush: can't exec 'let': No such file or directory | 66 | hush: can't exec 'let': No such file or directory |
67 | hush: arith: syntax error | 67 | hush: error in arithmetic |
68 | hush: can't exec 'let': No such file or directory | 68 | hush: can't exec 'let': No such file or directory |
69 | abc | 69 | abc |
70 | def | 70 | def |
71 | ghi | 71 | ghi |
72 | hush: arith: syntax error | 72 | hush: error in arithmetic |
73 | 16 16 | 73 | 16 16 |
74 | hush: arith: syntax error | 74 | hush: error in arithmetic |
75 | hush: arith: syntax error | 75 | hush: error in arithmetic |
76 | hush: arith: syntax error | 76 | hush: error in arithmetic |
77 | 9 9 | 77 | 9 9 |
78 | hush: arith: syntax error | 78 | hush: error in arithmetic |
79 | hush: arith: syntax error | 79 | hush: error in arithmetic |
80 | 9 9 | 80 | 9 9 |
81 | 9 9 | 81 | 9 9 |
82 | 9 9 | 82 | 9 9 |
@@ -97,18 +97,18 @@ hush: arith: syntax error | |||
97 | 3 3 | 97 | 3 3 |
98 | 4 4 | 98 | 4 4 |
99 | 4 4 | 99 | 4 4 |
100 | hush: arith: syntax error | 100 | hush: error in arithmetic |
101 | hush: arith: syntax error | 101 | hush: error in arithmetic |
102 | hush: arith: syntax error | 102 | hush: error in arithmetic |
103 | hush: arith: syntax error | 103 | hush: error in arithmetic |
104 | hush: arith: syntax error | 104 | hush: error in arithmetic |
105 | 4 4 | 105 | 4 4 |
106 | 7 7 | 106 | 7 7 |
107 | -7 -7 | 107 | -7 -7 |
108 | hush: arith: syntax error | 108 | hush: error in arithmetic |
109 | hush: arith: syntax error | 109 | hush: error in arithmetic |
110 | hush: arith: syntax error | 110 | hush: error in arithmetic |
111 | hush: arith: syntax error | 111 | hush: error in arithmetic |
112 | 6 6 | 112 | 6 6 |
113 | 3 3 | 113 | 3 3 |
114 | 7 7 | 114 | 7 7 |
@@ -119,19 +119,19 @@ hush: arith: syntax error | |||
119 | 2 2 | 119 | 2 2 |
120 | -2 -2 | 120 | -2 -2 |
121 | 1 1 | 121 | 1 1 |
122 | hush: arith: syntax error | 122 | hush: error in arithmetic |
123 | hush: arith: syntax error | 123 | hush: error in arithmetic |
124 | hush: arith: syntax error | 124 | hush: error in arithmetic |
125 | hush: arith: syntax error | 125 | hush: error in arithmetic |
126 | hush: arith: syntax error | 126 | hush: error in arithmetic |
127 | 5 5 | 127 | 5 5 |
128 | 1 1 | 128 | 1 1 |
129 | 4 4 | 129 | 4 4 |
130 | 0 0 | 130 | 0 0 |
131 | hush: arith: syntax error | 131 | hush: error in arithmetic |
132 | hush: arith: syntax error | 132 | hush: error in arithmetic |
133 | 8 12 | 133 | 8 12 |
134 | hush: arith: syntax error | 134 | hush: error in arithmetic |
135 | 42 | 135 | 42 |
136 | 42 | 136 | 42 |
137 | 42 | 137 | 42 |
diff --git a/shell/hush_test/hush-vars/param_expand_assign.right b/shell/hush_test/hush-vars/param_expand_assign.right index fff4ead33..d5b258073 100644 --- a/shell/hush_test/hush-vars/param_expand_assign.right +++ b/shell/hush_test/hush-vars/param_expand_assign.right | |||
@@ -2,10 +2,10 @@ hush: syntax error: unterminated ${name} | |||
2 | hush: syntax error: unterminated ${name} | 2 | hush: syntax error: unterminated ${name} |
3 | 0 | 3 | 0 |
4 | 0 | 4 | 0 |
5 | hush: 1: special vars cannot assign in this way | 5 | hush: $1: cannot assign in this way |
6 | hush: 1: special vars cannot assign in this way | 6 | hush: $1: cannot assign in this way |
7 | hush: 1: special vars cannot assign in this way | 7 | hush: $1: cannot assign in this way |
8 | hush: 1: special vars cannot assign in this way | 8 | hush: $1: cannot assign in this way |
9 | _aa | 9 | _aa |
10 | _aa | 10 | _aa |
11 | _aa | 11 | _aa |
diff --git a/shell/hush_test/hush-vars/param_expand_indicate_error.right b/shell/hush_test/hush-vars/param_expand_indicate_error.right index f440f6fae..ec4908c35 100644 --- a/shell/hush_test/hush-vars/param_expand_indicate_error.right +++ b/shell/hush_test/hush-vars/param_expand_indicate_error.right | |||
@@ -5,8 +5,8 @@ hush: syntax error: unterminated ${name} | |||
5 | _ | 5 | _ |
6 | hush: 1: parameter null or not set | 6 | hush: 1: parameter null or not set |
7 | hush: 1: parameter null or not set | 7 | hush: 1: parameter null or not set |
8 | hush: 1: word | 8 | hush: 1: message1 |
9 | hush: 1: word | 9 | hush: 1: message1 |
10 | _aaaa | 10 | _aaaa |
11 | _aaaa | 11 | _aaaa |
12 | _aaaa | 12 | _aaaa |
@@ -15,13 +15,13 @@ _aaaa | |||
15 | _ | 15 | _ |
16 | hush: f: parameter null or not set | 16 | hush: f: parameter null or not set |
17 | hush: f: parameter null or not set | 17 | hush: f: parameter null or not set |
18 | hush: f: word | 18 | hush: f: message3 |
19 | hush: f: word | 19 | hush: f: message3 |
20 | _ | 20 | _ |
21 | _ | 21 | _ |
22 | hush: f: parameter null or not set | 22 | hush: f: parameter null or not set |
23 | _ | 23 | _ |
24 | hush: f: word | 24 | hush: f: message4 |
25 | _fff | 25 | _fff |
26 | _fff | 26 | _fff |
27 | _fff | 27 | _fff |
diff --git a/shell/hush_test/hush-vars/param_expand_indicate_error.tests b/shell/hush_test/hush-vars/param_expand_indicate_error.tests index 77834fedd..1f94181a9 100755 --- a/shell/hush_test/hush-vars/param_expand_indicate_error.tests +++ b/shell/hush_test/hush-vars/param_expand_indicate_error.tests | |||
@@ -12,8 +12,8 @@ | |||
12 | "$THIS_SH" -c 'set --; echo _$1' | 12 | "$THIS_SH" -c 'set --; echo _$1' |
13 | "$THIS_SH" -c 'set --; echo _${1?}' | 13 | "$THIS_SH" -c 'set --; echo _${1?}' |
14 | "$THIS_SH" -c 'set --; echo _${1:?}' | 14 | "$THIS_SH" -c 'set --; echo _${1:?}' |
15 | "$THIS_SH" -c 'set --; echo _${1?word}' | 15 | "$THIS_SH" -c 'set --; echo _${1?message1}' |
16 | "$THIS_SH" -c 'set --; echo _${1:?word}' | 16 | "$THIS_SH" -c 'set --; echo _${1:?message1}' |
17 | 17 | ||
18 | "$THIS_SH" -c 'set -- aaaa; echo _$1' | 18 | "$THIS_SH" -c 'set -- aaaa; echo _$1' |
19 | "$THIS_SH" -c 'set -- aaaa; echo _${1?}' | 19 | "$THIS_SH" -c 'set -- aaaa; echo _${1?}' |
@@ -24,14 +24,14 @@ | |||
24 | "$THIS_SH" -c 'unset f; echo _$f' | 24 | "$THIS_SH" -c 'unset f; echo _$f' |
25 | "$THIS_SH" -c 'unset f; echo _${f?}' | 25 | "$THIS_SH" -c 'unset f; echo _${f?}' |
26 | "$THIS_SH" -c 'unset f; echo _${f:?}' | 26 | "$THIS_SH" -c 'unset f; echo _${f:?}' |
27 | "$THIS_SH" -c 'unset f; echo _${f?word}' | 27 | "$THIS_SH" -c 'unset f; echo _${f?message3}' |
28 | "$THIS_SH" -c 'unset f; echo _${f:?word}' | 28 | "$THIS_SH" -c 'unset f; echo _${f:?message3}' |
29 | 29 | ||
30 | "$THIS_SH" -c 'f=; echo _$f' | 30 | "$THIS_SH" -c 'f=; echo _$f' |
31 | "$THIS_SH" -c 'f=; echo _${f?}' | 31 | "$THIS_SH" -c 'f=; echo _${f?}' |
32 | "$THIS_SH" -c 'f=; echo _${f:?}' | 32 | "$THIS_SH" -c 'f=; echo _${f:?}' |
33 | "$THIS_SH" -c 'f=; echo _${f?word}' | 33 | "$THIS_SH" -c 'f=; echo _${f?word}' |
34 | "$THIS_SH" -c 'f=; echo _${f:?word}' | 34 | "$THIS_SH" -c 'f=; echo _${f:?message4}' |
35 | 35 | ||
36 | "$THIS_SH" -c 'f=fff; echo _$f' | 36 | "$THIS_SH" -c 'f=fff; echo _$f' |
37 | "$THIS_SH" -c 'f=fff; echo _${f?}' | 37 | "$THIS_SH" -c 'f=fff; echo _${f?}' |