aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2009-04-07 06:03:22 +0000
committerMike Frysinger <vapier@gentoo.org>2009-04-07 06:03:22 +0000
commita4f331d3c3ea5b358613992a48556cc9cbfdf139 (patch)
tree316143ec21a1efd2eb7e135121134c0b8b86221e
parent6c9be7f4518bf5594f5b9aaf981ed5dcc4a6939c (diff)
downloadbusybox-w32-a4f331d3c3ea5b358613992a48556cc9cbfdf139.tar.gz
busybox-w32-a4f331d3c3ea5b358613992a48556cc9cbfdf139.tar.bz2
busybox-w32-a4f331d3c3ea5b358613992a48556cc9cbfdf139.zip
implement support for parameter substitution via #/% operators
-rw-r--r--shell/Kbuild2
-rw-r--r--shell/hush.c65
-rw-r--r--shell/hush_test/hush-vars/var_posix1.right17
-rwxr-xr-xshell/hush_test/hush-vars/var_posix1.tests21
-rw-r--r--shell/match.c141
-rw-r--r--shell/match.h22
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
7lib-y:= 7lib-y:=
8lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o 8lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o
9lib-$(CONFIG_HUSH) += hush.o 9lib-$(CONFIG_HUSH) += hush.o match.o
10lib-$(CONFIG_MSH) += msh.o 10lib-$(CONFIG_MSH) += msh.o
11lib-$(CONFIG_CTTYHACK) += cttyhack.o 11lib-$(CONFIG_CTTYHACK) += cttyhack.o
12lib-$(CONFIG_SH_MATH_SUPPORT) += math.o 12lib-$(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 @@
1abcdcd
2abcdcd
3abcdcd
4cdcd
5babcdcd
6babcdcd
7ababcdcd
8
9ababcd
10ababcd
11ababcd
12abab
13ababcdc
14ababcdc
15ababcdcd
16
17end
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 @@
1var=ababcdcd
2
3echo ${var#ab}
4echo ${var##ab}
5echo ${var#a*b}
6echo ${var##a*b}
7echo ${var#?}
8echo ${var##?}
9echo ${var#*}
10echo ${var##*}
11
12echo ${var%cd}
13echo ${var%%cd}
14echo ${var%c*d}
15echo ${var%%c*d}
16echo ${var%?}
17echo ${var%%?}
18echo ${var%*}
19echo ${var%%*}
20
21echo 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
32char *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
59char *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
87int 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
3typedef char *(*scan_t)(char *string, char *match, bool zero);
4
5char *scanleft(char *string, char *match, bool zero);
6char *scanright(char *string, char *match, bool zero);
7
8static 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}