hush: improve HUSH_BRACE_EXP code (still disabled). ~0 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		
							
								
								
									
										223
									
								
								shell/hush.c
									
									
									
									
									
								
							
							
						
						
									
										223
									
								
								shell/hush.c
									
									
									
									
									
								
							@@ -889,18 +889,6 @@ static void cmdedit_update_prompt(void);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Utility functions
 | 
					/* Utility functions
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int glob_needed(const char *s)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	while (*s) {
 | 
					 | 
				
			||||||
		if (*s == '\\')
 | 
					 | 
				
			||||||
			s++;
 | 
					 | 
				
			||||||
		if (*s == '*' || *s == '[' || *s == '?')
 | 
					 | 
				
			||||||
			return 1;
 | 
					 | 
				
			||||||
		s++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int is_well_formed_var_name(const char *s, char terminator)
 | 
					static int is_well_formed_var_name(const char *s, char terminator)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!s || !(isalpha(*s) || *s == '_'))
 | 
						if (!s || !(isalpha(*s) || *s == '_'))
 | 
				
			||||||
@@ -1856,13 +1844,31 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef HUSH_BRACE_EXP
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * HUSH_BRACE_EXP code needs corresponding quoting on variable expansion side.
 | 
				
			||||||
 | 
					 * Currently, "v='{q,w}'; echo $v" erroneously expands braces in $v.
 | 
				
			||||||
 | 
					 * Apparently, on unquoted $v bash still does globbing
 | 
				
			||||||
 | 
					 * ("v='*.txt'; echo $v" prints all .txt files),
 | 
				
			||||||
 | 
					 * but NOT brace expansion! Thus, there should be TWO independent
 | 
				
			||||||
 | 
					 * quoting mechanisms on $v expansion side: one protects
 | 
				
			||||||
 | 
					 * $v from brace expansion, and other additionally protects "$v" against globbing.
 | 
				
			||||||
 | 
					 * We have only second one.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HUSH_BRACE_EXP
 | 
				
			||||||
 | 
					# define MAYBE_BRACES "{}"
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					# define MAYBE_BRACES ""
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* My analysis of quoting semantics tells me that state information
 | 
					/* My analysis of quoting semantics tells me that state information
 | 
				
			||||||
 * is associated with a destination, not a source.
 | 
					 * is associated with a destination, not a source.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void o_addqchr(o_string *o, int ch)
 | 
					static void o_addqchr(o_string *o, int ch)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int sz = 1;
 | 
						int sz = 1;
 | 
				
			||||||
	char *found = strchr("*?[\\", ch);
 | 
						char *found = strchr("*?[\\" MAYBE_BRACES, ch);
 | 
				
			||||||
	if (found)
 | 
						if (found)
 | 
				
			||||||
		sz++;
 | 
							sz++;
 | 
				
			||||||
	o_grow_by(o, sz);
 | 
						o_grow_by(o, sz);
 | 
				
			||||||
@@ -1878,7 +1884,7 @@ static void o_addqchr(o_string *o, int ch)
 | 
				
			|||||||
static void o_addQchr(o_string *o, int ch)
 | 
					static void o_addQchr(o_string *o, int ch)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int sz = 1;
 | 
						int sz = 1;
 | 
				
			||||||
	if (o->o_escape && strchr("*?[\\", ch)) {
 | 
						if (o->o_escape && strchr("*?[\\" MAYBE_BRACES, ch)) {
 | 
				
			||||||
		sz++;
 | 
							sz++;
 | 
				
			||||||
		o->data[o->length] = '\\';
 | 
							o->data[o->length] = '\\';
 | 
				
			||||||
		o->length++;
 | 
							o->length++;
 | 
				
			||||||
@@ -1898,7 +1904,7 @@ static void o_addQstr(o_string *o, const char *str, int len)
 | 
				
			|||||||
	while (len) {
 | 
						while (len) {
 | 
				
			||||||
		char ch;
 | 
							char ch;
 | 
				
			||||||
		int sz;
 | 
							int sz;
 | 
				
			||||||
		int ordinary_cnt = strcspn(str, "*?[\\");
 | 
							int ordinary_cnt = strcspn(str, "*?[\\" MAYBE_BRACES);
 | 
				
			||||||
		if (ordinary_cnt > len) /* paranoia */
 | 
							if (ordinary_cnt > len) /* paranoia */
 | 
				
			||||||
			ordinary_cnt = len;
 | 
								ordinary_cnt = len;
 | 
				
			||||||
		o_addblock(o, str, ordinary_cnt);
 | 
							o_addblock(o, str, ordinary_cnt);
 | 
				
			||||||
@@ -1909,7 +1915,7 @@ static void o_addQstr(o_string *o, const char *str, int len)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		ch = *str++;
 | 
							ch = *str++;
 | 
				
			||||||
		sz = 1;
 | 
							sz = 1;
 | 
				
			||||||
		if (ch) { /* it is necessarily one of "*?[\\" */
 | 
							if (ch) { /* it is necessarily one of "*?[\\" MAYBE_BRACES */
 | 
				
			||||||
			sz++;
 | 
								sz++;
 | 
				
			||||||
			o->data[o->length] = '\\';
 | 
								o->data[o->length] = '\\';
 | 
				
			||||||
			o->length++;
 | 
								o->length++;
 | 
				
			||||||
@@ -2003,16 +2009,29 @@ 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
 | 
					#ifdef HUSH_BRACE_EXP
 | 
				
			||||||
/* There in a GNU extension, GLOB_BRACE, but it is not usable:
 | 
					/* There in a GNU extension, GLOB_BRACE, but it is not usable:
 | 
				
			||||||
 * first, it processes even {a} (no commas), second,
 | 
					 * first, it processes even {a} (no commas), second,
 | 
				
			||||||
 * I didn't manage to make it return strings when they don't match
 | 
					 * I didn't manage to make it return strings when they don't match
 | 
				
			||||||
 * existing files. Need to re-implement it.
 | 
					 * 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
 | 
					
 | 
				
			||||||
 | 
					/* Helper */
 | 
				
			||||||
 | 
					static int glob_needed(const char *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						while (*s) {
 | 
				
			||||||
 | 
							if (*s == '\\') {
 | 
				
			||||||
 | 
								if (!s[1])
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								s += 2;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (*s == '*' || *s == '[' || *s == '?' || *s == '{')
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
							s++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
/* Return pointer to next closing brace or to comma */
 | 
					/* Return pointer to next closing brace or to comma */
 | 
				
			||||||
static const char *next_brace_sub(const char *cp)
 | 
					static const char *next_brace_sub(const char *cp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -2033,29 +2052,29 @@ static const char *next_brace_sub(const char *cp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return *cp != '\0' ? cp : NULL;
 | 
						return *cp != '\0' ? cp : NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static int glob_brace(const char *pattern, int flags, glob_t *pglob)
 | 
					/* Recursive brace globber. Note: may garble pattern[]. */
 | 
				
			||||||
 | 
					static int glob_brace(char *pattern, o_string *o, int n)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						char *new_pattern_buf;
 | 
				
			||||||
	const char *begin;
 | 
						const char *begin;
 | 
				
			||||||
	char *alt_start;
 | 
					 | 
				
			||||||
	const char *p;
 | 
					 | 
				
			||||||
	const char *next;
 | 
						const char *next;
 | 
				
			||||||
	const char *rest;
 | 
						const char *rest;
 | 
				
			||||||
 | 
						const char *p;
 | 
				
			||||||
	size_t rest_len;
 | 
						size_t rest_len;
 | 
				
			||||||
	char *onealt;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	debug_printf_glob("glob_brace('%s')\n", pattern);
 | 
						debug_printf_glob("glob_brace('%s')\n", pattern);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	begin = pattern;
 | 
						begin = pattern;
 | 
				
			||||||
	while (1) {
 | 
						while (1) {
 | 
				
			||||||
		if (*begin == '\0')
 | 
							if (*begin == '\0')
 | 
				
			||||||
			goto do_glob;
 | 
								goto simple_glob;
 | 
				
			||||||
		if (*begin == '{') /*}*/ {
 | 
							if (*begin == '{') /*}*/ {
 | 
				
			||||||
			/* Find the first sub-pattern and at the same time
 | 
								/* Find the first sub-pattern and at the same time
 | 
				
			||||||
			 * find the rest after the closing brace */
 | 
								 * find the rest after the closing brace */
 | 
				
			||||||
			next = next_brace_sub(begin);
 | 
								next = next_brace_sub(begin);
 | 
				
			||||||
			if (next == NULL) {
 | 
								if (next == NULL) {
 | 
				
			||||||
				/* An illegal expression */
 | 
									/* An illegal expression */
 | 
				
			||||||
				goto do_glob;
 | 
									goto simple_glob;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			/*{*/ if (*next == '}') {
 | 
								/*{*/ if (*next == '}') {
 | 
				
			||||||
				/* "{abc}" with no commas - illegal
 | 
									/* "{abc}" with no commas - illegal
 | 
				
			||||||
@@ -2078,7 +2097,7 @@ static int glob_brace(const char *pattern, int flags, glob_t *pglob)
 | 
				
			|||||||
		rest = next_brace_sub(rest);
 | 
							rest = next_brace_sub(rest);
 | 
				
			||||||
		if (rest == NULL) {
 | 
							if (rest == NULL) {
 | 
				
			||||||
			/* An illegal expression */
 | 
								/* An illegal expression */
 | 
				
			||||||
			goto do_glob;
 | 
								goto simple_glob;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		debug_printf_glob("rest:%s\n", rest);
 | 
							debug_printf_glob("rest:%s\n", rest);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -2087,9 +2106,7 @@ static int glob_brace(const char *pattern, int flags, glob_t *pglob)
 | 
				
			|||||||
	/* We are sure the brace expression is well-formed */
 | 
						/* We are sure the brace expression is well-formed */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate working buffer large enough for our work */
 | 
						/* Allocate working buffer large enough for our work */
 | 
				
			||||||
	onealt = alloca(strlen(pattern));
 | 
						new_pattern_buf = xmalloc(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 {,
 | 
						/* We have a brace expression.  BEGIN points to the opening {,
 | 
				
			||||||
	 * NEXT points past the terminator of the first element, and REST
 | 
						 * 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)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	p = begin + 1;
 | 
						p = begin + 1;
 | 
				
			||||||
	while (1) {
 | 
						while (1) {
 | 
				
			||||||
		int result;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Construct the new glob expression */
 | 
							/* Construct the new glob expression */
 | 
				
			||||||
		memcpy(mempcpy(alt_start, p, next - p), rest, rest_len);
 | 
							memcpy(
 | 
				
			||||||
 | 
								mempcpy(
 | 
				
			||||||
		result = glob_brace(onealt, flags, pglob);
 | 
									mempcpy(new_pattern_buf,
 | 
				
			||||||
		/* If we got an error, return it */
 | 
										/* We know the prefix for all sub-patterns */
 | 
				
			||||||
		if (result && result != GLOB_NOMATCH)
 | 
										pattern, begin - pattern),
 | 
				
			||||||
			return result;
 | 
									p, next - p),
 | 
				
			||||||
 | 
								rest, rest_len);
 | 
				
			||||||
		flags |= GLOB_APPEND;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Note: glob_brace() may garble new_pattern_buf[].
 | 
				
			||||||
 | 
							 * That's why we re-copy prefix every time (1st memcpy above).
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							n = glob_brace(new_pattern_buf, o, n);
 | 
				
			||||||
		/*{*/ if (*next == '}') {
 | 
							/*{*/ if (*next == '}') {
 | 
				
			||||||
			/* We saw the last entry */
 | 
								/* We saw the last entry */
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -2118,17 +2136,96 @@ static int glob_brace(const char *pattern, int flags, glob_t *pglob)
 | 
				
			|||||||
		p = next + 1;
 | 
							p = next + 1;
 | 
				
			||||||
		next = next_brace_sub(next);
 | 
							next = next_brace_sub(next);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						free(new_pattern_buf);
 | 
				
			||||||
 | 
						return n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* We found some entries */
 | 
					 simple_glob:
 | 
				
			||||||
	return 0;
 | 
						{
 | 
				
			||||||
 | 
							int gr;
 | 
				
			||||||
 | 
							glob_t globdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 do_glob:
 | 
							memset(&globdata, 0, sizeof(globdata));
 | 
				
			||||||
	return glob(pattern, flags, NULL, pglob);
 | 
							gr = glob(pattern, 0, NULL, &globdata);
 | 
				
			||||||
 | 
							debug_printf_glob("glob('%s'):%d\n", pattern, gr);
 | 
				
			||||||
 | 
							if (gr != 0) {
 | 
				
			||||||
 | 
								if (gr == GLOB_NOMATCH) {
 | 
				
			||||||
 | 
									globfree(&globdata);
 | 
				
			||||||
 | 
									/* NB: garbles parameter */
 | 
				
			||||||
 | 
									unbackslash(pattern);
 | 
				
			||||||
 | 
									o_addstr_with_NUL(o, pattern);
 | 
				
			||||||
 | 
									debug_printf_glob("glob pattern '%s' is literal\n", pattern);
 | 
				
			||||||
 | 
									return o_save_ptr_helper(o, n);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (gr == GLOB_NOSPACE)
 | 
				
			||||||
 | 
									bb_error_msg_and_die(bb_msg_memory_exhausted);
 | 
				
			||||||
 | 
								/* GLOB_ABORTED? Only happens with GLOB_ERR flag,
 | 
				
			||||||
 | 
								 * but we didn't specify it. Paranoia again. */
 | 
				
			||||||
 | 
								bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (globdata.gl_pathv && globdata.gl_pathv[0]) {
 | 
				
			||||||
 | 
								char **argv = globdata.gl_pathv;
 | 
				
			||||||
 | 
								while (1) {
 | 
				
			||||||
 | 
									o_addstr_with_NUL(o, *argv);
 | 
				
			||||||
 | 
									n = o_save_ptr_helper(o, n);
 | 
				
			||||||
 | 
									argv++;
 | 
				
			||||||
 | 
									if (!*argv)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							globfree(&globdata);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return n;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					/* Performs globbing on last list[],
 | 
				
			||||||
 | 
					 * saving each result as a new list[].
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int o_glob(o_string *o, int n)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *pattern, *copy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* o_glob performs globbing on last list[], saving each result
 | 
						debug_printf_glob("start o_glob: n:%d o->data:%p\n", n, o->data);
 | 
				
			||||||
 * as a new list[]. */
 | 
						if (!o->data)
 | 
				
			||||||
 | 
							return o_save_ptr_helper(o, n);
 | 
				
			||||||
 | 
						pattern = o->data + o_get_last_ptr(o, n);
 | 
				
			||||||
 | 
						debug_printf_glob("glob pattern '%s'\n", pattern);
 | 
				
			||||||
 | 
						if (!glob_needed(pattern)) {
 | 
				
			||||||
 | 
							/* unbackslash last string in o in place, fix length */
 | 
				
			||||||
 | 
							o->length = unbackslash(pattern) - o->data;
 | 
				
			||||||
 | 
							debug_printf_glob("glob pattern '%s' is literal\n", pattern);
 | 
				
			||||||
 | 
							return o_save_ptr_helper(o, n);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						copy = xstrdup(pattern);
 | 
				
			||||||
 | 
						/* "forget" pattern in o */
 | 
				
			||||||
 | 
						o->length = pattern - o->data;
 | 
				
			||||||
 | 
						n = glob_brace(copy, o, n);
 | 
				
			||||||
 | 
						free(copy);
 | 
				
			||||||
 | 
						if (DEBUG_GLOB)
 | 
				
			||||||
 | 
							debug_print_list("o_glob returning", o, n);
 | 
				
			||||||
 | 
						return n;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Helper */
 | 
				
			||||||
 | 
					static int glob_needed(const char *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						while (*s) {
 | 
				
			||||||
 | 
							if (*s == '\\') {
 | 
				
			||||||
 | 
								if (!s[1])
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								s += 2;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (*s == '*' || *s == '[' || *s == '?')
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
							s++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/* Performs globbing on last list[],
 | 
				
			||||||
 | 
					 * saving each result as a new list[].
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
static int o_glob(o_string *o, int n)
 | 
					static int o_glob(o_string *o, int n)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	glob_t globdata;
 | 
						glob_t globdata;
 | 
				
			||||||
@@ -2142,33 +2239,35 @@ static int o_glob(o_string *o, int n)
 | 
				
			|||||||
	debug_printf_glob("glob pattern '%s'\n", pattern);
 | 
						debug_printf_glob("glob pattern '%s'\n", pattern);
 | 
				
			||||||
	if (!glob_needed(pattern)) {
 | 
						if (!glob_needed(pattern)) {
 | 
				
			||||||
 literal:
 | 
					 literal:
 | 
				
			||||||
 | 
							/* unbackslash last string in o in place, fix length */
 | 
				
			||||||
		o->length = unbackslash(pattern) - o->data;
 | 
							o->length = unbackslash(pattern) - o->data;
 | 
				
			||||||
		debug_printf_glob("glob pattern '%s' is literal\n", pattern);
 | 
							debug_printf_glob("glob pattern '%s' is literal\n", pattern);
 | 
				
			||||||
		return o_save_ptr_helper(o, n);
 | 
							return o_save_ptr_helper(o, n);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&globdata, 0, sizeof(globdata));
 | 
						memset(&globdata, 0, sizeof(globdata));
 | 
				
			||||||
#ifdef HUSH_BRACE_EXP
 | 
						/* Can't use GLOB_NOCHECK: it does not unescape the string.
 | 
				
			||||||
	gr = glob_brace(pattern, GLOB_NOCHECK, &globdata);
 | 
						 * If we glob "*.\*" and don't find anything, we need
 | 
				
			||||||
	debug_printf_glob("glob_brace('%s'):%d\n", pattern, gr);
 | 
						 * to fall back to using literal "*.*", but GLOB_NOCHECK
 | 
				
			||||||
#else
 | 
						 * will return "*.\*"!
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	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)
 | 
					 | 
				
			||||||
		bb_error_msg_and_die(bb_msg_memory_exhausted);
 | 
					 | 
				
			||||||
	if (gr == GLOB_NOMATCH) {
 | 
					 | 
				
			||||||
		globfree(&globdata);
 | 
					 | 
				
			||||||
		goto literal;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (gr != 0) {
 | 
						if (gr != 0) {
 | 
				
			||||||
 | 
							if (gr == GLOB_NOMATCH) {
 | 
				
			||||||
 | 
								globfree(&globdata);
 | 
				
			||||||
 | 
								goto literal;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (gr == GLOB_NOSPACE)
 | 
				
			||||||
 | 
								bb_error_msg_and_die(bb_msg_memory_exhausted);
 | 
				
			||||||
		/* GLOB_ABORTED? Only happens with GLOB_ERR flag,
 | 
							/* GLOB_ABORTED? Only happens with GLOB_ERR flag,
 | 
				
			||||||
		 * but we didn't specify it. Paranoia again. */
 | 
							 * but we didn't specify it. Paranoia again. */
 | 
				
			||||||
		bb_error_msg("glob(3) error %d on '%s'", gr, pattern);
 | 
							bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (globdata.gl_pathv && globdata.gl_pathv[0]) {
 | 
						if (globdata.gl_pathv && globdata.gl_pathv[0]) {
 | 
				
			||||||
		char **argv = globdata.gl_pathv;
 | 
							char **argv = globdata.gl_pathv;
 | 
				
			||||||
		o->length = pattern - o->data; /* "forget" pattern */
 | 
							/* "forget" pattern in o */
 | 
				
			||||||
 | 
							o->length = pattern - o->data;
 | 
				
			||||||
		while (1) {
 | 
							while (1) {
 | 
				
			||||||
			o_addstr_with_NUL(o, *argv);
 | 
								o_addstr_with_NUL(o, *argv);
 | 
				
			||||||
			n = o_save_ptr_helper(o, n);
 | 
								n = o_save_ptr_helper(o, n);
 | 
				
			||||||
@@ -2183,6 +2282,8 @@ static int o_glob(o_string *o, int n)
 | 
				
			|||||||
	return n;
 | 
						return n;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* If o->o_glob == 1, glob the string so far remembered.
 | 
					/* If o->o_glob == 1, glob the string so far remembered.
 | 
				
			||||||
 * Otherwise, just finish current list[] and start new */
 | 
					 * Otherwise, just finish current list[] and start new */
 | 
				
			||||||
static int o_save_ptr(o_string *o, int n)
 | 
					static int o_save_ptr(o_string *o, int n)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								shell/hush_test/hush-parsing/brace2.right
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								shell/hush_test/hush-parsing/brace2.right
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					{q,w}
 | 
				
			||||||
 | 
					{q,w}
 | 
				
			||||||
 | 
					Done
 | 
				
			||||||
							
								
								
									
										5
									
								
								shell/hush_test/hush-parsing/brace2.tests
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										5
									
								
								shell/hush_test/hush-parsing/brace2.tests
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					v='{q,w}'
 | 
				
			||||||
 | 
					# Should not brace-expand v value
 | 
				
			||||||
 | 
					echo $v
 | 
				
			||||||
 | 
					echo "$v"
 | 
				
			||||||
 | 
					echo Done
 | 
				
			||||||
		Reference in New Issue
	
	Block a user