aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-05-22 03:12:29 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-05-22 03:12:29 +0200
commit1e811b12317d0eab4e78d848caa640cca497a0a7 (patch)
treeef60262af7944dfe557542bec9e1fb8bea367b60 /shell/hush.c
parentddc62f64baad8abdeb587b13afe8d47fb347981c (diff)
downloadbusybox-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.c130
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
1821static void o_addstr(o_string *o, const char *str) 1825static 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
1825static void nommu_addchr(o_string *o, int ch) 1830static 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
5898static void add_till_closing_bracket(o_string *dest, struct in_str *input, char end_ch) 5915static 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 }