From 43df7bbb633aed019e4b92d6c1c7964b3816ae70 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Sat, 3 Dec 2011 13:37:16 -0500 Subject: [PATCH] commit bash-20041005 snapshot --- CWRU/CWRU.chlog | 126 ++++++++++++++++++++++++++++ MANIFEST | 8 +- braces.c.diff2 | 16 ++++ builtins/common.c | 1 - builtins/declare.def | 6 ++ builtins/reserved.def.new | 203 ++++++++++++++++++++++++++++++++++++++++++++++ command.h | 32 ++++---- doc/bash.1 | 10 ++- doc/bashref.texi | 15 ++-- doc/version.texi | 10 +-- execute_cmd.c | 41 +++++----- general.h | 1 + jobs.c | 3 +- lib/readline/complete.c | 4 +- parse.y | 13 ++- subst.c | 149 +++++++++++++++++++++++++++++----- subst.h | 12 +-- tests/RUN-ONE-TEST | 2 +- tests/extglob3.right | 26 ++++++ tests/extglob3.tests | 53 ++++++++++++ tests/run-extglob3 | 4 + tests/run-tilde | 2 +- tests/run-tilde2 | 2 + tests/tilde.tests | 66 +++++++++++++++ tests/tilde2.right | 17 ++++ tests/tilde2.tests | 46 +++++++++++ variables.c | 23 ++++-- variables.h | 3 +- 28 files changed, 805 insertions(+), 89 deletions(-) create mode 100644 braces.c.diff2 create mode 100644 builtins/reserved.def.new create mode 100644 tests/extglob3.right create mode 100644 tests/extglob3.tests create mode 100644 tests/run-extglob3 create mode 100644 tests/run-tilde2 create mode 100644 tests/tilde.tests create mode 100644 tests/tilde2.right create mode 100644 tests/tilde2.tests diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 63804b2..5f7aedd 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -10155,3 +10155,129 @@ execute_cmd.c 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 + + 10/3 + ---- +subst.c + - use W_COMPASSIGN flag in do_assignment_internal instead of deciding + lexically which assignments are compound array assignments diff --git a/MANIFEST b/MANIFEST index 398d522..2985f54 100644 --- a/MANIFEST +++ b/MANIFEST @@ -731,6 +731,8 @@ 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 @@ -840,6 +842,7 @@ 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 @@ -873,6 +876,7 @@ 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 @@ -886,8 +890,10 @@ 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/braces.c.diff2 b/braces.c.diff2 new file mode 100644 index 0000000..7558551 --- /dev/null +++ b/braces.c.diff2 @@ -0,0 +1,16 @@ +*** ../bash-3.0-patched/braces.c Wed Sep 8 11:07:53 2004 +--- braces.c Fri Sep 17 18:42:36 2004 +*************** +*** 403,407 **** + pass_next = 1; + i++; +! level++; + continue; + } +--- 403,408 ---- + pass_next = 1; + i++; +! if (quoted == 0) +! level++; + continue; + } diff --git a/builtins/common.c b/builtins/common.c index 8c2dde4..b7ea000 100644 --- a/builtins/common.c +++ b/builtins/common.c @@ -588,7 +588,6 @@ get_job_spec (list) switch (*word) { case 0: - return NO_JOB; case '%': case '+': return (current_job); diff --git a/builtins/declare.def b/builtins/declare.def index fe112dd..3afed55 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -377,7 +377,13 @@ declare_internal (list, local_var) #if defined (ARRAY_VARS) if ((making_array_special || (flags_on & att_array) || array_p (var)) && offset) { + int vlen; + vlen = STRLEN (value); +#if 0 if (value[0] == '(' && strchr (value, ')')) +#else + if (value[0] == '(' && value[vlen-1] == ')') +#endif compound_array_assign = 1; else simple_array_assign = 1; diff --git a/builtins/reserved.def.new b/builtins/reserved.def.new new file mode 100644 index 0000000..76e5965 --- /dev/null +++ b/builtins/reserved.def.new @@ -0,0 +1,203 @@ +This file is reserved.def, in which the shell reserved words are defined. +It has no direct C file production, but defines builtins for the Bash +builtin help command. + +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. + +$BUILTIN for +$SHORT_DOC for NAME [in WORDS ... ;] do COMMANDS; done +The `for' loop executes a sequence of commands for each member in a +list of items. If `in WORDS ...;' is not present, then `in "$@"' is +assumed. For each element in WORDS, NAME is set to that element, and +the COMMANDS are executed. +$END + +$BUILTIN for (( +$DOCNAME arith_for +$SHORT_DOC for (( exp1; exp2; exp3 )); do COMMANDS; done +Equivalent to + (( EXP1 )) + while (( EXP2 )); do + COMMANDS + (( EXP3 )) + done +EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is +omitted, it behaves as if it evaluates to 1. +$END + +$BUILTIN select +$SHORT_DOC select NAME [in WORDS ... ;] do COMMANDS; done +The WORDS are expanded, generating a list of words. The +set of expanded words is printed on the standard error, each +preceded by a number. If `in WORDS' is not present, `in "$@"' +is assumed. The PS3 prompt is then displayed and a line read +from the standard input. If the line consists of the number +corresponding to one of the displayed words, then NAME is set +to that word. If the line is empty, WORDS and the prompt are +redisplayed. If EOF is read, the command completes. Any other +value read causes NAME to be set to null. The line read is saved +in the variable REPLY. COMMANDS are executed after each selection +until a break command is executed. +$END + +$BUILTIN time +$SHORT_DOC time [-p] PIPELINE +Execute PIPELINE and print a summary of the real time, user CPU time, +and system CPU time spent executing PIPELINE when it terminates. +The return status is the return status of PIPELINE. The `-p' option +prints the timing summary in a slightly different format. This uses +the value of the TIMEFORMAT variable as the output format. +$END + +$BUILTIN case +$SHORT_DOC case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac +Selectively execute COMMANDS based upon WORD matching PATTERN. The +`|' is used to separate multiple patterns. +$END + +$BUILTIN if +$SHORT_DOC if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi +The if COMMANDS are executed. If the exit status is zero, then the then +COMMANDS are executed. Otherwise, each of the elif COMMANDS are executed +in turn, and if the exit status is zero, the corresponding then COMMANDS +are executed and the if command completes. Otherwise, the else COMMANDS +are executed, if present. The exit status is the exit status of the last +command executed, or zero if no condition tested true. +$END + +$BUILTIN while +$SHORT_DOC while COMMANDS; do COMMANDS; done +Expand and execute COMMANDS as long as the final command in the +`while' COMMANDS has an exit status of zero. +$END + +$BUILTIN until +$SHORT_DOC until COMMANDS; do COMMANDS; done +Expand and execute COMMANDS as long as the final command in the +`until' COMMANDS has an exit status which is not zero. +$END + +$BUILTIN function +$SHORT_DOC function NAME { COMMANDS ; } or NAME () { COMMANDS ; } +Create a simple command invoked by NAME which runs COMMANDS. +Arguments on the command line along with NAME are passed to the +function as $0 .. $n. +$END + +$BUILTIN { ... } +$DOCNAME grouping_braces +$SHORT_DOC { COMMANDS ; } +Run a set of commands in a group. This is one way to redirect an +entire set of commands. +$END + +$BUILTIN % +$DOCNAME fg_percent +$SHORT_DOC job_spec [&] +Equivalent to the JOB_SPEC argument to the `fg' command. Resume a +stopped or background job. JOB_SPEC can specify either a job name +or a job number. Following JOB_SPEC with a `&' places the job in +the background, as if the job specification had been supplied as an +argument to `bg'. +$END + +$BUILTIN (( ... )) +$DOCNAME arith +$SHORT_DOC (( expression )) +The EXPRESSION is evaluated according to the rules for arithmetic +evaluation. Equivalent to "let EXPRESSION". +$END + +$BUILTIN [[ ... ]] +$DOCNAME conditional +$SHORT_DOC [[ expression ]] +Returns a status of 0 or 1 depending on the evaluation of the conditional +expression EXPRESSION. Expressions are composed of the same primaries used +by the `test' builtin, and may be combined using the following operators + + ( EXPRESSION ) Returns the value of EXPRESSION + ! EXPRESSION True if EXPRESSION is false; else false + EXPR1 && EXPR2 True if both EXPR1 and EXPR2 are true; else false + EXPR1 || EXPR2 True if either EXPR1 or EXPR2 is true; else false + +When the `==' and `!=' operators are used, the string to the right of the +operator is used as a pattern and pattern matching is performed. The +&& and || operators do not evaluate EXPR2 if EXPR1 is sufficient to +determine the expression's value. +$END + +$BUILTIN variables +$DOCNAME variable_help +$SHORT_DOC variables - Some variable names and meanings +BASH_VERSION Version information for this Bash. +CDPATH A colon separated list of directories to search + when the argument to `cd' is not found in the current + directory. +GLOBIGNORE A colon-separated list of patterns describing filenames to + be ignored by pathname expansion. +#if defined (HISTORY) +HISTFILE The name of the file where your command history is stored. +HISTFILESIZE The maximum number of lines this file can contain. +HISTSIZE The maximum number of history lines that a running + shell can access. +#endif /* HISTORY */ +HOME The complete pathname to your login directory. +HOSTNAME The name of the current host. +HOSTTYPE The type of CPU this version of Bash is running under. +IGNOREEOF Controls the action of the shell on receipt of an EOF + character as the sole input. If set, then the value + of it is the number of EOF characters that can be seen + in a row on an empty line before the shell will exit + (default 10). When unset, EOF signifies the end of input. +MACHTYPE A string describing the current system Bash is running on. +MAILCHECK How often, in seconds, Bash checks for new mail. +MAILPATH A colon-separated list of filenames which Bash checks + for new mail. +OSTYPE The version of Unix this version of Bash is running on. +PATH A colon-separated list of directories to search when + looking for commands. +PROMPT_COMMAND A command to be executed before the printing of each + primary prompt. +PS1 The primary prompt string. +PS2 The secondary prompt string. +PWD The full pathname of the current directory. +SHELLOPTS A colon-separated list of enabled shell options. +TERM The name of the current terminal type. +TIMEFORMAT The output format for timing statistics displayed by the + `time' reserved word. +auto_resume Non-null means a command word appearing on a line by + itself is first looked for in the list of currently + stopped jobs. If found there, that job is foregrounded. + A value of `exact' means that the command word must + exactly match a command in the list of stopped jobs. A + value of `substring' means that the command word must + match a substring of the job. Any other value means that + the command must be a prefix of a stopped job. +#if defined (HISTORY) +# if defined (BANG_HISTORY) +histchars Characters controlling history expansion and quick + substitution. The first character is the history + substitution character, usually `!'. The second is + the `quick substitution' character, usually `^'. The + third is the `history comment' character, usually `#'. +# endif /* BANG_HISTORY */ +HISTIGNORE A colon-separated list of patterns used to decide which + commands should be saved on the history list. +#endif /* HISTORY */ +$END diff --git a/command.h b/command.h index 8d05376..7cfeaf7 100644 --- a/command.h +++ b/command.h @@ -67,20 +67,24 @@ 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_ITILDE 0x2000 /* Internal flag for word expansion */ +#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 */ +#define W_ASSIGNARG 0x20000 /* word is assignment argument to command */ /* Possible values for subshell_environment */ #define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */ diff --git a/doc/bash.1 b/doc/bash.1 index cbd986d..e0d7f79 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: Sat Oct 2 18:05:57 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 Oct 2" "GNU Bash-3.1-devel" .\" .\" 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 @@ -2853,7 +2853,7 @@ Matches zero or more occurrences of the given patterns Matches one or more occurrences of the given patterns .TP \fB@(\fP\^\fIpattern-list\^\fP\fB)\fP -Matches exactly one of the given patterns +Matches one of the given patterns .TP \fB!(\fP\^\fIpattern-list\^\fP\fB)\fP Matches anything except one of the given patterns @@ -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: diff --git a/doc/bashref.texi b/doc/bashref.texi index eb46079..9df7ead 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}, @@ -1931,7 +1931,7 @@ Matches zero or more occurrences of the given patterns. Matches one or more occurrences of the given patterns. @item @@(@var{pattern-list}) -Matches exactly one of the given patterns. +Matches one of the given patterns. @item !(@var{pattern-list}) Matches anything except one of the given patterns. @@ -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 2b47057..af20a42 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -2,9 +2,9 @@ Copyright (C) 1988-2004 Free Software Foundation, Inc. @end ignore -@set EDITION 3.0 -@set VERSION 3.0 -@set UPDATED 17 September 2004 -@set UPDATED-MONTH September 2004 +@set EDITION 3.1-devel +@set VERSION 3.1-devel +@set UPDATED 2 October 2004 +@set UPDATED-MONTH October 2004 -@set LASTCHANGE Fri Sep 17 22:43:56 EDT 2004 +@set LASTCHANGE Sat Oct 2 18:05:41 EDT 2004 diff --git a/execute_cmd.c b/execute_cmd.c index 98c4a42..968f234 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -160,7 +160,7 @@ static int execute_while_command __P((WHILE_COM *)); static int execute_until_command __P((WHILE_COM *)); static int execute_while_or_until __P((WHILE_COM *, int)); static int execute_if_command __P((IF_COM *)); -static int execute_null_command __P((REDIRECT *, int, int, int, pid_t)); +static int execute_null_command __P((REDIRECT *, int, int, int)); static void fix_assignment_words __P((WORD_LIST *)); static int execute_simple_command __P((SIMPLE_COM *, int, int, int, struct fd_bitmap *)); static int execute_builtin __P((sh_builtin_func_t *, WORD_LIST *, int, int)); @@ -491,7 +491,6 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, { int exec_result, invert, ignore_return, was_error_trap; REDIRECT *my_undo_list, *exec_undo_list; - volatile pid_t last_pid; volatile int save_line_number; if (command == 0 || breaking || continuing || read_but_dont_execute) @@ -648,7 +647,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, /* We can't rely on variables retaining their values across a call to execute_simple_command if a longjmp occurs as the result of a `return' builtin. This is true for sure with gcc. */ - last_pid = last_made_pid; + last_made_pid = NO_PID; was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; if (ignore_return && command->value.Simple) @@ -678,7 +677,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, /* XXX - this is something to watch out for if there are problems when the shell is compiled without job control. */ if (already_making_children && pipe_out == NO_PIPE && - last_pid != last_made_pid) + last_made_pid != NO_PID) { stop_pipeline (asynchronous, (COMMAND *)NULL); @@ -698,14 +697,6 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, subshells forked to execute builtin commands (e.g., in pipelines) to be waited for twice. */ exec_result = wait_for (last_made_pid); -#if defined (RECYCLES_PIDS) - /* LynxOS, for one, recycles pids very quickly -- so quickly - that a new process may have the same pid as the last one - created. This has been reported to fix the problem on that - OS, and a similar problem on Cygwin. */ - if (exec_result == 0) - last_made_pid = NO_PID; -#endif } } @@ -2583,10 +2574,9 @@ bind_lastarg (arg) to be run asynchronously. This handles all the side effects that are supposed to take place. */ static int -execute_null_command (redirects, pipe_in, pipe_out, async, old_last_command_subst_pid) +execute_null_command (redirects, pipe_in, pipe_out, async) REDIRECT *redirects; int pipe_in, pipe_out, async; - pid_t old_last_command_subst_pid; { int r; @@ -2632,7 +2622,7 @@ execute_null_command (redirects, pipe_in, pipe_out, async, old_last_command_subs if (r != 0) return (EXECUTION_FAILURE); - else if (old_last_command_subst_pid != last_command_subst_pid) + else if (last_command_subst_pid != NO_PID) return (last_command_exit_value); else return (EXECUTION_SUCCESS); @@ -2661,8 +2651,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); } } @@ -2678,7 +2670,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) WORD_LIST *words, *lastword; char *command_line, *lastarg, *temp; int first_word_quoted, result, builtin_is_special, already_forked, dofork; - pid_t old_last_command_subst_pid, old_last_async_pid; + pid_t old_last_async_pid; sh_builtin_func_t *builtin; SHELL_VAR *func; @@ -2697,7 +2689,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 @@ -2713,7 +2705,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) first_word_quoted = simple_command->words ? (simple_command->words->word->flags & W_QUOTED): 0; - old_last_command_subst_pid = last_command_subst_pid; + last_command_subst_pid = NO_PID; old_last_async_pid = last_asynchronous_pid; already_forked = dofork = 0; @@ -2752,9 +2744,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 @@ -2799,8 +2799,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) this_command_name = 0; result = execute_null_command (simple_command->redirects, pipe_in, pipe_out, - already_forked ? 0 : async, - old_last_command_subst_pid); + already_forked ? 0 : async); if (already_forked) exit (result); else diff --git a/general.h b/general.h index ce76e16..f4d001b 100644 --- a/general.h +++ b/general.h @@ -216,6 +216,7 @@ typedef void sh_resetsig_func_t __P((int)); /* sh_vintfunc_t */ typedef int sh_ignore_func_t __P((const char *)); /* sh_icpfunc_t */ typedef int sh_assign_func_t __P((const char *)); /* sh_icpfunc_t */ +typedef int sh_wassign_func_t __P((WORD_DESC *)); typedef int sh_builtin_func_t __P((WORD_LIST *)); /* sh_wlist_func_t */ diff --git a/jobs.c b/jobs.c index b89cf24..3747ec1 100644 --- a/jobs.c +++ b/jobs.c @@ -129,7 +129,8 @@ extern int errno; #endif /* !MUST_REINSTALL_SIGHANDLERS */ /* Some systems let waitpid(2) tell callers about stopped children. */ -#if !defined (WCONTINUED) +#if !defined (WCONTINUED) || defined (WCONTINUED_BROKEN) +# undef WCONTINUED # define WCONTINUED 0 #endif #if !defined (WIFCONTINUED) diff --git a/lib/readline/complete.c b/lib/readline/complete.c index 14d8187..a065e9b 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -2178,9 +2178,11 @@ rl_menu_complete (count, ignore) return (0); } - match_list_index = (match_list_index + count) % match_list_size; + match_list_index += count; if (match_list_index < 0) match_list_index += match_list_size; + else + match_list_index %= match_list_size; if (match_list_index == 0 && match_list_size > 1) { diff --git a/parse.y b/parse.y index 4b448ad..5acbaef 100644 --- a/parse.y +++ b/parse.y @@ -3285,6 +3285,10 @@ read_token_word (character) /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */ int dollar_present; + /* COMPOUND_ASSIGNMENT becomes non-zero if we are parsing a compound + assignment. */ + int compound_assignment; + /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */ int quoted; @@ -3304,7 +3308,7 @@ read_token_word (character) token_index = 0; all_digit_token = DIGIT (character); - dollar_present = quoted = pass_next_character = 0; + dollar_present = quoted = pass_next_character = compound_assignment = 0; for (;;) { @@ -3543,7 +3547,12 @@ read_token_word (character) token[token_index++] = ')'; FREE (ttok); all_digit_token = 0; + compound_assignment = 1; +#if 0 goto next_character; +#else + goto got_token; /* ksh93 seems to do this */ +#endif } else shell_ungetc (peek_char); @@ -3638,6 +3647,8 @@ got_token: the_word->flags |= W_HASDOLLAR; if (quoted) the_word->flags |= W_QUOTED; + if (compound_assignment) + the_word->flags |= W_COMPASSIGN; /* A word is an assignment if it appears at the beginning of a simple command, or after another assignment word. This is context-dependent, so it cannot be handled in the grammar. */ diff --git a/subst.c b/subst.c index 9a1e0f0..1372bf8 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,21 @@ 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 0 + if (expand && temp[0] == LPAREN && temp[tlen-1] == RPAREN) +#else + if (expand && (word->flags & W_COMPASSIGN)) +#endif { 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 +2243,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 +2258,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; { - return do_assignment_internal (string, 1); + 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 (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 +2513,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 * @@ -6845,8 +6921,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 +6952,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 +7519,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 +7630,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 +7678,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 7484743..1832c64 100644 --- a/subst.h +++ b/subst.h @@ -93,11 +93,12 @@ 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 *)); +extern int do_word_assignment __P((WORD_DESC *)); /* Append SOURCE to TARGET at INDEX. SIZE is the current amount of space allocated to TARGET. SOURCE can be NULL, in which @@ -144,6 +145,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 72ec06a..3efcf32 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/bash/bash-current +BUILD_DIR=/usr/local/build/chet/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/extglob3.right b/tests/extglob3.right new file mode 100644 index 0000000..f677f96 --- /dev/null +++ b/tests/extglob3.right @@ -0,0 +1,26 @@ +match 1 +match 2 +match 3 +match 4 +match 1a +match 1b +match 2a +match 2b +match 3a +match 3b +match 4a +match 4b +match 5 +match 6 +match 7 +match 8 +match 9 +match 10 +match 11 +match 12 +match 13 +match 14 +match 15 +match 16 +match 17 +match 18 diff --git a/tests/extglob3.tests b/tests/extglob3.tests new file mode 100644 index 0000000..e77edd2 --- /dev/null +++ b/tests/extglob3.tests @@ -0,0 +1,53 @@ +shopt -s extglob + +[[ ab/../ == @(ab|+([^/]))/..?(/) ]] && echo match 1 + +[[ ab/../ == +([^/])/..?(/) ]] && echo match 2 + +[[ ab/../ == @(ab|?b)/..?(/) ]] && echo match 3 + +[[ ab/../ == +([^/])/../ ]] && echo match 4 + +[[ ab/../ == +([!/])/..?(/) ]] && echo match 1a + +[[ ab/../ == @(ab|+([!/]))/..?(/) ]] && echo match 1b + +[[ ab/../ == +([!/])/../ ]] && echo match 2a + +[[ ab/../ == +([!/])/..?(/) ]] && echo match 2b + +[[ ab/../ == +([!/])/..@(/) ]] && echo match 3a + +[[ ab/../ == +(ab)/..?(/) ]] && echo match 3b + +[[ ab/../ == [!/][!/]/../ ]] && echo match 4a + +[[ ab/../ == @(ab|?b)/..?(/) ]] && echo match 4b + +[[ ab/../ == [^/][^/]/../ ]] && echo match 5 + +[[ ab/../ == ?b/..?(/) ]] && echo match 6 + +[[ ab/../ == +(?b)/..?(/) ]] && echo match 7 + +[[ ab/../ == +(?b|?b)/..?(/) ]] && echo match 8 + +[[ ab/../ == @(?b|?b)/..?(/) ]] && echo match 9 + +[[ ab/../ == @(a?|?b)/..?(/) ]] && echo match 10 + +[[ ab/../ == ?(ab)/..?(/) ]] && echo match 11 + +[[ ab/../ == ?(ab|??)/..?(/) ]] && echo match 12 + +[[ ab/../ == @(??)/..?(/) ]] && echo match 13 + +[[ ab/../ == @(??|a*)/..?(/) ]] && echo match 14 + +[[ ab/../ == @(a*)/..?(/) ]] && echo match 15 + +[[ ab/../ == +(??)/..?(/) ]] && echo match 16 + +[[ ab/../ == +(??|a*)/..?(/) ]] && echo match 17 + +[[ ab/../ == +(a*)/..?(/) ]] && echo match 18 diff --git a/tests/run-extglob3 b/tests/run-extglob3 new file mode 100644 index 0000000..2675196 --- /dev/null +++ b/tests/run-extglob3 @@ -0,0 +1,4 @@ +PATH=$PATH:`pwd` +export PATH +${THIS_SH} ./extglob3.tests > /tmp/xx +diff /tmp/xx extglob3.right && rm -f /tmp/xx diff --git a/tests/run-tilde b/tests/run-tilde index ecb7e9a..b8569c1 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/tests/run-tilde2 b/tests/run-tilde2 new file mode 100644 index 0000000..4446989 --- /dev/null +++ b/tests/run-tilde2 @@ -0,0 +1,2 @@ +${THIS_SH} ./tilde2.tests > /tmp/xx +diff /tmp/xx tilde2.right && rm -f /tmp/xx diff --git a/tests/tilde.tests b/tests/tilde.tests new file mode 100644 index 0000000..f5f5309 --- /dev/null +++ b/tests/tilde.tests @@ -0,0 +1,66 @@ +# this is needed because posix mode restricts tilde expansion to assignment +# statements preceding a command, instead of the default of expanding all +# assignment statements on the line (e.g., after `export'). Without this, +# the next-to-last test fails +set +o posix + +HOME=/usr/xyz +SHELL=~/bash +echo ~ch\et +echo ~/"foo" +echo "~chet"/"foo" +echo \~chet/"foo" +echo \~chet/bar +echo ~\chet/bar +echo ~chet""/bar +echo ":~chet/" +echo abcd~chet +echo "SHELL=~/bash" +echo $SHELL +echo abcd:~chet +path=/usr/ucb:/bin:~/bin:~/tmp/bin:/usr/bin +echo $path + +cd /usr +cd /tmp +echo ~- +echo ~+ + +XPATH=/bin:/usr/bin:. + +# yes tilde expansion +PPATH=$XPATH:~/bin +echo "$PPATH" + +# no tilde expansion +PPATH="$XPATH:~/bin" +echo "$PPATH" + +# yes tilde expansion +export PPATH=$XPATH:~/bin +echo "$PPATH" +declare -x PPATH=$XPATH:~/bin +echo "$PPATH" + +# no tilde expansion +export PPATH="$XPATH:~/bin" +echo "$PPATH" +declare -x PPATH="$XPATH:~/bin" +echo "$PPATH" + +# more tests of tilde expansion when executing case commands +case ~ in +$HOME) echo ok 1;; +*) echo bad 1 ;; +esac + +case ~ in +~) echo ok 2 ;; +\~) echo bad 2a ;; +*) echo bad 2b ;; +esac + +case $unset in +"") echo ok 3 ;; +*) echo bad 3 ;; +esac diff --git a/tests/tilde2.right b/tests/tilde2.right new file mode 100644 index 0000000..90897fc --- /dev/null +++ b/tests/tilde2.right @@ -0,0 +1,17 @@ +PATH=~/bin:/bin:/usr/bin:. +/usr/xyz/bin:~/bin2:/bin:/usr/bin:. +PATH=~/bin:~/bin2:/bin:/usr/bin:. +~/bin +~ +/usr/xyz +~ +~ +~ +argv[1] = <\a> +argv[1] = <\a> +/usr/xyz/bash +ok +~ +~ +make -k FOO=/usr/xyz/mumble +/usr/xyz/mumble diff --git a/tests/tilde2.tests b/tests/tilde2.tests new file mode 100644 index 0000000..3e2464f --- /dev/null +++ b/tests/tilde2.tests @@ -0,0 +1,46 @@ +HOME=/usr/xyz +XPATH=/bin:/usr/bin:. + +ADDPATH=PATH=~/bin:$XPATH + +echo $ADDPATH + +unset ADDPATH +: ${ADDPATH:=~/bin:~/bin2:$XPATH} +echo $ADDPATH + +unset ADDPATH +: ${ADDPATH:=PATH=~/bin:~/bin2:$XPATH} +echo $ADDPATH + +cat << ! +~/bin +! + +echo "~" + +echo ${TPATH:-~} +echo "${TPATH:-~}" +echo "${TPATH:-"~"}" + +echo "${XPATH+~}" + +recho "\a" +recho "${TPATH:-\a}" + +SHELL=~/bash +echo $SHELL + +case $SHELL in +~/bash) echo ok;; +*) echo bad;; +esac + +somevar= +echo "${somevar:-~}" +echo "${somevar:-"~"}" + +echo make -k FOO=~/mumble + +typeset FOO=~/mumble +echo "$FOO" diff --git a/variables.c b/variables.c index 7d4d930..9271758 100644 --- a/variables.c +++ b/variables.c @@ -320,7 +320,7 @@ initialize_shell_variables (env, privmode) #if defined (ARRAY_VARS) # if 0 /* Array variables may not yet be exported. */ - else if (*string == '(' && string[1] == '[' && xstrchr (string, ')')) + else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')') { string_length = 1; temp_string = extract_array_assignment_list (string, &string_length); @@ -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); @@ -2067,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); @@ -2092,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 index cd11fd9..08db0f5 100644 --- a/variables.h +++ b/variables.h @@ -256,7 +256,8 @@ 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 assign_in_env __P((WORD_DESC *)); + extern int unbind_variable __P((const char *)); extern int unbind_func __P((const char *)); extern int unbind_function_def __P((const char *)); -- 2.7.4