aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-11-16 05:49:36 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2009-11-16 05:49:36 +0100
commit5b2db97703630885b8f4c1ce0371415d1d2501a9 (patch)
tree59bf827229f0f52b63f7f10ffd3e105a09de41de /shell
parentd8389ad76028a536d1869ec163c15fd817dc7b65 (diff)
downloadbusybox-w32-5b2db97703630885b8f4c1ce0371415d1d2501a9.tar.gz
busybox-w32-5b2db97703630885b8f4c1ce0371415d1d2501a9.tar.bz2
busybox-w32-5b2db97703630885b8f4c1ce0371415d1d2501a9.zip
hush: initial stab at brace expansion support
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c137
1 files changed, 133 insertions, 4 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 235cee9ee..171b73940 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -2003,6 +2003,130 @@ static int o_get_last_ptr(o_string *o, int n)
2003 return ((int)(ptrdiff_t)list[n-1]) + string_start; 2003 return ((int)(ptrdiff_t)list[n-1]) + string_start;
2004} 2004}
2005 2005
2006#undef HUSH_BRACE_EXP
2007/* There in a GNU extension, GLOB_BRACE, but it is not usable:
2008 * first, it processes even {a} (no commas), second,
2009 * I didn't manage to make it return strings when they don't match
2010 # 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 */
2015#ifdef HUSH_BRACE_EXP
2016/* Return pointer to next closing brace or to comma */
2017static const char *next_brace_sub(const char *cp)
2018{
2019 unsigned depth = 0;
2020 cp++;
2021 while (*cp != '\0') {
2022 if (*cp == '\\') {
2023 if (*++cp == '\0')
2024 break;
2025 cp++;
2026 continue;
2027 }
2028 /*{*/ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
2029 break;
2030 if (*cp++ == '{') /*}*/
2031 depth++;
2032 }
2033
2034 return *cp != '\0' ? cp : NULL;
2035}
2036static int glob_brace(const char *pattern, int flags, glob_t *pglob)
2037{
2038 const char *begin;
2039 char *alt_start;
2040 const char *p;
2041 const char *next;
2042 const char *rest;
2043 size_t rest_len;
2044 char *onealt;
2045
2046 debug_printf_glob("glob_brace('%s')\n", pattern);
2047
2048 begin = pattern;
2049 while (1) {
2050 if (*begin == '\0')
2051 goto do_glob;
2052 if (*begin == '{') /*}*/ {
2053 /* Find the first sub-pattern and at the same time
2054 * find the rest after the closing brace */
2055 next = next_brace_sub(begin);
2056 if (next == NULL) {
2057 /* An illegal expression */
2058 goto do_glob;
2059 }
2060 /*{*/ if (*next == '}') {
2061 /* "{abc}" with no commas - illegal
2062 * brace expr, disregard and skip it */
2063 begin = next + 1;
2064 continue;
2065 }
2066 break;
2067 }
2068 if (*begin == '\\' && begin[1] != '\0')
2069 begin++;
2070 begin++;
2071 }
2072 debug_printf_glob("begin:%s\n", begin);
2073 debug_printf_glob("next:%s\n", next);
2074
2075 /* Now find the end of the whole brace expression */
2076 rest = next;
2077 /*{*/ while (*rest != '}') {
2078 rest = next_brace_sub(rest);
2079 if (rest == NULL) {
2080 /* An illegal expression */
2081 goto do_glob;
2082 }
2083 debug_printf_glob("rest:%s\n", rest);
2084 }
2085 rest_len = strlen(++rest) + 1;
2086
2087 /* We are sure the brace expression is well-formed */
2088
2089 /* Allocate working buffer large enough for our work */
2090 onealt = alloca(strlen(pattern));
2091 /* We know the prefix for all sub-patterns */
2092 alt_start = mempcpy(onealt, pattern, begin - pattern);
2093
2094 /* We have a brace expression. BEGIN points to the opening {,
2095 * NEXT points past the terminator of the first element, and REST
2096 * points past the final }. We will accumulate result names from
2097 * recursive runs for each brace alternative in the buffer using
2098 * GLOB_APPEND. */
2099
2100 p = begin + 1;
2101 while (1) {
2102 int result;
2103
2104 /* Construct the new glob expression */
2105 memcpy(mempcpy(alt_start, p, next - p), rest, rest_len);
2106
2107 result = glob_brace(onealt, flags, pglob);
2108 /* If we got an error, return it */
2109 if (result && result != GLOB_NOMATCH)
2110 return result;
2111
2112 flags |= GLOB_APPEND;
2113
2114 /*{*/ if (*next == '}') {
2115 /* We saw the last entry */
2116 break;
2117 }
2118 p = next + 1;
2119 next = next_brace_sub(next);
2120 }
2121
2122 /* We found some entries */
2123 return 0;
2124
2125 do_glob:
2126 return glob(pattern, flags, NULL, pglob);
2127}
2128#endif
2129
2006/* o_glob performs globbing on last list[], saving each result 2130/* o_glob performs globbing on last list[], saving each result
2007 * as a new list[]. */ 2131 * as a new list[]. */
2008static int o_glob(o_string *o, int n) 2132static int o_glob(o_string *o, int n)
@@ -2024,17 +2148,22 @@ static int o_glob(o_string *o, int n)
2024 } 2148 }
2025 2149
2026 memset(&globdata, 0, sizeof(globdata)); 2150 memset(&globdata, 0, sizeof(globdata));
2027//TODO: can use GLOB_BRACE | GLOB_TILDE here: 2151#ifdef HUSH_BRACE_EXP
2152 gr = glob_brace(pattern, GLOB_NOCHECK, &globdata);
2153 debug_printf_glob("glob_brace('%s'):%d\n", pattern, gr);
2154#else
2028 gr = glob(pattern, 0, NULL, &globdata); 2155 gr = glob(pattern, 0, NULL, &globdata);
2029 debug_printf_glob("glob('%s'):%d\n", pattern, gr); 2156 debug_printf_glob("glob('%s'):%d\n", pattern, gr);
2157#endif
2030 if (gr == GLOB_NOSPACE) 2158 if (gr == GLOB_NOSPACE)
2031 bb_error_msg_and_die("out of memory during glob"); 2159 bb_error_msg_and_die(bb_msg_memory_exhausted);
2032 if (gr == GLOB_NOMATCH) { 2160 if (gr == GLOB_NOMATCH) {
2033 globfree(&globdata); 2161 globfree(&globdata);
2034 goto literal; 2162 goto literal;
2035 } 2163 }
2036 if (gr != 0) { /* GLOB_ABORTED ? */ 2164 if (gr != 0) {
2037 /* TODO: testcase for bad glob pattern behavior */ 2165 /* GLOB_ABORTED? Only happens with GLOB_ERR flag,
2166 * but we didn't specify it. Paranoia again. */
2038 bb_error_msg("glob(3) error %d on '%s'", gr, pattern); 2167 bb_error_msg("glob(3) error %d on '%s'", gr, pattern);
2039 } 2168 }
2040 if (globdata.gl_pathv && globdata.gl_pathv[0]) { 2169 if (globdata.gl_pathv && globdata.gl_pathv[0]) {