diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 0d5a20a8..ebe8505c 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -9956,3 +9956,22 @@ builtins/setattr.def be ANSI-C quoted, use ansic_quote instead of sh_double_quote to format the value string. From proposal by Greg Wooledge + + 4/5 + --- +arrayfunc.c + - unbind_array_element: if FLAGS includes VA_ONEWORD, don't use + skipsubscript to parse the subscript, just assume the entire SUB is + the subcript and that it contains the closing `]', so we just want + everything in SUB except the last character. + +parse.y: + - select_command: use compound_list instead of list, like for_command. + Report by Greywolf + - list: move this into compound_list (replacing the instance of `list' + in the compound_list production), remove from the grammar + + 4/6 + --- +arrayfunc.c + - unbind_array_element: use VA_NOEXPAND instead of literal 1 diff --git a/arrayfunc.c b/arrayfunc.c index 778c4008..62a076b2 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -1025,7 +1025,10 @@ quote_array_assignment_chars (list) /* This function is called with SUB pointing to just after the beginning `[' of an array subscript and removes the array element to which SUB expands from array VAR. A subscript of `*' or `@' unsets the array. */ -/* If FLAGS&1 we don't expand the subscript; we just use it as-is. */ +/* If FLAGS&1 (VA_NOEXPAND) we don't expand the subscript; we just use it + as-is. If FLAGS&VA_ONEWORD, we don't try to use skipsubscript to parse + the subscript, we just assume the subscript ends with a close bracket + and use the rest. */ int unbind_array_element (var, sub, flags) SHELL_VAR *var; @@ -1037,7 +1040,12 @@ unbind_array_element (var, sub, flags) char *akey; ARRAY_ELEMENT *ae; - len = skipsubscript (sub, 0, (flags&1) || (var && assoc_p(var))); /* XXX */ + /* If the caller tells us to treat the entire `sub' as one word, we don't + bother to call skipsubscript. */ + if (var && assoc_p (var) && (flags&VA_ONEWORD)) + len = strlen (sub) - 1; + else + len = skipsubscript (sub, 0, (flags&VA_NOEXPAND) || (var && assoc_p(var))); /* XXX */ if (sub[len] != ']' || len == 0) { builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg)); @@ -1058,7 +1066,7 @@ unbind_array_element (var, sub, flags) if (assoc_p (var)) { - akey = (flags & 1) ? sub : expand_assignment_string_to_string (sub, 0); + akey = (flags & VA_NOEXPAND) ? sub : expand_assignment_string_to_string (sub, 0); if (akey == 0 || *akey == 0) { builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg)); diff --git a/arrayfunc.h b/arrayfunc.h index 838e76d2..b13d272f 100644 --- a/arrayfunc.h +++ b/arrayfunc.h @@ -40,9 +40,11 @@ extern int array_expand_once; #define AV_ASSIGNRHS 0x010 /* no splitting, special case ${a[@]} */ #define AV_NOEXPAND 0x020 /* don't run assoc subscripts through word expansion */ -/* Flags for valid_array_reference. Value 1 is reserved for skipsubscript() */ +/* Flags for valid_array_reference. Value 1 is reserved for skipsubscript(). + Also used by unbind_array_element. */ #define VA_NOEXPAND 0x001 #define VA_ONEWORD 0x002 +#define VA_ALLOWALL 0x004 /* allow @ to mean all elements of the array */ extern SHELL_VAR *convert_var_to_array PARAMS((SHELL_VAR *)); extern SHELL_VAR *convert_var_to_assoc PARAMS((SHELL_VAR *)); @@ -93,7 +95,9 @@ extern SHELL_VAR *array_variable_part PARAMS((const char *, int, char **, int *) #define AV_USEIND 0 #define AV_ASSIGNRHS 0 +#define VA_NOEXPAND 0 #define VA_ONEWORD 0 +#define VA_ALLOWALL 0 #endif diff --git a/doc/bash.1 b/doc/bash.1 index 7ceb2ba8..503e2425 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -1218,8 +1218,8 @@ and \fBTEXTDOMAIN\fP shell variables. If the current locale is \fBC\fP or \fBPOSIX\fP, or if there are no translations available, the dollar sign is ignored. -If the string is translated and replaced, the replacement is -double-quoted. +This is a form of quoting, so the string always remains double-quoted, +whether or not it is translated and replaced. .SH PARAMETERS A .I parameter diff --git a/doc/bashref.texi b/doc/bashref.texi index 7c887fa7..e43b9d44 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -549,8 +549,8 @@ If the current locale is @code{C} or @code{POSIX}, or if there are no translations available, the dollar sign is ignored, and the shell doesn't attempt to translate the string. -If the string is translated and replaced, the replacement -remains double-quoted. +Since this is a form of quoting, the string always remains double-quoted, +whether or not it is translated and replaced. The rest of this section is a brief overview of how you use gettext to create translations for strings in a shell script named @var{scriptname}. diff --git a/parse.y b/parse.y index 2d39347a..54957442 100644 --- a/parse.y +++ b/parse.y @@ -356,7 +356,7 @@ static FILE *yyerrstream; /* The types that the various syntactical units return. */ %type inputunit command pipeline pipeline_command -%type list list0 list1 compound_list simple_list simple_list1 +%type list0 list1 compound_list simple_list simple_list1 %type simple_command shell_command %type for_command select_command case_command group_command %type arith_command @@ -865,32 +865,32 @@ arith_for_command: FOR ARITH_FOR_EXPRS list_terminator newline_list DO compound_ } ; -select_command: SELECT WORD newline_list DO list DONE +select_command: SELECT WORD newline_list DO compound_list DONE { $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); if (word_top > 0) word_top--; } - | SELECT WORD newline_list '{' list '}' + | SELECT WORD newline_list '{' compound_list '}' { $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5, word_lineno[word_top]); if (word_top > 0) word_top--; } - | SELECT WORD ';' newline_list DO list DONE + | SELECT WORD ';' newline_list DO compound_list DONE { $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); if (word_top > 0) word_top--; } - | SELECT WORD ';' newline_list '{' list '}' + | SELECT WORD ';' newline_list '{' compound_list '}' { $$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $6, word_lineno[word_top]); if (word_top > 0) word_top--; } - | SELECT WORD newline_list IN word_list list_terminator newline_list DO list DONE + | SELECT WORD newline_list IN word_list list_terminator newline_list DO compound_list DONE { $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); if (word_top > 0) word_top--; } - | SELECT WORD newline_list IN word_list list_terminator newline_list '{' list '}' + | SELECT WORD newline_list IN word_list list_terminator newline_list '{' compound_list '}' { $$ = make_select_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9, word_lineno[word_top]); if (word_top > 0) word_top--; @@ -1094,15 +1094,12 @@ pattern: WORD It must end with a newline or semicolon. Lists are used within commands such as if, for, while. */ -list: newline_list list0 +compound_list: newline_list list0 { $$ = $2; if (need_here_doc) gather_here_documents (); } - ; - -compound_list: list | newline_list list1 { $$ = $2; diff --git a/tests/exp.right b/tests/exp.right index c14db001..b6b3747d 100644 --- a/tests/exp.right +++ b/tests/exp.right @@ -231,7 +231,7 @@ declare -- var=$'x\001y\177z' argv[1] = argv[2] = <--> argv[3] = -declare -- var=$'x\001y\177z'$ +var=x\001y\177z$ declare -- var="x\001y\177z"$ argv[1] = <$'x\001y\177z'> argv[1] = diff --git a/tests/exp8.sub b/tests/exp8.sub index abd2e9a6..7dd5a286 100644 --- a/tests/exp8.sub +++ b/tests/exp8.sub @@ -19,7 +19,7 @@ recho $var declare -p var recho $(declare -p var) -declare -p var | sed -n l +echo "var=$var" | sed -n l echo "declare -- var=\"$var\"" | sed -n l recho ${var@Q}