static WORD_LIST *
shell_expand_word_list (tlist, eflags)
     WORD_LIST *tlist;
     int eflags;
{
  WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd;
  int expanded_something, has_dollar_at;
  char *temp_string;

  /* We do tilde expansion all the time.  This is what 1003.2 says. */
  new_list = (WORD_LIST *)NULL;
  for (wcmd = tlist; wcmd; wcmd = wcmd->next)
    if (wcmd->word->flags & W_ASSNBLTIN)
      break;

  for (orig_list = tlist; tlist; tlist = next)
    {
      temp_string = tlist->word->word;

      next = tlist->next;

#if defined (ARRAY_VARS)
      /* If this is a compound array assignment to a builtin that accepts
         such assignments (e.g., `declare'), take the assignment and perform
         it separately, handling the semantics of declarations inside shell
         functions.  This avoids the double-evaluation of such arguments,
         because `declare' does some evaluation of compound assignments on
         its own. */
      if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
	{
	  int t;
	  char opts[16], opti;

	  opti = 0;
	  if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_ASSIGNARRAY))
	    opts[opti++] = '-';

	  if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
	    {
	      opts[opti++] = 'g';
	      opts[opti++] = 'A';
	    }
	  else if (tlist->word->flags & W_ASSIGNASSOC)
	    opts[opti++] = 'A';
	  else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
	    {
	      opts[opti++] = 'g';
	      opts[opti++] = 'a';
	    }
	  else if (tlist->word->flags & W_ASSIGNARRAY)
	    opts[opti++] = 'a';
	  else if (tlist->word->flags & W_ASSNGLOBAL)
	    opts[opti++] = 'g';

	  /* If we have special handling note the integer attribute and others
	     that transform the value upon assignment.  What we do is take all
	     of the option arguments and scan through them looking for options
	     that cause such transformations, and add them to the `opts' array. */
/*	  if (opti > 0) */
	    {
	      char omap[128];
	      int oind;
	      WORD_LIST *l;

	      memset (omap, '\0', sizeof (omap));
	      for (l = orig_list->next; l != tlist; l = l->next)
		{
		  if (l->word->word[0] != '-')
		    break;	/* non-option argument */
		  if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0)
		    break;	/* -- signals end of options */
		  for (oind = 1; l->word->word[oind]; oind++)
		    switch (l->word->word[oind])
		      {
			case 'i':
			case 'l':
			case 'u':
			case 'c':
			  omap[l->word->word[oind]] = 1;
			  if (opti == 0)
			    opts[opti++] = '-';
			  break;
			default:
			  break;
		      }
		}

	      for (oind = 0; oind < sizeof (omap); oind++)
		if (omap[oind])
		  opts[opti++] = oind;
	    }

	  opts[opti] = '\0';
	  if (opti > 0)
	    {
	      t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0);
	      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)
	    {
	      last_command_exit_value = EXECUTION_FAILURE;
	      exp_jump_to_top_level (DISCARD);
	    }

	  /* Now transform the word as ksh93 appears to do and go on */
	  t = assignment (tlist->word->word, 0);
	  tlist->word->word[t] = '\0';
	  if (tlist->word->word[t - 1] == '+')
	    tlist->word->word[t - 1] = '\0';	/* cut off append op */
	  tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
	}
#endif

      expanded_something = 0;
      expanded = expand_word_internal
	(tlist->word, 0, 0, &has_dollar_at, &expanded_something);

      if (expanded == &expand_word_error || expanded == &expand_word_fatal)
	{
	  /* By convention, each time this error is returned,
	     tlist->word->word has already been freed. */
	  tlist->word->word = (char *)NULL;

	  /* Dispose our copy of the original list. */
	  dispose_words (orig_list);
	  /* Dispose the new list we're building. */
	  dispose_words (new_list);

	  last_command_exit_value = EXECUTION_FAILURE;
	  if (expanded == &expand_word_error)
	    exp_jump_to_top_level (DISCARD);
	  else
	    exp_jump_to_top_level (FORCE_EOF);
	}

      /* Don't split words marked W_NOSPLIT. */
      if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
	{
	  temp_list = word_list_split (expanded);
	  dispose_words (expanded);
	}
      else
	{
	  /* If no parameter expansion, command substitution, process
	     substitution, or arithmetic substitution took place, then
	     do not do word splitting.  We still have to remove quoted
	     null characters from the result. */
	  word_list_remove_quoted_nulls (expanded);
	  temp_list = expanded;
	}

      expanded = REVERSE_LIST (temp_list, WORD_LIST *);
      new_list = (WORD_LIST *)list_append (expanded, new_list);
    }

  if (orig_list)  
    dispose_words (orig_list);

  if (new_list)
    new_list = REVERSE_LIST (new_list, WORD_LIST *);

  return (new_list);