From 7a2f2783f4e319cb759d5e8d25e8e9b7184376cf Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Sat, 3 Dec 2011 13:37:34 -0500 Subject: [PATCH] commit bash-20040928 snapshot --- CWRU/CWRU.chlog~ | 126 ++++++++++++++ MANIFEST | 8 +- builtins/common.c~ | 6 + command.h~ | 30 ++-- doc/bash.1~ | 10 +- doc/bashref.texi~ | 17 +- doc/version.texi~ | 6 +- execute_cmd.c~ | 18 +- general.h~ | 1 - jobs.c~ | 4 +- lib/readline/complete.c~ | 10 +- subst.c~ | 149 +++++++++++++--- subst.h~ | 14 +- tests/RUN-ONE-TEST | 2 +- tests/run-tilde | 2 +- variables.c~ | 34 +++- variables.h~ | 359 +++++++++++++++++++++++++++++++++++++++ wifcontinued-test.c | 18 ++ 18 files changed, 733 insertions(+), 81 deletions(-) create mode 100644 variables.h~ create mode 100644 wifcontinued-test.c diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ index a65e1eaa9..17f6c575d 100644 --- a/CWRU/CWRU.chlog~ +++ b/CWRU/CWRU.chlog~ @@ -10149,3 +10149,129 @@ subst.c execute_cmd.c - take out calls to bash_tilde_expand before calling word expansion functions + + 9/26 + ---- +execute_cmd.c + - make sure to call UNBLOCK_CHILD before returning on a pipe creation + failure in execute_pipeline + + 9/27 + ---- +variables.c + - change get_bash_command to deal with the_printed_command_except_trap + being NULL + +execute_cmd.c + - fix execute_simple_command to deal with the_printed_command being + NULL when assigning to the_printed_command_except_trap -- fixes + seg fault in savestring() + +parse.y + - change the parser so that the closing `)' in a compound variable + assignment delimits a token -- ksh93 does it this way + +doc/{bash.1,bashref.texi} + - change description of tilde expansion to note that expansion is + attempted only after the first =~ in an assignment statement + +builtins/declare.def + - when assigning to an array variable with declare -a x=(...), make + sure the last character in the rhs of the variable assignment is + `)', not just that it appears somewhere + + 9/28 + ---- +command.h + - add a `W_NOEXPAND' flag to inhibit all expansion except quote removal + - add a `W_COMPASSIGN' flag to denote a word is a compound assignment + statement + +parse.y + - set W_COMPASSIGN on words that appear to be compound assignments + +subst.c + - pass W_NOXPAND and W_COMPASSIGN through end of expand_word_internal + +subst.[ch] + - new function, expand_assignment_string_to_string, calls + expand_string_assignment and then string_list on the result + +variables.c + - assign_in_env now calls expand_assignment_string_to_string + + 9/30 + ---- +builtins/common.c + - change get_job_spec so the null job `%' once again means the current + job + + 10/1 + ---- +subst.c + - do_assignment_internal now takes a WORD_DESC * as its first + argument, and uses its `word' member as the assignment string + - change expand_word_list_internal to call do_word_assignment instead + of do_assignment, passing it `word' instead of, e.g., `word->word' + - change extract_array_assignment_list to just return the passed + string minus a trailing `)' if the last character is a right + paren + - change do_assignment_internal to call extract_array_assignment_list + +subst.[ch] + - change do_assignment and do_assignment_no_expand to take a `char *' + instead of `const char *' first argument; change extern prototypes + - new function, do_word_assignment, takes a WORD_DESC * and calls + do_assignment_internal on it; add extern declaration with prototype + +general.h + - new typedef, sh_wassign_func_t, like sh_assign_func_t but takes a + WORD_DESC * as its first argument + +variables.[ch] + - assign_in_env now takes a WORD_DESC * as its first argument + + 10/2 + ---- +command.h + - new word flag, W_ASSNBLTIN, denotes that the word is a builtin + command (in a command position) that takes assignment statements + as arguments, like `declare' + - new word flags, W_ASSIGNARG, denotes that word is an assignment + statement given as argument to assignment builtin + +execute_cmd.c + - set W_ASSNBLTIN flag in fix_assignment_words if necessary (if there + are any arguments that are assignment statements) + - set W_ASSIGNARG flag in fix_assignment_words if necessary + +subst.c + - new function, do_compound_assignment, encapsulates the necessary + code to perform a compound array assignment (including creation of + local variables); called from do_assignment_internal + - to fix the double-expansion problem with compound array assignments + that are arguments to builtins like `declare', changed + shell_expand_word_list to treat those arguments like assignment + statements (with proper creation of local variables inside shell + functions) and pass the attribute-setting portion of the statement + onto the builtin. This is what ksh93 appears to do, from inspection + of the `ksh93 -x' output + +execute_cmd.c + - fix execute_simple_command: in case of pipeline or async command, + when forking early, set `subshell_environment' so that it can contain + both SUBSHELL_PIPE and SUBSHELL_ASYNC -- the two should not be + mutually exclusive. Fixes bug reported by pierre.humblet@ieee.org + - remove references to last_pid, old_command_subst_pid; use NO_PID as + a sentinel value to decide whether or not a child process has been + created and needs to be waited for. Submitted by + pierre.humblet@ieee.org to fix recycling-pid problem on cygwin + +doc/{bash.1,bashref.texi} + - fixed documentation of `@(pattern)' extended globbing operator -- + it succeeds if the string matches one of the patterns, not exactly + one. This is what ksh93 does, too + +lib/readline/complete.c + - fixed rl_menu_complete so that a negative argument cycles backwards + through the list diff --git a/MANIFEST b/MANIFEST index 2985f5402..398d522df 100644 --- a/MANIFEST +++ b/MANIFEST @@ -731,8 +731,6 @@ tests/extglob.tests f tests/extglob.right f tests/extglob2.tests f tests/extglob2.right f -tests/extglob3.tests f -tests/extglob3.right f tests/func.tests f tests/func.right f tests/func1.sub f @@ -842,7 +840,6 @@ tests/run-execscript f tests/run-exp-tests f tests/run-extglob f tests/run-extglob2 f -tests/run-extglob3 f tests/run-func f tests/run-getopts f tests/run-glob-test f @@ -876,7 +873,6 @@ tests/run-shopt f tests/run-strip f tests/run-test f tests/run-tilde f -tests/run-tilde2 f tests/run-trap f tests/run-type f tests/run-varenv f @@ -890,10 +886,8 @@ tests/strip.tests f tests/strip.right f tests/test.tests f tests/test.right f -tests/tilde.tests f +tests/tilde-tests f tests/tilde.right f -tests/tilde2.tests f -tests/tilde2.right f tests/trap.tests f tests/trap.right f tests/trap1.sub f 755 diff --git a/builtins/common.c~ b/builtins/common.c~ index 3d3dd5947..8c2dde4a2 100644 --- a/builtins/common.c~ +++ b/builtins/common.c~ @@ -270,6 +270,12 @@ sh_notbuiltin (s) builtin_error (_("%s: not a shell builtin"), s); } +void +sh_wrerror () +{ + builtin_error (_("write error: %s"), strerror (errno)); +} + /* **************************************************************** */ /* */ /* Shell positional parameter manipulation */ diff --git a/command.h~ b/command.h~ index 83aeea0d7..dbdcd47ae 100644 --- a/command.h~ +++ b/command.h~ @@ -67,19 +67,23 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select, cm_arith, cm_cond, cm_arith_for, cm_subshell }; /* Possible values for the `flags' field of a WORD_DESC. */ -#define W_HASDOLLAR 0x0001 /* Dollar sign present. */ -#define W_QUOTED 0x0002 /* Some form of quote character is present. */ -#define W_ASSIGNMENT 0x0004 /* This word is a variable assignment. */ -#define W_GLOBEXP 0x0008 /* This word is the result of a glob expansion. */ -#define W_NOSPLIT 0x0010 /* Do not perform word splitting on this word. */ -#define W_NOGLOB 0x0020 /* Do not perform globbing on this word. */ -#define W_NOSPLIT2 0x0040 /* Don't split word except for $@ expansion. */ -#define W_TILDEEXP 0x0080 /* Tilde expand this assignment word */ -#define W_DOLLARAT 0x0100 /* $@ and its special handling */ -#define W_DOLLARSTAR 0x0200 /* $* and its special handling */ -#define W_NOCOMSUB 0x0400 /* Don't perform command substitution on this word */ -#define W_ASSIGNRHS 0x0800 /* Word is rhs of an assignment statement */ -#define W_NOTILDE 0x1000 /* Don't perform tilde expansion on this word */ +#define W_HASDOLLAR 0x00001 /* Dollar sign present. */ +#define W_QUOTED 0x00002 /* Some form of quote character is present. */ +#define W_ASSIGNMENT 0x00004 /* This word is a variable assignment. */ +#define W_GLOBEXP 0x00008 /* This word is the result of a glob expansion. */ +#define W_NOSPLIT 0x00010 /* Do not perform word splitting on this word. */ +#define W_NOGLOB 0x00020 /* Do not perform globbing on this word. */ +#define W_NOSPLIT2 0x00040 /* Don't split word except for $@ expansion. */ +#define W_TILDEEXP 0x00080 /* Tilde expand this assignment word */ +#define W_DOLLARAT 0x00100 /* $@ and its special handling */ +#define W_DOLLARSTAR 0x00200 /* $* and its special handling */ +#define W_NOCOMSUB 0x00400 /* Don't perform command substitution on this word */ +#define W_ASSIGNRHS 0x00800 /* Word is rhs of an assignment statement */ +#define W_NOTILDE 0x01000 /* Don't perform tilde expansion on this word */ +#define W_ITILDE 0x02000 /* Internal flag for word expansion */ +#define W_NOEXPAND 0x04000 /* Don't expand at all -- do quote removal */ +#define W_COMPASSIGN 0x08000 /* Compound assignment */ +#define W_ASSNBLTIN 0x10000 /* word is a builtin command that takes assignments */ /* Possible values for subshell_environment */ #define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */ diff --git a/doc/bash.1~ b/doc/bash.1~ index cf7a9d030..e95567fa6 100644 --- a/doc/bash.1~ +++ b/doc/bash.1~ @@ -6,12 +6,12 @@ .\" Case Western Reserve University .\" chet@po.CWRU.Edu .\" -.\" Last Change: Fri Sep 17 22:44:17 EDT 2004 +.\" Last Change: Thu Sep 30 22:29:05 EDT 2004 .\" .\" bash_builtins, strip all but Built-Ins section .if \n(zZ=1 .ig zZ .if \n(zY=1 .ig zY -.TH BASH 1 "2004 Sep 17" "GNU Bash-3.0" +.TH BASH 1 "2004 Sep 30" "GNU Bash-3.0" .\" .\" There's some problem with having a `@' .\" in a tagged paragraph with the BSD man macros. @@ -2236,7 +2236,7 @@ is unchanged. Each variable assignment is checked for unquoted tilde-prefixes immediately following a .B : -or +or the first .BR = . In these cases, tilde expansion is also performed. Consequently, one may use file names with tildes in assignments to @@ -4063,6 +4063,8 @@ command), the current job is always flagged with a .BR + , and the previous job with a .BR \- . +A single % (with no accompanying job specification) also refers to the +current job. .PP Simply naming a job can be used to bring it into the foreground: @@ -5285,7 +5287,7 @@ of an \fIinputrc\fP file. .TP .B dump\-macros Print all of the readline key sequences bound to macros and the -strings they ouput. If a numeric argument is supplied, +strings they output. If a numeric argument is supplied, the output is formatted in such a way that it can be made part of an \fIinputrc\fP file. .TP diff --git a/doc/bashref.texi~ b/doc/bashref.texi~ index 5bfee31a9..1e0e446da 100644 --- a/doc/bashref.texi~ +++ b/doc/bashref.texi~ @@ -1456,7 +1456,7 @@ If the login name is invalid, or the tilde expansion fails, the word is left unchanged. Each variable assignment is checked for unquoted tilde-prefixes immediately -following a @samp{:} or @samp{=}. +following a @samp{:} or the first @samp{=}. In these cases, tilde expansion is also performed. Consequently, one may use file names with tildes in assignments to @env{PATH}, @env{MAILPATH}, and @env{CDPATH}, @@ -4787,7 +4787,7 @@ option). @item --dump-po-strings A list of all double-quoted strings preceded by @samp{$} -is printed on the standard ouput +is printed on the standard output in the @sc{gnu} @code{gettext} PO (portable object) file format. Equivalent to @option{-D} except for the output format. @@ -4874,7 +4874,7 @@ when invoking an interactive shell. @item -D A list of all double-quoted strings preceded by @samp{$} -is printed on the standard ouput. +is printed on the standard output. These are the strings that are subject to language translation when the current locale is not @code{C} or @code{POSIX} (@pxref{Locale Translation}). @@ -6118,11 +6118,12 @@ There are a number of ways to refer to a job in the shell. The character @samp{%} introduces a job name. Job number @code{n} may be referred to as @samp{%n}. -The symbols @samp{%%} and -@samp{%+} refer to the shell's notion of the current job, which -is the last job stopped while it was in the foreground or started -in the background. The -previous job may be referenced using @samp{%-}. In output +The symbols @samp{%%} and @samp{%+} refer to the shell's notion of the +current job, which is the last job stopped while it was in the foreground +or started in the background. +A single @samp{%} (with no accompanying job specification) also refers +to the current job. +The previous job may be referenced using @samp{%-}. In output pertaining to jobs (e.g., the output of the @code{jobs} command), the current job is always flagged with a @samp{+}, and the previous job with a @samp{-}. diff --git a/doc/version.texi~ b/doc/version.texi~ index 559af1e30..9dd2c46a0 100644 --- a/doc/version.texi~ +++ b/doc/version.texi~ @@ -4,7 +4,7 @@ Copyright (C) 1988-2004 Free Software Foundation, Inc. @set EDITION 3.0 @set VERSION 3.0 -@set UPDATED 11 September 2004 -@set UPDATED-MONTH September 2004 +@set UPDATED 2 October 2004 +@set UPDATED-MONTH October 2004 -@set LASTCHANGE Sat Sep 11 10:13:36 EDT 2004 +@set LASTCHANGE Sat Oct 2 18:05:41 EDT 2004 diff --git a/execute_cmd.c~ b/execute_cmd.c~ index 7873ec5ee..cea110aba 100644 --- a/execute_cmd.c~ +++ b/execute_cmd.c~ @@ -1360,14 +1360,12 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) #if defined (JOB_CONTROL) terminate_current_pipeline (); kill_current_pipeline (); + UNBLOCK_CHILD (oset); #endif /* JOB_CONTROL */ last_command_exit_value = EXECUTION_FAILURE; /* The unwind-protects installed below will take care of closing all of the open file descriptors. */ throw_to_top_level (); -#if defined (JOB_CONTROL) - UNBLOCK_CHILD (oset); -#endif return (EXECUTION_FAILURE); /* XXX */ } @@ -2663,8 +2661,10 @@ fix_assignment_words (words) b = builtin_address_internal (words->word->word, 0); if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0) return; + else if (b && (b->flags & ASSIGNMENT_BUILTIN)) + words->word->flags |= W_ASSNBLTIN; } - w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP); + w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG); } } @@ -2699,7 +2699,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) if (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)) { FREE (the_printed_command_except_trap); - the_printed_command_except_trap = savestring (the_printed_command); + the_printed_command_except_trap = the_printed_command ? savestring (the_printed_command) : (char *)0; } /* Run the debug trap before each simple command, but do it after we @@ -2754,9 +2754,17 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) already_forked = 1; simple_command->flags |= CMD_NO_FORK; +#if 0 subshell_environment = (pipe_in != NO_PIPE || pipe_out != NO_PIPE) ? (SUBSHELL_PIPE|SUBSHELL_FORK) : (SUBSHELL_ASYNC|SUBSHELL_FORK); +#else + subshell_environment = SUBSHELL_FORK; + if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) + subshell_environment |= SUBSHELL_PIPE; + if (async) + subshell_environment |= SUBSHELL_ASYNC; +#endif /* We need to do this before piping to handle some really pathological cases where one of the pipe file descriptors diff --git a/general.h~ b/general.h~ index c0eabd753..ce76e1633 100644 --- a/general.h~ +++ b/general.h~ @@ -303,7 +303,6 @@ extern char *polite_directory_format __P((char *)); extern char *extract_colon_unit __P((char *, int *)); extern void tilde_initialize __P((void)); -extern int unquoted_tilde_word __P((const char *)); extern char *bash_tilde_find_word __P((const char *, int, int *)); extern char *bash_tilde_expand __P((const char *, int)); diff --git a/jobs.c~ b/jobs.c~ index c1b1c2418..b89cf2427 100644 --- a/jobs.c~ +++ b/jobs.c~ @@ -1433,7 +1433,9 @@ make_child (command, async_p) last_made_pid = pid; - /* Unblock SIGINT and SIGCHLD. */ + /* Unblock SIGINT and SIGCHLD unless creating a pipeline, in which case + SIGCHLD remains blocked until all commands in the pipeline have been + created. */ sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); } diff --git a/lib/readline/complete.c~ b/lib/readline/complete.c~ index f0149a3e2..d7009e874 100644 --- a/lib/readline/complete.c~ +++ b/lib/readline/complete.c~ @@ -1543,7 +1543,7 @@ append_to_match (text, delimiter, quote_char, nontrivial_match) : stat (filename, &finfo); if (s == 0 && S_ISDIR (finfo.st_mode)) { - if (_rl_complete_mark_directories && rl_completion_suppress_append == 0) + if (_rl_complete_mark_directories /* && rl_completion_suppress_append == 0 */) { /* This is clumsy. Avoid putting in a double slash if point is at the end of the line and the previous character is a @@ -2178,9 +2178,17 @@ rl_menu_complete (count, ignore) return (0); } +#if 0 match_list_index = (match_list_index + count) % match_list_size; if (match_list_index < 0) match_list_index += match_list_size; +#else + match_list_index += count; + if (match_list_index < 0) + match_list_index += match_list_size; + else + match_list_index %= match_list_size; +#endif if (match_list_index == 0 && match_list_size > 1) { diff --git a/subst.c~ b/subst.c~ index 49de9af70..9ba8aa6cd 100644 --- a/subst.c~ +++ b/subst.c~ @@ -204,7 +204,10 @@ static char *remove_quoted_nulls __P((char *)); static int unquoted_substring __P((char *, char *)); static int unquoted_member __P((int, char *)); -static int do_assignment_internal __P((const char *, int)); +#if defined (ARRAY_VARS) +static SHELL_VAR *do_compound_assignment __P((char *, char *, int)); +#endif +static int do_assignment_internal __P((const WORD_DESC *, int)); static char *string_extract_verbatim __P((char *, int *, char *)); static char *string_extract __P((char *, int *, char *, int)); @@ -983,12 +986,28 @@ extract_process_subst (string, starter, sindex) #endif /* PROCESS_SUBSTITUTION */ #if defined (ARRAY_VARS) +/* This can be fooled by unquoted right parens in the passed string. If + each caller verifies that the last character in STRING is a right paren, + we don't even need to call extract_delimited_string. */ char * extract_array_assignment_list (string, sindex) char *string; int *sindex; { +#if 0 return (extract_delimited_string (string, sindex, "(", (char *)NULL, ")", 0)); +#else + int slen; + char *ret; + + slen = strlen (string); /* ( */ + if (string[slen - 1] == ')') + { + ret = substring (string, *sindex, slen - 1); + *sindex = slen - 1; + return ret; + } +#endif } #endif @@ -2122,17 +2141,40 @@ list_string_with_quotes (string) /* */ /********************************************************/ +#if defined (ARRAY_VARS) +static SHELL_VAR * +do_compound_assignment (name, value, mklocal) + char *name, *value; + int mklocal; +{ + SHELL_VAR *v; + int off; + + if (mklocal && variable_context) + { + v = find_variable (name); + if (v == 0 || array_p (v) == 0) + v = make_local_array_variable (name); + v = assign_array_var_from_string (v, value); + } + else + v = assign_array_from_string (name, value); + + return (v); +} +#endif + /* Given STRING, an assignment string, get the value of the right side of the `=', and bind it to the left side. If EXPAND is true, then perform parameter expansion, command substitution, and arithmetic expansion on the right-hand side. Perform tilde expansion in any case. Do not perform word splitting on the result of expansion. */ static int -do_assignment_internal (string, expand) - const char *string; +do_assignment_internal (word, expand) + const WORD_DESC *word; int expand; { - int offset; + int offset, tlen; char *name, *value; SHELL_VAR *entry; #if defined (ARRAY_VARS) @@ -2140,7 +2182,12 @@ do_assignment_internal (string, expand) int ni; #endif int assign_list = 0; + const char *string; + if (word == 0 || word->word == 0) + return 0; + + string = word->word; offset = assignment (string, 0); name = savestring (string); value = (char *)NULL; @@ -2151,17 +2198,17 @@ do_assignment_internal (string, expand) name[offset] = 0; temp = name + offset + 1; + tlen = STRLEN (temp); #if defined (ARRAY_VARS) - if (expand && temp[0] == LPAREN && xstrchr (temp, RPAREN)) + if (expand && temp[0] == LPAREN && temp[tlen-1] == RPAREN) { assign_list = ni = 1; - value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")", 0); + value = extract_array_assignment_list (temp, &ni); } else #endif - /* Perform tilde expansion. */ if (expand && temp[0]) value = expand_string_if_necessary (temp, 0, expand_string_assignment); else @@ -2192,7 +2239,7 @@ do_assignment_internal (string, expand) ASSIGN_RETURN (0); } else if (assign_list) - entry = assign_array_from_string (name, value); + entry = do_compound_assignment (name, value, (word->flags & W_ASSIGNARG)); else #endif /* ARRAY_VARS */ entry = bind_variable (name, value); @@ -2207,22 +2254,39 @@ do_assignment_internal (string, expand) } /* Perform the assignment statement in STRING, and expand the - right side by doing command and parameter expansion. */ + right side by doing tilde, command and parameter expansion. */ int do_assignment (string) - const char *string; + char *string; +{ + WORD_DESC td; + + td.flags = W_ASSIGNMENT; + td.word = string; + + return do_assignment_internal (&td, 1); +} + +int +do_word_assignment (word) + WORD_DESC *word; { - return do_assignment_internal (string, 1); + return do_assignment_internal (word, 1); } /* Given STRING, an assignment string, get the value of the right side - of the `=', and bind it to the left side. Do not do command and - parameter substitution on the right hand side. */ + of the `=', and bind it to the left side. Do not perform any word + expansions on the right hand side. */ int do_assignment_no_expand (string) - const char *string; + char *string; { - return do_assignment_internal (string, 0); + WORD_DESC td; + + td.flags = W_ASSIGNMENT; + td.word = string; + + do_assignment_internal (&td, 0); } /*************************************************** @@ -2445,6 +2509,14 @@ expand_string_unsplit_to_string (string, quoted) return (expand_string_to_string_internal (string, quoted, expand_string_unsplit)); } +char * +expand_assignment_string_to_string (string, quoted) + char *string; + int quoted; +{ + return (expand_string_to_string_internal (string, quoted, expand_string_assignment)); +} + #if defined (COND_COMMAND) /* Just remove backslashes in STRING. Returns a new string. */ char * @@ -6430,8 +6502,8 @@ add_string: if (word->flags & W_NOTILDE) goto add_character; if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) && - (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && - string[sindex+1] == '~') + (posixly_correct == 0 || (word->flags & W_TILDEEXP)) && + string[sindex+1] == '~') word->flags |= W_ITILDE; goto add_character; @@ -6845,8 +6917,12 @@ finished_with_string: list = make_word_list (tword, (WORD_LIST *)NULL); if (word->flags & W_ASSIGNMENT) tword->flags |= W_ASSIGNMENT; /* XXX */ + if (word->flags & W_COMPASSIGN) + tword->flags |= W_COMPASSIGN; /* XXX */ if (word->flags & W_NOGLOB) tword->flags |= W_NOGLOB; /* XXX */ + if (word->flags & W_NOEXPAND) + tword->flags |= W_NOEXPAND; /* XXX */ if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) tword->flags |= W_QUOTED; } @@ -6872,8 +6948,12 @@ finished_with_string: tword->flags |= W_QUOTED; if (word->flags & W_ASSIGNMENT) tword->flags |= W_ASSIGNMENT; + if (word->flags & W_COMPASSIGN) + tword->flags |= W_COMPASSIGN; if (word->flags & W_NOGLOB) tword->flags |= W_NOGLOB; + if (word->flags & W_NOEXPAND) + tword->flags |= W_NOEXPAND; } } @@ -7435,6 +7515,31 @@ shell_expand_word_list (tlist, eflags) next = tlist->next; +#if defined (ARRAY_VARS) + /* If this is a compound array assignment to a builtin that accepts + such assignments (e.g., `declare'), take the assignment and perform + it separately, handling the semantics of declarations inside shell + functions. This avoids the double-evaluation of such arguments, + because `declare' does some evaluation of compound assignments on + its own. */ + if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG)) + { + int t; + + t = do_word_assignment (tlist->word); + 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 */ + t = assignment (tlist->word->word, 0); + tlist->word->word[t] = '\0'; + tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG); + } +#endif + expanded_something = 0; expanded = expand_word_internal (tlist->word, 0, 0, &has_dollar_at, &expanded_something); @@ -7521,7 +7626,7 @@ expand_word_list_internal (list, eflags) for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) { this_command_name = (char *)NULL; /* no arithmetic errors */ - tint = do_assignment (temp_list->word->word); + tint = do_word_assignment (temp_list->word); /* Variable assignment errors in non-interactive shells running in Posix.2 mode cause the shell to exit. */ if (tint == 0) @@ -7569,23 +7674,23 @@ expand_word_list_internal (list, eflags) if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) { - sh_assign_func_t *assign_func; + sh_wassign_func_t *assign_func; /* If the remainder of the words expand to nothing, Posix.2 requires that the variable and environment assignments affect the shell's environment. */ - assign_func = new_list ? assign_in_env : do_assignment; + assign_func = new_list ? assign_in_env : do_word_assignment; tempenv_assign_error = 0; for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) { this_command_name = (char *)NULL; - tint = (*assign_func) (temp_list->word->word); + tint = (*assign_func) (temp_list->word); /* Variable assignment errors in non-interactive shells running in Posix.2 mode cause the shell to exit. */ if (tint == 0) { - if (assign_func == do_assignment) + if (assign_func == do_word_assignment) { last_command_exit_value = EXECUTION_FAILURE; if (interactive_shell == 0 && posixly_correct) diff --git a/subst.h~ b/subst.h~ index c725df501..350e82aa7 100644 --- a/subst.h~ +++ b/subst.h~ @@ -93,11 +93,11 @@ extern char *strip_trailing_ifs_whitespace __P((char *, char *, int)); /* Given STRING, an assignment string, get the value of the right side of the `=', and bind it to the left side. If EXPAND is true, then - perform parameter expansion, command substitution, and arithmetic - expansion on the right-hand side. Perform tilde expansion in any - case. Do not perform word splitting on the result of expansion. */ -extern int do_assignment __P((const char *)); -extern int do_assignment_no_expand __P((const char *)); + perform tilde expansion, parameter expansion, command substitution, + and arithmetic expansion on the right-hand side. Do not perform word + splitting on the result of expansion. */ +extern int do_assignment __P((char *)); +extern int do_assignment_no_expand __P((char *)); /* Append SOURCE to TARGET at INDEX. SIZE is the current amount of space allocated to TARGET. SOURCE can be NULL, in which @@ -126,6 +126,9 @@ extern int number_of_args __P((void)); takes care of quote removal. */ extern WORD_LIST *expand_string_unsplit __P((char *, int)); +/* Expand the rhs of an assignment statement. */ +extern WORD_LIST *expand_string_assignment __P((char *, int)); + /* Expand a prompt string. */ extern WORD_LIST *expand_prompt_string __P((char *, int)); @@ -141,6 +144,7 @@ extern WORD_LIST *expand_string __P((char *, int)); to a string and deallocating the WORD_LIST *. */ extern char *expand_string_to_string __P((char *, int)); extern char *expand_string_unsplit_to_string __P((char *, int)); +extern char *expand_assignment_string_to_string __P((char *, int)); /* De-quoted quoted characters in STRING. */ extern char *dequote_string __P((char *)); diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 3efcf32d6..72ec06a2c 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current +BUILD_DIR=/usr/local/build/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/run-tilde b/tests/run-tilde index b8569c11c..ecb7e9a25 100644 --- a/tests/run-tilde +++ b/tests/run-tilde @@ -1,2 +1,2 @@ -${THIS_SH} ./tilde.tests > /tmp/xx +${THIS_SH} ./tilde-tests > /tmp/xx diff /tmp/xx tilde.right && rm -f /tmp/xx diff --git a/variables.c~ b/variables.c~ index 75f16cd9f..cdf1a195b 100644 --- a/variables.c~ +++ b/variables.c~ @@ -1228,7 +1228,14 @@ get_bash_command (var) { char *p; - p = savestring (the_printed_command_except_trap); + + if (the_printed_command_except_trap) + p = savestring (the_printed_command_except_trap); + else + { + p = (char *)xmalloc (1); + p[0] = '\0'; + } FREE (value_cell (var)); var_setvalue (var, p); return (var); @@ -1419,11 +1426,11 @@ initialize_dynamic_variables () v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign); # if defined (DEBUGGER) - v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, (att_invisible|att_noassign)); - v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, (att_invisible|att_noassign)); + v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset); # endif /* DEBUGGER */ - v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, (att_invisible|att_noassign)); - v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, (att_invisible|att_noassign)); + v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset); + v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); #endif v = init_funcname_var (); @@ -1599,7 +1606,10 @@ make_local_variable (name) /* local foo; local foo; is a no-op. */ old_var = find_variable (name); if (old_var && local_p (old_var) && old_var->context == variable_context) - return (old_var); + { + VUNSETATTR (old_var, att_invisible); + return (old_var); + } was_tmpvar = old_var && tempvar_p (old_var); if (was_tmpvar) @@ -2064,12 +2074,15 @@ bind_function_def (name, value) responsible for moving the main temporary env to one of the other temporary environments. The expansion code in subst.c calls this. */ int -assign_in_env (string) - const char *string; +assign_in_env (word) + WORD_DESC *word; { int offset; char *name, *temp, *value; SHELL_VAR *var; + const char *string; + + string = word->word; offset = assignment (string, 0); name = savestring (string); @@ -2089,10 +2102,13 @@ assign_in_env (string) } temp = name + offset + 1; +#if 0 temp = (xstrchr (temp, '~') != 0) ? bash_tilde_expand (temp, 1) : savestring (temp); - value = expand_string_unsplit_to_string (temp, 0); free (temp); +#else + value = expand_assignment_string_to_string (temp, 0); +#endif } if (temporary_env == 0) diff --git a/variables.h~ b/variables.h~ new file mode 100644 index 000000000..cd11fd97c --- /dev/null +++ b/variables.h~ @@ -0,0 +1,359 @@ +/* variables.h -- data structures for shell variables. */ + +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash 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 2, or (at your option) + any later version. + + Bash 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 Bash; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_VARIABLES_H_) +#define _VARIABLES_H_ + +#include "stdc.h" +#include "array.h" + +/* Shell variables and functions are stored in hash tables. */ +#include "hashlib.h" + +#include "conftypes.h" + +/* A variable context. */ +typedef struct var_context { + char *name; /* empty or NULL means global context */ + int scope; /* 0 means global context */ + int flags; + struct var_context *up; /* previous function calls */ + struct var_context *down; /* down towards global context */ + HASH_TABLE *table; /* variables at this scope */ +} VAR_CONTEXT; + +/* Flags for var_context->flags */ +#define VC_HASLOCAL 0x01 +#define VC_HASTMPVAR 0x02 +#define VC_FUNCENV 0x04 /* also function if name != NULL */ +#define VC_BLTNENV 0x08 /* builtin_env */ +#define VC_TEMPENV 0x10 /* temporary_env */ + +#define VC_TEMPFLAGS (VC_FUNCENV|VC_BLTNENV|VC_TEMPENV) + +/* Accessing macros */ +#define vc_isfuncenv(vc) (((vc)->flags & VC_FUNCENV) != 0) +#define vc_isbltnenv(vc) (((vc)->flags & VC_BLTNENV) != 0) +#define vc_istempenv(vc) (((vc)->flags & (VC_TEMPFLAGS)) == VC_TEMPENV) + +#define vc_istempscope(vc) (((vc)->flags & (VC_TEMPENV|VC_BLTNENV)) != 0) + +#define vc_haslocals(vc) (((vc)->flags & VC_HASLOCAL) != 0) +#define vc_hastmpvars(vc) (((vc)->flags & VC_HASTMPVAR) != 0) + +/* What a shell variable looks like. */ + +typedef struct variable *sh_var_value_func_t __P((struct variable *)); +typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t)); + +/* For the future */ +union _value { + char *s; /* string value */ + intmax_t i; /* int value */ + COMMAND *f; /* function */ + ARRAY *a; /* array */ + HASH_TABLE *h; /* associative array */ + double d; /* floating point number */ +#if defined (HAVE_LONG_DOUBLE) + long double ld; /* long double */ +#endif + struct variable *v; /* possible indirect variable use */ + void *opaque; /* opaque data for future use */ +}; + +typedef struct variable { + char *name; /* Symbol that the user types. */ + char *value; /* Value that is returned. */ + char *exportstr; /* String for the environment. */ + sh_var_value_func_t *dynamic_value; /* Function called to return a `dynamic' + value for a variable, like $SECONDS + or $RANDOM. */ + sh_var_assign_func_t *assign_func; /* Function called when this `special + variable' is assigned a value in + bind_variable. */ + int attributes; /* export, readonly, array, invisible... */ + int context; /* Which context this variable belongs to. */ +} SHELL_VAR; + +typedef struct _vlist { + SHELL_VAR **list; + int list_size; /* allocated size */ + int list_len; /* current number of entries */ +} VARLIST; + +/* The various attributes that a given variable can have. */ +/* First, the user-visible attributes */ +#define att_exported 0x0000001 /* export to environment */ +#define att_readonly 0x0000002 /* cannot change */ +#define att_array 0x0000004 /* value is an array */ +#define att_function 0x0000008 /* value is a function */ +#define att_integer 0x0000010 /* internal representation is int */ +#define att_local 0x0000020 /* variable is local to a function */ +#define att_assoc 0x0000040 /* variable is an associative array */ +#define att_trace 0x0000080 /* function is traced with DEBUG trap */ + +#define attmask_user 0x0000fff + +/* Internal attributes used for bookkeeping */ +#define att_invisible 0x0001000 /* cannot see */ +#define att_nounset 0x0002000 /* cannot unset */ +#define att_noassign 0x0004000 /* assignment not allowed */ +#define att_imported 0x0008000 /* came from environment */ +#define att_special 0x0010000 /* requires special handling */ + +#define attmask_int 0x00ff000 + +/* Internal attributes used for variable scoping. */ +#define att_tempvar 0x0100000 /* variable came from the temp environment */ +#define att_propagate 0x0200000 /* propagate to previous scope */ + +#define attmask_scope 0x0f00000 + +#define exported_p(var) ((((var)->attributes) & (att_exported))) +#define readonly_p(var) ((((var)->attributes) & (att_readonly))) +#define array_p(var) ((((var)->attributes) & (att_array))) +#define function_p(var) ((((var)->attributes) & (att_function))) +#define integer_p(var) ((((var)->attributes) & (att_integer))) +#define local_p(var) ((((var)->attributes) & (att_local))) +#define assoc_p(var) ((((var)->attributes) & (att_assoc))) +#define trace_p(var) ((((var)->attributes) & (att_trace))) + +#define invisible_p(var) ((((var)->attributes) & (att_invisible))) +#define non_unsettable_p(var) ((((var)->attributes) & (att_nounset))) +#define noassign_p(var) ((((var)->attributes) & (att_noassign))) +#define imported_p(var) ((((var)->attributes) & (att_imported))) +#define specialvar_p(var) ((((var)->attributes) & (att_special))) + +#define tempvar_p(var) ((((var)->attributes) & (att_tempvar))) + +/* Acessing variable values: rvalues */ +#define value_cell(var) ((var)->value) +#define function_cell(var) (COMMAND *)((var)->value) +#define array_cell(var) (ARRAY *)((var)->value) + +#define var_isnull(var) ((var)->value == 0) +#define var_isset(var) ((var)->value != 0) + +/* Assigning variable values: lvalues */ +#define var_setvalue(var, str) ((var)->value = (str)) +#define var_setfunc(var, func) ((var)->value = (char *)(func)) +#define var_setarray(var, arr) ((var)->value = (char *)(arr)) + +/* Make VAR be auto-exported. */ +#define set_auto_export(var) \ + do { (var)->attributes |= att_exported; array_needs_making = 1; } while (0) + +#define SETVARATTR(var, attr, undo) \ + ((undo == 0) ? ((var)->attributes |= (attr)) \ + : ((var)->attributes &= ~(attr))) + +#define VSETATTR(var, attr) ((var)->attributes |= (attr)) +#define VUNSETATTR(var, attr) ((var)->attributes &= ~(attr)) + +#define VGETFLAGS(var) ((var)->attributes) + +#define VSETFLAGS(var, flags) ((var)->attributes = (flags)) +#define VCLRFLAGS(var) ((var)->attributes = 0) + +/* Macros to perform various operations on `exportstr' member of a SHELL_VAR. */ +#define CLEAR_EXPORTSTR(var) (var)->exportstr = (char *)NULL +#define COPY_EXPORTSTR(var) ((var)->exportstr) ? savestring ((var)->exportstr) : (char *)NULL +#define SET_EXPORTSTR(var, value) (var)->exportstr = (value) +#define SAVE_EXPORTSTR(var, value) (var)->exportstr = (value) ? savestring (value) : (char *)NULL + +#define FREE_EXPORTSTR(var) \ + do { if ((var)->exportstr) free ((var)->exportstr); } while (0) + +#define CACHE_IMPORTSTR(var, value) \ + (var)->exportstr = savestring (value) + +#define INVALIDATE_EXPORTSTR(var) \ + do { \ + if ((var)->exportstr) \ + { \ + free ((var)->exportstr); \ + (var)->exportstr = (char *)NULL; \ + } \ + } while (0) + +/* Stuff for hacking variables. */ +typedef int sh_var_map_func_t __P((SHELL_VAR *)); + +/* Where we keep the variables and functions */ +extern VAR_CONTEXT *global_variables; +extern VAR_CONTEXT *shell_variables; + +extern HASH_TABLE *shell_functions; +extern HASH_TABLE *temporary_env; + +extern int variable_context; +extern char *dollar_vars[]; +extern char **export_env; + +extern void initialize_shell_variables __P((char **, int)); +extern SHELL_VAR *set_if_not __P((char *, char *)); + +extern void sh_set_lines_and_columns __P((int, int)); +extern void set_pwd __P((void)); +extern void set_ppid __P((void)); +extern void make_funcname_visible __P((int)); + +extern SHELL_VAR *var_lookup __P((const char *, VAR_CONTEXT *)); + +extern SHELL_VAR *find_function __P((const char *)); +extern FUNCTION_DEF *find_function_def __P((const char *)); +extern SHELL_VAR *find_variable __P((const char *)); +extern SHELL_VAR *find_variable_internal __P((const char *, int)); +extern SHELL_VAR *find_tempenv_variable __P((const char *)); +extern SHELL_VAR *copy_variable __P((SHELL_VAR *)); +extern SHELL_VAR *make_local_variable __P((const char *)); +extern SHELL_VAR *bind_variable __P((const char *, char *)); +extern SHELL_VAR *bind_function __P((const char *, COMMAND *)); + +extern void bind_function_def __P((const char *, FUNCTION_DEF *)); + +extern SHELL_VAR **map_over __P((sh_var_map_func_t *, VAR_CONTEXT *)); +SHELL_VAR **map_over_funcs __P((sh_var_map_func_t *)); + +extern SHELL_VAR **all_shell_variables __P((void)); +extern SHELL_VAR **all_shell_functions __P((void)); +extern SHELL_VAR **all_visible_variables __P((void)); +extern SHELL_VAR **all_visible_functions __P((void)); +extern SHELL_VAR **all_exported_variables __P((void)); +extern SHELL_VAR **local_exported_variables __P((void)); +extern SHELL_VAR **all_local_variables __P((void)); +#if defined (ARRAY_VARS) +extern SHELL_VAR **all_array_variables __P((void)); +#endif +extern char **all_variables_matching_prefix __P((const char *)); + +extern char **make_var_array __P((HASH_TABLE *)); +extern char **add_or_supercede_exported_var __P((char *, int)); + +extern char *get_variable_value __P((SHELL_VAR *)); +extern char *get_string_value __P((const char *)); +extern char *sh_get_env_value __P((const char *)); +extern char *make_variable_value __P((SHELL_VAR *, char *)); + +extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *)); +extern SHELL_VAR *bind_int_variable __P((char *, char *)); +extern SHELL_VAR *bind_var_to_int __P((char *, intmax_t)); + +extern int assign_in_env __P((const char *)); +extern int unbind_variable __P((const char *)); +extern int unbind_func __P((const char *)); +extern int unbind_function_def __P((const char *)); +extern int makunbound __P((const char *, VAR_CONTEXT *)); +extern int kill_local_variable __P((const char *)); +extern void delete_all_variables __P((HASH_TABLE *)); +extern void delete_all_contexts __P((VAR_CONTEXT *)); + +extern VAR_CONTEXT *new_var_context __P((char *, int)); +extern void dispose_var_context __P((VAR_CONTEXT *)); +extern VAR_CONTEXT *push_var_context __P((char *, int, HASH_TABLE *)); +extern void pop_var_context __P((void)); +extern VAR_CONTEXT *push_scope __P((int, HASH_TABLE *)); +extern void pop_scope __P((int)); + +extern void push_context __P((char *, int, HASH_TABLE *)); +extern void pop_context __P((void)); +extern void push_dollar_vars __P((void)); +extern void pop_dollar_vars __P((void)); +extern void dispose_saved_dollar_vars __P((void)); + +extern void push_args __P((WORD_LIST *)); +extern void pop_args __P((void)); + +extern void adjust_shell_level __P((int)); +extern void non_unsettable __P((char *)); +extern void dispose_variable __P((SHELL_VAR *)); +extern void dispose_used_env_vars __P((void)); +extern void dispose_function_env __P((void)); +extern void dispose_builtin_env __P((void)); +extern void merge_temporary_env __P((void)); +extern void merge_builtin_env __P((void)); +extern void kill_all_local_variables __P((void)); + +extern void set_var_read_only __P((char *)); +extern void set_func_read_only __P((const char *)); +extern void set_var_auto_export __P((char *)); +extern void set_func_auto_export __P((const char *)); + +extern void sort_variables __P((SHELL_VAR **)); + +extern void maybe_make_export_env __P((void)); +extern void update_export_env_inplace __P((char *, int, char *)); +extern void put_command_name_into_env __P((char *)); +extern void put_gnu_argv_flags_into_env __P((intmax_t, char *)); + +extern void print_var_list __P((SHELL_VAR **)); +extern void print_func_list __P((SHELL_VAR **)); +extern void print_assignment __P((SHELL_VAR *)); +extern void print_var_value __P((SHELL_VAR *, int)); +extern void print_var_function __P((SHELL_VAR *)); + +#if defined (ARRAY_VARS) +extern SHELL_VAR *make_new_array_variable __P((char *)); +extern SHELL_VAR *make_local_array_variable __P((char *)); + +extern void set_pipestatus_array __P((int *, int)); +#endif + +extern void set_pipestatus_from_exit __P((int)); + +/* The variable in NAME has just had its state changed. Check to see if it + is one of the special ones where something special happens. */ +extern void stupidly_hack_special_variables __P((char *)); + +extern int get_random_number __P((void)); + +/* The `special variable' functions that get called when a particular + variable is set. */ +extern void sv_ifs __P((char *)); +extern void sv_path __P((char *)); +extern void sv_mail __P((char *)); +extern void sv_globignore __P((char *)); +extern void sv_ignoreeof __P((char *)); +extern void sv_strict_posix __P((char *)); +extern void sv_optind __P((char *)); +extern void sv_opterr __P((char *)); +extern void sv_locale __P((char *)); + +#if defined (READLINE) +extern void sv_comp_wordbreaks __P((char *)); +extern void sv_terminal __P((char *)); +extern void sv_hostfile __P((char *)); +#endif + +#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) +extern void sv_tz __P((char *)); +#endif + +#if defined (HISTORY) +extern void sv_histsize __P((char *)); +extern void sv_histignore __P((char *)); +extern void sv_history_control __P((char *)); +# if defined (BANG_HISTORY) +extern void sv_histchars __P((char *)); +# endif +extern void sv_histtimefmt __P((char *)); +#endif /* HISTORY */ + +#endif /* !_VARIABLES_H_ */ diff --git a/wifcontinued-test.c b/wifcontinued-test.c new file mode 100644 index 000000000..4c2c6e0d2 --- /dev/null +++ b/wifcontinued-test.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +#ifndef errno +extern int errno; +#endif +main() +{ + int x; + + x = waitpid(-1, (int *)0, WNOHANG|WCONTINUED); + if (x == -1 && errno == ECHILD) + exit (0); + else + exit (1); +} -- 2.47.3