aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-11-17 03:35:31 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2009-11-17 03:35:31 +0100
commitf3e2818895a6f570a365001f625946a1b75c085a (patch)
tree8bd5ba3dad83b32439be4f7e166aa0eb6ab6384e
parent160746b60398a8a018e1791e259504f9d97a1b33 (diff)
downloadbusybox-w32-f3e2818895a6f570a365001f625946a1b75c085a.tar.gz
busybox-w32-f3e2818895a6f570a365001f625946a1b75c085a.tar.bz2
busybox-w32-f3e2818895a6f570a365001f625946a1b75c085a.zip
hush: improve HUSH_BRACE_EXP code (still disabled). ~0 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/hush.c225
-rw-r--r--shell/hush_test/hush-parsing/brace2.right3
-rwxr-xr-xshell/hush_test/hush-parsing/brace2.tests5
3 files changed, 171 insertions, 62 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 24134fd8a..2d6f55bc7 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -889,18 +889,6 @@ static void cmdedit_update_prompt(void);
889 889
890/* Utility functions 890/* Utility functions
891 */ 891 */
892static int glob_needed(const char *s)
893{
894 while (*s) {
895 if (*s == '\\')
896 s++;
897 if (*s == '*' || *s == '[' || *s == '?')
898 return 1;
899 s++;
900 }
901 return 0;
902}
903
904static int is_well_formed_var_name(const char *s, char terminator) 892static int is_well_formed_var_name(const char *s, char terminator)
905{ 893{
906 if (!s || !(isalpha(*s) || *s == '_')) 894 if (!s || !(isalpha(*s) || *s == '_'))
@@ -1856,13 +1844,31 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len
1856 } 1844 }
1857} 1845}
1858 1846
1847#undef HUSH_BRACE_EXP
1848/*
1849 * HUSH_BRACE_EXP code needs corresponding quoting on variable expansion side.
1850 * Currently, "v='{q,w}'; echo $v" erroneously expands braces in $v.
1851 * Apparently, on unquoted $v bash still does globbing
1852 * ("v='*.txt'; echo $v" prints all .txt files),
1853 * but NOT brace expansion! Thus, there should be TWO independent
1854 * quoting mechanisms on $v expansion side: one protects
1855 * $v from brace expansion, and other additionally protects "$v" against globbing.
1856 * We have only second one.
1857 */
1858
1859#ifdef HUSH_BRACE_EXP
1860# define MAYBE_BRACES "{}"
1861#else
1862# define MAYBE_BRACES ""
1863#endif
1864
1859/* My analysis of quoting semantics tells me that state information 1865/* My analysis of quoting semantics tells me that state information
1860 * is associated with a destination, not a source. 1866 * is associated with a destination, not a source.
1861 */ 1867 */
1862static void o_addqchr(o_string *o, int ch) 1868static void o_addqchr(o_string *o, int ch)
1863{ 1869{
1864 int sz = 1; 1870 int sz = 1;
1865 char *found = strchr("*?[\\", ch); 1871 char *found = strchr("*?[\\" MAYBE_BRACES, ch);
1866 if (found) 1872 if (found)
1867 sz++; 1873 sz++;
1868 o_grow_by(o, sz); 1874 o_grow_by(o, sz);
@@ -1878,7 +1884,7 @@ static void o_addqchr(o_string *o, int ch)
1878static void o_addQchr(o_string *o, int ch) 1884static void o_addQchr(o_string *o, int ch)
1879{ 1885{
1880 int sz = 1; 1886 int sz = 1;
1881 if (o->o_escape && strchr("*?[\\", ch)) { 1887 if (o->o_escape && strchr("*?[\\" MAYBE_BRACES, ch)) {
1882 sz++; 1888 sz++;
1883 o->data[o->length] = '\\'; 1889 o->data[o->length] = '\\';
1884 o->length++; 1890 o->length++;
@@ -1898,7 +1904,7 @@ static void o_addQstr(o_string *o, const char *str, int len)
1898 while (len) { 1904 while (len) {
1899 char ch; 1905 char ch;
1900 int sz; 1906 int sz;
1901 int ordinary_cnt = strcspn(str, "*?[\\"); 1907 int ordinary_cnt = strcspn(str, "*?[\\" MAYBE_BRACES);
1902 if (ordinary_cnt > len) /* paranoia */ 1908 if (ordinary_cnt > len) /* paranoia */
1903 ordinary_cnt = len; 1909 ordinary_cnt = len;
1904 o_addblock(o, str, ordinary_cnt); 1910 o_addblock(o, str, ordinary_cnt);
@@ -1909,7 +1915,7 @@ static void o_addQstr(o_string *o, const char *str, int len)
1909 1915
1910 ch = *str++; 1916 ch = *str++;
1911 sz = 1; 1917 sz = 1;
1912 if (ch) { /* it is necessarily one of "*?[\\" */ 1918 if (ch) { /* it is necessarily one of "*?[\\" MAYBE_BRACES */
1913 sz++; 1919 sz++;
1914 o->data[o->length] = '\\'; 1920 o->data[o->length] = '\\';
1915 o->length++; 1921 o->length++;
@@ -2003,16 +2009,29 @@ static int o_get_last_ptr(o_string *o, int n)
2003 return ((int)(ptrdiff_t)list[n-1]) + string_start; 2009 return ((int)(ptrdiff_t)list[n-1]) + string_start;
2004} 2010}
2005 2011
2006#undef HUSH_BRACE_EXP 2012#ifdef HUSH_BRACE_EXP
2007/* There in a GNU extension, GLOB_BRACE, but it is not usable: 2013/* There in a GNU extension, GLOB_BRACE, but it is not usable:
2008 * first, it processes even {a} (no commas), second, 2014 * first, it processes even {a} (no commas), second,
2009 * I didn't manage to make it return strings when they don't match 2015 * I didn't manage to make it return strings when they don't match
2010 * existing files. Need to re-implement it. 2016 * existing files. Need to re-implement it.
2011 *
2012 * This code needs corresponding quoting on variable expansion side.
2013 * Currently, "a='{q,w}'; echo $a" erroneously expands braces in $a
2014 */ 2017 */
2015#ifdef HUSH_BRACE_EXP 2018
2019/* Helper */
2020static int glob_needed(const char *s)
2021{
2022 while (*s) {
2023 if (*s == '\\') {
2024 if (!s[1])
2025 return 0;
2026 s += 2;
2027 continue;
2028 }
2029 if (*s == '*' || *s == '[' || *s == '?' || *s == '{')
2030 return 1;
2031 s++;
2032 }
2033 return 0;
2034}
2016/* Return pointer to next closing brace or to comma */ 2035/* Return pointer to next closing brace or to comma */
2017static const char *next_brace_sub(const char *cp) 2036static const char *next_brace_sub(const char *cp)
2018{ 2037{
@@ -2033,29 +2052,29 @@ static const char *next_brace_sub(const char *cp)
2033 2052
2034 return *cp != '\0' ? cp : NULL; 2053 return *cp != '\0' ? cp : NULL;
2035} 2054}
2036static int glob_brace(const char *pattern, int flags, glob_t *pglob) 2055/* Recursive brace globber. Note: may garble pattern[]. */
2056static int glob_brace(char *pattern, o_string *o, int n)
2037{ 2057{
2058 char *new_pattern_buf;
2038 const char *begin; 2059 const char *begin;
2039 char *alt_start;
2040 const char *p;
2041 const char *next; 2060 const char *next;
2042 const char *rest; 2061 const char *rest;
2062 const char *p;
2043 size_t rest_len; 2063 size_t rest_len;
2044 char *onealt;
2045 2064
2046 debug_printf_glob("glob_brace('%s')\n", pattern); 2065 debug_printf_glob("glob_brace('%s')\n", pattern);
2047 2066
2048 begin = pattern; 2067 begin = pattern;
2049 while (1) { 2068 while (1) {
2050 if (*begin == '\0') 2069 if (*begin == '\0')
2051 goto do_glob; 2070 goto simple_glob;
2052 if (*begin == '{') /*}*/ { 2071 if (*begin == '{') /*}*/ {
2053 /* Find the first sub-pattern and at the same time 2072 /* Find the first sub-pattern and at the same time
2054 * find the rest after the closing brace */ 2073 * find the rest after the closing brace */
2055 next = next_brace_sub(begin); 2074 next = next_brace_sub(begin);
2056 if (next == NULL) { 2075 if (next == NULL) {
2057 /* An illegal expression */ 2076 /* An illegal expression */
2058 goto do_glob; 2077 goto simple_glob;
2059 } 2078 }
2060 /*{*/ if (*next == '}') { 2079 /*{*/ if (*next == '}') {
2061 /* "{abc}" with no commas - illegal 2080 /* "{abc}" with no commas - illegal
@@ -2078,7 +2097,7 @@ static int glob_brace(const char *pattern, int flags, glob_t *pglob)
2078 rest = next_brace_sub(rest); 2097 rest = next_brace_sub(rest);
2079 if (rest == NULL) { 2098 if (rest == NULL) {
2080 /* An illegal expression */ 2099 /* An illegal expression */
2081 goto do_glob; 2100 goto simple_glob;
2082 } 2101 }
2083 debug_printf_glob("rest:%s\n", rest); 2102 debug_printf_glob("rest:%s\n", rest);
2084 } 2103 }
@@ -2087,9 +2106,7 @@ static int glob_brace(const char *pattern, int flags, glob_t *pglob)
2087 /* We are sure the brace expression is well-formed */ 2106 /* We are sure the brace expression is well-formed */
2088 2107
2089 /* Allocate working buffer large enough for our work */ 2108 /* Allocate working buffer large enough for our work */
2090 onealt = alloca(strlen(pattern)); 2109 new_pattern_buf = xmalloc(strlen(pattern));
2091 /* We know the prefix for all sub-patterns */
2092 alt_start = mempcpy(onealt, pattern, begin - pattern);
2093 2110
2094 /* We have a brace expression. BEGIN points to the opening {, 2111 /* We have a brace expression. BEGIN points to the opening {,
2095 * NEXT points past the terminator of the first element, and REST 2112 * NEXT points past the terminator of the first element, and REST
@@ -2099,18 +2116,19 @@ static int glob_brace(const char *pattern, int flags, glob_t *pglob)
2099 2116
2100 p = begin + 1; 2117 p = begin + 1;
2101 while (1) { 2118 while (1) {
2102 int result;
2103
2104 /* Construct the new glob expression */ 2119 /* Construct the new glob expression */
2105 memcpy(mempcpy(alt_start, p, next - p), rest, rest_len); 2120 memcpy(
2106 2121 mempcpy(
2107 result = glob_brace(onealt, flags, pglob); 2122 mempcpy(new_pattern_buf,
2108 /* If we got an error, return it */ 2123 /* We know the prefix for all sub-patterns */
2109 if (result && result != GLOB_NOMATCH) 2124 pattern, begin - pattern),
2110 return result; 2125 p, next - p),
2111 2126 rest, rest_len);
2112 flags |= GLOB_APPEND; 2127
2113 2128 /* Note: glob_brace() may garble new_pattern_buf[].
2129 * That's why we re-copy prefix every time (1st memcpy above).
2130 */
2131 n = glob_brace(new_pattern_buf, o, n);
2114 /*{*/ if (*next == '}') { 2132 /*{*/ if (*next == '}') {
2115 /* We saw the last entry */ 2133 /* We saw the last entry */
2116 break; 2134 break;
@@ -2118,17 +2136,96 @@ static int glob_brace(const char *pattern, int flags, glob_t *pglob)
2118 p = next + 1; 2136 p = next + 1;
2119 next = next_brace_sub(next); 2137 next = next_brace_sub(next);
2120 } 2138 }
2139 free(new_pattern_buf);
2140 return n;
2121 2141
2122 /* We found some entries */ 2142 simple_glob:
2123 return 0; 2143 {
2144 int gr;
2145 glob_t globdata;
2146
2147 memset(&globdata, 0, sizeof(globdata));
2148 gr = glob(pattern, 0, NULL, &globdata);
2149 debug_printf_glob("glob('%s'):%d\n", pattern, gr);
2150 if (gr != 0) {
2151 if (gr == GLOB_NOMATCH) {
2152 globfree(&globdata);
2153 /* NB: garbles parameter */
2154 unbackslash(pattern);
2155 o_addstr_with_NUL(o, pattern);
2156 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
2157 return o_save_ptr_helper(o, n);
2158 }
2159 if (gr == GLOB_NOSPACE)
2160 bb_error_msg_and_die(bb_msg_memory_exhausted);
2161 /* GLOB_ABORTED? Only happens with GLOB_ERR flag,
2162 * but we didn't specify it. Paranoia again. */
2163 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
2164 }
2165 if (globdata.gl_pathv && globdata.gl_pathv[0]) {
2166 char **argv = globdata.gl_pathv;
2167 while (1) {
2168 o_addstr_with_NUL(o, *argv);
2169 n = o_save_ptr_helper(o, n);
2170 argv++;
2171 if (!*argv)
2172 break;
2173 }
2174 }
2175 globfree(&globdata);
2176 }
2177 return n;
2178}
2179/* Performs globbing on last list[],
2180 * saving each result as a new list[].
2181 */
2182static int o_glob(o_string *o, int n)
2183{
2184 char *pattern, *copy;
2185
2186 debug_printf_glob("start o_glob: n:%d o->data:%p\n", n, o->data);
2187 if (!o->data)
2188 return o_save_ptr_helper(o, n);
2189 pattern = o->data + o_get_last_ptr(o, n);
2190 debug_printf_glob("glob pattern '%s'\n", pattern);
2191 if (!glob_needed(pattern)) {
2192 /* unbackslash last string in o in place, fix length */
2193 o->length = unbackslash(pattern) - o->data;
2194 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
2195 return o_save_ptr_helper(o, n);
2196 }
2124 2197
2125 do_glob: 2198 copy = xstrdup(pattern);
2126 return glob(pattern, flags, NULL, pglob); 2199 /* "forget" pattern in o */
2200 o->length = pattern - o->data;
2201 n = glob_brace(copy, o, n);
2202 free(copy);
2203 if (DEBUG_GLOB)
2204 debug_print_list("o_glob returning", o, n);
2205 return n;
2127} 2206}
2128#endif
2129 2207
2130/* o_glob performs globbing on last list[], saving each result 2208#else
2131 * as a new list[]. */ 2209
2210/* Helper */
2211static int glob_needed(const char *s)
2212{
2213 while (*s) {
2214 if (*s == '\\') {
2215 if (!s[1])
2216 return 0;
2217 s += 2;
2218 continue;
2219 }
2220 if (*s == '*' || *s == '[' || *s == '?')
2221 return 1;
2222 s++;
2223 }
2224 return 0;
2225}
2226/* Performs globbing on last list[],
2227 * saving each result as a new list[].
2228 */
2132static int o_glob(o_string *o, int n) 2229static int o_glob(o_string *o, int n)
2133{ 2230{
2134 glob_t globdata; 2231 glob_t globdata;
@@ -2142,33 +2239,35 @@ static int o_glob(o_string *o, int n)
2142 debug_printf_glob("glob pattern '%s'\n", pattern); 2239 debug_printf_glob("glob pattern '%s'\n", pattern);
2143 if (!glob_needed(pattern)) { 2240 if (!glob_needed(pattern)) {
2144 literal: 2241 literal:
2242 /* unbackslash last string in o in place, fix length */
2145 o->length = unbackslash(pattern) - o->data; 2243 o->length = unbackslash(pattern) - o->data;
2146 debug_printf_glob("glob pattern '%s' is literal\n", pattern); 2244 debug_printf_glob("glob pattern '%s' is literal\n", pattern);
2147 return o_save_ptr_helper(o, n); 2245 return o_save_ptr_helper(o, n);
2148 } 2246 }
2149 2247
2150 memset(&globdata, 0, sizeof(globdata)); 2248 memset(&globdata, 0, sizeof(globdata));
2151#ifdef HUSH_BRACE_EXP 2249 /* Can't use GLOB_NOCHECK: it does not unescape the string.
2152 gr = glob_brace(pattern, GLOB_NOCHECK, &globdata); 2250 * If we glob "*.\*" and don't find anything, we need
2153 debug_printf_glob("glob_brace('%s'):%d\n", pattern, gr); 2251 * to fall back to using literal "*.*", but GLOB_NOCHECK
2154#else 2252 * will return "*.\*"!
2253 */
2155 gr = glob(pattern, 0, NULL, &globdata); 2254 gr = glob(pattern, 0, NULL, &globdata);
2156 debug_printf_glob("glob('%s'):%d\n", pattern, gr); 2255 debug_printf_glob("glob('%s'):%d\n", pattern, gr);
2157#endif
2158 if (gr == GLOB_NOSPACE)
2159 bb_error_msg_and_die(bb_msg_memory_exhausted);
2160 if (gr == GLOB_NOMATCH) {
2161 globfree(&globdata);
2162 goto literal;
2163 }
2164 if (gr != 0) { 2256 if (gr != 0) {
2257 if (gr == GLOB_NOMATCH) {
2258 globfree(&globdata);
2259 goto literal;
2260 }
2261 if (gr == GLOB_NOSPACE)
2262 bb_error_msg_and_die(bb_msg_memory_exhausted);
2165 /* GLOB_ABORTED? Only happens with GLOB_ERR flag, 2263 /* GLOB_ABORTED? Only happens with GLOB_ERR flag,
2166 * but we didn't specify it. Paranoia again. */ 2264 * but we didn't specify it. Paranoia again. */
2167 bb_error_msg("glob(3) error %d on '%s'", gr, pattern); 2265 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
2168 } 2266 }
2169 if (globdata.gl_pathv && globdata.gl_pathv[0]) { 2267 if (globdata.gl_pathv && globdata.gl_pathv[0]) {
2170 char **argv = globdata.gl_pathv; 2268 char **argv = globdata.gl_pathv;
2171 o->length = pattern - o->data; /* "forget" pattern */ 2269 /* "forget" pattern in o */
2270 o->length = pattern - o->data;
2172 while (1) { 2271 while (1) {
2173 o_addstr_with_NUL(o, *argv); 2272 o_addstr_with_NUL(o, *argv);
2174 n = o_save_ptr_helper(o, n); 2273 n = o_save_ptr_helper(o, n);
@@ -2183,6 +2282,8 @@ static int o_glob(o_string *o, int n)
2183 return n; 2282 return n;
2184} 2283}
2185 2284
2285#endif
2286
2186/* If o->o_glob == 1, glob the string so far remembered. 2287/* If o->o_glob == 1, glob the string so far remembered.
2187 * Otherwise, just finish current list[] and start new */ 2288 * Otherwise, just finish current list[] and start new */
2188static int o_save_ptr(o_string *o, int n) 2289static int o_save_ptr(o_string *o, int n)
diff --git a/shell/hush_test/hush-parsing/brace2.right b/shell/hush_test/hush-parsing/brace2.right
new file mode 100644
index 000000000..37a966654
--- /dev/null
+++ b/shell/hush_test/hush-parsing/brace2.right
@@ -0,0 +1,3 @@
1{q,w}
2{q,w}
3Done
diff --git a/shell/hush_test/hush-parsing/brace2.tests b/shell/hush_test/hush-parsing/brace2.tests
new file mode 100755
index 000000000..ef75f0b70
--- /dev/null
+++ b/shell/hush_test/hush-parsing/brace2.tests
@@ -0,0 +1,5 @@
1v='{q,w}'
2# Should not brace-expand v value
3echo $v
4echo "$v"
5echo Done