diff options
author | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2010-04-09 16:13:32 -0700 |
---|---|---|
committer | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2010-04-09 16:15:01 -0700 |
commit | 2d698b6e42d8dca191ac795ef5dba3bf62496eec (patch) | |
tree | ac5e0b67043c50f49160e9fe407435706cf30444 /subst.c | |
parent | f1250933e4a2ac09a3d0b25b3877068e12f44da5 (diff) | |
download | vyatta-bash-2d698b6e42d8dca191ac795ef5dba3bf62496eec.tar.gz vyatta-bash-2d698b6e42d8dca191ac795ef5dba3bf62496eec.zip |
Integrate bash 3.2 version
This is merge of current Debian stable (Lenny) version of Bash
with Vyatta changes.
Diffstat (limited to 'subst.c')
-rw-r--r-- | subst.c | 256 |
1 files changed, 174 insertions, 82 deletions
@@ -4,7 +4,7 @@ /* ``Have a little faith, there's magic in the night. You ain't a beauty, but, hey, you're alright.'' */ -/* Copyright (C) 1987-2005 Free Software Foundation, Inc. +/* Copyright (C) 1987-2006 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -82,6 +82,7 @@ extern int errno; #define EX_NOALLOC 0x01 /* just skip; don't return substring */ #define EX_VARNAME 0x02 /* variable name; for string_extract () */ #define EX_REQMATCH 0x04 /* closing/matching delimiter required */ +#define EX_COMMAND 0x08 /* extracting a shell script/command */ /* Flags for the `pflags' argument to param_expand() */ #define PF_NOCOMSUB 0x01 /* Do not perform command substitution */ @@ -147,6 +148,10 @@ extern int wordexp_only; extern int expanding_redir; extern int tempenv_assign_error; +#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE) +extern wchar_t *wcsdup __P((const wchar_t *)); +#endif + /* Non-zero means to allow unmatched globbed filenames to expand to a null file. */ int allow_null_glob_expansion; @@ -200,7 +205,6 @@ static WORD_LIST *list_quote_escapes __P((WORD_LIST *)); static char *dequote_escapes __P((char *)); static char *make_quoted_char __P((int)); static WORD_LIST *quote_list __P((WORD_LIST *)); -static WORD_LIST *dequote_list __P((WORD_LIST *)); static char *remove_quoted_escapes __P((char *)); static char *remove_quoted_nulls __P((char *)); @@ -216,7 +220,7 @@ static char *string_extract_verbatim __P((char *, size_t, int *, char *)); static char *string_extract __P((char *, int *, char *, int)); static char *string_extract_double_quoted __P((char *, int *, int)); static inline char *string_extract_single_quoted __P((char *, int *)); -static inline int skip_single_quoted __P((char *, size_t, int)); +static inline int skip_single_quoted __P((const char *, size_t, int)); static int skip_double_quoted __P((char *, size_t, int)); static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int)); static char *extract_dollar_brace_string __P((char *, int *, int, int)); @@ -226,10 +230,7 @@ static char *pos_params __P((char *, int, int, int)); static unsigned char *mb_getcharlens __P((char *, int)); static char *remove_upattern __P((char *, char *, int)); -#if defined (HANDLE_MULTIBYTE) -# if !defined (HAVE_WCSDUP) -static wchar_t *wcsdup __P((wchar_t *)); -# endif +#if defined (HANDLE_MULTIBYTE) static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int)); #endif static char *remove_pattern __P((char *, char *, int)); @@ -261,6 +262,7 @@ static arrayind_t array_length_reference __P((char *)); static int valid_brace_expansion_word __P((char *, int)); static int chk_atstar __P((char *, int, int *, int *)); +static int chk_arithsub __P((const char *, int)); static WORD_DESC *parameter_brace_expand_word __P((char *, int, int)); static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *)); @@ -710,7 +712,7 @@ add_one_character: si = i + 2; if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", 0); /*)*/ + ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_COMMAND); /*)*/ else ret = extract_dollar_brace_string (string, &si, 1, 0); @@ -812,7 +814,7 @@ skip_double_quoted (string, slen, sind) { si = i + 2; if (string[i + 1] == LPAREN) - ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); /* ) */ + ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC|EX_COMMAND); /* ) */ else ret = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); @@ -865,7 +867,7 @@ string_extract_single_quoted (string, sindex) static inline int skip_single_quoted (string, slen, sind) - char *string; + const char *string; size_t slen; int sind; { @@ -946,8 +948,8 @@ string_extract_verbatim (string, slen, sindex, charlist) len = mbstowcs (wcharlist, charlist, 0); if (len == -1) len = 0; - wcharlist = xmalloc ((sizeof (wchar_t) * len) + 1); - mbstowcs (wcharlist, charlist, len); + wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1)); + mbstowcs (wcharlist, charlist, len + 1); } if (wcschr (wcharlist, wc)) @@ -980,7 +982,7 @@ extract_command_subst (string, sindex) char *string; int *sindex; { - return (extract_delimited_string (string, sindex, "$(", "(", ")", 0)); /*)*/ + return (extract_delimited_string (string, sindex, "$(", "(", ")", EX_COMMAND)); /*)*/ } /* Extract the $[ construct in STRING, and return a new string. (]) @@ -1049,7 +1051,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) int i, c, si; size_t slen; char *t, *result; - int pass_character, nesting_level; + int pass_character, nesting_level, in_comment; int len_closer, len_opener, len_alt_opener; DECLARE_MBSTATE; @@ -1058,7 +1060,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) len_alt_opener = STRLEN (alt_opener); len_closer = STRLEN (closer); - pass_character = 0; + pass_character = in_comment = 0; nesting_level = 1; i = *sindex; @@ -1070,6 +1072,14 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) if (c == 0) break; + if (in_comment) + { + if (c == '\n') + in_comment = 0; + ADVANCE_CHAR (string, slen, i); + continue; + } + if (pass_character) /* previous char was backslash */ { pass_character = 0; @@ -1077,6 +1087,15 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) continue; } + /* Not exactly right yet; should handle shell metacharacters and + multibyte characters, too. */ + if ((flags & EX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1]))) + { + in_comment = 1; + ADVANCE_CHAR (string, slen, i); + continue; + } + if (c == CTLESC || c == '\\') { pass_character++; @@ -1235,7 +1254,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags) if (string[i] == '$' && string[i+1] == LPAREN) { si = i + 2; - t = extract_delimited_string (string, &si, "$(", "(", ")", flags|EX_NOALLOC); /*)*/ + t = extract_delimited_string (string, &si, "$(", "(", ")", flags|EX_NOALLOC|EX_COMMAND); /*)*/ i = si + 1; continue; } @@ -1498,7 +1517,7 @@ skip_to_delim (string, start, delims) CQ_RETURN(si); if (string[i+1] == LPAREN) - temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC); /* ) */ + temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC|EX_COMMAND); /* ) */ else temp = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC); i = si; @@ -1563,7 +1582,8 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp) while (delims[i]) { #if defined (HANDLE_MULTIBYTE) - mbstate_t state_bak = state; + mbstate_t state_bak; + state_bak = state; mblength = MBRLEN (delims + i, slength, &state); if (MB_INVALIDCH (mblength)) state = state_bak; @@ -1774,14 +1794,21 @@ char * string_list_dollar_star (list) WORD_LIST *list; { + char *ret; #if defined (HANDLE_MULTIBYTE) +# if defined (__GNUC__) char sep[MB_CUR_MAX + 1]; +# else + char *sep = 0; +# endif #else char sep[2]; #endif - #if defined (HANDLE_MULTIBYTE) +# if !defined (__GNUC__) + sep = (char *)xmalloc (MB_CUR_MAX + 1); +# endif /* !__GNUC__ */ if (ifs_firstc_len == 1) { sep[0] = ifs_firstc[0]; @@ -1797,7 +1824,11 @@ string_list_dollar_star (list) sep[1] = '\0'; #endif - return (string_list_internal (list, sep)); + ret = string_list_internal (list, sep); +#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) + free (sep); +#endif + return ret; } /* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) @@ -1816,7 +1847,11 @@ string_list_dollar_at (list, quoted) { char *ifs, *ret; #if defined (HANDLE_MULTIBYTE) +# if defined (__GNUC__) char sep[MB_CUR_MAX + 1]; +# else + char *sep = 0; +# endif /* !__GNUC__ */ #else char sep[2]; #endif @@ -1826,6 +1861,9 @@ string_list_dollar_at (list, quoted) ifs = ifs_var ? value_cell (ifs_var) : (char *)0; #if defined (HANDLE_MULTIBYTE) +# if !defined (__GNUC__) + sep = (char *)xmalloc (MB_CUR_MAX + 1); +# endif /* !__GNUC__ */ if (ifs && *ifs) { if (ifs_firstc_len == 1) @@ -1852,7 +1890,12 @@ string_list_dollar_at (list, quoted) tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) ? quote_list (list) : list_quote_escapes (list); - return (string_list_internal (tlist, sep)); + + ret = string_list_internal (tlist, sep); +#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__) + free (sep); +#endif + return ret; } /* Return the list of words present in STRING. Separate the string into @@ -1992,7 +2035,7 @@ list_string (string, separators, quoted) sindex++; /* An IFS character that is not IFS white space, along with any adjacent IFS white space, shall delimit a field. (SUSv3) */ - while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex])) + while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex])) sindex++; } } @@ -2180,16 +2223,18 @@ do_compound_assignment (name, value, flags) int flags; { SHELL_VAR *v; - int off, mklocal; + int mklocal; + WORD_LIST *list; mklocal = flags & ASS_MKLOCAL; if (mklocal && variable_context) { + list = expand_compound_array_assignment (value, flags); v = find_variable (name); if (v == 0 || array_p (v) == 0 || v->context != variable_context) v = make_local_array_variable (name); - v = assign_array_var_from_string (v, value, flags); + assign_compound_array_list (v, list, flags); } else v = assign_array_from_string (name, value, flags); @@ -2209,7 +2254,7 @@ do_assignment_internal (word, expand) int expand; { int offset, tlen, appendop, assign_list, aflags; - char *name, *value, *ovalue, *nvalue; + char *name, *value; SHELL_VAR *entry; #if defined (ARRAY_VARS) char *t; @@ -2241,11 +2286,7 @@ do_assignment_internal (word, expand) tlen = STRLEN (temp); #if defined (ARRAY_VARS) -# 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_array_assignment_list (temp, &ni); @@ -2963,7 +3004,9 @@ dequote_escapes (string) return result; } -/* Return a new string with the quoted representation of character C. */ +/* Return a new string with the quoted representation of character C. + This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be + set in any resultant WORD_DESC where this value is the word. */ static char * make_quoted_char (c) int c; @@ -2985,7 +3028,9 @@ make_quoted_char (c) return (temp); } -/* Quote STRING. Return a new string. */ +/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so + the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where + this value is the word. */ char * quote_string (string) char *string; @@ -3019,7 +3064,7 @@ quote_string (string) return (result); } -/* De-quoted quoted characters in STRING. */ +/* De-quote quoted characters in STRING. */ char * dequote_string (string) char *string; @@ -3075,11 +3120,13 @@ quote_list (list) w->word->word = quote_string (t); free (t); w->word->flags |= W_QUOTED; + /* XXX - turn on W_HAVEQUOTEDNULL here? */ } return list; } -static WORD_LIST * +/* De-quote quoted characters in each word in LIST. */ +WORD_LIST * dequote_list (list) WORD_LIST *list; { @@ -3091,6 +3138,7 @@ dequote_list (list) s = dequote_string (tlist->word->word); free (tlist->word->word); tlist->word->word = s; + /* XXX - turn off W_HAVEQUOTEDNULL here? */ } return list; } @@ -3294,23 +3342,6 @@ remove_upattern (param, pattern, op) } #if defined (HANDLE_MULTIBYTE) - -#if !defined (HAVE_WCSDUP) -static wchar_t * -wcsdup (ws) - wchar_t *ws; -{ - wchar_t *ret; - size_t len; - - len = wcslen (ws); - ret = xmalloc ((len + 1) * sizeof (wchar_t)); - if (ret == 0) - return ret; - return (wcscpy (ret, ws)); -} -#endif /* !HAVE_WCSDUP */ - static wchar_t * remove_wpattern (wparam, wstrlen, wpattern, op) wchar_t *wparam; @@ -3318,9 +3349,8 @@ remove_wpattern (wparam, wstrlen, wpattern, op) wchar_t *wpattern; int op; { - wchar_t wc; - int n, n1; - wchar_t *ret; + wchar_t wc, *ret; + int n; switch (op) { @@ -3415,7 +3445,7 @@ remove_pattern (param, pattern, op) free (wpattern); n = strlen (param); - xret = xmalloc (n + 1); + xret = (char *)xmalloc (n + 1); memset (&ps, '\0', sizeof (mbstate_t)); n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps); xret[n] = '\0'; /* just to make sure */ @@ -3484,7 +3514,7 @@ match_upattern (string, pat, mtype, sp, ep) len = STRLEN (pat); if (pat[0] != '*' || pat[len - 1] != '*') { - p = npat = xmalloc (len + 3); + p = npat = (char *)xmalloc (len + 3); p1 = pat; if (*p1 != '*') *p++ = '*'; @@ -3628,7 +3658,7 @@ match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep) len = wcslen (wpat); if (wpat[0] != L'*' || wpat[len - 1] != L'*') { - wp = nwpat = xmalloc ((len + 3) * sizeof (wchar_t)); + wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t)); wp1 = wpat; if (*wp1 != L'*') *wp++ = L'*'; @@ -3774,7 +3804,9 @@ getpattern (value, quoted, expandpat) { char *pat, *tword; WORD_LIST *l; +#if 0 int i; +#endif /* There is a problem here: how to handle single or double quotes in the pattern string when the whole expression is between double quotes? @@ -4985,9 +5017,7 @@ parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat) a $@ in TEMP. It does not matter if the $@ is quoted, as long as it does not expand to anything. In this case, we want to return a quoted empty string. */ - temp = (char *)xmalloc (2); - temp[0] = CTLNUL; - temp[1] = '\0'; + temp = make_quoted_char ('\0'); w->flags |= W_HASQUOTEDNULL; } else @@ -5457,22 +5487,27 @@ parameter_brace_substring (varname, value, substr, quoted) { intmax_t e1, e2; int vtype, r, starsub; - char *temp, *val, *tt; + char *temp, *val, *tt, *oname; SHELL_VAR *v; if (value == 0) return ((char *)NULL); + oname = this_command_name; this_command_name = varname; vtype = get_var_and_type (varname, value, quoted, &v, &val); if (vtype == -1) - return ((char *)NULL); + { + this_command_name = oname; + return ((char *)NULL); + } starsub = vtype & VT_STARSUB; vtype &= ~VT_STARSUB; r = verify_substring_values (val, substr, vtype, &e1, &e2); + this_command_name = oname; if (r <= 0) return ((r == 0) ? &expand_param_error : (char *)NULL); @@ -5622,7 +5657,7 @@ pos_params_pat_subst (string, pat, rep, mflags) { WORD_LIST *save, *params; WORD_DESC *w; - char *ret, *tt; + char *ret; save = params = list_rest_of_args (); if (save == 0) @@ -5672,11 +5707,6 @@ parameter_brace_patsub (varname, value, patsub, quoted) vtype &= ~VT_STARSUB; mflags = 0; - if (*patsub == '/') - { - mflags |= MATCH_GLOBREP; - patsub++; - } /* Malloc this because expand_string_if_necessary or one of the expansion functions in its call chain may free it on a substitution error. */ @@ -5688,7 +5718,9 @@ parameter_brace_patsub (varname, value, patsub, quoted) if (starsub) mflags |= MATCH_STARSUB; - if (rep = quoted_strchr (lpatsub, '/', ST_BACKSL)) + /* If the pattern starts with a `/', make sure we skip over it when looking + for the replacement delimiter. */ + if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL)) *rep++ = '\0'; else rep = (char *)NULL; @@ -5708,8 +5740,15 @@ parameter_brace_patsub (varname, value, patsub, quoted) rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit); } + /* ksh93 doesn't allow the match specifier to be a part of the expanded + pattern. This is an extension. */ p = pat; - if (pat && pat[0] == '#') + if (pat && pat[0] == '/') + { + mflags |= MATCH_GLOBREP|MATCH_ANY; + p++; + } + else if (pat && pat[0] == '#') { mflags |= MATCH_BEG; p++; @@ -5776,6 +5815,57 @@ parameter_brace_patsub (varname, value, patsub, quoted) return temp; } +/* Check for unbalanced parens in S, which is the contents of $(( ... )). If + any occur, this must be a nested command substitution, so return 0. + Otherwise, return 1. A valid arithmetic expression must always have a + ( before a matching ), so any cases where there are more right parens + means that this must not be an arithmetic expression, though the parser + will not accept it without a balanced total number of parens. */ +static int +chk_arithsub (s, len) + const char *s; + int len; +{ + int i, count; + DECLARE_MBSTATE; + + i = count = 0; + while (i < len) + { + if (s[i] == '(') + count++; + else if (s[i] == ')') + { + count--; + if (count < 0) + return 0; + } + + switch (s[i]) + { + default: + ADVANCE_CHAR (s, len, i); + break; + + case '\\': + i++; + if (s[i]) + ADVANCE_CHAR (s, len, i); + break; + + case '\'': + i = skip_single_quoted (s, len, ++i); + break; + + case '"': + i = skip_double_quoted ((char *)s, len, ++i); + break; + } + } + + return (count == 0); +} + /****************************************************************/ /* */ /* Functions to perform parameter expansion on a string */ @@ -5801,7 +5891,11 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll sindex = *indexp; t_index = ++sindex; - name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME); + /* ${#var} doesn't have any of the other parameter expansions on it. */ + if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */ + name = string_extract (string, &t_index, "}", EX_VARNAME); + else + name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME); ret = 0; tflag = 0; @@ -5821,7 +5915,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll { t_index++; free (name); - temp1 = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME); + temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0); name = (char *)xmalloc (3 + (strlen (temp1))); *name = string[sindex]; if (string[sindex] == '!') @@ -6055,6 +6149,8 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll ret = alloc_word_desc (); ret->word = temp1; + if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))) + ret->flags |= W_QUOTED|W_HASQUOTEDNULL; return ret; } else if (want_patsub) @@ -6383,7 +6479,6 @@ param_expand (string, sindex, quoted, expanded_something, quoted_dollar_at_p, contains_dollar_at); - /* Fix this later when parameter_brace_expand returns a WORD_DESC * */ if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal) return (tdesc); temp = tdesc ? tdesc->word : (char *)0; @@ -6396,12 +6491,7 @@ param_expand (string, sindex, quoted, expanded_something, in the string, discard TEMP, and go on. The exception to this is when we have "${@}" and $1 is '', since $@ needs special handling. */ - /* XXX - fix this once parameter_brace_expand returns a WORD_DESC * */ -#if 0 - if (temp && QUOTED_NULL (temp)) -#else if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp)) -#endif { if (had_quoted_null_p) *had_quoted_null_p = 1; @@ -6441,6 +6531,12 @@ param_expand (string, sindex, quoted, expanded_something, /* Cut off ending `)' */ temp2[t_index] = '\0'; + if (chk_arithsub (temp2, t_index) == 0) + { + free (temp2); + goto comsub; + } + /* Expand variables found inside the expression. */ temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); free (temp2); @@ -6714,7 +6810,7 @@ add_string: case '<': case '>': { - if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & W_DQUOTE) || posixly_correct) + if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || posixly_correct) { sindex--; /* add_character: label increments sindex */ goto add_character; @@ -7484,9 +7580,6 @@ word_list_split (list) for (t = list, result = (WORD_LIST *)NULL; t; t = t->next) { tresult = word_split (t->word, ifs_value); -#if 0 - result = (WORD_LIST *) list_append (result, tresult); -#else if (result == 0) result = e = tresult; else @@ -7495,7 +7588,6 @@ word_list_split (list) while (e->next) e = e->next; } -#endif } return (result); } |