diff options
| author | Mike Frysinger <vapier@gentoo.org> | 2009-04-07 06:03:22 +0000 |
|---|---|---|
| committer | Mike Frysinger <vapier@gentoo.org> | 2009-04-07 06:03:22 +0000 |
| commit | a4f331d3c3ea5b358613992a48556cc9cbfdf139 (patch) | |
| tree | 316143ec21a1efd2eb7e135121134c0b8b86221e /shell | |
| parent | 6c9be7f4518bf5594f5b9aaf981ed5dcc4a6939c (diff) | |
| download | busybox-w32-a4f331d3c3ea5b358613992a48556cc9cbfdf139.tar.gz busybox-w32-a4f331d3c3ea5b358613992a48556cc9cbfdf139.tar.bz2 busybox-w32-a4f331d3c3ea5b358613992a48556cc9cbfdf139.zip | |
implement support for parameter substitution via #/% operators
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/Kbuild | 2 | ||||
| -rw-r--r-- | shell/hush.c | 65 | ||||
| -rw-r--r-- | shell/hush_test/hush-vars/var_posix1.right | 17 | ||||
| -rwxr-xr-x | shell/hush_test/hush-vars/var_posix1.tests | 21 | ||||
| -rw-r--r-- | shell/match.c | 141 | ||||
| -rw-r--r-- | shell/match.h | 22 |
6 files changed, 243 insertions, 25 deletions
diff --git a/shell/Kbuild b/shell/Kbuild index 2b461b3bd..8b693ecc3 100644 --- a/shell/Kbuild +++ b/shell/Kbuild | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | lib-y:= | 7 | lib-y:= |
| 8 | lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o | 8 | lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o |
| 9 | lib-$(CONFIG_HUSH) += hush.o | 9 | lib-$(CONFIG_HUSH) += hush.o match.o |
| 10 | lib-$(CONFIG_MSH) += msh.o | 10 | lib-$(CONFIG_MSH) += msh.o |
| 11 | lib-$(CONFIG_CTTYHACK) += cttyhack.o | 11 | lib-$(CONFIG_CTTYHACK) += cttyhack.o |
| 12 | lib-$(CONFIG_SH_MATH_SUPPORT) += math.o | 12 | lib-$(CONFIG_SH_MATH_SUPPORT) += math.o |
diff --git a/shell/hush.c b/shell/hush.c index 792886944..1740187d4 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -43,7 +43,6 @@ | |||
| 43 | * Here Documents ( << word ) | 43 | * Here Documents ( << word ) |
| 44 | * Functions | 44 | * Functions |
| 45 | * Tilde Expansion | 45 | * Tilde Expansion |
| 46 | * Parameter Expansion for substring processing ${var#word} ${var%word} | ||
| 47 | * | 46 | * |
| 48 | * Bash stuff (maybe optionally enable?): | 47 | * Bash stuff (maybe optionally enable?): |
| 49 | * &> and >& redirection of stdout+stderr | 48 | * &> and >& redirection of stdout+stderr |
| @@ -76,6 +75,7 @@ | |||
| 76 | #include <fnmatch.h> | 75 | #include <fnmatch.h> |
| 77 | #endif | 76 | #endif |
| 78 | #include "math.h" | 77 | #include "math.h" |
| 78 | #include "match.h" | ||
| 79 | 79 | ||
| 80 | #ifdef WANT_TO_TEST_NOMMU | 80 | #ifdef WANT_TO_TEST_NOMMU |
| 81 | # undef BB_MMU | 81 | # undef BB_MMU |
| @@ -1667,8 +1667,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 1667 | char first_ch, ored_ch; | 1667 | char first_ch, ored_ch; |
| 1668 | int i; | 1668 | int i; |
| 1669 | const char *val; | 1669 | const char *val; |
| 1670 | char *p; | 1670 | char *dyn_val, *p; |
| 1671 | 1671 | ||
| 1672 | dyn_val = NULL; | ||
| 1672 | ored_ch = 0; | 1673 | ored_ch = 0; |
| 1673 | 1674 | ||
| 1674 | debug_printf_expand("expand_vars_to_list: arg '%s'\n", arg); | 1675 | debug_printf_expand("expand_vars_to_list: arg '%s'\n", arg); |
| @@ -1844,7 +1845,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 1844 | ++var; | 1845 | ++var; |
| 1845 | } else { | 1846 | } else { |
| 1846 | /* maybe handle parameter expansion */ | 1847 | /* maybe handle parameter expansion */ |
| 1847 | exp_off = strcspn(var, ":-=+?"); | 1848 | exp_off = strcspn(var, ":-=+?%#"); |
| 1848 | if (!var[exp_off]) | 1849 | if (!var[exp_off]) |
| 1849 | exp_off = 0; | 1850 | exp_off = 0; |
| 1850 | if (exp_off) { | 1851 | if (exp_off) { |
| @@ -1873,29 +1874,45 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 1873 | val = utoa(val ? strlen(val) : 0); | 1874 | val = utoa(val ? strlen(val) : 0); |
| 1874 | debug_printf_expand("%s\n", val); | 1875 | debug_printf_expand("%s\n", val); |
| 1875 | } else if (exp_off) { | 1876 | } else if (exp_off) { |
| 1876 | /* we need to do an expansion */ | 1877 | if (exp_op == '%' || exp_op == '#') { |
| 1877 | int exp_test = (!val || (exp_null && !val[0])); | 1878 | /* we need to do a pattern match */ |
| 1878 | if (exp_op == '+') | 1879 | bool zero; |
| 1879 | exp_test = !exp_test; | 1880 | char *loc; |
| 1880 | debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op, | 1881 | scan_t scan = pick_scan(exp_op, *exp_word, &zero); |
| 1881 | exp_null ? "true" : "false", exp_test); | 1882 | if (exp_op == *exp_word) /* ## or %% */ |
| 1882 | if (exp_test) { | 1883 | ++exp_word; |
| 1883 | if (exp_op == '?') | 1884 | val = dyn_val = xstrdup(val); |
| 1884 | maybe_die(var, *exp_word ? exp_word : "parameter null or not set"); | 1885 | loc = scan(dyn_val, exp_word, zero); |
| 1886 | if (zero) | ||
| 1887 | val = loc; | ||
| 1885 | else | 1888 | else |
| 1886 | val = exp_word; | 1889 | *loc = '\0'; |
| 1887 | 1890 | } else { | |
| 1888 | if (exp_op == '=') { | 1891 | /* we need to do an expansion */ |
| 1889 | if (isdigit(var[0]) || var[0] == '#') { | 1892 | int exp_test = (!val || (exp_null && !val[0])); |
| 1890 | maybe_die(var, "special vars cannot assign in this way"); | 1893 | if (exp_op == '+') |
| 1891 | val = NULL; | 1894 | exp_test = !exp_test; |
| 1892 | } else { | 1895 | debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op, |
| 1893 | char *new_var = xmalloc(strlen(var) + strlen(val) + 2); | 1896 | exp_null ? "true" : "false", exp_test); |
| 1894 | sprintf(new_var, "%s=%s", var, val); | 1897 | if (exp_test) { |
| 1895 | set_local_var(new_var, -1, 0); | 1898 | if (exp_op == '?') |
| 1899 | maybe_die(var, *exp_word ? exp_word : "parameter null or not set"); | ||
| 1900 | else | ||
| 1901 | val = exp_word; | ||
| 1902 | |||
| 1903 | if (exp_op == '=') { | ||
| 1904 | if (isdigit(var[0]) || var[0] == '#') { | ||
| 1905 | maybe_die(var, "special vars cannot assign in this way"); | ||
| 1906 | val = NULL; | ||
| 1907 | } else { | ||
| 1908 | char *new_var = xmalloc(strlen(var) + strlen(val) + 2); | ||
| 1909 | sprintf(new_var, "%s=%s", var, val); | ||
| 1910 | set_local_var(new_var, -1, 0); | ||
| 1911 | } | ||
| 1896 | } | 1912 | } |
| 1897 | } | 1913 | } |
| 1898 | } | 1914 | } |
| 1915 | |||
| 1899 | var[exp_off] = exp_save; | 1916 | var[exp_off] = exp_save; |
| 1900 | } | 1917 | } |
| 1901 | 1918 | ||
| @@ -1921,6 +1938,8 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 1921 | if (val) { | 1938 | if (val) { |
| 1922 | o_addQstr(output, val, strlen(val)); | 1939 | o_addQstr(output, val, strlen(val)); |
| 1923 | } | 1940 | } |
| 1941 | free(dyn_val); | ||
| 1942 | dyn_val = NULL; | ||
| 1924 | /* Do the check to avoid writing to a const string */ | 1943 | /* Do the check to avoid writing to a const string */ |
| 1925 | if (*p != SPECIAL_VAR_SYMBOL) | 1944 | if (*p != SPECIAL_VAR_SYMBOL) |
| 1926 | *p = SPECIAL_VAR_SYMBOL; | 1945 | *p = SPECIAL_VAR_SYMBOL; |
| @@ -4428,7 +4447,6 @@ static int handle_dollar(o_string *as_string, | |||
| 4428 | break; | 4447 | break; |
| 4429 | } | 4448 | } |
| 4430 | goto case_default; | 4449 | goto case_default; |
| 4431 | #if 0 /* not implemented yet :( */ | ||
| 4432 | case '#': /* remove prefix */ | 4450 | case '#': /* remove prefix */ |
| 4433 | case '%': /* remove suffix */ | 4451 | case '%': /* remove suffix */ |
| 4434 | if (expansion == 0) { | 4452 | if (expansion == 0) { |
| @@ -4437,7 +4455,6 @@ static int handle_dollar(o_string *as_string, | |||
| 4437 | break; | 4455 | break; |
| 4438 | } | 4456 | } |
| 4439 | goto case_default; | 4457 | goto case_default; |
| 4440 | #endif | ||
| 4441 | case '-': /* default value */ | 4458 | case '-': /* default value */ |
| 4442 | case '=': /* assign default */ | 4459 | case '=': /* assign default */ |
| 4443 | case '+': /* alternative */ | 4460 | case '+': /* alternative */ |
diff --git a/shell/hush_test/hush-vars/var_posix1.right b/shell/hush_test/hush-vars/var_posix1.right new file mode 100644 index 000000000..55f35798a --- /dev/null +++ b/shell/hush_test/hush-vars/var_posix1.right | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | abcdcd | ||
| 2 | abcdcd | ||
| 3 | abcdcd | ||
| 4 | cdcd | ||
| 5 | babcdcd | ||
| 6 | babcdcd | ||
| 7 | ababcdcd | ||
| 8 | |||
| 9 | ababcd | ||
| 10 | ababcd | ||
| 11 | ababcd | ||
| 12 | abab | ||
| 13 | ababcdc | ||
| 14 | ababcdc | ||
| 15 | ababcdcd | ||
| 16 | |||
| 17 | end | ||
diff --git a/shell/hush_test/hush-vars/var_posix1.tests b/shell/hush_test/hush-vars/var_posix1.tests new file mode 100755 index 000000000..4139e2cc3 --- /dev/null +++ b/shell/hush_test/hush-vars/var_posix1.tests | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | var=ababcdcd | ||
| 2 | |||
| 3 | echo ${var#ab} | ||
| 4 | echo ${var##ab} | ||
| 5 | echo ${var#a*b} | ||
| 6 | echo ${var##a*b} | ||
| 7 | echo ${var#?} | ||
| 8 | echo ${var##?} | ||
| 9 | echo ${var#*} | ||
| 10 | echo ${var##*} | ||
| 11 | |||
| 12 | echo ${var%cd} | ||
| 13 | echo ${var%%cd} | ||
| 14 | echo ${var%c*d} | ||
| 15 | echo ${var%%c*d} | ||
| 16 | echo ${var%?} | ||
| 17 | echo ${var%%?} | ||
| 18 | echo ${var%*} | ||
| 19 | echo ${var%%*} | ||
| 20 | |||
| 21 | echo end | ||
diff --git a/shell/match.c b/shell/match.c new file mode 100644 index 000000000..0810fd8f6 --- /dev/null +++ b/shell/match.c | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | /* | ||
| 2 | * ##/%% variable matching code ripped out of ash shell for code sharing | ||
| 3 | * | ||
| 4 | * Copyright (c) 1989, 1991, 1993, 1994 | ||
| 5 | * The Regents of the University of California. All rights reserved. | ||
| 6 | * | ||
| 7 | * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au> | ||
| 8 | * was re-ported from NetBSD and debianized. | ||
| 9 | * | ||
| 10 | * This code is derived from software contributed to Berkeley by | ||
| 11 | * Kenneth Almquist. | ||
| 12 | * | ||
| 13 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. | ||
| 14 | * | ||
| 15 | * Original BSD copyright notice is retained at the end of this file. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifdef STANDALONE | ||
| 19 | # include <stdbool.h> | ||
| 20 | # include <stdio.h> | ||
| 21 | # include <stdlib.h> | ||
| 22 | # include <string.h> | ||
| 23 | # include <unistd.h> | ||
| 24 | #else | ||
| 25 | # include "busybox.h" | ||
| 26 | #endif | ||
| 27 | #include <fnmatch.h> | ||
| 28 | #include "match.h" | ||
| 29 | |||
| 30 | #define pmatch(a, b) !fnmatch((a), (b), 0) | ||
| 31 | |||
| 32 | char *scanleft(char *string, char *pattern, bool zero) | ||
| 33 | { | ||
| 34 | char c; | ||
| 35 | char *loc = string; | ||
| 36 | |||
| 37 | do { | ||
| 38 | int match; | ||
| 39 | const char *s; | ||
| 40 | |||
| 41 | c = *loc; | ||
| 42 | if (zero) { | ||
| 43 | *loc = '\0'; | ||
| 44 | s = string; | ||
| 45 | } else | ||
| 46 | s = loc; | ||
| 47 | match = pmatch(pattern, s); | ||
| 48 | *loc = c; | ||
| 49 | |||
| 50 | if (match) | ||
| 51 | return loc; | ||
| 52 | |||
| 53 | loc++; | ||
| 54 | } while (c); | ||
| 55 | |||
| 56 | return NULL; | ||
| 57 | } | ||
| 58 | |||
| 59 | char *scanright(char *string, char *pattern, bool zero) | ||
| 60 | { | ||
| 61 | char c; | ||
| 62 | char *loc = string + strlen(string); | ||
| 63 | |||
| 64 | while (loc >= string) { | ||
| 65 | int match; | ||
| 66 | const char *s; | ||
| 67 | |||
| 68 | c = *loc; | ||
| 69 | if (zero) { | ||
| 70 | *loc = '\0'; | ||
| 71 | s = string; | ||
| 72 | } else | ||
| 73 | s = loc; | ||
| 74 | match = pmatch(pattern, s); | ||
| 75 | *loc = c; | ||
| 76 | |||
| 77 | if (match) | ||
| 78 | return loc; | ||
| 79 | |||
| 80 | loc--; | ||
| 81 | } | ||
| 82 | |||
| 83 | return NULL; | ||
| 84 | } | ||
| 85 | |||
| 86 | #ifdef STANDALONE | ||
| 87 | int main(int argc, char *argv[]) | ||
| 88 | { | ||
| 89 | char *string; | ||
| 90 | char *op; | ||
| 91 | char *pattern; | ||
| 92 | bool zero; | ||
| 93 | char *loc; | ||
| 94 | |||
| 95 | int i; | ||
| 96 | |||
| 97 | if (argc == 1) { | ||
| 98 | puts( | ||
| 99 | "Usage: match <test> [test...]\n\n" | ||
| 100 | "Where a <test> is the form: <string><op><match>\n" | ||
| 101 | "This is to test the shell ${var#val} expression type.\n\n" | ||
| 102 | "e.g. `match 'abc#a*'` -> bc" | ||
| 103 | ); | ||
| 104 | return 1; | ||
| 105 | } | ||
| 106 | |||
| 107 | for (i = 1; i < argc; ++i) { | ||
| 108 | size_t off; | ||
| 109 | scan_t scan; | ||
| 110 | |||
| 111 | printf("'%s': ", argv[i]); | ||
| 112 | |||
| 113 | string = strdup(argv[i]); | ||
| 114 | off = strcspn(string, "#%"); | ||
| 115 | if (!off) { | ||
| 116 | printf("invalid format\n"); | ||
| 117 | free(string); | ||
| 118 | continue; | ||
| 119 | } | ||
| 120 | op = string + off; | ||
| 121 | scan = pick_scan(op[0], op[1], &zero); | ||
| 122 | pattern = op + 1; | ||
| 123 | if (op[0] == op[1]) | ||
| 124 | op[1] = '\0', ++pattern; | ||
| 125 | op[0] = '\0'; | ||
| 126 | |||
| 127 | loc = scan(string, pattern, zero); | ||
| 128 | |||
| 129 | if (zero) { | ||
| 130 | printf("'%s'\n", loc); | ||
| 131 | } else { | ||
| 132 | *loc = '\0'; | ||
| 133 | printf("'%s'\n", string); | ||
| 134 | } | ||
| 135 | |||
| 136 | free(string); | ||
| 137 | } | ||
| 138 | |||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | #endif | ||
diff --git a/shell/match.h b/shell/match.h new file mode 100644 index 000000000..863f52539 --- /dev/null +++ b/shell/match.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* match.h - interface to shell ##/%% matching code */ | ||
| 2 | |||
| 3 | typedef char *(*scan_t)(char *string, char *match, bool zero); | ||
| 4 | |||
| 5 | char *scanleft(char *string, char *match, bool zero); | ||
| 6 | char *scanright(char *string, char *match, bool zero); | ||
| 7 | |||
| 8 | static inline scan_t pick_scan(char op1, char op2, bool *zero) | ||
| 9 | { | ||
| 10 | /* # - scanleft | ||
| 11 | * ## - scanright | ||
| 12 | * % - scanright | ||
| 13 | * %% - scanleft | ||
| 14 | */ | ||
| 15 | if (op1 == '#') { | ||
| 16 | *zero = true; | ||
| 17 | return op1 == op2 ? scanright : scanleft; | ||
| 18 | } else { | ||
| 19 | *zero = false; | ||
| 20 | return op1 == op2 ? scanleft : scanright; | ||
| 21 | } | ||
| 22 | } | ||
