hush: fix incorrect processing of echo "'$var'".
hush: rename map[] and MAP_xxx, making them easier to understand. hush: move testcase (which now passes) from hush-bugs to hush-parsing
This commit is contained in:
parent
418a7fb29b
commit
8f6bdb42df
50
shell/hush.c
50
shell/hush.c
@ -71,7 +71,7 @@
|
|||||||
* memory leak finding and plugging - done?
|
* memory leak finding and plugging - done?
|
||||||
* more testing, especially quoting rules and redirection
|
* more testing, especially quoting rules and redirection
|
||||||
* document how quoting rules not precisely followed for variable assignments
|
* document how quoting rules not precisely followed for variable assignments
|
||||||
* maybe change map[] to use 2-bit entries
|
* maybe change charmap[] to use 2-bit entries
|
||||||
* (eventually) remove all the printf's
|
* (eventually) remove all the printf's
|
||||||
*
|
*
|
||||||
* Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
|
* Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
|
||||||
@ -281,12 +281,12 @@ extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
|
|||||||
|
|
||||||
/* "globals" within this file */
|
/* "globals" within this file */
|
||||||
enum {
|
enum {
|
||||||
MAP_ORDINARY = 0,
|
CHAR_ORDINARY = 0,
|
||||||
MAP_FLOWTROUGH_IF_QUOTED = 1,
|
CHAR_ORDINARY_IF_QUOTED = 1, /* example: *, # */
|
||||||
MAP_IFS_IF_UNQUOTED = 2, /* flow through if quoted too */
|
CHAR_IFS = 2, /* treated as ordinary if quoted */
|
||||||
MAP_NEVER_FLOWTROUGH = 3,
|
CHAR_SPECIAL = 3, /* example: $ */
|
||||||
};
|
};
|
||||||
static unsigned char map[256];
|
static unsigned char charmap[256];
|
||||||
static const char *ifs;
|
static const char *ifs;
|
||||||
static int fake_mode;
|
static int fake_mode;
|
||||||
static struct close_me *close_me_head;
|
static struct close_me *close_me_head;
|
||||||
@ -2311,7 +2311,7 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
|
|||||||
* Caller can deallocate entire list by single free(list). */
|
* Caller can deallocate entire list by single free(list). */
|
||||||
|
|
||||||
/* Helpers first:
|
/* Helpers first:
|
||||||
* count_XXX estimates, how large block do we need. It's okay
|
* count_XXX estimates size of the block we need. It's okay
|
||||||
* to over-estimate sizes a bit, if it makes code simpler */
|
* to over-estimate sizes a bit, if it makes code simpler */
|
||||||
static int count_ifs(const char *str)
|
static int count_ifs(const char *str)
|
||||||
{
|
{
|
||||||
@ -3360,17 +3360,17 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
|
|||||||
debug_printf_parse("parse_stream entered, end_trigger='%s'\n", end_trigger);
|
debug_printf_parse("parse_stream entered, end_trigger='%s'\n", end_trigger);
|
||||||
|
|
||||||
while ((ch = b_getch(input)) != EOF) {
|
while ((ch = b_getch(input)) != EOF) {
|
||||||
m = map[ch];
|
m = charmap[ch];
|
||||||
next = (ch == '\n') ? '\0' : b_peek(input);
|
next = (ch == '\n') ? '\0' : b_peek(input);
|
||||||
debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n",
|
debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n",
|
||||||
ch, ch, m, dest->quote);
|
ch, ch, m, dest->quote);
|
||||||
if (m == MAP_ORDINARY
|
if (m == CHAR_ORDINARY
|
||||||
|| (m != MAP_NEVER_FLOWTROUGH && dest->quote)
|
|| (m != CHAR_SPECIAL && dest->quote)
|
||||||
) {
|
) {
|
||||||
b_addqchr(dest, ch, dest->quote);
|
b_addqchr(dest, ch, dest->quote);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (m == MAP_IFS_IF_UNQUOTED) {
|
if (m == CHAR_IFS) {
|
||||||
if (done_word(dest, ctx)) {
|
if (done_word(dest, ctx)) {
|
||||||
debug_printf_parse("parse_stream return 1: done_word!=0\n");
|
debug_printf_parse("parse_stream return 1: done_word!=0\n");
|
||||||
return 1;
|
return 1;
|
||||||
@ -3388,7 +3388,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
|
|||||||
debug_printf_parse("parse_stream return 0: end_trigger char found\n");
|
debug_printf_parse("parse_stream return 0: end_trigger char found\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (m == MAP_IFS_IF_UNQUOTED)
|
if (m == CHAR_IFS)
|
||||||
continue;
|
continue;
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '#':
|
case '#':
|
||||||
@ -3527,28 +3527,28 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mapset(const char *set, int code)
|
static void set_in_charmap(const char *set, int code)
|
||||||
{
|
{
|
||||||
while (*set)
|
while (*set)
|
||||||
map[(unsigned char)*set++] = code;
|
charmap[(unsigned char)*set++] = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_ifs_map(void)
|
static void update_charmap(void)
|
||||||
{
|
{
|
||||||
/* char *ifs and char map[256] are both globals. */
|
/* char *ifs and char charmap[256] are both globals. */
|
||||||
ifs = getenv("IFS");
|
ifs = getenv("IFS");
|
||||||
if (ifs == NULL)
|
if (ifs == NULL)
|
||||||
ifs = " \t\n";
|
ifs = " \t\n";
|
||||||
/* Precompute a list of 'flow through' behavior so it can be treated
|
/* Precompute a list of 'flow through' behavior so it can be treated
|
||||||
* quickly up front. Computation is necessary because of IFS.
|
* quickly up front. Computation is necessary because of IFS.
|
||||||
* Special case handling of IFS == " \t\n" is not implemented.
|
* Special case handling of IFS == " \t\n" is not implemented.
|
||||||
* The map[] array only really needs two bits each, and on most machines
|
* The charmap[] array only really needs two bits each,
|
||||||
* that would be faster because of the reduced L1 cache footprint.
|
* and on most machines that would be faster (reduced L1 cache use).
|
||||||
*/
|
*/
|
||||||
memset(map, MAP_ORDINARY, sizeof(map)); /* most chars flow through always */
|
memset(charmap, CHAR_ORDINARY, sizeof(charmap));
|
||||||
mapset("\\$'\"`", MAP_NEVER_FLOWTROUGH);
|
set_in_charmap("\\$\"`", CHAR_SPECIAL);
|
||||||
mapset("<>;&|(){}#", MAP_FLOWTROUGH_IF_QUOTED);
|
set_in_charmap("<>;&|(){}#'", CHAR_ORDINARY_IF_QUOTED);
|
||||||
mapset(ifs, MAP_IFS_IF_UNQUOTED); /* also flow through if quoted */
|
set_in_charmap(ifs, CHAR_IFS); /* also flow through if quoted */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* most recursion does not come through here, the exception is
|
/* most recursion does not come through here, the exception is
|
||||||
@ -3561,9 +3561,9 @@ static int parse_stream_outer(struct in_str *inp, int parse_flag)
|
|||||||
do {
|
do {
|
||||||
ctx.parse_type = parse_flag;
|
ctx.parse_type = parse_flag;
|
||||||
initialize_context(&ctx);
|
initialize_context(&ctx);
|
||||||
update_ifs_map();
|
update_charmap();
|
||||||
if (!(parse_flag & FLAG_PARSE_SEMICOLON) || (parse_flag & FLAG_REPARSING))
|
if (!(parse_flag & FLAG_PARSE_SEMICOLON) || (parse_flag & FLAG_REPARSING))
|
||||||
mapset(";$&|", MAP_ORDINARY);
|
set_in_charmap(";$&|", CHAR_ORDINARY);
|
||||||
#if ENABLE_HUSH_INTERACTIVE
|
#if ENABLE_HUSH_INTERACTIVE
|
||||||
inp->promptmode = 1;
|
inp->promptmode = 1;
|
||||||
#endif
|
#endif
|
||||||
@ -3665,7 +3665,7 @@ int hush_main(int argc, char **argv)
|
|||||||
* hush_main(), therefore we cannot rely on the BSS to zero out this
|
* hush_main(), therefore we cannot rely on the BSS to zero out this
|
||||||
* stuff. Reset these to 0 every time. */
|
* stuff. Reset these to 0 every time. */
|
||||||
ifs = NULL;
|
ifs = NULL;
|
||||||
/* map[] is taken care of with call to update_ifs_map() */
|
/* charmap[] is taken care of with call to update_charmap() */
|
||||||
fake_mode = 0;
|
fake_mode = 0;
|
||||||
close_me_head = NULL;
|
close_me_head = NULL;
|
||||||
#if ENABLE_HUSH_INTERACTIVE
|
#if ENABLE_HUSH_INTERACTIVE
|
||||||
|
Loading…
Reference in New Issue
Block a user