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((const char *, size_t, int));
-static int skip_double_quoted __P((char *, size_t, int));
+static int skip_double_quoted __P((char *, size_t, int, int));
static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int));
static char *extract_dollar_brace_string __P((char *, int *, int, int));
static int skip_matched_pair __P((const char *, int, int, int, int));
break;
case '"':
- sindex = skip_double_quoted (string, slen, ++sindex);
+ sindex = skip_double_quoted (string, slen, ++sindex, 0);
break;
}
}
break;
case '"':
- sindex = skip_double_quoted (string, slen, ++sindex);
+ sindex = skip_double_quoted (string, slen, ++sindex, 0);
break;
default:
/* This should really be another option to string_extract_double_quoted. */
static int
-skip_double_quoted (string, slen, sind)
+skip_double_quoted (string, slen, sind, flags)
char *string;
size_t slen;
int sind;
{
si = i + 2;
if (string[i + 1] == LPAREN)
- ret = extract_command_subst (string, &si, SX_NOALLOC);
+ ret = extract_command_subst (string, &si, SX_NOALLOC|(flags&SX_COMPLETE));
else
ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC);
char *temp;
DECLARE_MBSTATE;
- if (charlist[0] == '\'' && charlist[1] == '\0')
+ if ((flags & SX_NOCTLESC) && charlist[0] == '\'' && charlist[1] == '\0')
{
temp = string_extract_single_quoted (string, sindex);
--*sindex; /* leave *sindex at separator character */
int *sindex;
int xflags;
{
- if (string[*sindex] == LPAREN)
+ char *ret;
+
+ if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE))
return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
else
{
xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
- return (xparse_dolparen (string, string+*sindex, sindex, xflags));
+ ret = xparse_dolparen (string, string+*sindex, sindex, xflags);
+ return ret;
}
}
{
c = string[i];
+ /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond
+ the end of the string, catch it and cut the loop. */
+ if (i > slen)
+ {
+ i = slen;
+ c = string[i = slen];
+ break;
+ }
+
if (c == 0)
break;
{
si = i + 1;
i = (c == '\'') ? skip_single_quoted (string, slen, si)
- : skip_double_quoted (string, slen, si);
+ : skip_double_quoted (string, slen, si, 0);
continue;
}
if (c == '"')
{
si = i + 1;
- i = skip_double_quoted (string, slen, si);
+ i = skip_double_quoted (string, slen, si, 0);
/* skip_XXX_quoted leaves index one past close quote */
continue;
}
else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
{
i = (c == '\'') ? skip_single_quoted (ss, slen, ++i)
- : skip_double_quoted (ss, slen, ++i);
+ : skip_double_quoted (ss, slen, ++i, 0);
/* no increment, the skip functions increment past the closing quote. */
}
else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
char *delims;
int flags;
{
- int i, pass_next, backq, si, c, invert, skipquote, skipcmd, noprocsub;
+ int i, pass_next, backq, dquote, si, c;
+ int invert, skipquote, skipcmd, noprocsub, completeflag, histexp;
size_t slen;
char *temp, open[3];
DECLARE_MBSTATE;
invert = (flags & SD_INVERT);
skipcmd = (flags & SD_NOSKIPCMD) == 0;
noprocsub = (flags & SD_NOPROCSUB);
+ histexp = (flags & SD_HISTEXP);
+ completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0;
i = start;
- pass_next = backq = 0;
+ pass_next = backq = dquote = 0;
while (c = string[i])
{
/* If this is non-zero, we should not let quote characters be delimiters
}
else if (skipquote == 0 && invert == 0 && member (c, delims))
break;
- else if (c == '\'' || c == '"')
+ /* the usual case is to use skip_xxx_quoted, but we don't skip over double
+ quoted strings when looking for the history expansion character as a
+ delimiter. */
+ else if (histexp && dquote && c == '\'')
+ {
+ i++;
+ continue;
+ }
+ else if (c == '\'')
+ i = skip_single_quoted (string, slen, ++i);
+ else if (histexp && c == '"')
{
- i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
- : skip_double_quoted (string, slen, ++i);
- /* no increment, the skip functions increment past the closing quote. */
- }
+ dquote = 1 - dquote;
+ i++;
+ continue;
+ }
+ else if (c == '"')
+ i = skip_double_quoted (string, slen, ++i, completeflag);
else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
{
si = i + 2;
else if (c == '\'' || c == '"')
{
i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
- : skip_double_quoted (string, slen, ++i);
+ : skip_double_quoted (string, slen, ++i, SX_COMPLETE);
if (i > eindex)
CQ_RETURN(1);
/* no increment, the skip_xxx functions go one past end */
else if (string[i] == '\'' || string[i] == '"')
{
i = (string[i] == '\'') ? skip_single_quoted (string, slen, i)
- : skip_double_quoted (string, slen, i);
+ : skip_double_quoted (string, slen, i, SX_COMPLETE);
if (i > eindex)
return 0;
}
else if (c == '\'')
i = skip_single_quoted (s, s_len, ++i);
else if (c == '"')
- i = skip_double_quoted (s, s_len, ++i);
+ i = skip_double_quoted (s, s_len, ++i, 0);
else if (c == 0 || spctabnl (c))
{
/* We have found the end of a token. Make a word out of it and
v = make_local_array_variable (name, 0);
if (v)
assign_compound_array_list (v, list, flags);
+ if (list)
+ dispose_words (list);
}
/* In a function but forcing assignment in global context */
else if (mkglobal && variable_context)
v = convert_var_to_array (v);
if (v)
assign_compound_array_list (v, list, flags);
+ if (list)
+ dispose_words (list);
}
else
v = assign_array_from_string (name, value, flags);
free_pushed_string_input ();
/* Cancel traps, in trap.c. */
restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */
+ QUIT; /* catch any interrupts we got post-fork */
setup_async_signals ();
subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB;
}
trap strings. Set a flag noting that we have to free the
trap strings if we run trap to change a signal disposition. */
reset_signal_handlers ();
+ QUIT; /* catch any interrupts we got post-fork */
subshell_environment |= SUBSHELL_RESETTRAP;
}
{
builtin_ignoring_errexit = 0;
change_flag ('e', FLAG_OFF);
- set_shellopts ();
}
+ set_shellopts ();
/* If we are expanding a redirection, we can dispose of any temporary
environment we received, since redirections are not supposed to have
else if (valid_array_reference (name, 0))
{
expand_arrayref:
- /* XXX - does this leak if name[@] or name[*]? */
if (pflags & PF_ASSIGNRHS)
{
var = array_variable_part (name, &tt, (int *)0);
if (t == 0)
return (WORD_DESC *)NULL;
+ if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0)
+ {
+ report_error (_("%s: bad substitution"), t);
+ free (t);
+ w = alloc_word_desc ();
+ w->word = &expand_param_error;
+ w->flags = 0;
+ return (w);
+ }
+
w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0, 0);
free (t);
/* XXX - what if vname == 0 || *vname == 0 ? */
else
vname = varname;
-
+
+ if (vname == 0)
+ {
+ vtype = VT_VARIABLE;
+ *varp = (SHELL_VAR *)NULL;
+ *valp = (char *)NULL;
+ return (vtype);
+ }
+
/* This sets vtype to VT_VARIABLE or VT_POSPARMS */
vtype = (vname[0] == '@' || vname[0] == '*') && vname[1] == '\0';
if (vtype == VT_POSPARMS && vname[0] == '*')
}
else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
{
- ret = (char *)xmalloc (STRLEN (rep) + 1);
- strcpy (ret, rep);
+ replen = STRLEN (rep);
+ ret = (char *)xmalloc (replen + 1);
+ if (replen == 0)
+ ret[0] = '\0';
+ else
+ strcpy (ret, rep);
return (ret);
}
break;
l = s - str;
- if (rxpand)
+ if (rep && rxpand)
{
- int x;
- mlen = e - s;
- mstr = xmalloc (mlen + 1);
+ int x;
+ mlen = e - s;
+ mstr = xmalloc (mlen + 1);
for (x = 0; x < mlen; x++)
mstr[x] = s[x];
- mstr[mlen] = '\0';
- rstr = strcreplace (rep, '&', mstr, 0);
- rslen = strlen (rstr);
+ mstr[mlen] = '\0';
+ rstr = strcreplace (rep, '&', mstr, 0);
+ rslen = strlen (rstr);
}
else
- {
- rstr = rep;
- rslen = replen;
- }
+ {
+ rstr = rep;
+ rslen = replen;
+ }
RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
break;
case '"':
- i = skip_double_quoted ((char *)s, len, ++i);
+ i = skip_double_quoted ((char *)s, len, ++i, 0);
break;
}
}
name[1] = '\0';
t_index++;
}
+ else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == '}')
+ {
+ name = (char *)xrealloc (name, t_index - sindex + 2);
+ name[t_index - sindex] = '@';
+ name[t_index - sindex + 1] = '\0';
+ t_index++;
+ }
ret = 0;
tflag = 0;
member (c, "%:=+/") && string[sindex] == RBRACE)
{
temp = (char *)NULL;
- goto bad_substitution;
+ goto bad_substitution; /* XXX - substitution error */
}
/* Indirect expansion begins with a `!'. A valid indirect expansion is
if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
{
temp = (char *)NULL;
- goto bad_substitution;
+ goto bad_substitution; /* substitution error */
}
number = parameter_brace_expand_length (name);
var_is_special) == 0)
{
temp = (char *)NULL;
- goto bad_substitution;
+ goto bad_substitution; /* substitution error */
}
if (want_indir)
{
tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
+ if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
+ {
+ temp = (char *)NULL;
+ goto bad_substitution;
+ }
/* Turn off the W_ARRAYIND flag because there is no way for this function
to return the index we're supposed to be using. */
if (tdesc && tdesc->flags)
if (string[sindex] == RBRACE)
sindex++;
else
- goto bad_substitution;
+ goto bad_substitution; /* substitution error */
}
else
value = (char *)NULL;
{
default:
case '\0':
- bad_substitution:
+bad_substitution:
last_command_exit_value = EXECUTION_FAILURE;
report_error (_("%s: bad substitution"), string ? string : "??");
FREE (value);
FREE (temp);
free (name);
- return &expand_wdesc_error;
+ if (shell_compatibility_level <= 43)
+ return &expand_wdesc_error;
+ else
+ return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error);
case RBRACE:
break;
case '@':
temp1 = parameter_brace_transform (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
- if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
- goto bad_substitution;
-
free (temp);
free (value);
free (name);
+ if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
+ {
+ last_command_exit_value = EXECUTION_FAILURE;
+ report_error (_("%s: bad substitution"), string ? string : "??");
+ return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
+ }
ret = alloc_word_desc ();
ret->word = temp1;
char *word;
char *option;
{
- int t;
+ int t, r;
WORD_LIST *wl;
WORD_DESC *w;
wl = make_word_list (w, (WORD_LIST *)NULL);
wl = make_word_list (make_word (option), wl);
- return (declare_builtin (wl));
+ r = declare_builtin (wl);
+
+ dispose_words (wl);
+ return r;
}
#endif
opts[opti] = '\0';
if (opti > 0)
- make_internal_declare (tlist->word->word, opts);
+ {
+ t = make_internal_declare (tlist->word->word, opts);
+ if (t != EXECUTION_SUCCESS)
+ {
+ last_command_exit_value = t;
+ exp_jump_to_top_level (DISCARD);
+ }
+ }
t = do_word_assignment (tlist->word, 0);
if (t == 0)