/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
-/* Copyright (C) 2001-2023 Free Software Foundation, Inc.
+/* Copyright (C) 2001-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
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 (SHELL_VAR *entry, arrayind_t ind, const char *key, const char *value, int 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);
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 (const char *name, int 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))
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));
}
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 */
{
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
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
+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;
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)
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))
{
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
/* 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)
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))
if (ind < 0)
{
err_badarraysub (w);
- continue;
+ any_failed++;
+ break;
}
last_ind = ind;
{
err_badarraysub (w);
FREE (akey);
- continue;
+ any_failed++;
+ break;
}
}
{
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 `=' */
{
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))
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
assign_array_var_from_string (SHELL_VAR *var, char *value, int flags)
{
WORD_LIST *nlist;
- int aflags;
+ int aflags, r;
if (value == 0)
return var;
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;
- assign_compound_array_list (var, nlist, aflags);
+ r = assign_compound_array_list (var, nlist, aflags);
if (nlist)
dispose_words (nlist);
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
if (t != w+ind)
free (t);
strcpy (nword + i, value);
+ free (value);
return nword;
}
nword[i++] = w[ind++];
nword[i++] = w[ind++];
-
t = expand_assignment_string_to_string (w+ind, 0);
s = (t && strchr (t, CTLESC)) ? quote_escapes (t) : t;
value = sh_single_quote (s ? s : "");
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 = '[';