mirror of
https://github.com/sheumann/hush.git
synced 2024-12-22 14:30:31 +00:00
hush: initial stab at brace expansion support
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
d8389ad760
commit
5b2db97703
137
shell/hush.c
137
shell/hush.c
@ -2003,6 +2003,130 @@ static int o_get_last_ptr(o_string *o, int n)
|
|||||||
return ((int)(ptrdiff_t)list[n-1]) + string_start;
|
return ((int)(ptrdiff_t)list[n-1]) + string_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef HUSH_BRACE_EXP
|
||||||
|
/* There in a GNU extension, GLOB_BRACE, but it is not usable:
|
||||||
|
* first, it processes even {a} (no commas), second,
|
||||||
|
* I didn't manage to make it return strings when they don't match
|
||||||
|
# existing files. Need to re-implement it.
|
||||||
|
*
|
||||||
|
* This code needs corresponding quoting on variable expansion side.
|
||||||
|
* Currently, "a='{q,w}'; echo $a" erroneously expands braces in $a
|
||||||
|
*/
|
||||||
|
#ifdef HUSH_BRACE_EXP
|
||||||
|
/* Return pointer to next closing brace or to comma */
|
||||||
|
static const char *next_brace_sub(const char *cp)
|
||||||
|
{
|
||||||
|
unsigned depth = 0;
|
||||||
|
cp++;
|
||||||
|
while (*cp != '\0') {
|
||||||
|
if (*cp == '\\') {
|
||||||
|
if (*++cp == '\0')
|
||||||
|
break;
|
||||||
|
cp++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/*{*/ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
|
||||||
|
break;
|
||||||
|
if (*cp++ == '{') /*}*/
|
||||||
|
depth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *cp != '\0' ? cp : NULL;
|
||||||
|
}
|
||||||
|
static int glob_brace(const char *pattern, int flags, glob_t *pglob)
|
||||||
|
{
|
||||||
|
const char *begin;
|
||||||
|
char *alt_start;
|
||||||
|
const char *p;
|
||||||
|
const char *next;
|
||||||
|
const char *rest;
|
||||||
|
size_t rest_len;
|
||||||
|
char *onealt;
|
||||||
|
|
||||||
|
debug_printf_glob("glob_brace('%s')\n", pattern);
|
||||||
|
|
||||||
|
begin = pattern;
|
||||||
|
while (1) {
|
||||||
|
if (*begin == '\0')
|
||||||
|
goto do_glob;
|
||||||
|
if (*begin == '{') /*}*/ {
|
||||||
|
/* Find the first sub-pattern and at the same time
|
||||||
|
* find the rest after the closing brace */
|
||||||
|
next = next_brace_sub(begin);
|
||||||
|
if (next == NULL) {
|
||||||
|
/* An illegal expression */
|
||||||
|
goto do_glob;
|
||||||
|
}
|
||||||
|
/*{*/ if (*next == '}') {
|
||||||
|
/* "{abc}" with no commas - illegal
|
||||||
|
* brace expr, disregard and skip it */
|
||||||
|
begin = next + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*begin == '\\' && begin[1] != '\0')
|
||||||
|
begin++;
|
||||||
|
begin++;
|
||||||
|
}
|
||||||
|
debug_printf_glob("begin:%s\n", begin);
|
||||||
|
debug_printf_glob("next:%s\n", next);
|
||||||
|
|
||||||
|
/* Now find the end of the whole brace expression */
|
||||||
|
rest = next;
|
||||||
|
/*{*/ while (*rest != '}') {
|
||||||
|
rest = next_brace_sub(rest);
|
||||||
|
if (rest == NULL) {
|
||||||
|
/* An illegal expression */
|
||||||
|
goto do_glob;
|
||||||
|
}
|
||||||
|
debug_printf_glob("rest:%s\n", rest);
|
||||||
|
}
|
||||||
|
rest_len = strlen(++rest) + 1;
|
||||||
|
|
||||||
|
/* We are sure the brace expression is well-formed */
|
||||||
|
|
||||||
|
/* Allocate working buffer large enough for our work */
|
||||||
|
onealt = alloca(strlen(pattern));
|
||||||
|
/* We know the prefix for all sub-patterns */
|
||||||
|
alt_start = mempcpy(onealt, pattern, begin - pattern);
|
||||||
|
|
||||||
|
/* We have a brace expression. BEGIN points to the opening {,
|
||||||
|
* NEXT points past the terminator of the first element, and REST
|
||||||
|
* points past the final }. We will accumulate result names from
|
||||||
|
* recursive runs for each brace alternative in the buffer using
|
||||||
|
* GLOB_APPEND. */
|
||||||
|
|
||||||
|
p = begin + 1;
|
||||||
|
while (1) {
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* Construct the new glob expression */
|
||||||
|
memcpy(mempcpy(alt_start, p, next - p), rest, rest_len);
|
||||||
|
|
||||||
|
result = glob_brace(onealt, flags, pglob);
|
||||||
|
/* If we got an error, return it */
|
||||||
|
if (result && result != GLOB_NOMATCH)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
flags |= GLOB_APPEND;
|
||||||
|
|
||||||
|
/*{*/ if (*next == '}') {
|
||||||
|
/* We saw the last entry */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = next + 1;
|
||||||
|
next = next_brace_sub(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We found some entries */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
do_glob:
|
||||||
|
return glob(pattern, flags, NULL, pglob);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* o_glob performs globbing on last list[], saving each result
|
/* o_glob performs globbing on last list[], saving each result
|
||||||
* as a new list[]. */
|
* as a new list[]. */
|
||||||
static int o_glob(o_string *o, int n)
|
static int o_glob(o_string *o, int n)
|
||||||
@ -2024,17 +2148,22 @@ static int o_glob(o_string *o, int n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(&globdata, 0, sizeof(globdata));
|
memset(&globdata, 0, sizeof(globdata));
|
||||||
//TODO: can use GLOB_BRACE | GLOB_TILDE here:
|
#ifdef HUSH_BRACE_EXP
|
||||||
|
gr = glob_brace(pattern, GLOB_NOCHECK, &globdata);
|
||||||
|
debug_printf_glob("glob_brace('%s'):%d\n", pattern, gr);
|
||||||
|
#else
|
||||||
gr = glob(pattern, 0, NULL, &globdata);
|
gr = glob(pattern, 0, NULL, &globdata);
|
||||||
debug_printf_glob("glob('%s'):%d\n", pattern, gr);
|
debug_printf_glob("glob('%s'):%d\n", pattern, gr);
|
||||||
|
#endif
|
||||||
if (gr == GLOB_NOSPACE)
|
if (gr == GLOB_NOSPACE)
|
||||||
bb_error_msg_and_die("out of memory during glob");
|
bb_error_msg_and_die(bb_msg_memory_exhausted);
|
||||||
if (gr == GLOB_NOMATCH) {
|
if (gr == GLOB_NOMATCH) {
|
||||||
globfree(&globdata);
|
globfree(&globdata);
|
||||||
goto literal;
|
goto literal;
|
||||||
}
|
}
|
||||||
if (gr != 0) { /* GLOB_ABORTED ? */
|
if (gr != 0) {
|
||||||
/* TODO: testcase for bad glob pattern behavior */
|
/* GLOB_ABORTED? Only happens with GLOB_ERR flag,
|
||||||
|
* but we didn't specify it. Paranoia again. */
|
||||||
bb_error_msg("glob(3) error %d on '%s'", gr, pattern);
|
bb_error_msg("glob(3) error %d on '%s'", gr, pattern);
|
||||||
}
|
}
|
||||||
if (globdata.gl_pathv && globdata.gl_pathv[0]) {
|
if (globdata.gl_pathv && globdata.gl_pathv[0]) {
|
||||||
|
Loading…
Reference in New Issue
Block a user