]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - arrayfunc.c
fix nofork comsub overwriting currently executing command; free readline undo list...
[thirdparty/bash.git] / arrayfunc.c
index 303a4a597e6144043401e7781c245d7dad744f7a..d56be4283d90286110085d4d87941344f055edb8 100644 (file)
@@ -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.
 
 #  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))
@@ -504,6 +490,8 @@ find_or_make_array_variable (name, flags)
       report_error (_("%s: cannot convert indexed to associative array"), name);
       return ((SHELL_VAR *)NULL);
     }
+  else if (flags & 2)
+    var = assoc_p (var) ? var : convert_var_to_assoc (var);
   else if (array_p (var) == 0 && assoc_p (var) == 0)
     var = convert_var_to_array (var);
 
@@ -513,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;
@@ -523,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));
 }
@@ -534,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;
@@ -547,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 */
 
@@ -555,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
@@ -622,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;
@@ -640,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);
@@ -648,7 +646,7 @@ assign_assoc_from_kvlist (var, nlist, h, flags)
          continue;
        }             
 
-      aval = expand_subscript_string (v, 0);
+      aval = split_kvpair_assignments ? savestring (v) : expand_assignment_string_to_string (v, 0);
       if (aval == 0)
        {
          aval = (char *)xmalloc (1);
@@ -656,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;
 
@@ -693,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;
 
@@ -713,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)
@@ -723,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))
     {
@@ -736,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
@@ -758,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)
@@ -776,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;
@@ -811,7 +818,8 @@ assign_compound_array_list (var, nlist, flags)
                {
                  err_badarraysub (w);
                  FREE (akey);
-                 continue;
+                 any_failed++;
+                 break;
                }
            }
 
@@ -828,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 `=' */
        {
@@ -836,11 +845,21 @@ 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))
        {
-         val = expand_subscript_string (val, 0);
+         val = expand_assignment_string_to_string (val, 0);
          if (val == 0)
            {
              val = (char *)xmalloc (1);
@@ -851,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
@@ -869,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);
@@ -893,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;
@@ -947,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;
@@ -983,6 +1012,7 @@ quote_compound_array_word (w, type)
   if (t != w+ind)
    free (t);
   strcpy (nword + i, value);
+  free (value);
 
   return nword;
 }
@@ -995,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;
@@ -1028,7 +1056,7 @@ expand_and_quote_assoc_word (w, type)
     nword[i++] = w[ind++];
   nword[i++] = w[ind++];
 
-  t = expand_subscript_string (w+ind, 0);
+  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 (s != t)
@@ -1048,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;
@@ -1076,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;
@@ -1110,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
@@ -1174,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;
@@ -1190,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)
        {
@@ -1207,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;
 
@@ -1227,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;
 
@@ -1252,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
@@ -1262,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;
@@ -1276,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 = '[';
@@ -1325,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;
@@ -1347,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;
@@ -1380,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;
@@ -1434,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;
@@ -1473,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;
@@ -1536,7 +1541,7 @@ array_value_internal (s, quoted, flags, estatep)
       else
        {
          if (estatep)
-           estatep->type = ARRAY_ASSOC;
+           estatep->type = ARRAY_INDEXED;
          l = array_to_word_list (array_cell (var));
          if (l == (WORD_LIST *)NULL)
            return ((char *) NULL);
@@ -1634,10 +1639,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;
 
@@ -1650,10 +1652,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;
 
@@ -1662,9 +1661,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;