diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-05-22 03:12:29 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-05-22 03:12:29 +0200 |
commit | 1e811b12317d0eab4e78d848caa640cca497a0a7 (patch) | |
tree | ef60262af7944dfe557542bec9e1fb8bea367b60 /shell/hush.c | |
parent | ddc62f64baad8abdeb587b13afe8d47fb347981c (diff) | |
download | busybox-w32-1e811b12317d0eab4e78d848caa640cca497a0a7.tar.gz busybox-w32-1e811b12317d0eab4e78d848caa640cca497a0a7.tar.bz2 busybox-w32-1e811b12317d0eab4e78d848caa640cca497a0a7.zip |
hush: support ${var:EXPR:EXPR}!
function old new delta
handle_dollar 574 681 +107
expand_and_evaluate_arith - 77 +77
expand_vars_to_list 2302 2374 +72
add_till_closing_bracket 359 368 +9
builtin_exit 48 47 -1
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 3/1 up/down: 265/-1) Total: 264 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 130 |
1 files changed, 88 insertions, 42 deletions
diff --git a/shell/hush.c b/shell/hush.c index 0f0151a21..41d5fcab2 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -171,6 +171,7 @@ | |||
171 | #define debug_printf_env(...) do {} while (0) | 171 | #define debug_printf_env(...) do {} while (0) |
172 | #define debug_printf_jobs(...) do {} while (0) | 172 | #define debug_printf_jobs(...) do {} while (0) |
173 | #define debug_printf_expand(...) do {} while (0) | 173 | #define debug_printf_expand(...) do {} while (0) |
174 | #define debug_printf_varexp(...) do {} while (0) | ||
174 | #define debug_printf_glob(...) do {} while (0) | 175 | #define debug_printf_glob(...) do {} while (0) |
175 | #define debug_printf_list(...) do {} while (0) | 176 | #define debug_printf_list(...) do {} while (0) |
176 | #define debug_printf_subst(...) do {} while (0) | 177 | #define debug_printf_subst(...) do {} while (0) |
@@ -743,6 +744,10 @@ static const struct built_in_command bltins2[] = { | |||
743 | # define DEBUG_EXPAND 0 | 744 | # define DEBUG_EXPAND 0 |
744 | #endif | 745 | #endif |
745 | 746 | ||
747 | #ifndef debug_printf_varexp | ||
748 | # define debug_printf_varexp(...) (indent(), fprintf(stderr, __VA_ARGS__)) | ||
749 | #endif | ||
750 | |||
746 | #ifndef debug_printf_glob | 751 | #ifndef debug_printf_glob |
747 | # define debug_printf_glob(...) (indent(), fprintf(stderr, __VA_ARGS__)) | 752 | # define debug_printf_glob(...) (indent(), fprintf(stderr, __VA_ARGS__)) |
748 | # define DEBUG_GLOB 1 | 753 | # define DEBUG_GLOB 1 |
@@ -1817,11 +1822,11 @@ static void o_addblock(o_string *o, const char *str, int len) | |||
1817 | o->data[o->length] = '\0'; | 1822 | o->data[o->length] = '\0'; |
1818 | } | 1823 | } |
1819 | 1824 | ||
1820 | #if !BB_MMU | ||
1821 | static void o_addstr(o_string *o, const char *str) | 1825 | static void o_addstr(o_string *o, const char *str) |
1822 | { | 1826 | { |
1823 | o_addblock(o, str, strlen(str)); | 1827 | o_addblock(o, str, strlen(str)); |
1824 | } | 1828 | } |
1829 | #if !BB_MMU | ||
1825 | static void nommu_addchr(o_string *o, int ch) | 1830 | static void nommu_addchr(o_string *o, int ch) |
1826 | { | 1831 | { |
1827 | if (o) | 1832 | if (o) |
@@ -2597,12 +2602,19 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2597 | } else { | 2602 | } else { |
2598 | /* maybe handle parameter expansion */ | 2603 | /* maybe handle parameter expansion */ |
2599 | exp_saveptr = var + strcspn(var, "%#:-=+?"); | 2604 | exp_saveptr = var + strcspn(var, "%#:-=+?"); |
2600 | exp_save = *exp_saveptr; | 2605 | exp_op = exp_save = *exp_saveptr; |
2601 | if (exp_save) { | 2606 | if (exp_op) { |
2602 | exp_word = exp_saveptr; | 2607 | exp_word = exp_saveptr + 1; |
2603 | if (exp_save == ':') | 2608 | if (exp_op == ':') { |
2604 | exp_word++; | 2609 | exp_op = *exp_word++; |
2605 | exp_op = *exp_word++; | 2610 | if (ENABLE_HUSH_BASH_COMPAT |
2611 | && (exp_op == '\0' || !strchr("%#:-=+?"+3, exp_op)) | ||
2612 | ) { | ||
2613 | /* oops... it's ${var:N[:M]}, not ${var:?xxx} or some such */ | ||
2614 | exp_op = ':'; | ||
2615 | exp_word--; | ||
2616 | } | ||
2617 | } | ||
2606 | *exp_saveptr = '\0'; | 2618 | *exp_saveptr = '\0'; |
2607 | } | 2619 | } |
2608 | } | 2620 | } |
@@ -2656,39 +2668,42 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2656 | *loc = '\0'; | 2668 | *loc = '\0'; |
2657 | } | 2669 | } |
2658 | } | 2670 | } |
2659 | } else if (!strchr("%#:-=+?"+3, exp_op)) { | 2671 | } else if (exp_op == ':') { |
2660 | #if ENABLE_HUSH_BASH_COMPAT | 2672 | #if ENABLE_HUSH_BASH_COMPAT |
2661 | /* exp_op is ':' and next char isn't a subst operator. | 2673 | /* It's ${var:N[:M]} bashism. |
2662 | * Assuming it's ${var:[N][:M]} bashism. | 2674 | * Note that in encoded form it has TWO parts: |
2663 | * TODO: N, M can be expressions similar to $((EXPR)): 2+2, 2+var etc | 2675 | * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL> |
2664 | */ | 2676 | */ |
2665 | char *end; | 2677 | arith_t beg, len; |
2666 | unsigned len = INT_MAX; | 2678 | int errcode = 0; |
2667 | unsigned beg = 0; | 2679 | |
2668 | end = --exp_word; | 2680 | beg = expand_and_evaluate_arith(exp_word, &errcode); |
2669 | if (*exp_word != ':') /* not ${var::...} */ | 2681 | debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg); |
2670 | beg = bb_strtou(exp_word, &end, 0); | 2682 | *p++ = SPECIAL_VAR_SYMBOL; |
2671 | //bb_error_msg("beg:'%s'=%u end:'%s'", exp_word, beg, end); | 2683 | exp_word = p; |
2672 | if (*end == ':') { | 2684 | p = strchr(p, SPECIAL_VAR_SYMBOL); |
2673 | if (end[1] != '\0') /* not ${var:NUM:} */ | 2685 | *p = '\0'; |
2674 | len = bb_strtou(end + 1, &end, 0); | 2686 | len = expand_and_evaluate_arith(exp_word, &errcode); |
2675 | else { | 2687 | debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len); |
2676 | len = 0; | 2688 | |
2677 | end++; | 2689 | if (errcode >= 0 && len >= 0) { /* bash compat: len < 0 is illegal */ |
2678 | } | 2690 | if (beg < 0) /* bash compat */ |
2679 | //bb_error_msg("len:%u end:'%s'", len, end); | 2691 | beg = 0; |
2680 | } | 2692 | debug_printf_varexp("from val:'%s'\n", val); |
2681 | if (*end == '\0') { | ||
2682 | //bb_error_msg("from val:'%s'", val); | ||
2683 | if (len == 0 || !val || beg >= strlen(val)) | 2693 | if (len == 0 || !val || beg >= strlen(val)) |
2684 | val = ""; | 2694 | val = ""; |
2685 | else | 2695 | else { |
2696 | /* Paranoia. What if user entered 9999999999999 | ||
2697 | * which fits in arith_t but not int? */ | ||
2698 | if (len >= INT_MAX) | ||
2699 | len = INT_MAX; | ||
2686 | val = to_be_freed = xstrndup(val + beg, len); | 2700 | val = to_be_freed = xstrndup(val + beg, len); |
2687 | //bb_error_msg("val:'%s'", val); | 2701 | } |
2702 | debug_printf_varexp("val:'%s'\n", val); | ||
2688 | } else | 2703 | } else |
2689 | #endif | 2704 | #endif |
2690 | { | 2705 | { |
2691 | die_if_script("malformed ${%s...}", var); | 2706 | die_if_script("malformed ${%s:...}", var); |
2692 | val = ""; | 2707 | val = ""; |
2693 | } | 2708 | } |
2694 | } else { /* one of "-=+?" */ | 2709 | } else { /* one of "-=+?" */ |
@@ -5891,21 +5906,28 @@ static void add_till_backquote(o_string *dest, struct in_str *input) | |||
5891 | * echo $(echo 'TEST)' BEST) TEST) BEST | 5906 | * echo $(echo 'TEST)' BEST) TEST) BEST |
5892 | * echo $(echo \(\(TEST\) BEST) ((TEST) BEST | 5907 | * echo $(echo \(\(TEST\) BEST) ((TEST) BEST |
5893 | * | 5908 | * |
5894 | * Also adapted to eat ${var%...} constructs, since ... part | 5909 | * Also adapted to eat ${var%...} and $((...)) constructs, since ... part |
5895 | * can contain arbitrary constructs, just like $(cmd). | 5910 | * can contain arbitrary constructs, just like $(cmd). |
5911 | * In bash compat mode, it needs to also be able to stop on '}' or ':' | ||
5912 | * for ${var:N[:M]} parsing. | ||
5896 | */ | 5913 | */ |
5897 | #define DOUBLE_CLOSE_CHAR_FLAG 0x80 | 5914 | #define DOUBLE_CLOSE_CHAR_FLAG 0x80 |
5898 | static void add_till_closing_bracket(o_string *dest, struct in_str *input, char end_ch) | 5915 | static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsigned end_ch) |
5899 | { | 5916 | { |
5917 | int ch; | ||
5900 | char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG; | 5918 | char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG; |
5901 | end_ch &= (DOUBLE_CLOSE_CHAR_FLAG-1); | 5919 | #if ENABLE_HUSH_BASH_COMPAT |
5920 | char end_char2 = end_ch >> 8; | ||
5921 | #endif | ||
5922 | end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); | ||
5923 | |||
5902 | while (1) { | 5924 | while (1) { |
5903 | int ch = i_getch(input); | 5925 | ch = i_getch(input); |
5904 | if (ch == EOF) { | 5926 | if (ch == EOF) { |
5905 | syntax_error_unterm_ch(end_ch); | 5927 | syntax_error_unterm_ch(end_ch); |
5906 | /*xfunc_die(); - redundant */ | 5928 | /*xfunc_die(); - redundant */ |
5907 | } | 5929 | } |
5908 | if (ch == end_ch) { | 5930 | if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { |
5909 | if (!dbl) | 5931 | if (!dbl) |
5910 | break; | 5932 | break; |
5911 | /* we look for closing )) of $((EXPR)) */ | 5933 | /* we look for closing )) of $((EXPR)) */ |
@@ -5947,6 +5969,7 @@ static void add_till_closing_bracket(o_string *dest, struct in_str *input, char | |||
5947 | continue; | 5969 | continue; |
5948 | } | 5970 | } |
5949 | } | 5971 | } |
5972 | return ch; | ||
5950 | } | 5973 | } |
5951 | #endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */ | 5974 | #endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */ |
5952 | 5975 | ||
@@ -6033,22 +6056,45 @@ static int handle_dollar(o_string *as_string, | |||
6033 | break; | 6056 | break; |
6034 | 6057 | ||
6035 | if (!isalnum(ch) && ch != '_') { | 6058 | if (!isalnum(ch) && ch != '_') { |
6059 | unsigned end_ch; | ||
6060 | unsigned char last_ch; | ||
6036 | /* handle parameter expansions | 6061 | /* handle parameter expansions |
6037 | * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02 | 6062 | * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02 |
6038 | */ | 6063 | */ |
6039 | if (!strchr("%#:-=+?", ch)) /* ${var<bad_char>... */ | 6064 | if (!strchr("%#:-=+?", ch)) /* ${var<bad_char>... */ |
6040 | goto bad_dollar_syntax; | 6065 | goto bad_dollar_syntax; |
6041 | /* Eat everything until closing '}' */ | ||
6042 | o_addchr(dest, ch); | 6066 | o_addchr(dest, ch); |
6067 | |||
6068 | /* Eat everything until closing '}' (or ':') */ | ||
6069 | end_ch = '}'; | ||
6070 | if (ENABLE_HUSH_BASH_COMPAT | ||
6071 | && ch == ':' | ||
6072 | && !strchr("%#:-=+?"+3, i_peek(input)) | ||
6073 | ) { | ||
6074 | /* It's ${var:N[:M]} thing */ | ||
6075 | end_ch = '}' * 0x100 + ':'; | ||
6076 | } | ||
6077 | again: | ||
6043 | if (!BB_MMU) | 6078 | if (!BB_MMU) |
6044 | pos = dest->length; | 6079 | pos = dest->length; |
6045 | add_till_closing_bracket(dest, input, '}'); | 6080 | last_ch = add_till_closing_bracket(dest, input, end_ch); |
6046 | #if !BB_MMU | ||
6047 | if (as_string) { | 6081 | if (as_string) { |
6048 | o_addstr(as_string, dest->data + pos); | 6082 | o_addstr(as_string, dest->data + pos); |
6049 | o_addchr(as_string, '}'); | 6083 | o_addchr(as_string, last_ch); |
6084 | } | ||
6085 | |||
6086 | if (ENABLE_HUSH_BASH_COMPAT && (end_ch & 0xff00)) { | ||
6087 | /* close the first block: */ | ||
6088 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
6089 | /* while parsing N from ${var:N[:M]}... */ | ||
6090 | if ((end_ch & 0xff) == last_ch) { | ||
6091 | /* ...got ':' - parse the rest */ | ||
6092 | end_ch = '}'; | ||
6093 | goto again; | ||
6094 | } | ||
6095 | /* ...got '}', not ':' - it's ${var:N}! emulate :999999999 */ | ||
6096 | o_addstr(dest, "999999999"); | ||
6050 | } | 6097 | } |
6051 | #endif | ||
6052 | break; | 6098 | break; |
6053 | } | 6099 | } |
6054 | } | 6100 | } |