mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-23 13:57:58 +02:00
Bash-5.3-alpha release
This commit is contained in:
+197
-196
@@ -1,6 +1,6 @@
|
||||
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
|
||||
|
||||
/* Copyright (C) 2001-2021 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2001-2024 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -45,22 +45,19 @@
|
||||
# define RBRACK ']'
|
||||
#endif
|
||||
|
||||
/* This variable means to not expand associative array subscripts more than
|
||||
once, when performing variable expansion. */
|
||||
int assoc_expand_once = 0;
|
||||
|
||||
/* Ditto for indexed array subscripts -- currently unused */
|
||||
/* This variable means to not expand associative or indexed array subscripts
|
||||
more than once, when performing variable expansion. */
|
||||
int array_expand_once = 0;
|
||||
|
||||
static SHELL_VAR *bind_array_var_internal PARAMS((SHELL_VAR *, arrayind_t, char *, char *, int));
|
||||
static SHELL_VAR *assign_array_element_internal PARAMS((SHELL_VAR *, char *, char *, char *, int, char *, int, array_eltstate_t *));
|
||||
static SHELL_VAR *bind_array_var_internal (SHELL_VAR *, arrayind_t, char *, const char *, int);
|
||||
static SHELL_VAR *assign_array_element_internal (SHELL_VAR *, const char *, char *, char *, int, const char *, int, array_eltstate_t *);
|
||||
|
||||
static void assign_assoc_from_kvlist PARAMS((SHELL_VAR *, WORD_LIST *, HASH_TABLE *, int));
|
||||
static void assign_assoc_from_kvlist (SHELL_VAR *, WORD_LIST *, HASH_TABLE *, int);
|
||||
|
||||
static char *quote_assign PARAMS((const char *));
|
||||
static void quote_array_assignment_chars PARAMS((WORD_LIST *));
|
||||
static char *quote_compound_array_word PARAMS((char *, int));
|
||||
static char *array_value_internal PARAMS((const char *, int, int, array_eltstate_t *));
|
||||
static char *quote_assign (const char *);
|
||||
static void quote_array_assignment_chars (WORD_LIST *);
|
||||
static char *quote_compound_array_word (char *, int);
|
||||
static char *array_value_internal (const char *, int, int, array_eltstate_t *);
|
||||
|
||||
/* Standard error message to use when encountering an invalid array subscript */
|
||||
const char * const bash_badsub_errmsg = N_("bad array subscript");
|
||||
@@ -74,8 +71,7 @@ const char * const bash_badsub_errmsg = N_("bad array subscript");
|
||||
/* Convert a shell variable to an array variable. The original value is
|
||||
saved as array[0]. */
|
||||
SHELL_VAR *
|
||||
convert_var_to_array (var)
|
||||
SHELL_VAR *var;
|
||||
convert_var_to_array (SHELL_VAR *var)
|
||||
{
|
||||
char *oldval;
|
||||
ARRAY *array;
|
||||
@@ -112,8 +108,7 @@ convert_var_to_array (var)
|
||||
/* Convert a shell variable to an array variable. The original value is
|
||||
saved as array[0]. */
|
||||
SHELL_VAR *
|
||||
convert_var_to_assoc (var)
|
||||
SHELL_VAR *var;
|
||||
convert_var_to_assoc (SHELL_VAR *var)
|
||||
{
|
||||
char *oldval;
|
||||
HASH_TABLE *hash;
|
||||
@@ -147,13 +142,28 @@ convert_var_to_assoc (var)
|
||||
return var;
|
||||
}
|
||||
|
||||
/* Copy the array (ARRAY *) or assoc (HASH_TABLE *) from variable V1 to V2,
|
||||
and return V2. */
|
||||
SHELL_VAR *
|
||||
arrayvar_copyval (SHELL_VAR *v1, SHELL_VAR *v2)
|
||||
{
|
||||
FREE (value_cell (v2));
|
||||
VUNSETATTR (v2, (att_array | att_assoc));
|
||||
if (array_p (v1))
|
||||
{
|
||||
var_setarray (v2, array_copy (array_cell (v1)));
|
||||
VSETATTR (v2, att_array);
|
||||
}
|
||||
else if (assoc_p (v1))
|
||||
{
|
||||
var_setassoc (v2, assoc_copy (assoc_cell (v1)));
|
||||
VSETATTR (v2, att_assoc);
|
||||
}
|
||||
return v2;
|
||||
}
|
||||
|
||||
char *
|
||||
make_array_variable_value (entry, ind, key, value, flags)
|
||||
SHELL_VAR *entry;
|
||||
arrayind_t ind;
|
||||
char *key;
|
||||
char *value;
|
||||
int flags;
|
||||
make_array_variable_value (SHELL_VAR *entry, arrayind_t ind, const char *key, const char *value, int flags)
|
||||
{
|
||||
SHELL_VAR *dentry;
|
||||
char *newval;
|
||||
@@ -195,12 +205,7 @@ make_array_variable_value (entry, ind, key, value, flags)
|
||||
XXX - make sure that any dynamic associative array variables recreate the
|
||||
hash table on each assignment. BASH_CMDS and BASH_ALIASES already do this */
|
||||
static SHELL_VAR *
|
||||
bind_assoc_var_internal (entry, hash, key, value, flags)
|
||||
SHELL_VAR *entry;
|
||||
HASH_TABLE *hash;
|
||||
char *key;
|
||||
char *value;
|
||||
int flags;
|
||||
bind_assoc_var_internal (SHELL_VAR *entry, HASH_TABLE *hash, char *key, const char *value, int flags)
|
||||
{
|
||||
char *newval;
|
||||
|
||||
@@ -208,7 +213,10 @@ bind_assoc_var_internal (entry, hash, key, value, flags)
|
||||
newval = make_array_variable_value (entry, 0, key, value, flags);
|
||||
|
||||
if (entry->assign_func)
|
||||
(*entry->assign_func) (entry, newval, 0, key);
|
||||
{
|
||||
(*entry->assign_func) (entry, newval, 0, key);
|
||||
FREE (key);
|
||||
}
|
||||
else
|
||||
assoc_insert (hash, key, newval);
|
||||
|
||||
@@ -223,12 +231,7 @@ bind_assoc_var_internal (entry, hash, key, value, flags)
|
||||
/* Perform ENTRY[IND]=VALUE or ENTRY[KEY]=VALUE. This is not called for every
|
||||
assignment to an associative array; see assign_compound_array_list below. */
|
||||
static SHELL_VAR *
|
||||
bind_array_var_internal (entry, ind, key, value, flags)
|
||||
SHELL_VAR *entry;
|
||||
arrayind_t ind;
|
||||
char *key;
|
||||
char *value;
|
||||
int flags;
|
||||
bind_array_var_internal (SHELL_VAR *entry, arrayind_t ind, char *key, const char *value, int flags)
|
||||
{
|
||||
char *newval;
|
||||
|
||||
@@ -256,11 +259,7 @@ bind_array_var_internal (entry, ind, key, value, flags)
|
||||
If NAME does not exist, just create an array variable, no matter what
|
||||
IND's value may be. */
|
||||
SHELL_VAR *
|
||||
bind_array_variable (name, ind, value, flags)
|
||||
char *name;
|
||||
arrayind_t ind;
|
||||
char *value;
|
||||
int flags;
|
||||
bind_array_variable (const char *name, arrayind_t ind, const char *value, int flags)
|
||||
{
|
||||
SHELL_VAR *entry;
|
||||
|
||||
@@ -291,22 +290,13 @@ bind_array_variable (name, ind, value, flags)
|
||||
}
|
||||
|
||||
SHELL_VAR *
|
||||
bind_array_element (entry, ind, value, flags)
|
||||
SHELL_VAR *entry;
|
||||
arrayind_t ind;
|
||||
char *value;
|
||||
int flags;
|
||||
bind_array_element (SHELL_VAR *entry, arrayind_t ind, char *value, int flags)
|
||||
{
|
||||
return (bind_array_var_internal (entry, ind, 0, value, flags));
|
||||
}
|
||||
|
||||
SHELL_VAR *
|
||||
bind_assoc_variable (entry, name, key, value, flags)
|
||||
SHELL_VAR *entry;
|
||||
char *name;
|
||||
char *key;
|
||||
char *value;
|
||||
int flags;
|
||||
bind_assoc_variable (SHELL_VAR *entry, const char *name, char *key, const char *value, int flags)
|
||||
{
|
||||
if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
|
||||
{
|
||||
@@ -341,20 +331,13 @@ flush_eltstate (array_eltstate_t *estatep)
|
||||
assign VALUE to that array element by calling bind_array_variable().
|
||||
Flags are ASS_ assignment flags */
|
||||
SHELL_VAR *
|
||||
assign_array_element (name, value, flags, estatep)
|
||||
char *name, *value;
|
||||
int flags;
|
||||
array_eltstate_t *estatep;
|
||||
assign_array_element (const char *name, const char *value, int flags, array_eltstate_t *estatep)
|
||||
{
|
||||
char *sub, *vname;
|
||||
int sublen, isassoc, avflags;
|
||||
SHELL_VAR *entry;
|
||||
|
||||
avflags = 0;
|
||||
if (flags & ASS_NOEXPAND)
|
||||
avflags |= AV_NOEXPAND;
|
||||
if (flags & ASS_ONEWORD)
|
||||
avflags |= AV_ONEWORD;
|
||||
avflags = convert_assign_flags_to_arrayval_flags (flags);
|
||||
vname = array_variable_name (name, avflags, &sub, &sublen);
|
||||
|
||||
if (vname == 0)
|
||||
@@ -391,16 +374,14 @@ assign_array_element (name, value, flags, estatep)
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Assign VALUE to the index computed from SUB of length SUBLEN of array
|
||||
VNAME. NAME is the complete variable reference. FLAGS are ASS_ assignment
|
||||
flags. ENTRY is the SHELL_VAR corresponding to VNAME. The caller
|
||||
initializes ESTATEP, and we set it to the values we compute. */
|
||||
static SHELL_VAR *
|
||||
assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, estatep)
|
||||
SHELL_VAR *entry;
|
||||
char *name; /* only used for error messages */
|
||||
char *vname;
|
||||
char *sub;
|
||||
int sublen;
|
||||
char *value;
|
||||
int flags;
|
||||
array_eltstate_t *estatep;
|
||||
assign_array_element_internal (SHELL_VAR *entry, const char *name, char *vname,
|
||||
char *sub, int sublen, const char *value,
|
||||
int flags, array_eltstate_t *estatep)
|
||||
{
|
||||
char *akey, *nkey;
|
||||
arrayind_t ind;
|
||||
@@ -434,7 +415,11 @@ assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, es
|
||||
}
|
||||
else
|
||||
{
|
||||
ind = array_expand_index (entry, sub, sublen, 0);
|
||||
/* convert ASS_ flags to AV_FLAGS here */
|
||||
int avflags;
|
||||
|
||||
avflags = convert_assign_flags_to_arrayval_flags (flags);
|
||||
ind = array_expand_index (entry, sub, sublen, avflags);
|
||||
/* negative subscripts to indexed arrays count back from end */
|
||||
if (entry && ind < 0)
|
||||
ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind;
|
||||
@@ -460,11 +445,10 @@ assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, es
|
||||
convert it to an indexed array. If FLAGS&1 is non-zero, an existing
|
||||
variable is checked for the readonly or noassign attribute in preparation
|
||||
for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we
|
||||
create an associative array. */
|
||||
create an associative array. If FLAGS&4 is non-zero, we return noassign
|
||||
variables instead of NULL because the caller wants to handle them. */
|
||||
SHELL_VAR *
|
||||
find_or_make_array_variable (name, flags)
|
||||
char *name;
|
||||
int flags;
|
||||
find_or_make_array_variable (const char *name, int flags)
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
@@ -496,6 +480,8 @@ find_or_make_array_variable (name, flags)
|
||||
{
|
||||
if (readonly_p (var))
|
||||
err_readonly (name);
|
||||
if ((flags & 4) && noassign_p (var))
|
||||
return (var);
|
||||
return ((SHELL_VAR *)NULL);
|
||||
}
|
||||
else if ((flags & 2) && array_p (var))
|
||||
@@ -515,9 +501,7 @@ find_or_make_array_variable (name, flags)
|
||||
/* Perform a compound assignment statement for array NAME, where VALUE is
|
||||
the text between the parens: NAME=( VALUE ) */
|
||||
SHELL_VAR *
|
||||
assign_array_from_string (name, value, flags)
|
||||
char *name, *value;
|
||||
int flags;
|
||||
assign_array_from_string (const char *name, char *value, int flags)
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
int vflags;
|
||||
@@ -525,10 +509,11 @@ assign_array_from_string (name, value, flags)
|
||||
vflags = 1;
|
||||
if (flags & ASS_MKASSOC)
|
||||
vflags |= 2;
|
||||
vflags |= 4; /* we want to handle noassign variables ourselves */
|
||||
|
||||
var = find_or_make_array_variable (name, vflags);
|
||||
if (var == 0)
|
||||
return ((SHELL_VAR *)NULL);
|
||||
if (var == 0 || noassign_p (var))
|
||||
return (var);
|
||||
|
||||
return (assign_array_var_from_string (var, value, flags));
|
||||
}
|
||||
@@ -536,10 +521,7 @@ assign_array_from_string (name, value, flags)
|
||||
/* Sequentially assign the indices of indexed array variable VAR from the
|
||||
words in LIST. */
|
||||
SHELL_VAR *
|
||||
assign_array_var_from_word_list (var, list, flags)
|
||||
SHELL_VAR *var;
|
||||
WORD_LIST *list;
|
||||
int flags;
|
||||
assign_array_var_from_word_list (SHELL_VAR *var, WORD_LIST *list, int flags)
|
||||
{
|
||||
register arrayind_t i;
|
||||
register WORD_LIST *l;
|
||||
@@ -549,7 +531,19 @@ assign_array_var_from_word_list (var, list, flags)
|
||||
i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
|
||||
|
||||
for (l = list; l; l = l->next, i++)
|
||||
bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND);
|
||||
{
|
||||
if (a && i < 0) /* overflow */
|
||||
{
|
||||
char *num;
|
||||
|
||||
num = itos (i);
|
||||
report_error ("%s[%s]: %s", var->name, num, bash_badsub_errmsg);
|
||||
free (num);
|
||||
return (var); /* XXX */
|
||||
}
|
||||
|
||||
bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND);
|
||||
}
|
||||
|
||||
VUNSETATTR (var, att_invisible); /* no longer invisible */
|
||||
|
||||
@@ -557,14 +551,11 @@ assign_array_var_from_word_list (var, list, flags)
|
||||
}
|
||||
|
||||
WORD_LIST *
|
||||
expand_compound_array_assignment (var, value, flags)
|
||||
SHELL_VAR *var;
|
||||
char *value;
|
||||
int flags;
|
||||
expand_compound_array_assignment (SHELL_VAR *var, char *value, int flags)
|
||||
{
|
||||
WORD_LIST *list, *nlist;
|
||||
char *val;
|
||||
int ni;
|
||||
size_t ni;
|
||||
|
||||
/* This condition is true when invoked from the declare builtin with a
|
||||
command like
|
||||
@@ -624,17 +615,22 @@ expand_compound_array_assignment (var, value, flags)
|
||||
}
|
||||
|
||||
#if ASSOC_KVPAIR_ASSIGNMENT
|
||||
/* If non-zero, we split the words in kv-pair compound array assignments in
|
||||
addition to performing the other expansions. */
|
||||
int split_kvpair_assignments = 0;
|
||||
|
||||
/* We have a set of key-value pairs that should be expanded and split
|
||||
(because they are not assignment statements). They are not expanded
|
||||
and split in expand_compound_array_assignment because assoc_p (var)
|
||||
is true. We defer the expansion until now. */
|
||||
static void
|
||||
assign_assoc_from_kvlist (var, nlist, h, flags)
|
||||
SHELL_VAR *var;
|
||||
WORD_LIST *nlist;
|
||||
HASH_TABLE *h;
|
||||
int flags;
|
||||
assign_assoc_from_kvlist (SHELL_VAR *var, WORD_LIST *nlist, HASH_TABLE *h, int flags)
|
||||
{
|
||||
WORD_LIST *list;
|
||||
WORD_LIST *list, *explist;
|
||||
char *akey, *aval, *k, *v;
|
||||
|
||||
for (list = nlist; list; list = list->next)
|
||||
explist = split_kvpair_assignments ? expand_words_no_vars (nlist) : nlist;
|
||||
for (list = explist; list; list = list->next)
|
||||
{
|
||||
k = list->word->word;
|
||||
v = list->next ? list->next->word->word : 0;
|
||||
@@ -642,7 +638,7 @@ assign_assoc_from_kvlist (var, nlist, h, flags)
|
||||
if (list->next)
|
||||
list = list->next;
|
||||
|
||||
akey = expand_subscript_string (k, 0);
|
||||
akey = split_kvpair_assignments ? savestring (k) : expand_subscript_string (k, 0);
|
||||
if (akey == 0 || *akey == 0)
|
||||
{
|
||||
err_badarraysub (k);
|
||||
@@ -650,7 +646,7 @@ assign_assoc_from_kvlist (var, nlist, h, flags)
|
||||
continue;
|
||||
}
|
||||
|
||||
aval = expand_assignment_string_to_string (v, 0);
|
||||
aval = split_kvpair_assignments ? savestring (v) : expand_assignment_string_to_string (v, 0);
|
||||
if (aval == 0)
|
||||
{
|
||||
aval = (char *)xmalloc (1);
|
||||
@@ -658,22 +654,24 @@ assign_assoc_from_kvlist (var, nlist, h, flags)
|
||||
}
|
||||
|
||||
bind_assoc_var_internal (var, h, akey, aval, flags);
|
||||
|
||||
free (aval);
|
||||
}
|
||||
|
||||
if (explist != nlist)
|
||||
dispose_words (explist);
|
||||
}
|
||||
|
||||
/* Return non-zero if L appears to be a key-value pair associative array
|
||||
compound assignment. */
|
||||
int
|
||||
kvpair_assignment_p (l)
|
||||
WORD_LIST *l;
|
||||
kvpair_assignment_p (WORD_LIST *l)
|
||||
{
|
||||
return (l && (l->word->flags & W_ASSIGNMENT) == 0 && l->word->word[0] != '['); /*]*/
|
||||
}
|
||||
|
||||
char *
|
||||
expand_and_quote_kvpair_word (w)
|
||||
char *w;
|
||||
expand_and_quote_kvpair_word (const char *w)
|
||||
{
|
||||
char *r, *s, *t;
|
||||
|
||||
@@ -695,17 +693,14 @@ expand_and_quote_kvpair_word (w)
|
||||
|
||||
If this is an associative array, we perform the assignments into NHASH and
|
||||
set NHASH to be the value of VAR after processing the assignments in NLIST */
|
||||
void
|
||||
assign_compound_array_list (var, nlist, flags)
|
||||
SHELL_VAR *var;
|
||||
WORD_LIST *nlist;
|
||||
int flags;
|
||||
int
|
||||
assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
|
||||
{
|
||||
ARRAY *a;
|
||||
HASH_TABLE *h, *nhash;
|
||||
WORD_LIST *list;
|
||||
char *w, *val, *nval, *savecmd;
|
||||
int len, iflags, free_val;
|
||||
int len, iflags, free_val, any_failed;
|
||||
arrayind_t ind, last_ind;
|
||||
char *akey;
|
||||
|
||||
@@ -715,6 +710,8 @@ assign_compound_array_list (var, nlist, flags)
|
||||
akey = (char *)0;
|
||||
ind = 0;
|
||||
|
||||
any_failed = 0;
|
||||
|
||||
/* Now that we are ready to assign values to the array, kill the existing
|
||||
value. */
|
||||
if ((flags & ASS_APPEND) == 0)
|
||||
@@ -725,8 +722,6 @@ assign_compound_array_list (var, nlist, flags)
|
||||
nhash = assoc_create (h->nbuckets);
|
||||
}
|
||||
|
||||
last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
|
||||
|
||||
#if ASSOC_KVPAIR_ASSIGNMENT
|
||||
if (assoc_p (var) && kvpair_assignment_p (nlist))
|
||||
{
|
||||
@@ -738,10 +733,12 @@ assign_compound_array_list (var, nlist, flags)
|
||||
var_setassoc (var, nhash);
|
||||
assoc_dispose (h);
|
||||
}
|
||||
return;
|
||||
return 1; /* XXX - check return value */
|
||||
}
|
||||
#endif
|
||||
|
||||
last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
|
||||
|
||||
for (list = nlist; list; list = list->next)
|
||||
{
|
||||
/* Don't allow var+=(values) to make assignments in VALUES append to
|
||||
@@ -760,10 +757,11 @@ assign_compound_array_list (var, nlist, flags)
|
||||
/* XXX - changes for `+=' */
|
||||
if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
|
||||
{
|
||||
if (assoc_p (var))
|
||||
if (assoc_p (var) || last_ind < 0)
|
||||
{
|
||||
err_badarraysub (w);
|
||||
continue;
|
||||
any_failed++;
|
||||
break;
|
||||
}
|
||||
nval = make_variable_value (var, w, flags);
|
||||
if (var->assign_func)
|
||||
@@ -778,26 +776,33 @@ assign_compound_array_list (var, nlist, flags)
|
||||
if (len == 1)
|
||||
{
|
||||
err_badarraysub (w);
|
||||
continue;
|
||||
any_failed++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ALL_ELEMENT_SUB (w[1]) && len == 2 && array_p (var))
|
||||
{
|
||||
set_exit_status (EXECUTION_FAILURE);
|
||||
report_error (_("%s: cannot assign to non-numeric index"), w);
|
||||
continue;
|
||||
any_failed++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (array_p (var))
|
||||
{
|
||||
ind = array_expand_index (var, w + 1, len, 0);
|
||||
int avflags;
|
||||
|
||||
/* convert ASS_ FLAGS to AV_ flags here */
|
||||
avflags = convert_assign_flags_to_arrayval_flags (flags);
|
||||
ind = array_expand_index (var, w + 1, len, avflags);
|
||||
/* negative subscripts to indexed arrays count back from end */
|
||||
if (ind < 0)
|
||||
ind = array_max_index (array_cell (var)) + 1 + ind;
|
||||
if (ind < 0)
|
||||
{
|
||||
err_badarraysub (w);
|
||||
continue;
|
||||
any_failed++;
|
||||
break;
|
||||
}
|
||||
|
||||
last_ind = ind;
|
||||
@@ -813,7 +818,8 @@ assign_compound_array_list (var, nlist, flags)
|
||||
{
|
||||
err_badarraysub (w);
|
||||
FREE (akey);
|
||||
continue;
|
||||
any_failed++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,7 +836,8 @@ assign_compound_array_list (var, nlist, flags)
|
||||
{
|
||||
set_exit_status (EXECUTION_FAILURE);
|
||||
report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
|
||||
continue;
|
||||
any_failed++;
|
||||
break;
|
||||
}
|
||||
else /* No [ind]=value, just a stray `=' */
|
||||
{
|
||||
@@ -838,6 +845,16 @@ assign_compound_array_list (var, nlist, flags)
|
||||
val = w;
|
||||
}
|
||||
|
||||
if (array_p (var) && ind < 0) /* overflow */
|
||||
{
|
||||
char *num;
|
||||
|
||||
num = itos (ind);
|
||||
report_error ("%s[%s]: %s", var->name, num, bash_badsub_errmsg);
|
||||
free (num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free_val = 0;
|
||||
/* See above; we need to expand the value here */
|
||||
if (assoc_p (var))
|
||||
@@ -853,7 +870,7 @@ assign_compound_array_list (var, nlist, flags)
|
||||
|
||||
savecmd = this_command_name;
|
||||
if (integer_p (var))
|
||||
this_command_name = (char *)NULL; /* no command name for errors */
|
||||
this_command_name = 0; /* no command name for errors */
|
||||
if (assoc_p (var))
|
||||
bind_assoc_var_internal (var, nhash, akey, val, iflags);
|
||||
else
|
||||
@@ -871,23 +888,36 @@ assign_compound_array_list (var, nlist, flags)
|
||||
var_setassoc (var, nhash);
|
||||
assoc_dispose (h);
|
||||
}
|
||||
|
||||
#if ARRAY_EXPORT
|
||||
if (var && exported_p (var))
|
||||
{
|
||||
INVALIDATE_EXPORTSTR (var);
|
||||
array_needs_making = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (any_failed ? 0 : 1);
|
||||
}
|
||||
|
||||
/* Perform a compound array assignment: VAR->name=( VALUE ). The
|
||||
VALUE has already had the parentheses stripped. */
|
||||
VALUE has already had the parentheses stripped. FLAGS are ASS_
|
||||
assignment flags. */
|
||||
SHELL_VAR *
|
||||
assign_array_var_from_string (var, value, flags)
|
||||
SHELL_VAR *var;
|
||||
char *value;
|
||||
int flags;
|
||||
assign_array_var_from_string (SHELL_VAR *var, char *value, int flags)
|
||||
{
|
||||
WORD_LIST *nlist;
|
||||
int aflags, r;
|
||||
|
||||
if (value == 0)
|
||||
return var;
|
||||
|
||||
nlist = expand_compound_array_assignment (var, value, flags);
|
||||
assign_compound_array_list (var, nlist, flags);
|
||||
/* This is were we set ASS_NOEXPAND and ASS_ONEWORD if we need to, since
|
||||
expand_compound_array_assignment performs word expansions. Honors
|
||||
array_expand_once; allows @ and * as associative array keys. */
|
||||
aflags = flags | (array_expand_once ? ASS_NOEXPAND : 0) | ASS_ALLOWALLSUB;
|
||||
r = assign_compound_array_list (var, nlist, aflags);
|
||||
|
||||
if (nlist)
|
||||
dispose_words (nlist);
|
||||
@@ -895,15 +925,14 @@ assign_array_var_from_string (var, value, flags)
|
||||
if (var)
|
||||
VUNSETATTR (var, att_invisible); /* no longer invisible */
|
||||
|
||||
return (var);
|
||||
return (r == 0 ? (SHELL_VAR *)0 : var);
|
||||
}
|
||||
|
||||
/* Quote globbing chars and characters in $IFS before the `=' in an assignment
|
||||
statement (usually a compound array assignment) to protect them from
|
||||
unwanted filename expansion or word splitting. */
|
||||
static char *
|
||||
quote_assign (string)
|
||||
const char *string;
|
||||
quote_assign (const char *string)
|
||||
{
|
||||
size_t slen;
|
||||
int saw_eq;
|
||||
@@ -949,9 +978,7 @@ quote_assign (string)
|
||||
indexed arrays. W has already undergone word expansions. If W has no [IND]=,
|
||||
just single-quote and return it. */
|
||||
static char *
|
||||
quote_compound_array_word (w, type)
|
||||
char *w;
|
||||
int type;
|
||||
quote_compound_array_word (char *w, int type)
|
||||
{
|
||||
char *nword, *sub, *value, *t;
|
||||
int ind, wlen, i;
|
||||
@@ -985,6 +1012,7 @@ quote_compound_array_word (w, type)
|
||||
if (t != w+ind)
|
||||
free (t);
|
||||
strcpy (nword + i, value);
|
||||
free (value);
|
||||
|
||||
return nword;
|
||||
}
|
||||
@@ -997,9 +1025,7 @@ quote_compound_array_word (w, type)
|
||||
Used for compound assignments to associative arrays that are arguments to
|
||||
declaration builtins (declare -A a=( list )). */
|
||||
char *
|
||||
expand_and_quote_assoc_word (w, type)
|
||||
char *w;
|
||||
int type;
|
||||
expand_and_quote_assoc_word (char *w, int type)
|
||||
{
|
||||
char *nword, *key, *value, *s, *t;
|
||||
int ind, wlen, i;
|
||||
@@ -1050,9 +1076,7 @@ expand_and_quote_assoc_word (w, type)
|
||||
the = sign (and any `+') alone. If it's not an assignment, just single-
|
||||
quote the word. This is used for indexed arrays. */
|
||||
void
|
||||
quote_compound_array_list (list, type)
|
||||
WORD_LIST *list;
|
||||
int type;
|
||||
quote_compound_array_list (WORD_LIST *list, int type)
|
||||
{
|
||||
char *s, *t;
|
||||
WORD_LIST *l;
|
||||
@@ -1078,8 +1102,7 @@ quote_compound_array_list (list, type)
|
||||
/* For each word in a compound array assignment, if the word looks like
|
||||
[ind]=value, quote globbing chars and characters in $IFS before the `='. */
|
||||
static void
|
||||
quote_array_assignment_chars (list)
|
||||
WORD_LIST *list;
|
||||
quote_array_assignment_chars (WORD_LIST *list)
|
||||
{
|
||||
char *nword;
|
||||
WORD_LIST *l;
|
||||
@@ -1112,14 +1135,12 @@ quote_array_assignment_chars (list)
|
||||
the subscript, we just assume the subscript ends with a close bracket,
|
||||
if one is present, and use what's inside the brackets. */
|
||||
int
|
||||
unbind_array_element (var, sub, flags)
|
||||
SHELL_VAR *var;
|
||||
char *sub;
|
||||
int flags;
|
||||
unbind_array_element (SHELL_VAR *var, char *sub, int flags)
|
||||
{
|
||||
arrayind_t ind;
|
||||
char *akey;
|
||||
ARRAY_ELEMENT *ae;
|
||||
int avflags;
|
||||
|
||||
/* Assume that the caller (unset_builtin) passes us a null-terminated SUB,
|
||||
so we don't have to use VA_ONEWORD or parse the subscript again with
|
||||
@@ -1176,7 +1197,9 @@ unbind_array_element (var, sub, flags)
|
||||
}
|
||||
/* Fall through for behavior 3 */
|
||||
}
|
||||
ind = array_expand_index (var, sub, strlen (sub) + 1, 0);
|
||||
|
||||
avflags = convert_validarray_flags_to_arrayval_flags (flags);
|
||||
ind = array_expand_index (var, sub, strlen (sub) + 1, avflags);
|
||||
/* negative subscripts to indexed arrays count back from end */
|
||||
if (ind < 0)
|
||||
ind = array_max_index (array_cell (var)) + 1 + ind;
|
||||
@@ -1192,7 +1215,8 @@ unbind_array_element (var, sub, flags)
|
||||
else /* array_p (var) == 0 && assoc_p (var) == 0 */
|
||||
{
|
||||
akey = this_command_name;
|
||||
ind = array_expand_index (var, sub, strlen (sub) + 1, 0);
|
||||
avflags = convert_validarray_flags_to_arrayval_flags (flags);
|
||||
ind = array_expand_index (var, sub, strlen (sub) + 1, avflags);
|
||||
this_command_name = akey;
|
||||
if (ind == 0)
|
||||
{
|
||||
@@ -1209,9 +1233,7 @@ unbind_array_element (var, sub, flags)
|
||||
/* Format and output an array assignment in compound form VAR=(VALUES),
|
||||
suitable for re-use as input. */
|
||||
void
|
||||
print_array_assignment (var, quoted)
|
||||
SHELL_VAR *var;
|
||||
int quoted;
|
||||
print_array_assignment (SHELL_VAR *var, int quoted)
|
||||
{
|
||||
char *vstr;
|
||||
|
||||
@@ -1229,9 +1251,7 @@ print_array_assignment (var, quoted)
|
||||
/* Format and output an associative array assignment in compound form
|
||||
VAR=(VALUES), suitable for re-use as input. */
|
||||
void
|
||||
print_assoc_assignment (var, quoted)
|
||||
SHELL_VAR *var;
|
||||
int quoted;
|
||||
print_assoc_assignment (SHELL_VAR *var, int quoted)
|
||||
{
|
||||
char *vstr;
|
||||
|
||||
@@ -1254,8 +1274,6 @@ print_assoc_assignment (var, quoted)
|
||||
|
||||
/* Return 1 if NAME is a properly-formed array reference v[sub]. */
|
||||
|
||||
/* Return 1 if NAME is a properly-formed array reference v[sub]. */
|
||||
|
||||
/* When NAME is a properly-formed array reference and a non-null argument SUBP
|
||||
is supplied, '[' and ']' that enclose the subscript are replaced by '\0',
|
||||
and the pointer to the subscript in NAME is assigned to *SUBP, so that NAME
|
||||
@@ -1264,10 +1282,7 @@ print_assoc_assignment (var, quoted)
|
||||
not be modified. */
|
||||
/* We need to reserve 1 for FLAGS, which we pass to skipsubscript. */
|
||||
int
|
||||
tokenize_array_reference (name, flags, subp)
|
||||
char *name;
|
||||
int flags;
|
||||
char **subp;
|
||||
tokenize_array_reference (const char *name, int flags, char **subp)
|
||||
{
|
||||
char *t;
|
||||
int r, len, isassoc, ssflags;
|
||||
@@ -1278,7 +1293,7 @@ tokenize_array_reference (name, flags, subp)
|
||||
if (t)
|
||||
{
|
||||
*t = '\0';
|
||||
r = legal_identifier (name);
|
||||
r = valid_identifier (name);
|
||||
if (flags & VA_NOEXPAND) /* Don't waste a lookup if we don't need one */
|
||||
isassoc = (entry = find_variable (name)) && assoc_p (entry);
|
||||
*t = '[';
|
||||
@@ -1327,20 +1342,15 @@ tokenize_array_reference (name, flags, subp)
|
||||
|
||||
/* We need to reserve 1 for FLAGS, which we pass to skipsubscript. */
|
||||
int
|
||||
valid_array_reference (name, flags)
|
||||
const char *name;
|
||||
int flags;
|
||||
valid_array_reference (const char *name, int flags)
|
||||
{
|
||||
return tokenize_array_reference ((char *)name, flags, (char **)NULL);
|
||||
return tokenize_array_reference (name, flags, (char **)NULL);
|
||||
}
|
||||
|
||||
/* Expand the array index beginning at S and extending LEN characters. */
|
||||
/* Expand the array index beginning at S and extending LEN characters. FLAGS
|
||||
are AV_ flags saying how to compute the array value. */
|
||||
arrayind_t
|
||||
array_expand_index (var, s, len, flags)
|
||||
SHELL_VAR *var;
|
||||
char *s;
|
||||
int len;
|
||||
int flags;
|
||||
array_expand_index (SHELL_VAR *var, const char *s, int len, int flags)
|
||||
{
|
||||
char *exp, *t, *savecmd;
|
||||
int expok, eflag;
|
||||
@@ -1349,8 +1359,12 @@ array_expand_index (var, s, len, flags)
|
||||
exp = (char *)xmalloc (len);
|
||||
strncpy (exp, s, len - 1);
|
||||
exp[len - 1] = '\0';
|
||||
#if 0 /* TAG: maybe bash-5.2 */
|
||||
#if 1 /* TAG: bash-5.3 */
|
||||
#if 0
|
||||
if (shell_compatibility_level <= 52 || (flags & AV_NOEXPAND) == 0)
|
||||
#else
|
||||
if ((flags & AV_NOEXPAND) == 0)
|
||||
#endif
|
||||
t = expand_arith_string (exp, Q_DOUBLE_QUOTES|Q_ARITH|Q_ARRAYSUB); /* XXX - Q_ARRAYSUB for future use */
|
||||
else
|
||||
t = exp;
|
||||
@@ -1382,11 +1396,7 @@ array_expand_index (var, s, len, flags)
|
||||
in *SUBP. If LENP is non-null, the length of the subscript is returned
|
||||
in *LENP. This returns newly-allocated memory. */
|
||||
char *
|
||||
array_variable_name (s, flags, subp, lenp)
|
||||
const char *s;
|
||||
int flags;
|
||||
char **subp;
|
||||
int *lenp;
|
||||
array_variable_name (const char *s, int flags, char **subp, int *lenp)
|
||||
{
|
||||
char *t, *ret;
|
||||
int ind, ni, ssflags;
|
||||
@@ -1436,11 +1446,7 @@ array_variable_name (s, flags, subp, lenp)
|
||||
non-null, return a pointer to the start of the subscript in *SUBP.
|
||||
If LENP is non-null, the length of the subscript is returned in *LENP. */
|
||||
SHELL_VAR *
|
||||
array_variable_part (s, flags, subp, lenp)
|
||||
const char *s;
|
||||
int flags;
|
||||
char **subp;
|
||||
int *lenp;
|
||||
array_variable_part (const char *s, int flags, char **subp, int *lenp)
|
||||
{
|
||||
char *t;
|
||||
SHELL_VAR *var;
|
||||
@@ -1475,10 +1481,7 @@ array_variable_part (s, flags, subp, lenp)
|
||||
is non-null it gets 1 if the array reference is name[*], 2 if the
|
||||
reference is name[@], and 0 otherwise. */
|
||||
static char *
|
||||
array_value_internal (s, quoted, flags, estatep)
|
||||
const char *s;
|
||||
int quoted, flags;
|
||||
array_eltstate_t *estatep;
|
||||
array_value_internal (const char *s, int quoted, int flags, array_eltstate_t *estatep)
|
||||
{
|
||||
int len, isassoc, subtype;
|
||||
arrayind_t ind;
|
||||
@@ -1552,6 +1555,12 @@ array_value_internal (s, quoted, flags, estatep)
|
||||
retval = quote_string (temp);
|
||||
free (temp);
|
||||
}
|
||||
else if (t[0] == '*' && quoted == 0 && (flags & AV_ASSIGNRHS))
|
||||
{
|
||||
temp = string_list_dollar_star (l, quoted, PF_ASSIGNRHS);
|
||||
retval = quote_nosplit (temp);
|
||||
free (temp);
|
||||
}
|
||||
else /* ${name[@]} or unquoted ${name[*]} */
|
||||
retval = string_list_dollar_at (l, quoted, (flags & AV_ASSIGNRHS) ? PF_ASSIGNRHS : 0);
|
||||
|
||||
@@ -1636,10 +1645,7 @@ array_value_internal (s, quoted, flags, estatep)
|
||||
/* Return a string containing the elements described by the array and
|
||||
subscript contained in S, obeying quoting for subscripts * and @. */
|
||||
char *
|
||||
array_value (s, quoted, flags, estatep)
|
||||
const char *s;
|
||||
int quoted, flags;
|
||||
array_eltstate_t *estatep;
|
||||
array_value (const char *s, int quoted, int flags, array_eltstate_t *estatep)
|
||||
{
|
||||
char *retval;
|
||||
|
||||
@@ -1652,10 +1658,7 @@ array_value (s, quoted, flags, estatep)
|
||||
is used by other parts of the shell such as the arithmetic expression
|
||||
evaluator in expr.c. */
|
||||
char *
|
||||
get_array_value (s, flags, estatep)
|
||||
const char *s;
|
||||
int flags;
|
||||
array_eltstate_t *estatep;
|
||||
get_array_value (const char *s, int flags, array_eltstate_t *estatep)
|
||||
{
|
||||
char *retval;
|
||||
|
||||
@@ -1664,9 +1667,7 @@ get_array_value (s, flags, estatep)
|
||||
}
|
||||
|
||||
char *
|
||||
array_keys (s, quoted, pflags)
|
||||
char *s;
|
||||
int quoted, pflags;
|
||||
array_keys (const char *s, int quoted, int pflags)
|
||||
{
|
||||
int len;
|
||||
char *retval, *t, *temp;
|
||||
|
||||
Reference in New Issue
Block a user