diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 122d615c..604a3375 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -7384,3 +7384,109 @@ execute_cmd.c parse.y - special_case_tokens: allow `time -- command' + + 2/21 + ---- +subst.c + - get_var_and_type: if an unset variable (not an array) is supplied + with the `[@]' subscript, don't return "". Fix to bug reported by + Arfrever Frehtes Taifersar Arahesis ; + original bug introduced 7/29/2018 + - array_transform: take a STARSUB argument instead of VARNAME, since + we've already computed what kind of index the array reference uses + in get_var_and_type, and passing VARNAME to figure out the index + type doesn't do the right thing when we're using indirect variable + expansion. Fixes bug reported by + Arfrever Frehtes Taifersar Arahesis + - array_remove_pattern: take the same new STARSUB argument for the + same reason + - parameter_brace_transform,parameter_brace_remove_pattern: change + callers to pass STARSUB instead of VARNAME + + 2/22 + ---- +execute_cmd.c + - fix_assignment_words: if an assignment is supplied to a builtin that + creates or modifies local variables while a function is executing, + set the W_FORCELOCAL flag for that word in addition to any of the + various assignment flags + +subst.c + - shell_expand_word_list: while processing a list of assignments that + are arguments to a builtin that creates or modifies local variables, + if make_internal_declare fails while attempting to create the local + variable (or give it attributes), skip attempting the assignment but + otherwise do not make this a fatal error. This results in two error + messages: one to create the variable or modify its attributes, and + one while attempting to assign the value, but the errors to not + cause the function to return immediately. Fixes inconsistency + reported by Arfrever Frehtes Taifersar Arahesis + + + 2/23 + ---- +trap.c + - first_pending_trap: generalize into first_pending_trap and + next_pending_trap + +wait.def + - wait_builtin: close up the trapped-signal-arrives hole a little more + by looking for a signal that arrived between the last check for + pending traps and setting wait_intr_flag and behaving as if it + arrived while wait was executing. Use first_pending_trap and + next_pending_trap to find a pending trap that is not SIGCHLD + +trap.c + - trap_handler: longjmp to wait_intr_buf unconditionally if + wait_intr_flag is set; don't bother with interrupt_immediately any + more + +variables.c + - all_local_variables: now takes an arg saying whether to restrict + return value to visible variables or return all local variables, + even those that are unset (the new default) + - visible_variable_in_context: new function, restricts return values + to set local variables in the current context; variable_in_context + now returns all local variables in the current context, even the + unset ones + +variables.h + - all_local_variables: change extern function declaration + +builtins/setattr.def + - show_local_var_attributes: show all local variables at the current + variable context, including unset ones, and their attributes + - show_localname_attributes: show attributes for NAME as long as NAME + resolves to a local variable at the current variable context, even + if NAME is unset + +builtins/common.h + - show_local_var_attributes, show_localname_attributes: new extern + declarations + +builtins/declare.def + - declare_internal: allow `-p' option for `local' builtin + - declare_internal: if `local' is supplied without options, or with + the `-p' option, but no variable name arguments, display all local + variables at the current variable context by calling + show_local_var_attributes + - declare_internal: if `local -p' is supplied with variable name + arguments, call show_localname_attributes to display the attributes + for that name if it resolves to a local variable at the current + variable context. Fixes issue reported by + pepa65 + +subst.c + - array_var_assignment: if VAR is unset, print the declare command + without the assignment statement, just with the attributes + - array_transform: special-case the 'a' attribute and return the + attribute string even if the array variable is unset. Feature request + from Arfrever Frehtes Taifersar Arahesis + - parameter_brace_transform: if asked to display the attributes and + value ('A') of an unset variable, make sure we pass the variable, if + it exists with attributes but without a value, to string_transform + - string_transform: if we don't have a value but the operator is 'A', + pass the variable through to string_var_assignment + - string_var_assignment: if we have an unset variable with attributes, + return a declare command that just sets the attributes. Feature request + from Arfrever Frehtes Taifersar Arahesis diff --git a/MANIFEST b/MANIFEST index 8588d50e..554f6816 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1212,6 +1212,7 @@ tests/new-exp9.sub f tests/new-exp10.sub f tests/new-exp11.sub f tests/new-exp12.sub f +tests/new-exp13.sub f tests/new-exp.right f tests/nquote.tests f tests/nquote.right f diff --git a/builtins/common.h b/builtins/common.h index d6fd99d9..0aecc9ce 100644 --- a/builtins/common.h +++ b/builtins/common.h @@ -187,8 +187,10 @@ extern int describe_command PARAMS((char *, int)); /* Functions from setattr.def */ extern int set_or_show_attributes PARAMS((WORD_LIST *, int, int)); extern int show_all_var_attributes PARAMS((int, int)); +extern int show_local_var_attributes PARAMS((int, int)); extern int show_var_attributes PARAMS((SHELL_VAR *, int, int)); extern int show_name_attributes PARAMS((char *, int)); +extern int show_localname_attributes PARAMS((char *, int)); extern int show_func_attributes PARAMS((char *, int)); extern void set_var_attribute PARAMS((char *, int, int)); extern int var_attribute_string PARAMS((SHELL_VAR *, int, char *)); diff --git a/builtins/declare.def b/builtins/declare.def index 3fd1eb64..b1b69274 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -202,7 +202,7 @@ declare_internal (list, local_var) return (EX_USAGE); #endif case 'p': - if (local_var == 0) +/* if (local_var == 0) */ pflag++; break; case 'F': @@ -271,20 +271,7 @@ declare_internal (list, local_var) /* Show local variables defined at this context level if this is the `local' builtin. */ if (local_var) - { - register SHELL_VAR **vlist; - register int i; - - vlist = all_local_variables (); - - if (vlist) - { - for (i = 0; vlist[i]; i++) - print_assignment (vlist[i]); - - free (vlist); - } - } + show_local_var_attributes (0, nodefs); /* XXX - fix up args later */ else if (pflag && (flags_on == 0 || flags_on == att_function)) show_all_var_attributes (flags_on == 0, nodefs); else if (flags_on == 0) @@ -301,6 +288,8 @@ declare_internal (list, local_var) { if (flags_on & att_function) pflag = show_func_attributes (list->word->word, nodefs); + else if (local_var) + pflag = show_localname_attributes (list->word->word, nodefs); else pflag = show_name_attributes (list->word->word, nodefs); if (pflag) diff --git a/builtins/setattr.def b/builtins/setattr.def index 251bcacb..a75af70c 100644 --- a/builtins/setattr.def +++ b/builtins/setattr.def @@ -371,6 +371,30 @@ show_all_var_attributes (v, nodefs) return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE); } +/* Show all local variable variables with their attributes. This shows unset + local variables (all_local_variables called with 0 argment). */ +int +show_local_var_attributes (v, nodefs) + int v, nodefs; +{ + SHELL_VAR **variable_list, *var; + int any_failed; + register int i; + + variable_list = all_local_variables (0); + if (variable_list == 0) + return (EXECUTION_SUCCESS); + + for (i = any_failed = 0; var = variable_list[i]; i++) + { + show_var_attributes (var, READONLY_OR_EXPORT, nodefs); + if (any_failed = sh_chkwrite (any_failed)) + break; + } + free (variable_list); + return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE); +} + int var_attribute_string (var, pattr, flags) SHELL_VAR *var; @@ -504,13 +528,27 @@ show_name_attributes (name, nodefs) { SHELL_VAR *var; -#if 0 - var = find_variable_tempenv (name); -#else var = find_variable_noref (name); -#endif - if (var /* && invisible_p (var) == 0 */) + if (var) /* show every variable with attributes, even unset ones */ + { + show_var_attributes (var, READONLY_OR_EXPORT, nodefs); + return (0); + } + else + return (1); +} + +int +show_localname_attributes (name, nodefs) + char *name; + int nodefs; +{ + SHELL_VAR *var; + + var = find_variable_noref (name); + + if (var && local_p (var) && var->context == variable_context) /* show every variable with attributes, even unset ones */ { show_var_attributes (var, READONLY_OR_EXPORT, nodefs); return (0); diff --git a/builtins/wait.def b/builtins/wait.def index a96a6c66..2aa0d3cf 100644 --- a/builtins/wait.def +++ b/builtins/wait.def @@ -176,6 +176,21 @@ wait_builtin (list) WAIT_RETURN (status); } + opt = first_pending_trap (); +#if defined (SIGCHLD) + /* We special case SIGCHLD when not in posix mode because we don't break + out of the wait even when the signal is trapped; we run the trap after + the wait completes. See how it's handled in jobs.c:waitchld(). */ + if (opt == SIGCHLD && posixly_correct == 0) + opt = next_pending_trap (opt+1); +#endif + if (opt != -1) + { + last_command_exit_signal = wait_signal_received = opt; + status = opt + 128; + WAIT_RETURN (status); + } + /* We support jobs or pids. wait [pid-or-job ...] */ diff --git a/command.h b/command.h index 886aa17d..87c6f92b 100644 --- a/command.h +++ b/command.h @@ -73,36 +73,37 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select, cm_arith, cm_cond, cm_arith_for, cm_subshell, cm_coproc }; /* Possible values for the `flags' field of a WORD_DESC. */ -#define W_HASDOLLAR 0x000001 /* Dollar sign present. */ -#define W_QUOTED 0x000002 /* Some form of quote character is present. */ -#define W_ASSIGNMENT 0x000004 /* This word is a variable assignment. */ -#define W_SPLITSPACE 0x000008 /* Split this word on " " regardless of IFS */ -#define W_NOSPLIT 0x000010 /* Do not perform word splitting on this word because ifs is empty string. */ -#define W_NOGLOB 0x000020 /* Do not perform globbing on this word. */ -#define W_NOSPLIT2 0x000040 /* Don't split word except for $@ expansion (using spaces) because context does not allow it. */ -#define W_TILDEEXP 0x000080 /* Tilde expand this assignment word */ -#define W_DOLLARAT 0x000100 /* $@ and its special handling */ -#define W_DOLLARSTAR 0x000200 /* $* and its special handling */ -#define W_NOCOMSUB 0x000400 /* Don't perform command substitution on this word */ -#define W_ASSIGNRHS 0x000800 /* Word is rhs of an assignment statement */ -#define W_NOTILDE 0x001000 /* Don't perform tilde expansion on this word */ -#define W_ITILDE 0x002000 /* Internal flag for word expansion */ -#define W_EXPANDRHS 0x004000 /* Expanding word in ${paramOPword} */ -#define W_COMPASSIGN 0x008000 /* Compound assignment */ -#define W_ASSNBLTIN 0x010000 /* word is a builtin command that takes assignments */ -#define W_ASSIGNARG 0x020000 /* word is assignment argument to command */ -#define W_HASQUOTEDNULL 0x040000 /* word contains a quoted null character */ -#define W_DQUOTE 0x080000 /* word should be treated as if double-quoted */ -#define W_NOPROCSUB 0x100000 /* don't perform process substitution */ -#define W_SAWQUOTEDNULL 0x200000 /* word contained a quoted null that was removed */ -#define W_ASSIGNASSOC 0x400000 /* word looks like associative array assignment */ -#define W_ASSIGNARRAY 0x800000 /* word looks like a compound indexed array assignment */ -#define W_ARRAYIND 0x1000000 /* word is an array index being expanded */ -#define W_ASSNGLOBAL 0x2000000 /* word is a global assignment to declare (declare/typeset -g) */ -#define W_NOBRACE 0x4000000 /* Don't perform brace expansion */ -#define W_COMPLETE 0x8000000 /* word is being expanded for completion */ -#define W_CHKLOCAL 0x10000000 /* check for local vars on assignment */ -#define W_NOASSNTILDE 0x20000000 /* don't do tilde expansion like an assignment statement */ +#define W_HASDOLLAR (1 << 0) /* Dollar sign present. */ +#define W_QUOTED (1 << 1) /* Some form of quote character is present. */ +#define W_ASSIGNMENT (1 << 2) /* This word is a variable assignment. */ +#define W_SPLITSPACE (1 << 3) /* Split this word on " " regardless of IFS */ +#define W_NOSPLIT (1 << 4) /* Do not perform word splitting on this word because ifs is empty string. */ +#define W_NOGLOB (1 << 5) /* Do not perform globbing on this word. */ +#define W_NOSPLIT2 (1 << 6) /* Don't split word except for $@ expansion (using spaces) because context does not allow it. */ +#define W_TILDEEXP (1 << 7) /* Tilde expand this assignment word */ +#define W_DOLLARAT (1 << 8) /* $@ and its special handling -- UNUSED */ +#define W_DOLLARSTAR (1 << 9) /* $* and its special handling -- UNUSED */ +#define W_NOCOMSUB (1 << 10) /* Don't perform command substitution on this word */ +#define W_ASSIGNRHS (1 << 11) /* Word is rhs of an assignment statement */ +#define W_NOTILDE (1 << 12) /* Don't perform tilde expansion on this word */ +#define W_ITILDE (1 << 13) /* Internal flag for word expansion */ +#define W_EXPANDRHS (1 << 14) /* Expanding word in ${paramOPword} */ +#define W_COMPASSIGN (1 << 15) /* Compound assignment */ +#define W_ASSNBLTIN (1 << 16) /* word is a builtin command that takes assignments */ +#define W_ASSIGNARG (1 << 17) /* word is assignment argument to command */ +#define W_HASQUOTEDNULL (1 << 18) /* word contains a quoted null character */ +#define W_DQUOTE (1 << 19) /* word should be treated as if double-quoted */ +#define W_NOPROCSUB (1 << 20) /* don't perform process substitution */ +#define W_SAWQUOTEDNULL (1 << 21) /* word contained a quoted null that was removed */ +#define W_ASSIGNASSOC (1 << 22) /* word looks like associative array assignment */ +#define W_ASSIGNARRAY (1 << 23) /* word looks like a compound indexed array assignment */ +#define W_ARRAYIND (1 << 24) /* word is an array index being expanded */ +#define W_ASSNGLOBAL (1 << 25) /* word is a global assignment to declare (declare/typeset -g) */ +#define W_NOBRACE (1 << 26) /* Don't perform brace expansion */ +#define W_COMPLETE (1 << 27) /* word is being expanded for completion */ +#define W_CHKLOCAL (1 << 28) /* check for local vars on assignment */ +#define W_NOASSNTILDE (1 << 29) /* don't do tilde expansion like an assignment statement */ +#define W_FORCELOCAL (1 << 30) /* force assignments to be to local variables, non-fatal on assignment errors */ /* Flags for the `pflags' argument to param_expand() and various parameter_brace_expand_xxx functions; also used for string_list_dollar_at */ diff --git a/execute_cmd.c b/execute_cmd.c index 8a011607..a1ddc2d2 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -4120,10 +4120,8 @@ fix_assignment_words (words) an existing local variable, if there is one. */ if (b && ((b->flags & (ASSIGNMENT_BUILTIN|LOCALVAR_BUILTIN)) == ASSIGNMENT_BUILTIN)) w->word->flags |= W_ASSNGLOBAL|W_CHKLOCAL; -#if 0 - else if (b && (b->flags & ASSIGNMENT_BUILTIN) && (b->flags & LOCALVAR_BUILTIN)) - w->word->flags |= W_CHKLOCAL; -#endif + else if (b && (b->flags & ASSIGNMENT_BUILTIN) && (b->flags & LOCALVAR_BUILTIN) && variable_context) + w->word->flags |= W_FORCELOCAL; } #if defined (ARRAY_VARS) /* Note that we saw an associative array option to a builtin that takes diff --git a/jobs.c b/jobs.c index 1f239171..83d5ebcb 100644 --- a/jobs.c +++ b/jobs.c @@ -2739,8 +2739,7 @@ wait_sigint_handler (sig) if (interrupt_immediately || (this_shell_builtin && this_shell_builtin == wait_builtin)) { - last_command_exit_value = 128+SIGINT; - set_pipestatus_from_exit (last_command_exit_value); + set_exit_status (128+SIGINT); restore_sigint_handler (); /* If we got a SIGINT while in `wait', and SIGINT is trapped, do what POSIX.2 says (see builtins/wait.def for more info). */ @@ -2774,8 +2773,7 @@ wait_sigint_handler (sig) wait_sigint_received = 1; else { - last_command_exit_value = 128+SIGINT; - set_pipestatus_from_exit (last_command_exit_value); + set_exit_status (128+SIGINT); restore_sigint_handler (); kill (getpid (), SIGINT); } diff --git a/subst.c b/subst.c index 539834a2..92ca863c 100644 --- a/subst.c +++ b/subst.c @@ -285,7 +285,7 @@ static char *variable_remove_pattern PARAMS((char *, char *, int, int)); static char *list_remove_pattern PARAMS((WORD_LIST *, char *, int, int, int)); static char *parameter_list_remove_pattern PARAMS((int, char *, int, int)); #ifdef ARRAY_VARS -static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, char *, int)); +static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int)); #endif static char *parameter_brace_remove_pattern PARAMS((char *, char *, int, char *, int, int, int)); @@ -298,7 +298,7 @@ static char *string_transform PARAMS((int, SHELL_VAR *, char *)); static char *list_transform PARAMS((int, SHELL_VAR *, WORD_LIST *, int, int)); static char *parameter_list_transform PARAMS((int, int, int)); #if defined ARRAY_VARS -static char *array_transform PARAMS((int, SHELL_VAR *, char *, int)); +static char *array_transform PARAMS((int, SHELL_VAR *, int, int)); #endif static char *parameter_brace_transform PARAMS((char *, char *, int, char *, int, int, int, int)); @@ -523,7 +523,12 @@ dump_word_flags (flags) f &= ~W_CHKLOCAL; fprintf (stderr, "W_CHKLOCAL%s", f ? "|" : ""); } - + if (f & W_FORCELOCAL) + { + f &= ~W_FORCELOCAL; + fprintf (stderr, "W_FORCELOCAL%s", f ? "|" : ""); + } + fprintf (stderr, "\n"); fflush (stderr); } @@ -5224,11 +5229,11 @@ parameter_list_remove_pattern (itype, pattern, patspec, quoted) #if defined (ARRAY_VARS) static char * -array_remove_pattern (var, pattern, patspec, varname, quoted) +array_remove_pattern (var, pattern, patspec, starsub, quoted) SHELL_VAR *var; char *pattern; int patspec; - char *varname; /* so we can figure out how it's indexed */ + int starsub; /* so we can figure out how it's indexed */ int quoted; { ARRAY *a; @@ -5238,14 +5243,9 @@ array_remove_pattern (var, pattern, patspec, varname, quoted) WORD_LIST *list; SHELL_VAR *v; - /* compute itype from varname here */ - v = array_variable_part (varname, 0, &ret, 0); + v = var; /* XXX - for now */ - /* XXX */ - if (v && invisible_p (v)) - return ((char *)NULL); - - itype = ret[0]; + itype = starsub ? '*' : '@'; a = (v && array_p (v)) ? array_cell (v) : 0; h = (v && assoc_p (v)) ? assoc_cell (v) : 0; @@ -5316,7 +5316,7 @@ parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flag break; #if defined (ARRAY_VARS) case VT_ARRAYVAR: - temp1 = array_remove_pattern (v, pattern, patspec, varname, quoted); + temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted); if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) { val = quote_escapes (temp1); @@ -7560,7 +7560,7 @@ get_var_and_type (varname, value, ind, quoted, flags, varp, valp) vtype = VT_VARIABLE; *varp = v; if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - *valp = value ? dequote_string (value) : savestring (""); + *valp = value ? dequote_string (value) : (char *)NULL; else *valp = value ? dequote_escapes (value) : (char *)NULL; } @@ -7612,10 +7612,15 @@ string_var_assignment (v, s) char flags[MAX_ATTRIBUTES], *ret, *val; int i; - val = sh_quote_reusable (s, 0); + val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0); i = var_attribute_string (v, 0, flags); - ret = (char *)xmalloc (i + strlen (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES); - if (i > 0) + if (i == 0 && val == 0) + return (char *)NULL; + + ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES); + if (i > 0 && val == 0) + sprintf (ret, "declare -%s %s", flags, v->name); + else if (i > 0) sprintf (ret, "declare -%s %s=%s", flags, v->name, val); else sprintf (ret, "%s=%s", v->name, val); @@ -7636,7 +7641,10 @@ array_var_assignment (v, itype, quoted) return (char *)NULL; val = array_p (v) ? array_to_assign (array_cell (v), 0) : assoc_to_assign (assoc_cell (v), 0); - if (val == 0) + + if (val == 0 && (invisible_p (v) || var_isset (v) == 0)) + ; /* placeholder */ + else if (val == 0) { val = (char *)xmalloc (3); val[0] = LPAREN; @@ -7650,8 +7658,11 @@ array_var_assignment (v, itype, quoted) val = ret; } i = var_attribute_string (v, 0, flags); - ret = (char *)xmalloc (i + strlen (val) + strlen (v->name) + 16); - sprintf (ret, "declare -%s %s=%s", flags, v->name, val); + ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16); + if (val) + sprintf (ret, "declare -%s %s=%s", flags, v->name, val); + else + sprintf (ret, "declare -%s %s", flags, v->name); free (val); return ret; } @@ -7683,7 +7694,9 @@ string_transform (xc, v, s) char *ret, flags[MAX_ATTRIBUTES], *t; int i; - if (((xc == 'A' || xc == 'a') && v == 0) || (xc != 'a' && s == 0)) + if (((xc == 'A' || xc == 'a') && v == 0)) + return (char *)NULL; + else if (xc != 'a' && xc != 'A' && s == 0) return (char *)NULL; switch (xc) @@ -7770,10 +7783,10 @@ parameter_list_transform (xc, itype, quoted) #if defined (ARRAY_VARS) static char * -array_transform (xc, var, varname, quoted) +array_transform (xc, var, starsub, quoted) int xc; SHELL_VAR *var; - char *varname; /* so we can figure out how it's indexed */ + int starsub; /* so we can figure out how it's indexed */ int quoted; { ARRAY *a; @@ -7783,21 +7796,26 @@ array_transform (xc, var, varname, quoted) WORD_LIST *list; SHELL_VAR *v; - /* compute itype from varname here */ - v = array_variable_part (varname, 0, &ret, 0); + v = var; /* XXX - for now */ - /* XXX */ - if (v && invisible_p (v)) - return ((char *)NULL); - - itype = ret[0]; + itype = starsub ? '*' : '@'; if (xc == 'A') return (array_var_assignment (v, itype, quoted)); + /* special case for unset arrays and attributes */ + if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0)) + { + char flags[MAX_ATTRIBUTES]; + int i; + + i = var_attribute_string (v, 0, flags); + return ((i > 0) ? savestring (flags) : (char *)NULL); + } + a = (v && array_p (v)) ? array_cell (v) : 0; h = (v && assoc_p (v)) ? assoc_cell (v) : 0; - + list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); if (list == 0) return ((char *)NULL); @@ -7815,7 +7833,7 @@ parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, fl char *xform; int rtype, quoted, pflags, flags; { - int vtype, xc; + int vtype, xc, starsub; char *temp1, *val, *oname; SHELL_VAR *v; @@ -7847,13 +7865,16 @@ parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, fl return &expand_param_error; } + starsub = vtype & VT_STARSUB; + vtype &= ~VT_STARSUB; + /* If we are asked to display the attributes of an unset variable, V will be NULL after the call to get_var_and_type. Double-check here. */ - if (xc == 'a' && vtype == VT_VARIABLE && varname && v == 0) + if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0) v = find_variable (varname); temp1 = (char *)NULL; /* shut up gcc */ - switch (vtype & ~VT_STARSUB) + switch (vtype) { case VT_VARIABLE: case VT_ARRAYMEMBER: @@ -7871,7 +7892,7 @@ parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, fl break; #if defined (ARRAY_VARS) case VT_ARRAYVAR: - temp1 = array_transform (xc, v, varname, quoted); + temp1 = array_transform (xc, v, starsub, quoted); if (temp1 && quoted == 0 && ifs_is_null) { /* Posix interp 888 */ @@ -11479,7 +11500,7 @@ shell_expand_word_list (tlist, eflags) { int t; char opts[16]; - int opti; + int opti, skip; opti = 0; if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY)) @@ -11544,21 +11565,28 @@ shell_expand_word_list (tlist, eflags) } opts[opti] = '\0'; + skip = 0; if (opti > 0) { t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0); if (t != EXECUTION_SUCCESS) { last_command_exit_value = t; - exp_jump_to_top_level (DISCARD); + if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */ + skip = 1; + else + exp_jump_to_top_level (DISCARD); } } - t = do_word_assignment (tlist->word, 0); - if (t == 0) + if (skip == 0) { - last_command_exit_value = EXECUTION_FAILURE; - exp_jump_to_top_level (DISCARD); + t = do_word_assignment (tlist->word, 0); + if (t == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + exp_jump_to_top_level (DISCARD); + } } /* Now transform the word as ksh93 appears to do and go on */ diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index a3a5e471..c8bef8dd 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,5 +1,4 @@ BUILD_DIR=/usr/local/build/bash/bash-current -#BUILD_DIR=/fs2/chet/scratch/bash-20200214.fifo THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/new-exp.right b/tests/new-exp.right index fe5c4618..cbc25832 100644 --- a/tests/new-exp.right +++ b/tests/new-exp.right @@ -670,7 +670,38 @@ prependå HELLO;1 foo;2 foo; PASS;1 foo;2 foo; after: PASS +'zzz' +'zzz' +declare -rl VAR1 +declare -rl VAR1 +declare -rl VAR1 +declare -rl VAR1 +rl +rl +rl +rl +declare -arl VAR3 +declare -arl VAR3 +declare -arl VAR3 +declare -arl VAR3 +arl +arl +arl +arl +one +one +'aaa' +'aaa' 'bbb' +./new-exp13.sub: line 56: aaa bbb: invalid variable name +aaa bbb +0 1 +'aaa' +'aaa' 'bbb' +'aaa' 'bbb' +'aaa' 'bbb' +a bbb +aaa bb argv[1] = argv[1] = -./new-exp.tests: line 640: ABXD: parameter unset +./new-exp.tests: line 643: ABXD: parameter unset diff --git a/tests/new-exp.tests b/tests/new-exp.tests index 20463ae8..f4a16be1 100644 --- a/tests/new-exp.tests +++ b/tests/new-exp.tests @@ -620,6 +620,9 @@ ${THIS_SH} ./new-exp11.sub # indirect expansion with arrays and local variables ${THIS_SH} ./new-exp12.sub +# more indirect expansion and parameter transformation issues +${THIS_SH} ./new-exp13.sub + # problems with stray CTLNUL in bash-4.0-alpha unset a a=/a diff --git a/tests/new-exp13.sub b/tests/new-exp13.sub new file mode 100644 index 00000000..7e8ed32c --- /dev/null +++ b/tests/new-exp13.sub @@ -0,0 +1,72 @@ +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +declare -lr VAR1 +declare -lr VAR2=zzz +declare -alr VAR3 + +var=VAR2 + +echo ${!var@Q} +echo ${VAR2@Q} + +echo ${VAR1@A} +echo ${VAR1[@]@A} +echo "${VAR1@A}" +echo "${VAR1[@]@A}" + +echo "${VAR1[@]@a}" +echo ${VAR1[@]@a} +echo "${VAR1@a}" +echo ${VAR1@a} + +echo ${VAR3@A} +echo ${VAR3[@]@A} +echo "${VAR3@A}" +echo "${VAR3[@]@A}" + +echo "${VAR3[@]@a}" +echo ${VAR3[@]@a} +echo "${VAR3@a}" +echo ${VAR3@a} + +var=one + +echo ${var} +echo ${var[@]} + +VAR4=(aaa bbb) + +varname=VAR4 + +echo ${!varname[@]@Q} + +echo ${VAR4[@]@Q} +echo ${!VAR4[@]@Q} + +echo ${VAR4[@]} +echo ${!VAR4[@]} + +VAR5=(aaa bbb) +varname="VAR5[@]" + +echo "${VAR5@Q}" +echo "${VAR5[@]@Q}" + +echo "${!varname@Q}" +echo "${!varname[@]@Q}" + +# caused core dumps through bash-5.0 +echo "${!varname##aa}" +echo "${!varname[@]%b}" diff --git a/tests/varenv.right b/tests/varenv.right index 8acb930b..2805bb2f 100644 --- a/tests/varenv.right +++ b/tests/varenv.right @@ -22,8 +22,8 @@ AVAR AVAR 42 /bin:/usr/bin:/usr/local/bin:. -avar=([0]="/bin:/usr/bin:/usr/local/bin:.") -z=yy +declare -a avar=([0]="/bin:/usr/bin:/usr/local/bin:.") +declare -- z="yy" 42 declare -i ivar="10" unset @@ -61,6 +61,7 @@ g: v = , w = f: v = , w = FIN: v = two, w = one ./varenv4.sub: line 67: bbb: unique: cannot convert indexed to associative array +./varenv4.sub: line 67: declare: unique: cannot convert indexed to associative array after bbb: 1 declare -Ar FOOBAR=([foo]="bar" ) declare -Ar FOOBAR=([foo]="bar" ) @@ -182,6 +183,8 @@ declare -a var=() ./varenv14.sub: line 25: warning: var: cannot inherit value from incompatible type declare -a var=() ./varenv14.sub: line 31: f: var: cannot convert indexed to associative array +./varenv14.sub: line 31: declare: var: cannot convert indexed to associative array +declare -a var=([0]="12") declare -a a=([0]="X") declare -a s=([0]="X") declare -a a=([0]="X" [1]="Y") diff --git a/trap.c b/trap.c index ad10e8f6..f1c219bf 100644 --- a/trap.c +++ b/trap.c @@ -487,7 +487,7 @@ trap_handler (sig) if (this_shell_builtin && (this_shell_builtin == wait_builtin)) { wait_signal_received = sig; - if (interrupt_immediately && wait_intr_flag) + if (/* interrupt_immediately && */wait_intr_flag) sh_longjmp (wait_intr_buf, 1); } @@ -509,16 +509,22 @@ trap_handler (sig) } int -first_pending_trap () +next_pending_trap (start) { register int i; - for (i = 1; i < NSIG; i++) + for (i = start; i < NSIG; i++) if (pending_traps[i]) return i; return -1; } +int +first_pending_trap () +{ + return (next_pending_trap (1)); +} + /* Return > 0 if any of the "real" signals (not fake signals like EXIT) are trapped. */ int diff --git a/trap.h b/trap.h index e8c93dd4..5c957c03 100644 --- a/trap.h +++ b/trap.h @@ -115,6 +115,7 @@ extern void set_signal_hard_ignored PARAMS((int)); extern void set_signal_ignored PARAMS((int)); extern int signal_in_progress PARAMS((int)); +extern int next_pending_trap PARAMS((int)); extern int first_pending_trap PARAMS((void)); extern int any_signals_trapped PARAMS((void)); extern void check_signals PARAMS((void)); diff --git a/variables.c b/variables.c index 01282d28..31caba06 100644 --- a/variables.c +++ b/variables.c @@ -295,6 +295,7 @@ static int visible_var PARAMS((SHELL_VAR *)); static int visible_and_exported PARAMS((SHELL_VAR *)); static int export_environment_candidate PARAMS((SHELL_VAR *)); static int local_and_exported PARAMS((SHELL_VAR *)); +static int visible_variable_in_context PARAMS((SHELL_VAR *)); static int variable_in_context PARAMS((SHELL_VAR *)); #if defined (ARRAY_VARS) static int visible_array_vars PARAMS((SHELL_VAR *)); @@ -4488,12 +4489,20 @@ local_exported_variables () static int variable_in_context (var) SHELL_VAR *var; +{ + return (local_p (var) && var->context == variable_context); +} + +static int +visible_variable_in_context (var) + SHELL_VAR *var; { return (invisible_p (var) == 0 && local_p (var) && var->context == variable_context); } SHELL_VAR ** -all_local_variables () +all_local_variables (visible_only) + int visible_only; { VARLIST *vlist; SHELL_VAR **ret; @@ -4514,7 +4523,10 @@ all_local_variables () vlist = vlist_alloc (HASH_ENTRIES (vc->table)); - flatten (vc->table, variable_in_context, vlist, 0); + if (visible_only) + flatten (vc->table, visible_variable_in_context, vlist, 0); + else + flatten (vc->table, variable_in_context, vlist, 0); ret = vlist->list; free (vlist); diff --git a/variables.h b/variables.h index 5911cfe7..a751afe4 100644 --- a/variables.h +++ b/variables.h @@ -300,7 +300,7 @@ extern SHELL_VAR **all_visible_variables PARAMS((void)); extern SHELL_VAR **all_visible_functions PARAMS((void)); extern SHELL_VAR **all_exported_variables PARAMS((void)); extern SHELL_VAR **local_exported_variables PARAMS((void)); -extern SHELL_VAR **all_local_variables PARAMS((void)); +extern SHELL_VAR **all_local_variables PARAMS((int)); #if defined (ARRAY_VARS) extern SHELL_VAR **all_array_variables PARAMS((void)); #endif