/* ``Have a little faith, there's magic in the night. You ain't a
beauty, but, hey, you're alright.'' */
-/* Copyright (C) 1987-2012 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2013 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
static int chk_arithsub __P((const char *, int));
static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int, arrayind_t *));
+static char *parameter_brace_find_indir __P((char *, int, int, int));
static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *));
static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *));
static void parameter_brace_expand_error __P((char *, char *));
if (c == '\'')
{
/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
- if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
+ if (posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
ADVANCE_CHAR (string, slen, i);
else
{
else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
dolbrace_state = DOLBRACE_QUOTE;
else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
- dolbrace_state = DOLBRACE_QUOTE;
+ dolbrace_state = DOLBRACE_QUOTE2; /* XXX */
else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
dolbrace_state = DOLBRACE_QUOTE;
else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
v = make_local_assoc_variable (name);
else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context)
v = make_local_array_variable (name, 0);
- assign_compound_array_list (v, list, flags);
+ if (v)
+ assign_compound_array_list (v, list, flags);
}
/* In a function but forcing assignment in global context */
else if (mkglobal && variable_context)
v = convert_var_to_assoc (v);
else if (v == 0)
v = make_new_array_variable (name);
- else if (v && array_p (v) == 0)
+ else if (v && mkassoc == 0 && array_p (v) == 0)
v = convert_var_to_array (v);
- assign_compound_array_list (v, list, flags);
+ if (v)
+ assign_compound_array_list (v, list, flags);
}
else
v = assign_array_from_string (name, value, flags);
char *string;
int quoted;
{
- return (expand_string_if_necessary (string, quoted, expand_string));
+ WORD_DESC td;
+ WORD_LIST *list, *tlist;
+ size_t slen;
+ int i, saw_quote;
+ char *ret;
+ DECLARE_MBSTATE;
+
+ /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
+ slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
+ i = saw_quote = 0;
+ while (string[i])
+ {
+ if (EXP_CHAR (string[i]))
+ break;
+ else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
+ saw_quote = 1;
+ ADVANCE_CHAR (string, slen, i);
+ }
+
+ if (string[i])
+ {
+ /* This is expanded version of expand_string_internal as it's called by
+ expand_string_leave_quoted */
+ td.flags = W_NOPROCSUB; /* don't want process substitution */
+ td.word = savestring (string);
+ list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
+ /* This takes care of the calls from expand_string_leave_quoted and
+ expand_string */
+ if (list)
+ {
+ tlist = word_list_split (list);
+ dispose_words (list);
+ list = tlist;
+ if (list)
+ dequote_list (list);
+ }
+ /* This comes from expand_string_if_necessary */
+ if (list)
+ {
+ ret = string_list (list);
+ dispose_words (list);
+ }
+ else
+ ret = (char *)NULL;
+ FREE (td.word);
+ }
+ else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
+ ret = string_quote_removal (string, quoted);
+ else
+ ret = savestring (string);
+
+ return ret;
}
#if defined (COND_COMMAND)
last_command_exit_value = EXECUTION_FAILURE;
exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
/* NOTREACHED */
+ return (NULL);
}
else
return (result);
return ((xret == param) ? savestring (param) : xret);
}
n = xdupmbstowcs (&wparam, NULL, param);
+
if (n == (size_t)-1)
{
free (wpattern);
/* compute itype from varname here */
v = array_variable_part (varname, &ret, 0);
+
+ /* XXX */
+ if (v && invisible_p (var))
+ return ((char *)NULL);
+
itype = ret[0];
a = (v && array_p (v)) ? array_cell (v) : 0;
close (open_for_read_in_child ? 0 : 1);
#endif /* !HAVE_DEV_FD */
+ last_command_exit_value = result;
+ result = run_exit_trap ();
exit (result);
/*NOTREACHED*/
}
/* If unbound variables should generate an error, report one and return
failure. */
- if ((var == 0 || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
+ if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
{
c = *--t;
*t = '\0';
*t = c;
return (-1);
}
- else if (var == 0)
+ else if (var == 0 || invisible_p (var))
return 0;
/* We support a couple of expansions for variables that are not arrays.
{
expand_arrayref:
/* XXX - does this leak if name[@] or name[*]? */
- temp = array_value (name, quoted, 0, &atype, &ind);
+ if (pflags & PF_ASSIGNRHS)
+ {
+ temp = array_variable_name (name, &tt, (int *)0);
+ if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == ']')
+ temp = array_value (name, quoted|Q_DOUBLE_QUOTES, 0, &atype, &ind);
+ else
+ temp = array_value (name, quoted, 0, &atype, &ind);
+ }
+ else
+ temp = array_value (name, quoted, 0, &atype, &ind);
if (atype == 0 && temp)
{
temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
name = temp;
goto expand_arrayref;
}
+ else
#endif
/* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */
- else if (temp && *temp && legal_identifier (temp) == 0)
+ if (temp && *temp && legal_identifier (temp) == 0)
{
last_command_exit_value = EXECUTION_FAILURE;
report_error (_("%s: invalid variable name for name reference"), temp);
return ret;
}
+static char *
+parameter_brace_find_indir (name, var_is_special, quoted, find_nameref)
+ char *name;
+ int var_is_special, quoted, find_nameref;
+{
+ char *temp, *t;
+ WORD_DESC *w;
+ SHELL_VAR *v;
+
+ if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name)) &&
+ nameref_p (v) && (t = nameref_cell (v)) && *t)
+ return (savestring (t));
+
+ /* If var_is_special == 0, and name is not an array reference, this does
+ more expansion than necessary. It should really look up the variable's
+ value and not try to expand it. */
+ w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND, 0);
+ t = w->word;
+ /* Have to dequote here if necessary */
+ if (t)
+ {
+ temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
+ ? dequote_string (t)
+ : dequote_escapes (t);
+ free (t);
+ t = temp;
+ }
+ dispose_word_desc (w);
+
+ return t;
+}
+
/* Expand an indirect reference to a variable: ${!NAME} expands to the
value of the variable whose name is the value of NAME. */
static WORD_DESC *
}
}
- /* If var_is_special == 0, and name is not an array reference, this does
- more expansion than necessary. It should really look up the variable's
- value and not try to expand it. */
- w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND, 0);
- t = w->word;
- /* Have to dequote here if necessary */
- if (t)
- {
- temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
- ? dequote_string (t)
- : dequote_escapes (t);
- free (t);
- t = temp;
- }
- dispose_word_desc (w);
+ t = parameter_brace_find_indir (name, var_is_special, quoted, 0);
chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at);
if (t == 0)
SHELL_VAR **varp;
char **valp;
{
- int vtype;
- char *temp;
+ int vtype, want_indir;
+ char *temp, *vname;
+ WORD_DESC *wd;
#if defined (ARRAY_VARS)
SHELL_VAR *v;
#endif
arrayind_t lind;
+ want_indir = *varname == '!' &&
+ (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1])
+ || VALID_INDIR_PARAM (varname[1]));
+ if (want_indir)
+ vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1);
+ else
+ vname = varname;
+
/* This sets vtype to VT_VARIABLE or VT_POSPARMS */
- vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0';
- if (vtype == VT_POSPARMS && varname[0] == '*')
+ vtype = (vname[0] == '@' || vname[0] == '*') && vname[1] == '\0';
+ if (vtype == VT_POSPARMS && vname[0] == '*')
vtype |= VT_STARSUB;
*varp = (SHELL_VAR *)NULL;
#if defined (ARRAY_VARS)
- if (valid_array_reference (varname))
+ if (valid_array_reference (vname))
{
- v = array_variable_part (varname, &temp, (int *)0);
+ v = array_variable_part (vname, &temp, (int *)0);
/* If we want to signal array_value to use an already-computed index,
set LIND to that index */
lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0;
+ if (v && invisible_p (v))
+ {
+ vtype = VT_ARRAYMEMBER;
+ *varp = (SHELL_VAR *)NULL;
+ *valp = (char *)NULL;
+ }
if (v && (array_p (v) || assoc_p (v)))
{ /* [ */
if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
else
{
vtype = VT_ARRAYMEMBER;
- *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
+ *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
}
*varp = v;
}
{
vtype = VT_ARRAYMEMBER;
*varp = v;
- *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
+ *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
}
}
- else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
+ else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
{
vtype = VT_ARRAYMEMBER;
*varp = v;
*valp = value;
}
+ if (want_indir)
+ free (vname);
+
return vtype;
}
if (want_indir)
tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
else
- tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&PF_NOSPLIT2), &ind);
+ tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS)), &ind);
if (tdesc)
{
else
{
temp = string_list_dollar_at (list, quoted);
- if (ifs_is_set == 0 || ifs_is_null)
-{
-itrace("param_expand: set W_SPLITSPACE flag");
+ if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null))
tflag |= W_SPLITSPACE;
-}
}
if (expand_no_split_dollar_star == 0 && contains_dollar_at)
&temp_has_dollar_at, "ed_dollar_at,
&had_quoted_null, pflags);
has_dollar_at += temp_has_dollar_at;
-
split_on_spaces += (tword->flags & W_SPLITSPACE);
-if (tword->flags & W_SPLITSPACE)
- itrace("expand_word_internal: param_expand return word has W_SPLITSPACE");
if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
{
{
char *ifs_chars;
-itrace("expand_word_internal: splitting `%s': split_on_spaces = %d", istring, split_on_spaces);
ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
/* If we have $@, we need to split the results no matter what. If
positional parameters with a space, so we split on space (we have
set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
string_list_dollar_at has separated the positional parameters
- with the first character of $IFS, so we split on $IFS. */
- if (has_dollar_at && ifs_chars)
+ with the first character of $IFS, so we split on $IFS. If
+ SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
+ unset or null, and we want to make sure that we split on spaces
+ regardless of what else has happened to IFS since the expansion. */
+ if (split_on_spaces)
+ list = list_string (istring, " ", 1); /* XXX quoted == 1? */
+ else if (has_dollar_at && ifs_chars)
list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
else
{
make_internal_declare (tlist->word->word, "-gA");
else if (tlist->word->flags & W_ASSIGNASSOC)
make_internal_declare (tlist->word->word, "-A");
- if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
+ else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
make_internal_declare (tlist->word->word, "-ga");
else if (tlist->word->flags & W_ASSIGNARRAY)
make_internal_declare (tlist->word->word, "-a");