1/* subst.c -- The part of the shell that does parameter, command, arithmetic,
2   and globbing substitutions. */
3
4/* ``Have a little faith, there's magic in the night.  You ain't a
5     beauty, but, hey, you're alright.'' */
6
7/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
8
9   This file is part of GNU Bash, the Bourne Again SHell.
10
11   Bash is free software: you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation, either version 3 of the License, or
14   (at your option) any later version.
15
16   Bash is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "config.h"
26
27#include "bashtypes.h"
28#include <stdio.h>
29#include "chartypes.h"
30#if defined (HAVE_PWD_H)
31#  include <pwd.h>
32#endif
33#include <signal.h>
34#include <errno.h>
35
36#if defined (HAVE_UNISTD_H)
37#  include <unistd.h>
38#endif
39
40#include "bashansi.h"
41#include "posixstat.h"
42#include "bashintl.h"
43
44#include "shell.h"
45#include "flags.h"
46#include "jobs.h"
47#include "execute_cmd.h"
48#include "filecntl.h"
49#include "trap.h"
50#include "pathexp.h"
51#include "mailcheck.h"
52
53#include "shmbutil.h"
54
55#include "builtins/getopt.h"
56#include "builtins/common.h"
57
58#include "builtins/builtext.h"
59
60#include <tilde/tilde.h>
61#include <glob/strmatch.h>
62
63#if !defined (errno)
64extern int errno;
65#endif /* !errno */
66
67/* The size that strings change by. */
68#define DEFAULT_INITIAL_ARRAY_SIZE 112
69#define DEFAULT_ARRAY_SIZE 128
70
71/* Variable types. */
72#define VT_VARIABLE	0
73#define VT_POSPARMS	1
74#define VT_ARRAYVAR	2
75#define VT_ARRAYMEMBER	3
76#define VT_ASSOCVAR	4
77
78#define VT_STARSUB	128	/* $* or ${array[*]} -- used to split */
79
80/* Flags for quoted_strchr */
81#define ST_BACKSL	0x01
82#define ST_CTLESC	0x02
83#define ST_SQUOTE	0x04	/* unused yet */
84#define ST_DQUOTE	0x08	/* unused yet */
85
86/* Flags for the `pflags' argument to param_expand() */
87#define PF_NOCOMSUB	0x01	/* Do not perform command substitution */
88#define PF_IGNUNBOUND	0x02	/* ignore unbound vars even if -u set */
89
90/* These defs make it easier to use the editor. */
91#define LBRACE		'{'
92#define RBRACE		'}'
93#define LPAREN		'('
94#define RPAREN		')'
95
96/* Evaluates to 1 if C is one of the shell's special parameters whose length
97   can be taken, but is also one of the special expansion characters. */
98#define VALID_SPECIAL_LENGTH_PARAM(c) \
99  ((c) == '-' || (c) == '?' || (c) == '#')
100
101/* Evaluates to 1 if C is one of the shell's special parameters for which an
102   indirect variable reference may be made. */
103#define VALID_INDIR_PARAM(c) \
104  ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*')
105
106/* Evaluates to 1 if C is one of the OP characters that follows the parameter
107   in ${parameter[:]OPword}. */
108#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)
109
110/* Evaluates to 1 if this is one of the shell's special variables. */
111#define SPECIAL_VAR(name, wi) \
112 ((DIGIT (*name) && all_digits (name)) || \
113      (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \
114      (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1])))
115
116/* An expansion function that takes a string and a quoted flag and returns
117   a WORD_LIST *.  Used as the type of the third argument to
118   expand_string_if_necessary(). */
119typedef WORD_LIST *EXPFUNC __P((char *, int));
120
121/* Process ID of the last command executed within command substitution. */
122pid_t last_command_subst_pid = NO_PID;
123pid_t current_command_subst_pid = NO_PID;
124
125/* Variables used to keep track of the characters in IFS. */
126SHELL_VAR *ifs_var;
127char *ifs_value;
128unsigned char ifs_cmap[UCHAR_MAX + 1];
129
130#if defined (HANDLE_MULTIBYTE)
131unsigned char ifs_firstc[MB_LEN_MAX];
132size_t ifs_firstc_len;
133#else
134unsigned char ifs_firstc;
135#endif
136
137int assigning_in_environment;
138
139/* Extern functions and variables from different files. */
140extern int last_command_exit_value, last_command_exit_signal;
141extern int subshell_environment;
142extern int subshell_level, parse_and_execute_level;
143extern int eof_encountered;
144extern int return_catch_flag, return_catch_value;
145extern pid_t dollar_dollar_pid;
146extern int posixly_correct;
147extern char *this_command_name;
148extern struct fd_bitmap *current_fds_to_close;
149extern int wordexp_only;
150extern int expanding_redir;
151extern int tempenv_assign_error;
152
153#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)
154extern wchar_t *wcsdup __P((const wchar_t *));
155#endif
156
157/* Non-zero means to allow unmatched globbed filenames to expand to
158   a null file. */
159int allow_null_glob_expansion;
160
161/* Non-zero means to throw an error when globbing fails to match anything. */
162int fail_glob_expansion;
163
164#if 0
165/* Variables to keep track of which words in an expanded word list (the
166   output of expand_word_list_internal) are the result of globbing
167   expansions.  GLOB_ARGV_FLAGS is used by execute_cmd.c.
168   (CURRENTLY UNUSED). */
169char *glob_argv_flags;
170static int glob_argv_flags_size;
171#endif
172
173static WORD_LIST expand_word_error, expand_word_fatal;
174static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
175static char expand_param_error, expand_param_fatal;
176static char extract_string_error, extract_string_fatal;
177
178/* Tell the expansion functions to not longjmp back to top_level on fatal
179   errors.  Enabled when doing completion and prompt string expansion. */
180static int no_longjmp_on_fatal_error = 0;
181
182/* Set by expand_word_unsplit; used to inhibit splitting and re-joining
183   $* on $IFS, primarily when doing assignment statements. */
184static int expand_no_split_dollar_star = 0;
185
186/* Used to hold a list of variable assignments preceding a command.  Global
187   so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
188   SIGCHLD trap. */
189WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
190
191/* A WORD_LIST of words to be expanded by expand_word_list_internal,
192   without any leading variable assignments. */
193static WORD_LIST *garglist = (WORD_LIST *)NULL;
194
195static char *quoted_substring __P((char *, int, int));
196static int quoted_strlen __P((char *));
197static char *quoted_strchr __P((char *, int, int));
198
199static char *expand_string_if_necessary __P((char *, int, EXPFUNC *));
200static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *));
201static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *));
202static WORD_LIST *expand_string_internal __P((char *, int));
203static WORD_LIST *expand_string_leave_quoted __P((char *, int));
204static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *));
205
206static WORD_LIST *list_quote_escapes __P((WORD_LIST *));
207static char *make_quoted_char __P((int));
208static WORD_LIST *quote_list __P((WORD_LIST *));
209
210static int unquoted_substring __P((char *, char *));
211static int unquoted_member __P((int, char *));
212
213#if defined (ARRAY_VARS)
214static SHELL_VAR *do_compound_assignment __P((char *, char *, int));
215#endif
216static int do_assignment_internal __P((const WORD_DESC *, int));
217
218static char *string_extract_verbatim __P((char *, size_t, int *, char *, int));
219static char *string_extract __P((char *, int *, char *, int));
220static char *string_extract_double_quoted __P((char *, int *, int));
221static inline char *string_extract_single_quoted __P((char *, int *));
222static inline int skip_single_quoted __P((const char *, size_t, int));
223static int skip_double_quoted __P((char *, size_t, int));
224static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int));
225static char *extract_dollar_brace_string __P((char *, int *, int, int));
226static int skip_matched_pair __P((const char *, int, int, int, int));
227
228static char *pos_params __P((char *, int, int, int));
229
230static unsigned char *mb_getcharlens __P((char *, int));
231
232static char *remove_upattern __P((char *, char *, int));
233#if defined (HANDLE_MULTIBYTE)
234static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int));
235#endif
236static char *remove_pattern __P((char *, char *, int));
237
238static int match_pattern_char __P((char *, char *));
239static int match_upattern __P((char *, char *, int, char **, char **));
240#if defined (HANDLE_MULTIBYTE)
241static int match_pattern_wchar __P((wchar_t *, wchar_t *));
242static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
243#endif
244static int match_pattern __P((char *, char *, int, char **, char **));
245static int getpatspec __P((int, char *));
246static char *getpattern __P((char *, int, int));
247static char *variable_remove_pattern __P((char *, char *, int, int));
248static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int));
249static char *parameter_list_remove_pattern __P((int, char *, int, int));
250#ifdef ARRAY_VARS
251static char *array_remove_pattern __P((SHELL_VAR *, char *, int, char *, int));
252#endif
253static char *parameter_brace_remove_pattern __P((char *, char *, char *, int, int));
254
255static char *process_substitute __P((char *, int));
256
257static char *read_comsub __P((int, int, int *));
258
259#ifdef ARRAY_VARS
260static arrayind_t array_length_reference __P((char *));
261#endif
262
263static int valid_brace_expansion_word __P((char *, int));
264static int chk_atstar __P((char *, int, int *, int *));
265static int chk_arithsub __P((const char *, int));
266
267static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int));
268static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *));
269static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *));
270static void parameter_brace_expand_error __P((char *, char *));
271
272static int valid_length_expression __P((char *));
273static intmax_t parameter_brace_expand_length __P((char *));
274
275static char *skiparith __P((char *, int));
276static int verify_substring_values __P((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
277static int get_var_and_type __P((char *, char *, int, SHELL_VAR **, char **));
278static char *mb_substring __P((char *, int, int));
279static char *parameter_brace_substring __P((char *, char *, char *, int));
280
281static char *pos_params_pat_subst __P((char *, char *, char *, int));
282
283static char *parameter_brace_patsub __P((char *, char *, char *, int));
284
285static char *pos_params_casemod __P((char *, char *, int, int));
286static char *parameter_brace_casemod __P((char *, char *, int, char *, int));
287
288static WORD_DESC *parameter_brace_expand __P((char *, int *, int, int *, int *));
289static WORD_DESC *param_expand __P((char *, int *, int, int *, int *, int *, int *, int));
290
291static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *));
292
293static WORD_LIST *word_list_split __P((WORD_LIST *));
294
295static void exp_jump_to_top_level __P((int));
296
297static WORD_LIST *separate_out_assignments __P((WORD_LIST *));
298static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int));
299#ifdef BRACE_EXPANSION
300static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int));
301#endif
302#if defined (ARRAY_VARS)
303static int make_internal_declare __P((char *, char *));
304#endif
305static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int));
306static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int));
307
308/* **************************************************************** */
309/*								    */
310/*			Utility Functions			    */
311/*								    */
312/* **************************************************************** */
313
314#ifdef INCLUDE_UNUSED
315static char *
316quoted_substring (string, start, end)
317     char *string;
318     int start, end;
319{
320  register int len, l;
321  register char *result, *s, *r;
322
323  len = end - start;
324
325  /* Move to string[start], skipping quoted characters. */
326  for (s = string, l = 0; *s && l < start; )
327    {
328      if (*s == CTLESC)
329	{
330	  s++;
331	  continue;
332	}
333      l++;
334      if (*s == 0)
335	break;
336    }
337
338  r = result = (char *)xmalloc (2*len + 1);      /* save room for quotes */
339
340  /* Copy LEN characters, including quote characters. */
341  s = string + l;
342  for (l = 0; l < len; s++)
343    {
344      if (*s == CTLESC)
345	*r++ = *s++;
346      *r++ = *s;
347      l++;
348      if (*s == 0)
349	break;
350    }
351  *r = '\0';
352  return result;
353}
354#endif
355
356#ifdef INCLUDE_UNUSED
357/* Return the length of S, skipping over quoted characters */
358static int
359quoted_strlen (s)
360     char *s;
361{
362  register char *p;
363  int i;
364
365  i = 0;
366  for (p = s; *p; p++)
367    {
368      if (*p == CTLESC)
369	{
370	  p++;
371	  if (*p == 0)
372	    return (i + 1);
373	}
374      i++;
375    }
376
377  return i;
378}
379#endif
380
381/* Find the first occurrence of character C in string S, obeying shell
382   quoting rules.  If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
383   characters are skipped.  If (FLAGS & ST_CTLESC) is non-zero, characters
384   escaped with CTLESC are skipped. */
385static char *
386quoted_strchr (s, c, flags)
387     char *s;
388     int c, flags;
389{
390  register char *p;
391
392  for (p = s; *p; p++)
393    {
394      if (((flags & ST_BACKSL) && *p == '\\')
395	    || ((flags & ST_CTLESC) && *p == CTLESC))
396	{
397	  p++;
398	  if (*p == '\0')
399	    return ((char *)NULL);
400	  continue;
401	}
402      else if (*p == c)
403	return p;
404    }
405  return ((char *)NULL);
406}
407
408/* Return 1 if CHARACTER appears in an unquoted portion of
409   STRING.  Return 0 otherwise.  CHARACTER must be a single-byte character. */
410static int
411unquoted_member (character, string)
412     int character;
413     char *string;
414{
415  size_t slen;
416  int sindex, c;
417  DECLARE_MBSTATE;
418
419  slen = strlen (string);
420  sindex = 0;
421  while (c = string[sindex])
422    {
423      if (c == character)
424	return (1);
425
426      switch (c)
427	{
428	default:
429	  ADVANCE_CHAR (string, slen, sindex);
430	  break;
431
432	case '\\':
433	  sindex++;
434	  if (string[sindex])
435	    ADVANCE_CHAR (string, slen, sindex);
436	  break;
437
438	case '\'':
439	  sindex = skip_single_quoted (string, slen, ++sindex);
440	  break;
441
442	case '"':
443	  sindex = skip_double_quoted (string, slen, ++sindex);
444	  break;
445	}
446    }
447  return (0);
448}
449
450/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
451static int
452unquoted_substring (substr, string)
453     char *substr, *string;
454{
455  size_t slen;
456  int sindex, c, sublen;
457  DECLARE_MBSTATE;
458
459  if (substr == 0 || *substr == '\0')
460    return (0);
461
462  slen = strlen (string);
463  sublen = strlen (substr);
464  for (sindex = 0; c = string[sindex]; )
465    {
466      if (STREQN (string + sindex, substr, sublen))
467	return (1);
468
469      switch (c)
470	{
471	case '\\':
472	  sindex++;
473
474	  if (string[sindex])
475	    ADVANCE_CHAR (string, slen, sindex);
476	  break;
477
478	case '\'':
479	  sindex = skip_single_quoted (string, slen, ++sindex);
480	  break;
481
482	case '"':
483	  sindex = skip_double_quoted (string, slen, ++sindex);
484	  break;
485
486	default:
487	  ADVANCE_CHAR (string, slen, sindex);
488	  break;
489	}
490    }
491  return (0);
492}
493
494/* Most of the substitutions must be done in parallel.  In order
495   to avoid using tons of unclear goto's, I have some functions
496   for manipulating malloc'ed strings.  They all take INDX, a
497   pointer to an integer which is the offset into the string
498   where manipulation is taking place.  They also take SIZE, a
499   pointer to an integer which is the current length of the
500   character array for this string. */
501
502/* Append SOURCE to TARGET at INDEX.  SIZE is the current amount
503   of space allocated to TARGET.  SOURCE can be NULL, in which
504   case nothing happens.  Gets rid of SOURCE by freeing it.
505   Returns TARGET in case the location has changed. */
506INLINE char *
507sub_append_string (source, target, indx, size)
508     char *source, *target;
509     int *indx, *size;
510{
511  if (source)
512    {
513      int srclen, n;
514
515      srclen = STRLEN (source);
516      if (srclen >= (int)(*size - *indx))
517	{
518	  n = srclen + *indx;
519	  n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
520	  target = (char *)xrealloc (target, (*size = n));
521	}
522
523      FASTCOPY (source, target + *indx, srclen);
524      *indx += srclen;
525      target[*indx] = '\0';
526
527      free (source);
528    }
529  return (target);
530}
531
532#if 0
533/* UNUSED */
534/* Append the textual representation of NUMBER to TARGET.
535   INDX and SIZE are as in SUB_APPEND_STRING. */
536char *
537sub_append_number (number, target, indx, size)
538     intmax_t number;
539     int *indx, *size;
540     char *target;
541{
542  char *temp;
543
544  temp = itos (number);
545  return (sub_append_string (temp, target, indx, size));
546}
547#endif
548
549/* Extract a substring from STRING, starting at SINDEX and ending with
550   one of the characters in CHARLIST.  Don't make the ending character
551   part of the string.  Leave SINDEX pointing at the ending character.
552   Understand about backslashes in the string.  If (flags & SX_VARNAME)
553   is non-zero, and array variables have been compiled into the shell,
554   everything between a `[' and a corresponding `]' is skipped over.
555   If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
556   update SINDEX.  If (flags & SX_REQMATCH) is non-zero, the string must
557   contain a closing character from CHARLIST. */
558static char *
559string_extract (string, sindex, charlist, flags)
560     char *string;
561     int *sindex;
562     char *charlist;
563     int flags;
564{
565  register int c, i;
566  int found;
567  size_t slen;
568  char *temp;
569  DECLARE_MBSTATE;
570
571  slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
572  i = *sindex;
573  found = 0;
574  while (c = string[i])
575    {
576      if (c == '\\')
577	{
578	  if (string[i + 1])
579	    i++;
580	  else
581	    break;
582	}
583#if defined (ARRAY_VARS)
584      else if ((flags & SX_VARNAME) && c == '[')
585	{
586	  int ni;
587	  /* If this is an array subscript, skip over it and continue. */
588	  ni = skipsubscript (string, i);
589	  if (string[ni] == ']')
590	    i = ni;
591	}
592#endif
593      else if (MEMBER (c, charlist))
594	{
595	  found = 1;
596	  break;
597	}
598
599      ADVANCE_CHAR (string, slen, i);
600    }
601
602  /* If we had to have a matching delimiter and didn't find one, return an
603     error and let the caller deal with it. */
604  if ((flags & SX_REQMATCH) && found == 0)
605    {
606      *sindex = i;
607      return (&extract_string_error);
608    }
609
610  temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
611  *sindex = i;
612
613  return (temp);
614}
615
616/* Extract the contents of STRING as if it is enclosed in double quotes.
617   SINDEX, when passed in, is the offset of the character immediately
618   following the opening double quote; on exit, SINDEX is left pointing after
619   the closing double quote.  If STRIPDQ is non-zero, unquoted double
620   quotes are stripped and the string is terminated by a null byte.
621   Backslashes between the embedded double quotes are processed.  If STRIPDQ
622   is zero, an unquoted `"' terminates the string. */
623static char *
624string_extract_double_quoted (string, sindex, stripdq)
625     char *string;
626     int *sindex, stripdq;
627{
628  size_t slen;
629  char *send;
630  int j, i, t;
631  unsigned char c;
632  char *temp, *ret;		/* The new string we return. */
633  int pass_next, backquote, si;	/* State variables for the machine. */
634  int dquote;
635  DECLARE_MBSTATE;
636
637  slen = strlen (string + *sindex) + *sindex;
638  send = string + slen;
639
640  pass_next = backquote = dquote = 0;
641  temp = (char *)xmalloc (1 + slen - *sindex);
642
643  j = 0;
644  i = *sindex;
645  while (c = string[i])
646    {
647      /* Process a character that was quoted by a backslash. */
648      if (pass_next)
649	{
650	  /* Posix.2 sez:
651
652	     ``The backslash shall retain its special meaning as an escape
653	     character only when followed by one of the characters:
654		$	`	"	\	<newline>''.
655
656	     If STRIPDQ is zero, we handle the double quotes here and let
657	     expand_word_internal handle the rest.  If STRIPDQ is non-zero,
658	     we have already been through one round of backslash stripping,
659	     and want to strip these backslashes only if DQUOTE is non-zero,
660	     indicating that we are inside an embedded double-quoted string. */
661
662	     /* If we are in an embedded quoted string, then don't strip
663		backslashes before characters for which the backslash
664		retains its special meaning, but remove backslashes in
665		front of other characters.  If we are not in an
666		embedded quoted string, don't strip backslashes at all.
667		This mess is necessary because the string was already
668		surrounded by double quotes (and sh has some really weird
669		quoting rules).
670		The returned string will be run through expansion as if
671		it were double-quoted. */
672	  if ((stripdq == 0 && c != '"') ||
673	      (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0)))
674	    temp[j++] = '\\';
675	  pass_next = 0;
676
677add_one_character:
678	  COPY_CHAR_I (temp, j, string, send, i);
679	  continue;
680	}
681
682      /* A backslash protects the next character.  The code just above
683	 handles preserving the backslash in front of any character but
684	 a double quote. */
685      if (c == '\\')
686	{
687	  pass_next++;
688	  i++;
689	  continue;
690	}
691
692      /* Inside backquotes, ``the portion of the quoted string from the
693	 initial backquote and the characters up to the next backquote
694	 that is not preceded by a backslash, having escape characters
695	 removed, defines that command''. */
696      if (backquote)
697	{
698	  if (c == '`')
699	    backquote = 0;
700	  temp[j++] = c;
701	  i++;
702	  continue;
703	}
704
705      if (c == '`')
706	{
707	  temp[j++] = c;
708	  backquote++;
709	  i++;
710	  continue;
711	}
712
713      /* Pass everything between `$(' and the matching `)' or a quoted
714	 ${ ... } pair through according to the Posix.2 specification. */
715      if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
716	{
717	  int free_ret = 1;
718
719	  si = i + 2;
720	  if (string[i + 1] == LPAREN)
721	    ret = extract_command_subst (string, &si, 0);
722	  else
723	    ret = extract_dollar_brace_string (string, &si, 1, 0);
724
725	  temp[j++] = '$';
726	  temp[j++] = string[i + 1];
727
728	  /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error
729	     is set. */
730	  if (ret == 0 && no_longjmp_on_fatal_error)
731	    {
732	      free_ret = 0;
733	      ret = string + i + 2;
734	    }
735
736	  for (t = 0; ret[t]; t++, j++)
737	    temp[j] = ret[t];
738	  temp[j] = string[si];
739
740	  if (string[si])
741	    {
742	      j++;
743	      i = si + 1;
744	    }
745	  else
746	    i = si;
747
748	  if (free_ret)
749	    free (ret);
750	  continue;
751	}
752
753      /* Add any character but a double quote to the quoted string we're
754	 accumulating. */
755      if (c != '"')
756	goto add_one_character;
757
758      /* c == '"' */
759      if (stripdq)
760	{
761	  dquote ^= 1;
762	  i++;
763	  continue;
764	}
765
766      break;
767    }
768  temp[j] = '\0';
769
770  /* Point to after the closing quote. */
771  if (c)
772    i++;
773  *sindex = i;
774
775  return (temp);
776}
777
778/* This should really be another option to string_extract_double_quoted. */
779static int
780skip_double_quoted (string, slen, sind)
781     char *string;
782     size_t slen;
783     int sind;
784{
785  int c, i;
786  char *ret;
787  int pass_next, backquote, si;
788  DECLARE_MBSTATE;
789
790  pass_next = backquote = 0;
791  i = sind;
792  while (c = string[i])
793    {
794      if (pass_next)
795	{
796	  pass_next = 0;
797	  ADVANCE_CHAR (string, slen, i);
798	  continue;
799	}
800      else if (c == '\\')
801	{
802	  pass_next++;
803	  i++;
804	  continue;
805	}
806      else if (backquote)
807	{
808	  if (c == '`')
809	    backquote = 0;
810	  ADVANCE_CHAR (string, slen, i);
811	  continue;
812	}
813      else if (c == '`')
814	{
815	  backquote++;
816	  i++;
817	  continue;
818	}
819      else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
820	{
821	  si = i + 2;
822	  if (string[i + 1] == LPAREN)
823	    ret = extract_command_subst (string, &si, SX_NOALLOC);
824	  else
825	    ret = extract_dollar_brace_string (string, &si, 1, SX_NOALLOC);
826
827	  i = si + 1;
828	  continue;
829	}
830      else if (c != '"')
831	{
832	  ADVANCE_CHAR (string, slen, i);
833	  continue;
834	}
835      else
836	break;
837    }
838
839  if (c)
840    i++;
841
842  return (i);
843}
844
845/* Extract the contents of STRING as if it is enclosed in single quotes.
846   SINDEX, when passed in, is the offset of the character immediately
847   following the opening single quote; on exit, SINDEX is left pointing after
848   the closing single quote. */
849static inline char *
850string_extract_single_quoted (string, sindex)
851     char *string;
852     int *sindex;
853{
854  register int i;
855  size_t slen;
856  char *t;
857  DECLARE_MBSTATE;
858
859  /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */
860  slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
861  i = *sindex;
862  while (string[i] && string[i] != '\'')
863    ADVANCE_CHAR (string, slen, i);
864
865  t = substring (string, *sindex, i);
866
867  if (string[i])
868    i++;
869  *sindex = i;
870
871  return (t);
872}
873
874static inline int
875skip_single_quoted (string, slen, sind)
876     const char *string;
877     size_t slen;
878     int sind;
879{
880  register int c;
881  DECLARE_MBSTATE;
882
883  c = sind;
884  while (string[c] && string[c] != '\'')
885    ADVANCE_CHAR (string, slen, c);
886
887  if (string[c])
888    c++;
889  return c;
890}
891
892/* Just like string_extract, but doesn't hack backslashes or any of
893   that other stuff.  Obeys CTLESC quoting.  Used to do splitting on $IFS. */
894static char *
895string_extract_verbatim (string, slen, sindex, charlist, flags)
896     char *string;
897     size_t slen;
898     int *sindex;
899     char *charlist;
900     int flags;
901{
902  register int i = *sindex;
903#if defined (HANDLE_MULTIBYTE)
904  size_t clen;
905  wchar_t *wcharlist;
906#endif
907  int c;
908  char *temp;
909  DECLARE_MBSTATE;
910
911  if (charlist[0] == '\'' && charlist[1] == '\0')
912    {
913      temp = string_extract_single_quoted (string, sindex);
914      --*sindex;	/* leave *sindex at separator character */
915      return temp;
916    }
917
918  i = *sindex;
919#if 0
920  /* See how the MBLEN and ADVANCE_CHAR macros work to understand why we need
921     this only if MB_CUR_MAX > 1. */
922  slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 1;
923#endif
924#if defined (HANDLE_MULTIBYTE)
925  clen = strlen (charlist);
926  wcharlist = 0;
927#endif
928  while (c = string[i])
929    {
930#if defined (HANDLE_MULTIBYTE)
931      size_t mblength;
932#endif
933      if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
934	{
935	  i += 2;
936	  continue;
937	}
938      /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
939	 through, to protect the CTLNULs from later calls to
940	 remove_quoted_nulls. */
941      else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
942	{
943	  i += 2;
944	  continue;
945	}
946
947#if defined (HANDLE_MULTIBYTE)
948      mblength = MBLEN (string + i, slen - i);
949      if (mblength > 1)
950	{
951	  wchar_t wc;
952	  mblength = mbtowc (&wc, string + i, slen - i);
953	  if (MB_INVALIDCH (mblength))
954	    {
955	      if (MEMBER (c, charlist))
956		break;
957	    }
958	  else
959	    {
960	      if (wcharlist == 0)
961		{
962		  size_t len;
963		  len = mbstowcs (wcharlist, charlist, 0);
964		  if (len == -1)
965		    len = 0;
966		  wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
967		  mbstowcs (wcharlist, charlist, len + 1);
968		}
969
970	      if (wcschr (wcharlist, wc))
971		break;
972	    }
973	}
974      else
975#endif
976      if (MEMBER (c, charlist))
977	break;
978
979      ADVANCE_CHAR (string, slen, i);
980    }
981
982#if defined (HANDLE_MULTIBYTE)
983  FREE (wcharlist);
984#endif
985
986  temp = substring (string, *sindex, i);
987  *sindex = i;
988
989  return (temp);
990}
991
992/* Extract the $( construct in STRING, and return a new string.
993   Start extracting at (SINDEX) as if we had just seen "$(".
994   Make (SINDEX) get the position of the matching ")". )
995   XFLAGS is additional flags to pass to other extraction functions, */
996char *
997extract_command_subst (string, sindex, xflags)
998     char *string;
999     int *sindex;
1000     int xflags;
1001{
1002  if (string[*sindex] == '(')	/*)*/
1003    return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
1004  else
1005    {
1006      xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1007      return (xparse_dolparen (string, string+*sindex, sindex, xflags));
1008    }
1009}
1010
1011/* Extract the $[ construct in STRING, and return a new string. (])
1012   Start extracting at (SINDEX) as if we had just seen "$[".
1013   Make (SINDEX) get the position of the matching "]". */
1014char *
1015extract_arithmetic_subst (string, sindex)
1016     char *string;
1017     int *sindex;
1018{
1019  return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/
1020}
1021
1022#if defined (PROCESS_SUBSTITUTION)
1023/* Extract the <( or >( construct in STRING, and return a new string.
1024   Start extracting at (SINDEX) as if we had just seen "<(".
1025   Make (SINDEX) get the position of the matching ")". */ /*))*/
1026char *
1027extract_process_subst (string, starter, sindex)
1028     char *string;
1029     char *starter;
1030     int *sindex;
1031{
1032  return (extract_delimited_string (string, sindex, starter, "(", ")", 0));
1033}
1034#endif /* PROCESS_SUBSTITUTION */
1035
1036#if defined (ARRAY_VARS)
1037/* This can be fooled by unquoted right parens in the passed string. If
1038   each caller verifies that the last character in STRING is a right paren,
1039   we don't even need to call extract_delimited_string. */
1040char *
1041extract_array_assignment_list (string, sindex)
1042     char *string;
1043     int *sindex;
1044{
1045  int slen;
1046  char *ret;
1047
1048  slen = strlen (string);	/* ( */
1049  if (string[slen - 1] == ')')
1050   {
1051      ret = substring (string, *sindex, slen - 1);
1052      *sindex = slen - 1;
1053      return ret;
1054    }
1055  return 0;
1056}
1057#endif
1058
1059/* Extract and create a new string from the contents of STRING, a
1060   character string delimited with OPENER and CLOSER.  SINDEX is
1061   the address of an int describing the current offset in STRING;
1062   it should point to just after the first OPENER found.  On exit,
1063   SINDEX gets the position of the last character of the matching CLOSER.
1064   If OPENER is more than a single character, ALT_OPENER, if non-null,
1065   contains a character string that can also match CLOSER and thus
1066   needs to be skipped. */
1067static char *
1068extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
1069     char *string;
1070     int *sindex;
1071     char *opener, *alt_opener, *closer;
1072     int flags;
1073{
1074  int i, c, si;
1075  size_t slen;
1076  char *t, *result;
1077  int pass_character, nesting_level, in_comment;
1078  int len_closer, len_opener, len_alt_opener;
1079  DECLARE_MBSTATE;
1080
1081  slen = strlen (string + *sindex) + *sindex;
1082  len_opener = STRLEN (opener);
1083  len_alt_opener = STRLEN (alt_opener);
1084  len_closer = STRLEN (closer);
1085
1086  pass_character = in_comment = 0;
1087
1088  nesting_level = 1;
1089  i = *sindex;
1090
1091  while (nesting_level)
1092    {
1093      c = string[i];
1094
1095      if (c == 0)
1096	break;
1097
1098      if (in_comment)
1099	{
1100	  if (c == '\n')
1101	    in_comment = 0;
1102	  ADVANCE_CHAR (string, slen, i);
1103	  continue;
1104	}
1105
1106      if (pass_character)	/* previous char was backslash */
1107	{
1108	  pass_character = 0;
1109	  ADVANCE_CHAR (string, slen, i);
1110	  continue;
1111	}
1112
1113      /* Not exactly right yet; should handle shell metacharacters and
1114	 multibyte characters, too. */
1115      if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
1116	{
1117          in_comment = 1;
1118          ADVANCE_CHAR (string, slen, i);
1119          continue;
1120	}
1121
1122      if (c == CTLESC || c == '\\')
1123	{
1124	  pass_character++;
1125	  i++;
1126	  continue;
1127	}
1128
1129      /* Process a nested OPENER. */
1130      if (STREQN (string + i, opener, len_opener))
1131	{
1132	  si = i + len_opener;
1133	  t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
1134	  i = si + 1;
1135	  continue;
1136	}
1137
1138      /* Process a nested ALT_OPENER */
1139      if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
1140	{
1141	  si = i + len_alt_opener;
1142	  t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
1143	  i = si + 1;
1144	  continue;
1145	}
1146
1147      /* If the current substring terminates the delimited string, decrement
1148	 the nesting level. */
1149      if (STREQN (string + i, closer, len_closer))
1150	{
1151	  i += len_closer - 1;	/* move to last byte of the closer */
1152	  nesting_level--;
1153	  if (nesting_level == 0)
1154	    break;
1155	}
1156
1157      /* Pass old-style command substitution through verbatim. */
1158      if (c == '`')
1159	{
1160	  si = i + 1;
1161	  t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1162	  i = si + 1;
1163	  continue;
1164	}
1165
1166      /* Pass single-quoted and double-quoted strings through verbatim. */
1167      if (c == '\'' || c == '"')
1168	{
1169	  si = i + 1;
1170	  i = (c == '\'') ? skip_single_quoted (string, slen, si)
1171			  : skip_double_quoted (string, slen, si);
1172	  continue;
1173	}
1174
1175      /* move past this character, which was not special. */
1176      ADVANCE_CHAR (string, slen, i);
1177    }
1178
1179  if (c == 0 && nesting_level)
1180    {
1181      if (no_longjmp_on_fatal_error == 0)
1182	{
1183	  report_error (_("bad substitution: no closing `%s' in %s"), closer, string);
1184	  last_command_exit_value = EXECUTION_FAILURE;
1185	  exp_jump_to_top_level (DISCARD);
1186	}
1187      else
1188	{
1189	  *sindex = i;
1190	  return (char *)NULL;
1191	}
1192    }
1193
1194  si = i - *sindex - len_closer + 1;
1195  if (flags & SX_NOALLOC)
1196    result = (char *)NULL;
1197  else
1198    {
1199      result = (char *)xmalloc (1 + si);
1200      strncpy (result, string + *sindex, si);
1201      result[si] = '\0';
1202    }
1203  *sindex = i;
1204
1205  return (result);
1206}
1207
1208/* Extract a parameter expansion expression within ${ and } from STRING.
1209   Obey the Posix.2 rules for finding the ending `}': count braces while
1210   skipping over enclosed quoted strings and command substitutions.
1211   SINDEX is the address of an int describing the current offset in STRING;
1212   it should point to just after the first `{' found.  On exit, SINDEX
1213   gets the position of the matching `}'.  QUOTED is non-zero if this
1214   occurs inside double quotes. */
1215/* XXX -- this is very similar to extract_delimited_string -- XXX */
1216static char *
1217extract_dollar_brace_string (string, sindex, quoted, flags)
1218     char *string;
1219     int *sindex, quoted, flags;
1220{
1221  register int i, c;
1222  size_t slen;
1223  int pass_character, nesting_level, si;
1224  char *result, *t;
1225  DECLARE_MBSTATE;
1226
1227  pass_character = 0;
1228  nesting_level = 1;
1229  slen = strlen (string + *sindex) + *sindex;
1230
1231  i = *sindex;
1232  while (c = string[i])
1233    {
1234      if (pass_character)
1235	{
1236	  pass_character = 0;
1237	  ADVANCE_CHAR (string, slen, i);
1238	  continue;
1239	}
1240
1241      /* CTLESCs and backslashes quote the next character. */
1242      if (c == CTLESC || c == '\\')
1243	{
1244	  pass_character++;
1245	  i++;
1246	  continue;
1247	}
1248
1249      if (string[i] == '$' && string[i+1] == LBRACE)
1250	{
1251	  nesting_level++;
1252	  i += 2;
1253	  continue;
1254	}
1255
1256      if (c == RBRACE)
1257	{
1258	  nesting_level--;
1259	  if (nesting_level == 0)
1260	    break;
1261	  i++;
1262	  continue;
1263	}
1264
1265      /* Pass the contents of old-style command substitutions through
1266	 verbatim. */
1267      if (c == '`')
1268	{
1269	  si = i + 1;
1270	  t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1271	  i = si + 1;
1272	  continue;
1273	}
1274
1275      /* Pass the contents of new-style command substitutions and
1276	 arithmetic substitutions through verbatim. */
1277      if (string[i] == '$' && string[i+1] == LPAREN)
1278	{
1279	  si = i + 2;
1280	  t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1281	  i = si + 1;
1282	  continue;
1283	}
1284
1285      /* Pass the contents of single-quoted and double-quoted strings
1286	 through verbatim. */
1287      if (c == '\'' || c == '"')
1288	{
1289	  si = i + 1;
1290	  i = (c == '\'') ? skip_single_quoted (string, slen, si)
1291			  : skip_double_quoted (string, slen, si);
1292	  /* skip_XXX_quoted leaves index one past close quote */
1293	  continue;
1294	}
1295
1296      /* move past this character, which was not special. */
1297      ADVANCE_CHAR (string, slen, i);
1298    }
1299
1300  if (c == 0 && nesting_level)
1301    {
1302      if (no_longjmp_on_fatal_error == 0)
1303	{			/* { */
1304	  report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
1305	  last_command_exit_value = EXECUTION_FAILURE;
1306	  exp_jump_to_top_level (DISCARD);
1307	}
1308      else
1309	{
1310	  *sindex = i;
1311	  return ((char *)NULL);
1312	}
1313    }
1314
1315  result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
1316  *sindex = i;
1317
1318  return (result);
1319}
1320
1321/* Remove backslashes which are quoting backquotes from STRING.  Modifies
1322   STRING, and returns a pointer to it. */
1323char *
1324de_backslash (string)
1325     char *string;
1326{
1327  register size_t slen;
1328  register int i, j, prev_i;
1329  DECLARE_MBSTATE;
1330
1331  slen = strlen (string);
1332  i = j = 0;
1333
1334  /* Loop copying string[i] to string[j], i >= j. */
1335  while (i < slen)
1336    {
1337      if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
1338			      string[i + 1] == '$'))
1339	i++;
1340      prev_i = i;
1341      ADVANCE_CHAR (string, slen, i);
1342      if (j < prev_i)
1343	do string[j++] = string[prev_i++]; while (prev_i < i);
1344      else
1345	j = i;
1346    }
1347  string[j] = '\0';
1348
1349  return (string);
1350}
1351
1352#if 0
1353/*UNUSED*/
1354/* Replace instances of \! in a string with !. */
1355void
1356unquote_bang (string)
1357     char *string;
1358{
1359  register int i, j;
1360  register char *temp;
1361
1362  temp = (char *)xmalloc (1 + strlen (string));
1363
1364  for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
1365    {
1366      if (string[i] == '\\' && string[i + 1] == '!')
1367	{
1368	  temp[j] = '!';
1369	  i++;
1370	}
1371    }
1372  strcpy (string, temp);
1373  free (temp);
1374}
1375#endif
1376
1377#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
1378
1379/* This function assumes s[i] == open; returns with s[ret] == close; used to
1380   parse array subscripts.  FLAGS currently unused. */
1381static int
1382skip_matched_pair (string, start, open, close, flags)
1383     const char *string;
1384     int start, open, close, flags;
1385{
1386  int i, pass_next, backq, si, c, count;
1387  size_t slen;
1388  char *temp, *ss;
1389  DECLARE_MBSTATE;
1390
1391  slen = strlen (string + start) + start;
1392  no_longjmp_on_fatal_error = 1;
1393
1394  i = start + 1;		/* skip over leading bracket */
1395  count = 1;
1396  pass_next = backq = 0;
1397  ss = (char *)string;
1398  while (c = string[i])
1399    {
1400      if (pass_next)
1401	{
1402	  pass_next = 0;
1403	  if (c == 0)
1404	    CQ_RETURN(i);
1405	  ADVANCE_CHAR (string, slen, i);
1406	  continue;
1407	}
1408      else if (c == '\\')
1409	{
1410	  pass_next = 1;
1411	  i++;
1412	  continue;
1413	}
1414      else if (backq)
1415	{
1416	  if (c == '`')
1417	    backq = 0;
1418	  ADVANCE_CHAR (string, slen, i);
1419	  continue;
1420	}
1421      else if (c == '`')
1422	{
1423	  backq = 1;
1424	  i++;
1425	  continue;
1426	}
1427      else if (c == open)
1428	{
1429	  count++;
1430	  i++;
1431	  continue;
1432	}
1433      else if (c == close)
1434	{
1435	  count--;
1436	  if (count == 0)
1437	    break;
1438	  i++;
1439	  continue;
1440	}
1441      else if (c == '\'' || c == '"')
1442	{
1443	  i = (c == '\'') ? skip_single_quoted (ss, slen, ++i)
1444			  : skip_double_quoted (ss, slen, ++i);
1445	  /* no increment, the skip functions increment past the closing quote. */
1446	}
1447      else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
1448	{
1449	  si = i + 2;
1450	  if (string[si] == '\0')
1451	    CQ_RETURN(si);
1452
1453	  if (string[i+1] == LPAREN)
1454	    temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
1455	  else
1456	    temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
1457	  i = si;
1458	  if (string[i] == '\0')	/* don't increment i past EOS in loop */
1459	    break;
1460	  i++;
1461	  continue;
1462	}
1463      else
1464	ADVANCE_CHAR (string, slen, i);
1465    }
1466
1467  CQ_RETURN(i);
1468}
1469
1470#if defined (ARRAY_VARS)
1471int
1472skipsubscript (string, start)
1473     const char *string;
1474     int start;
1475{
1476  return (skip_matched_pair (string, start, '[', ']', 0));
1477}
1478#endif
1479
1480/* Skip characters in STRING until we find a character in DELIMS, and return
1481   the index of that character.  START is the index into string at which we
1482   begin.  This is similar in spirit to strpbrk, but it returns an index into
1483   STRING and takes a starting index.  This little piece of code knows quite
1484   a lot of shell syntax.  It's very similar to skip_double_quoted and other
1485   functions of that ilk. */
1486int
1487skip_to_delim (string, start, delims, flags)
1488     char *string;
1489     int start;
1490     char *delims;
1491     int flags;
1492{
1493  int i, pass_next, backq, si, c, invert;
1494  size_t slen;
1495  char *temp;
1496  DECLARE_MBSTATE;
1497
1498  slen = strlen (string + start) + start;
1499  if (flags & SD_NOJMP)
1500    no_longjmp_on_fatal_error = 1;
1501  invert = (flags & SD_INVERT);
1502
1503  i = start;
1504  pass_next = backq = 0;
1505  while (c = string[i])
1506    {
1507      if (pass_next)
1508	{
1509	  pass_next = 0;
1510	  if (c == 0)
1511	    CQ_RETURN(i);
1512	  ADVANCE_CHAR (string, slen, i);
1513	  continue;
1514	}
1515      else if (c == '\\')
1516	{
1517	  pass_next = 1;
1518	  i++;
1519	  continue;
1520	}
1521      else if (backq)
1522	{
1523	  if (c == '`')
1524	    backq = 0;
1525	  ADVANCE_CHAR (string, slen, i);
1526	  continue;
1527	}
1528      else if (c == '`')
1529	{
1530	  backq = 1;
1531	  i++;
1532	  continue;
1533	}
1534      else if (invert == 0 && member (c, delims))
1535	break;
1536      else if (c == '\'' || c == '"')
1537	{
1538	  i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
1539			  : skip_double_quoted (string, slen, ++i);
1540	  /* no increment, the skip functions increment past the closing quote. */
1541	}
1542      else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
1543	{
1544	  si = i + 2;
1545	  if (string[si] == '\0')
1546	    CQ_RETURN(si);
1547
1548	  if (string[i+1] == LPAREN)
1549	    temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
1550	  else
1551	    temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
1552	  i = si;
1553	  if (string[i] == '\0')	/* don't increment i past EOS in loop */
1554	    break;
1555	  i++;
1556	  continue;
1557	}
1558      else if (invert && (member (c, delims) == 0))
1559	break;
1560      else
1561	ADVANCE_CHAR (string, slen, i);
1562    }
1563
1564  CQ_RETURN(i);
1565}
1566
1567#if defined (READLINE)
1568/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
1569   an unclosed quoted string), or if the character at EINDEX is quoted
1570   by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various
1571   single and double-quoted string parsing functions should not return an
1572   error if there are unclosed quotes or braces.  The characters that this
1573   recognizes need to be the same as the contents of
1574   rl_completer_quote_characters. */
1575
1576int
1577char_is_quoted (string, eindex)
1578     char *string;
1579     int eindex;
1580{
1581  int i, pass_next, c;
1582  size_t slen;
1583  DECLARE_MBSTATE;
1584
1585  slen = strlen (string);
1586  no_longjmp_on_fatal_error = 1;
1587  i = pass_next = 0;
1588  while (i <= eindex)
1589    {
1590      c = string[i];
1591
1592      if (pass_next)
1593	{
1594	  pass_next = 0;
1595	  if (i >= eindex)	/* XXX was if (i >= eindex - 1) */
1596	    CQ_RETURN(1);
1597	  ADVANCE_CHAR (string, slen, i);
1598	  continue;
1599	}
1600      else if (c == '\\')
1601	{
1602	  pass_next = 1;
1603	  i++;
1604	  continue;
1605	}
1606      else if (c == '\'' || c == '"')
1607	{
1608	  i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
1609			  : skip_double_quoted (string, slen, ++i);
1610	  if (i > eindex)
1611	    CQ_RETURN(1);
1612	  /* no increment, the skip_xxx functions go one past end */
1613	}
1614      else
1615	ADVANCE_CHAR (string, slen, i);
1616    }
1617
1618  CQ_RETURN(0);
1619}
1620
1621int
1622unclosed_pair (string, eindex, openstr)
1623     char *string;
1624     int eindex;
1625     char *openstr;
1626{
1627  int i, pass_next, openc, olen;
1628  size_t slen;
1629  DECLARE_MBSTATE;
1630
1631  slen = strlen (string);
1632  olen = strlen (openstr);
1633  i = pass_next = openc = 0;
1634  while (i <= eindex)
1635    {
1636      if (pass_next)
1637	{
1638	  pass_next = 0;
1639	  if (i >= eindex)	/* XXX was if (i >= eindex - 1) */
1640	    return 0;
1641	  ADVANCE_CHAR (string, slen, i);
1642	  continue;
1643	}
1644      else if (string[i] == '\\')
1645	{
1646	  pass_next = 1;
1647	  i++;
1648	  continue;
1649	}
1650      else if (STREQN (string + i, openstr, olen))
1651	{
1652	  openc = 1 - openc;
1653	  i += olen;
1654	}
1655      else if (string[i] == '\'' || string[i] == '"')
1656	{
1657	  i = (string[i] == '\'') ? skip_single_quoted (string, slen, i)
1658				  : skip_double_quoted (string, slen, i);
1659	  if (i > eindex)
1660	    return 0;
1661	}
1662      else
1663	ADVANCE_CHAR (string, slen, i);
1664    }
1665  return (openc);
1666}
1667
1668/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
1669   individual words.  If DELIMS is NULL, the current value of $IFS is used
1670   to split the string, and the function follows the shell field splitting
1671   rules.  SENTINEL is an index to look for.  NWP, if non-NULL,
1672   gets the number of words in the returned list.  CWP, if non-NULL, gets
1673   the index of the word containing SENTINEL.  Non-whitespace chars in
1674   DELIMS delimit separate fields. */
1675WORD_LIST *
1676split_at_delims (string, slen, delims, sentinel, nwp, cwp)
1677     char *string;
1678     int slen;
1679     char *delims;
1680     int sentinel;
1681     int *nwp, *cwp;
1682{
1683  int ts, te, i, nw, cw, ifs_split;
1684  char *token, *d, *d2;
1685  WORD_LIST *ret, *tl;
1686
1687  if (string == 0 || *string == '\0')
1688    {
1689      if (nwp)
1690	*nwp = 0;
1691      if (cwp)
1692	*cwp = 0;
1693      return ((WORD_LIST *)NULL);
1694    }
1695
1696  d = (delims == 0) ? ifs_value : delims;
1697  ifs_split = delims == 0;
1698
1699  /* Make d2 the non-whitespace characters in delims */
1700  d2 = 0;
1701  if (delims)
1702    {
1703      size_t slength;
1704#if defined (HANDLE_MULTIBYTE)
1705      size_t mblength = 1;
1706#endif
1707      DECLARE_MBSTATE;
1708
1709      slength = strlen (delims);
1710      d2 = (char *)xmalloc (slength + 1);
1711      i = ts = 0;
1712      while (delims[i])
1713	{
1714#if defined (HANDLE_MULTIBYTE)
1715	  mbstate_t state_bak;
1716	  state_bak = state;
1717	  mblength = MBRLEN (delims + i, slength, &state);
1718	  if (MB_INVALIDCH (mblength))
1719	    state = state_bak;
1720	  else if (mblength > 1)
1721	    {
1722	      memcpy (d2 + ts, delims + i, mblength);
1723	      ts += mblength;
1724	      i += mblength;
1725	      slength -= mblength;
1726	      continue;
1727	    }
1728#endif
1729	  if (whitespace (delims[i]) == 0)
1730	    d2[ts++] = delims[i];
1731
1732	  i++;
1733	  slength--;
1734	}
1735      d2[ts] = '\0';
1736    }
1737
1738  ret = (WORD_LIST *)NULL;
1739
1740  /* Remove sequences of whitspace characters at the start of the string, as
1741     long as those characters are delimiters. */
1742  for (i = 0; member (string[i], d) && spctabnl (string[i]); i++)
1743    ;
1744  if (string[i] == '\0')
1745    return (ret);
1746
1747  ts = i;
1748  nw = 0;
1749  cw = -1;
1750  while (1)
1751    {
1752      te = skip_to_delim (string, ts, d, SD_NOJMP);
1753
1754      /* If we have a non-whitespace delimiter character, use it to make a
1755	 separate field.  This is just about what $IFS splitting does and
1756	 is closer to the behavior of the shell parser. */
1757      if (ts == te && d2 && member (string[ts], d2))
1758	{
1759	  te = ts + 1;
1760	  /* If we're using IFS splitting, the non-whitespace delimiter char
1761	     and any additional IFS whitespace delimits a field. */
1762	  if (ifs_split)
1763	    while (member (string[te], d) && spctabnl (string[te]))
1764	      te++;
1765	  else
1766	    while (member (string[te], d2))
1767	      te++;
1768	}
1769
1770      token = substring (string, ts, te);
1771
1772      ret = add_string_to_list (token, ret);
1773      free (token);
1774      nw++;
1775
1776      if (sentinel >= ts && sentinel <= te)
1777	cw = nw;
1778
1779      /* If the cursor is at whitespace just before word start, set the
1780	 sentinel word to the current word. */
1781      if (cwp && cw == -1 && sentinel == ts-1)
1782	cw = nw;
1783
1784      /* If the cursor is at whitespace between two words, make a new, empty
1785	 word, add it before (well, after, since the list is in reverse order)
1786	 the word we just added, and set the current word to that one. */
1787      if (cwp && cw == -1 && sentinel < ts)
1788	{
1789	  tl = make_word_list (make_word (""), ret->next);
1790	  ret->next = tl;
1791	  cw = nw;
1792	  nw++;
1793	}
1794
1795      if (string[te] == 0)
1796	break;
1797
1798      i = te;
1799      while (member (string[i], d) && (ifs_split || spctabnl(string[i])))
1800	i++;
1801
1802      if (string[i])
1803	ts = i;
1804      else
1805	break;
1806    }
1807
1808  /* Special case for SENTINEL at the end of STRING.  If we haven't found
1809     the word containing SENTINEL yet, and the index we're looking for is at
1810     the end of STRING, add an additional null argument and set the current
1811     word pointer to that. */
1812  if (cwp && cw == -1 && sentinel >= slen)
1813    {
1814      if (whitespace (string[sentinel - 1]))
1815	{
1816	  token = "";
1817	  ret = add_string_to_list (token, ret);
1818	  nw++;
1819	}
1820      cw = nw;
1821    }
1822
1823  if (nwp)
1824    *nwp = nw;
1825  if (cwp)
1826    *cwp = cw;
1827
1828  return (REVERSE_LIST (ret, WORD_LIST *));
1829}
1830#endif /* READLINE */
1831
1832#if 0
1833/* UNUSED */
1834/* Extract the name of the variable to bind to from the assignment string. */
1835char *
1836assignment_name (string)
1837     char *string;
1838{
1839  int offset;
1840  char *temp;
1841
1842  offset = assignment (string, 0);
1843  if (offset == 0)
1844    return (char *)NULL;
1845  temp = substring (string, 0, offset);
1846  return (temp);
1847}
1848#endif
1849
1850/* **************************************************************** */
1851/*								    */
1852/*     Functions to convert strings to WORD_LISTs and vice versa    */
1853/*								    */
1854/* **************************************************************** */
1855
1856/* Return a single string of all the words in LIST.  SEP is the separator
1857   to put between individual elements of LIST in the output string. */
1858char *
1859string_list_internal (list, sep)
1860     WORD_LIST *list;
1861     char *sep;
1862{
1863  register WORD_LIST *t;
1864  char *result, *r;
1865  int word_len, sep_len, result_size;
1866
1867  if (list == 0)
1868    return ((char *)NULL);
1869
1870  /* Short-circuit quickly if we don't need to separate anything. */
1871  if (list->next == 0)
1872    return (savestring (list->word->word));
1873
1874  /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
1875  sep_len = STRLEN (sep);
1876  result_size = 0;
1877
1878  for (t = list; t; t = t->next)
1879    {
1880      if (t != list)
1881	result_size += sep_len;
1882      result_size += strlen (t->word->word);
1883    }
1884
1885  r = result = (char *)xmalloc (result_size + 1);
1886
1887  for (t = list; t; t = t->next)
1888    {
1889      if (t != list && sep_len)
1890	{
1891	  if (sep_len > 1)
1892	    {
1893	      FASTCOPY (sep, r, sep_len);
1894	      r += sep_len;
1895	    }
1896	  else
1897	    *r++ = sep[0];
1898	}
1899
1900      word_len = strlen (t->word->word);
1901      FASTCOPY (t->word->word, r, word_len);
1902      r += word_len;
1903    }
1904
1905  *r = '\0';
1906  return (result);
1907}
1908
1909/* Return a single string of all the words present in LIST, separating
1910   each word with a space. */
1911char *
1912string_list (list)
1913     WORD_LIST *list;
1914{
1915  return (string_list_internal (list, " "));
1916}
1917
1918/* An external interface that can be used by the rest of the shell to
1919   obtain a string containing the first character in $IFS.  Handles all
1920   the multibyte complications.  If LENP is non-null, it is set to the
1921   length of the returned string. */
1922char *
1923ifs_firstchar (lenp)
1924     int *lenp;
1925{
1926  char *ret;
1927  int len;
1928
1929  ret = xmalloc (MB_LEN_MAX + 1);
1930#if defined (HANDLE_MULTIBYTE)
1931  if (ifs_firstc_len == 1)
1932    {
1933      ret[0] = ifs_firstc[0];
1934      ret[1] = '\0';
1935      len = ret[0] ? 1 : 0;
1936    }
1937  else
1938    {
1939      memcpy (ret, ifs_firstc, ifs_firstc_len);
1940      ret[len = ifs_firstc_len] = '\0';
1941    }
1942#else
1943  ret[0] = ifs_firstc;
1944  ret[1] = '\0';
1945  len = ret[0] ? 0 : 1;
1946#endif
1947
1948  if (lenp)
1949    *lenp = len;
1950
1951  return ret;
1952}
1953
1954/* Return a single string of all the words present in LIST, obeying the
1955   quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
1956   expansion [of $*] appears within a double quoted string, it expands
1957   to a single field with the value of each parameter separated by the
1958   first character of the IFS variable, or by a <space> if IFS is unset." */
1959char *
1960string_list_dollar_star (list)
1961     WORD_LIST *list;
1962{
1963  char *ret;
1964#if defined (HANDLE_MULTIBYTE)
1965#  if defined (__GNUC__)
1966  char sep[MB_CUR_MAX + 1];
1967#  else
1968  char *sep = 0;
1969#  endif
1970#else
1971  char sep[2];
1972#endif
1973
1974#if defined (HANDLE_MULTIBYTE)
1975#  if !defined (__GNUC__)
1976  sep = (char *)xmalloc (MB_CUR_MAX + 1);
1977#  endif /* !__GNUC__ */
1978  if (ifs_firstc_len == 1)
1979    {
1980      sep[0] = ifs_firstc[0];
1981      sep[1] = '\0';
1982    }
1983  else
1984    {
1985      memcpy (sep, ifs_firstc, ifs_firstc_len);
1986      sep[ifs_firstc_len] = '\0';
1987    }
1988#else
1989  sep[0] = ifs_firstc;
1990  sep[1] = '\0';
1991#endif
1992
1993  ret = string_list_internal (list, sep);
1994#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
1995  free (sep);
1996#endif
1997  return ret;
1998}
1999
2000/* Turn $@ into a string.  If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
2001   is non-zero, the $@ appears within double quotes, and we should quote
2002   the list before converting it into a string.  If IFS is unset, and the
2003   word is not quoted, we just need to quote CTLESC and CTLNUL characters
2004   in the words in the list, because the default value of $IFS is
2005   <space><tab><newline>, IFS characters in the words in the list should
2006   also be split.  If IFS is null, and the word is not quoted, we need
2007   to quote the words in the list to preserve the positional parameters
2008   exactly. */
2009char *
2010string_list_dollar_at (list, quoted)
2011     WORD_LIST *list;
2012     int quoted;
2013{
2014  char *ifs, *ret;
2015#if defined (HANDLE_MULTIBYTE)
2016#  if defined (__GNUC__)
2017  char sep[MB_CUR_MAX + 1];
2018#  else
2019  char *sep = 0;
2020#  endif /* !__GNUC__ */
2021#else
2022  char sep[2];
2023#endif
2024  WORD_LIST *tlist;
2025
2026  /* XXX this could just be ifs = ifs_value; */
2027  ifs = ifs_var ? value_cell (ifs_var) : (char *)0;
2028
2029#if defined (HANDLE_MULTIBYTE)
2030#  if !defined (__GNUC__)
2031  sep = (char *)xmalloc (MB_CUR_MAX + 1);
2032#  endif /* !__GNUC__ */
2033  if (ifs && *ifs)
2034    {
2035      if (ifs_firstc_len == 1)
2036	{
2037	  sep[0] = ifs_firstc[0];
2038	  sep[1] = '\0';
2039	}
2040      else
2041	{
2042	  memcpy (sep, ifs_firstc, ifs_firstc_len);
2043	  sep[ifs_firstc_len] = '\0';
2044	}
2045    }
2046  else
2047    {
2048      sep[0] = ' ';
2049      sep[1] = '\0';
2050    }
2051#else
2052  sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs;
2053  sep[1] = '\0';
2054#endif
2055
2056  /* XXX -- why call quote_list if ifs == 0?  we can get away without doing
2057     it now that quote_escapes quotes spaces */
2058#if 0
2059  tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0))
2060#else
2061  tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
2062#endif
2063		? quote_list (list)
2064		: list_quote_escapes (list);
2065
2066  ret = string_list_internal (tlist, sep);
2067#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2068  free (sep);
2069#endif
2070  return ret;
2071}
2072
2073/* Turn the positional paramters into a string, understanding quoting and
2074   the various subtleties of using the first character of $IFS as the
2075   separator.  Calls string_list_dollar_at, string_list_dollar_star, and
2076   string_list as appropriate. */
2077char *
2078string_list_pos_params (pchar, list, quoted)
2079     int pchar;
2080     WORD_LIST *list;
2081     int quoted;
2082{
2083  char *ret;
2084  WORD_LIST *tlist;
2085
2086  if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
2087    {
2088      tlist = quote_list (list);
2089      word_list_remove_quoted_nulls (tlist);
2090      ret = string_list_dollar_star (tlist);
2091    }
2092  else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
2093    {
2094      tlist = quote_list (list);
2095      word_list_remove_quoted_nulls (tlist);
2096      ret = string_list (tlist);
2097    }
2098  else if (pchar == '*')
2099    {
2100      /* Even when unquoted, string_list_dollar_star does the right thing
2101	 making sure that the first character of $IFS is used as the
2102	 separator. */
2103      ret = string_list_dollar_star (list);
2104    }
2105  else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
2106    /* We use string_list_dollar_at, but only if the string is quoted, since
2107       that quotes the escapes if it's not, which we don't want.  We could
2108       use string_list (the old code did), but that doesn't do the right
2109       thing if the first character of $IFS is not a space.  We use
2110       string_list_dollar_star if the string is unquoted so we make sure that
2111       the elements of $@ are separated by the first character of $IFS for
2112       later splitting. */
2113    ret = string_list_dollar_at (list, quoted);
2114  else if (pchar == '@')
2115    ret = string_list_dollar_star (list);
2116  else
2117    ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
2118
2119  return ret;
2120}
2121
2122/* Return the list of words present in STRING.  Separate the string into
2123   words at any of the characters found in SEPARATORS.  If QUOTED is
2124   non-zero then word in the list will have its quoted flag set, otherwise
2125   the quoted flag is left as make_word () deemed fit.
2126
2127   This obeys the P1003.2 word splitting semantics.  If `separators' is
2128   exactly <space><tab><newline>, then the splitting algorithm is that of
2129   the Bourne shell, which treats any sequence of characters from `separators'
2130   as a delimiter.  If IFS is unset, which results in `separators' being set
2131   to "", no splitting occurs.  If separators has some other value, the
2132   following rules are applied (`IFS white space' means zero or more
2133   occurrences of <space>, <tab>, or <newline>, as long as those characters
2134   are in `separators'):
2135
2136	1) IFS white space is ignored at the start and the end of the
2137	   string.
2138	2) Each occurrence of a character in `separators' that is not
2139	   IFS white space, along with any adjacent occurrences of
2140	   IFS white space delimits a field.
2141	3) Any nonzero-length sequence of IFS white space delimits a field.
2142   */
2143
2144/* BEWARE!  list_string strips null arguments.  Don't call it twice and
2145   expect to have "" preserved! */
2146
2147/* This performs word splitting and quoted null character removal on
2148   STRING. */
2149#define issep(c) \
2150	(((separators)[0]) ? ((separators)[1] ? isifs(c) \
2151					      : (c) == (separators)[0]) \
2152			   : 0)
2153
2154WORD_LIST *
2155list_string (string, separators, quoted)
2156     register char *string, *separators;
2157     int quoted;
2158{
2159  WORD_LIST *result;
2160  WORD_DESC *t;
2161  char *current_word, *s;
2162  int sindex, sh_style_split, whitesep, xflags;
2163  size_t slen;
2164
2165  if (!string || !*string)
2166    return ((WORD_LIST *)NULL);
2167
2168  sh_style_split = separators && separators[0] == ' ' &&
2169				 separators[1] == '\t' &&
2170				 separators[2] == '\n' &&
2171				 separators[3] == '\0';
2172  for (xflags = 0, s = ifs_value; s && *s; s++)
2173    {
2174      if (*s == CTLESC) xflags |= SX_NOCTLESC;
2175      else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
2176    }
2177
2178  slen = 0;
2179  /* Remove sequences of whitespace at the beginning of STRING, as
2180     long as those characters appear in IFS.  Do not do this if
2181     STRING is quoted or if there are no separator characters. */
2182  if (!quoted || !separators || !*separators)
2183    {
2184      for (s = string; *s && spctabnl (*s) && issep (*s); s++);
2185
2186      if (!*s)
2187	return ((WORD_LIST *)NULL);
2188
2189      string = s;
2190    }
2191
2192  /* OK, now STRING points to a word that does not begin with white space.
2193     The splitting algorithm is:
2194	extract a word, stopping at a separator
2195	skip sequences of spc, tab, or nl as long as they are separators
2196     This obeys the field splitting rules in Posix.2. */
2197  slen = (MB_CUR_MAX > 1) ? strlen (string) : 1;
2198  for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
2199    {
2200      /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
2201	 unless multibyte chars are possible. */
2202      current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
2203      if (current_word == 0)
2204	break;
2205
2206      /* If we have a quoted empty string, add a quoted null argument.  We
2207	 want to preserve the quoted null character iff this is a quoted
2208	 empty string; otherwise the quoted null characters are removed
2209	 below. */
2210      if (QUOTED_NULL (current_word))
2211	{
2212	  t = alloc_word_desc ();
2213	  t->word = make_quoted_char ('\0');
2214	  t->flags |= W_QUOTED|W_HASQUOTEDNULL;
2215	  result = make_word_list (t, result);
2216	}
2217      else if (current_word[0] != '\0')
2218	{
2219	  /* If we have something, then add it regardless.  However,
2220	     perform quoted null character removal on the current word. */
2221	  remove_quoted_nulls (current_word);
2222	  result = add_string_to_list (current_word, result);
2223	  result->word->flags &= ~W_HASQUOTEDNULL;	/* just to be sure */
2224	  if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
2225	    result->word->flags |= W_QUOTED;
2226	}
2227
2228      /* If we're not doing sequences of separators in the traditional
2229	 Bourne shell style, then add a quoted null argument. */
2230      else if (!sh_style_split && !spctabnl (string[sindex]))
2231	{
2232	  t = alloc_word_desc ();
2233	  t->word = make_quoted_char ('\0');
2234	  t->flags |= W_QUOTED|W_HASQUOTEDNULL;
2235	  result = make_word_list (t, result);
2236	}
2237
2238      free (current_word);
2239
2240      /* Note whether or not the separator is IFS whitespace, used later. */
2241      whitesep = string[sindex] && spctabnl (string[sindex]);
2242
2243      /* Move past the current separator character. */
2244      if (string[sindex])
2245	{
2246	  DECLARE_MBSTATE;
2247	  ADVANCE_CHAR (string, slen, sindex);
2248	}
2249
2250      /* Now skip sequences of space, tab, or newline characters if they are
2251	 in the list of separators. */
2252      while (string[sindex] && spctabnl (string[sindex]) && issep (string[sindex]))
2253	sindex++;
2254
2255      /* If the first separator was IFS whitespace and the current character
2256	 is a non-whitespace IFS character, it should be part of the current
2257	 field delimiter, not a separate delimiter that would result in an
2258	 empty field.  Look at POSIX.2, 3.6.5, (3)(b). */
2259      if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (string[sindex]))
2260	{
2261	  sindex++;
2262	  /* An IFS character that is not IFS white space, along with any
2263	     adjacent IFS white space, shall delimit a field. (SUSv3) */
2264	  while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex]))
2265	    sindex++;
2266	}
2267    }
2268  return (REVERSE_LIST (result, WORD_LIST *));
2269}
2270
2271/* Parse a single word from STRING, using SEPARATORS to separate fields.
2272   ENDPTR is set to the first character after the word.  This is used by
2273   the `read' builtin.  This is never called with SEPARATORS != $IFS;
2274   it should be simplified.
2275
2276   XXX - this function is very similar to list_string; they should be
2277	 combined - XXX */
2278char *
2279get_word_from_string (stringp, separators, endptr)
2280     char **stringp, *separators, **endptr;
2281{
2282  register char *s;
2283  char *current_word;
2284  int sindex, sh_style_split, whitesep, xflags;
2285  size_t slen;
2286
2287  if (!stringp || !*stringp || !**stringp)
2288    return ((char *)NULL);
2289
2290  sh_style_split = separators && separators[0] == ' ' &&
2291				 separators[1] == '\t' &&
2292				 separators[2] == '\n' &&
2293				 separators[3] == '\0';
2294  for (xflags = 0, s = ifs_value; s && *s; s++)
2295    {
2296      if (*s == CTLESC) xflags |= SX_NOCTLESC;
2297      if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
2298    }
2299
2300  s = *stringp;
2301  slen = 0;
2302
2303  /* Remove sequences of whitespace at the beginning of STRING, as
2304     long as those characters appear in IFS. */
2305  if (sh_style_split || !separators || !*separators)
2306    {
2307      for (; *s && spctabnl (*s) && isifs (*s); s++);
2308
2309      /* If the string is nothing but whitespace, update it and return. */
2310      if (!*s)
2311	{
2312	  *stringp = s;
2313	  if (endptr)
2314	    *endptr = s;
2315	  return ((char *)NULL);
2316	}
2317    }
2318
2319  /* OK, S points to a word that does not begin with white space.
2320     Now extract a word, stopping at a separator, save a pointer to
2321     the first character after the word, then skip sequences of spc,
2322     tab, or nl as long as they are separators.
2323
2324     This obeys the field splitting rules in Posix.2. */
2325  sindex = 0;
2326  /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
2327     unless multibyte chars are possible. */
2328  slen = (MB_CUR_MAX > 1) ? strlen (s) : 1;
2329  current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
2330
2331  /* Set ENDPTR to the first character after the end of the word. */
2332  if (endptr)
2333    *endptr = s + sindex;
2334
2335  /* Note whether or not the separator is IFS whitespace, used later. */
2336  whitesep = s[sindex] && spctabnl (s[sindex]);
2337
2338  /* Move past the current separator character. */
2339  if (s[sindex])
2340    {
2341      DECLARE_MBSTATE;
2342      ADVANCE_CHAR (s, slen, sindex);
2343    }
2344
2345  /* Now skip sequences of space, tab, or newline characters if they are
2346     in the list of separators. */
2347  while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
2348    sindex++;
2349
2350  /* If the first separator was IFS whitespace and the current character is
2351     a non-whitespace IFS character, it should be part of the current field
2352     delimiter, not a separate delimiter that would result in an empty field.
2353     Look at POSIX.2, 3.6.5, (3)(b). */
2354  if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (s[sindex]))
2355    {
2356      sindex++;
2357      /* An IFS character that is not IFS white space, along with any adjacent
2358	 IFS white space, shall delimit a field. */
2359      while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
2360	sindex++;
2361    }
2362
2363  /* Update STRING to point to the next field. */
2364  *stringp = s + sindex;
2365  return (current_word);
2366}
2367
2368/* Remove IFS white space at the end of STRING.  Start at the end
2369   of the string and walk backwards until the beginning of the string
2370   or we find a character that's not IFS white space and not CTLESC.
2371   Only let CTLESC escape a white space character if SAW_ESCAPE is
2372   non-zero.  */
2373char *
2374strip_trailing_ifs_whitespace (string, separators, saw_escape)
2375     char *string, *separators;
2376     int saw_escape;
2377{
2378  char *s;
2379
2380  s = string + STRLEN (string) - 1;
2381  while (s > string && ((spctabnl (*s) && isifs (*s)) ||
2382			(saw_escape && *s == CTLESC && spctabnl (s[1]))))
2383    s--;
2384  *++s = '\0';
2385  return string;
2386}
2387
2388#if 0
2389/* UNUSED */
2390/* Split STRING into words at whitespace.  Obeys shell-style quoting with
2391   backslashes, single and double quotes. */
2392WORD_LIST *
2393list_string_with_quotes (string)
2394     char *string;
2395{
2396  WORD_LIST *list;
2397  char *token, *s;
2398  size_t s_len;
2399  int c, i, tokstart, len;
2400
2401  for (s = string; s && *s && spctabnl (*s); s++)
2402    ;
2403  if (s == 0 || *s == 0)
2404    return ((WORD_LIST *)NULL);
2405
2406  s_len = strlen (s);
2407  tokstart = i = 0;
2408  list = (WORD_LIST *)NULL;
2409  while (1)
2410    {
2411      c = s[i];
2412      if (c == '\\')
2413	{
2414	  i++;
2415	  if (s[i])
2416	    i++;
2417	}
2418      else if (c == '\'')
2419	i = skip_single_quoted (s, s_len, ++i);
2420      else if (c == '"')
2421	i = skip_double_quoted (s, s_len, ++i);
2422      else if (c == 0 || spctabnl (c))
2423	{
2424	  /* We have found the end of a token.  Make a word out of it and
2425	     add it to the word list. */
2426	  token = substring (s, tokstart, i);
2427	  list = add_string_to_list (token, list);
2428	  free (token);
2429	  while (spctabnl (s[i]))
2430	    i++;
2431	  if (s[i])
2432	    tokstart = i;
2433	  else
2434	    break;
2435	}
2436      else
2437	i++;	/* normal character */
2438    }
2439  return (REVERSE_LIST (list, WORD_LIST *));
2440}
2441#endif
2442
2443/********************************************************/
2444/*							*/
2445/*	Functions to perform assignment statements	*/
2446/*							*/
2447/********************************************************/
2448
2449#if defined (ARRAY_VARS)
2450static SHELL_VAR *
2451do_compound_assignment (name, value, flags)
2452     char *name, *value;
2453     int flags;
2454{
2455  SHELL_VAR *v;
2456  int mklocal, mkassoc;
2457  WORD_LIST *list;
2458
2459  mklocal = flags & ASS_MKLOCAL;
2460  mkassoc = flags & ASS_MKASSOC;
2461
2462  if (mklocal && variable_context)
2463    {
2464      v = find_variable (name);
2465      list = expand_compound_array_assignment (v, value, flags);
2466      if (mkassoc)
2467	v = make_local_assoc_variable (name);
2468      else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context)
2469        v = make_local_array_variable (name);
2470      assign_compound_array_list (v, list, flags);
2471    }
2472  else
2473    v = assign_array_from_string (name, value, flags);
2474
2475  return (v);
2476}
2477#endif
2478
2479/* Given STRING, an assignment string, get the value of the right side
2480   of the `=', and bind it to the left side.  If EXPAND is true, then
2481   perform parameter expansion, command substitution, and arithmetic
2482   expansion on the right-hand side.  Perform tilde expansion in any
2483   case.  Do not perform word splitting on the result of expansion. */
2484static int
2485do_assignment_internal (word, expand)
2486     const WORD_DESC *word;
2487     int expand;
2488{
2489  int offset, tlen, appendop, assign_list, aflags, retval;
2490  char *name, *value;
2491  SHELL_VAR *entry;
2492#if defined (ARRAY_VARS)
2493  char *t;
2494  int ni;
2495#endif
2496  const char *string;
2497
2498  if (word == 0 || word->word == 0)
2499    return 0;
2500
2501  appendop = assign_list = aflags = 0;
2502  string = word->word;
2503  offset = assignment (string, 0);
2504  name = savestring (string);
2505  value = (char *)NULL;
2506
2507  if (name[offset] == '=')
2508    {
2509      char *temp;
2510
2511      if (name[offset - 1] == '+')
2512	{
2513	  appendop = 1;
2514	  name[offset - 1] = '\0';
2515	}
2516
2517      name[offset] = 0;		/* might need this set later */
2518      temp = name + offset + 1;
2519      tlen = STRLEN (temp);
2520
2521#if defined (ARRAY_VARS)
2522      if (expand && (word->flags & W_COMPASSIGN))
2523	{
2524	  assign_list = ni = 1;
2525	  value = extract_array_assignment_list (temp, &ni);
2526	}
2527      else
2528#endif
2529
2530      if (expand && temp[0])
2531	value = expand_string_if_necessary (temp, 0, expand_string_assignment);
2532      else
2533	value = savestring (temp);
2534    }
2535
2536  if (value == 0)
2537    {
2538      value = (char *)xmalloc (1);
2539      value[0] = '\0';
2540    }
2541
2542  if (echo_command_at_execute)
2543    {
2544      if (appendop)
2545	name[offset - 1] = '+';
2546      xtrace_print_assignment (name, value, assign_list, 1);
2547      if (appendop)
2548	name[offset - 1] = '\0';
2549    }
2550
2551#define ASSIGN_RETURN(r)	do { FREE (value); free (name); return (r); } while (0)
2552
2553  if (appendop)
2554    aflags |= ASS_APPEND;
2555
2556#if defined (ARRAY_VARS)
2557  if (t = xstrchr (name, '['))	/*]*/
2558    {
2559      if (assign_list)
2560	{
2561	  report_error (_("%s: cannot assign list to array member"), name);
2562	  ASSIGN_RETURN (0);
2563	}
2564      entry = assign_array_element (name, value, aflags);
2565      if (entry == 0)
2566	ASSIGN_RETURN (0);
2567    }
2568  else if (assign_list)
2569    {
2570      if (word->flags & W_ASSIGNARG)
2571	aflags |= ASS_MKLOCAL;
2572      if (word->flags & W_ASSIGNASSOC)
2573	aflags |= ASS_MKASSOC;
2574      entry = do_compound_assignment (name, value, aflags);
2575    }
2576  else
2577#endif /* ARRAY_VARS */
2578  entry = bind_variable (name, value, aflags);
2579
2580  stupidly_hack_special_variables (name);
2581
2582#if 1
2583  /* Return 1 if the assignment seems to have been performed correctly. */
2584  if (entry == 0 || readonly_p (entry))
2585    retval = 0;		/* assignment failure */
2586  else if (noassign_p (entry))
2587    {
2588      last_command_exit_value = EXECUTION_FAILURE;
2589      retval = 1;	/* error status, but not assignment failure */
2590    }
2591  else
2592    retval = 1;
2593
2594  if (entry && retval != 0 && noassign_p (entry) == 0)
2595    VUNSETATTR (entry, att_invisible);
2596
2597  ASSIGN_RETURN (retval);
2598#else
2599  if (entry)
2600    VUNSETATTR (entry, att_invisible);
2601
2602  ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0);
2603#endif
2604}
2605
2606/* Perform the assignment statement in STRING, and expand the
2607   right side by doing tilde, command and parameter expansion. */
2608int
2609do_assignment (string)
2610     char *string;
2611{
2612  WORD_DESC td;
2613
2614  td.flags = W_ASSIGNMENT;
2615  td.word = string;
2616
2617  return do_assignment_internal (&td, 1);
2618}
2619
2620int
2621do_word_assignment (word)
2622     WORD_DESC *word;
2623{
2624  return do_assignment_internal (word, 1);
2625}
2626
2627/* Given STRING, an assignment string, get the value of the right side
2628   of the `=', and bind it to the left side.  Do not perform any word
2629   expansions on the right hand side. */
2630int
2631do_assignment_no_expand (string)
2632     char *string;
2633{
2634  WORD_DESC td;
2635
2636  td.flags = W_ASSIGNMENT;
2637  td.word = string;
2638
2639  return (do_assignment_internal (&td, 0));
2640}
2641
2642/***************************************************
2643 *						   *
2644 *  Functions to manage the positional parameters  *
2645 *						   *
2646 ***************************************************/
2647
2648/* Return the word list that corresponds to `$*'. */
2649WORD_LIST *
2650list_rest_of_args ()
2651{
2652  register WORD_LIST *list, *args;
2653  int i;
2654
2655  /* Break out of the loop as soon as one of the dollar variables is null. */
2656  for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
2657    list = make_word_list (make_bare_word (dollar_vars[i]), list);
2658
2659  for (args = rest_of_args; args; args = args->next)
2660    list = make_word_list (make_bare_word (args->word->word), list);
2661
2662  return (REVERSE_LIST (list, WORD_LIST *));
2663}
2664
2665int
2666number_of_args ()
2667{
2668  register WORD_LIST *list;
2669  int n;
2670
2671  for (n = 0; n < 9 && dollar_vars[n+1]; n++)
2672    ;
2673  for (list = rest_of_args; list; list = list->next)
2674    n++;
2675  return n;
2676}
2677
2678/* Return the value of a positional parameter.  This handles values > 10. */
2679char *
2680get_dollar_var_value (ind)
2681     intmax_t ind;
2682{
2683  char *temp;
2684  WORD_LIST *p;
2685
2686  if (ind < 10)
2687    temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
2688  else	/* We want something like ${11} */
2689    {
2690      ind -= 10;
2691      for (p = rest_of_args; p && ind--; p = p->next)
2692	;
2693      temp = p ? savestring (p->word->word) : (char *)NULL;
2694    }
2695  return (temp);
2696}
2697
2698/* Make a single large string out of the dollar digit variables,
2699   and the rest_of_args.  If DOLLAR_STAR is 1, then obey the special
2700   case of "$*" with respect to IFS. */
2701char *
2702string_rest_of_args (dollar_star)
2703     int dollar_star;
2704{
2705  register WORD_LIST *list;
2706  char *string;
2707
2708  list = list_rest_of_args ();
2709  string = dollar_star ? string_list_dollar_star (list) : string_list (list);
2710  dispose_words (list);
2711  return (string);
2712}
2713
2714/* Return a string containing the positional parameters from START to
2715   END, inclusive.  If STRING[0] == '*', we obey the rules for $*,
2716   which only makes a difference if QUOTED is non-zero.  If QUOTED includes
2717   Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise
2718   no quoting chars are added. */
2719static char *
2720pos_params (string, start, end, quoted)
2721     char *string;
2722     int start, end, quoted;
2723{
2724  WORD_LIST *save, *params, *h, *t;
2725  char *ret;
2726  int i;
2727
2728  /* see if we can short-circuit.  if start == end, we want 0 parameters. */
2729  if (start == end)
2730    return ((char *)NULL);
2731
2732  save = params = list_rest_of_args ();
2733  if (save == 0)
2734    return ((char *)NULL);
2735
2736  if (start == 0)		/* handle ${@:0[:x]} specially */
2737    {
2738      t = make_word_list (make_word (dollar_vars[0]), params);
2739      save = params = t;
2740    }
2741
2742  for (i = 1; params && i < start; i++)
2743    params = params->next;
2744  if (params == 0)
2745    return ((char *)NULL);
2746  for (h = t = params; params && i < end; i++)
2747    {
2748      t = params;
2749      params = params->next;
2750    }
2751
2752  t->next = (WORD_LIST *)NULL;
2753
2754  ret = string_list_pos_params (string[0], h, quoted);
2755
2756  if (t != params)
2757    t->next = params;
2758
2759  dispose_words (save);
2760  return (ret);
2761}
2762
2763/******************************************************************/
2764/*								  */
2765/*	Functions to expand strings to strings or WORD_LISTs      */
2766/*								  */
2767/******************************************************************/
2768
2769#if defined (PROCESS_SUBSTITUTION)
2770#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~')
2771#else
2772#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
2773#endif
2774
2775/* If there are any characters in STRING that require full expansion,
2776   then call FUNC to expand STRING; otherwise just perform quote
2777   removal if necessary.  This returns a new string. */
2778static char *
2779expand_string_if_necessary (string, quoted, func)
2780     char *string;
2781     int quoted;
2782     EXPFUNC *func;
2783{
2784  WORD_LIST *list;
2785  size_t slen;
2786  int i, saw_quote;
2787  char *ret;
2788  DECLARE_MBSTATE;
2789
2790  /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
2791  slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
2792  i = saw_quote = 0;
2793  while (string[i])
2794    {
2795      if (EXP_CHAR (string[i]))
2796	break;
2797      else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
2798	saw_quote = 1;
2799      ADVANCE_CHAR (string, slen, i);
2800    }
2801
2802  if (string[i])
2803    {
2804      list = (*func) (string, quoted);
2805      if (list)
2806	{
2807	  ret = string_list (list);
2808	  dispose_words (list);
2809	}
2810      else
2811	ret = (char *)NULL;
2812    }
2813  else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
2814    ret = string_quote_removal (string, quoted);
2815  else
2816    ret = savestring (string);
2817
2818  return ret;
2819}
2820
2821static inline char *
2822expand_string_to_string_internal (string, quoted, func)
2823     char *string;
2824     int quoted;
2825     EXPFUNC *func;
2826{
2827  WORD_LIST *list;
2828  char *ret;
2829
2830  if (string == 0 || *string == '\0')
2831    return ((char *)NULL);
2832
2833  list = (*func) (string, quoted);
2834  if (list)
2835    {
2836      ret = string_list (list);
2837      dispose_words (list);
2838    }
2839  else
2840    ret = (char *)NULL;
2841
2842  return (ret);
2843}
2844
2845char *
2846expand_string_to_string (string, quoted)
2847     char *string;
2848     int quoted;
2849{
2850  return (expand_string_to_string_internal (string, quoted, expand_string));
2851}
2852
2853char *
2854expand_string_unsplit_to_string (string, quoted)
2855     char *string;
2856     int quoted;
2857{
2858  return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
2859}
2860
2861char *
2862expand_assignment_string_to_string (string, quoted)
2863     char *string;
2864     int quoted;
2865{
2866  return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
2867}
2868
2869char *
2870expand_arith_string (string, quoted)
2871     char *string;
2872     int quoted;
2873{
2874  return (expand_string_if_necessary (string, quoted, expand_string));
2875}
2876
2877#if defined (COND_COMMAND)
2878/* Just remove backslashes in STRING.  Returns a new string. */
2879char *
2880remove_backslashes (string)
2881     char *string;
2882{
2883  char *r, *ret, *s;
2884
2885  r = ret = (char *)xmalloc (strlen (string) + 1);
2886  for (s = string; s && *s; )
2887    {
2888      if (*s == '\\')
2889	s++;
2890      if (*s == 0)
2891	break;
2892      *r++ = *s++;
2893    }
2894  *r = '\0';
2895  return ret;
2896}
2897
2898/* This needs better error handling. */
2899/* Expand W for use as an argument to a unary or binary operator in a
2900   [[...]] expression.  If SPECIAL is 1, this is the rhs argument
2901   to the != or == operator, and should be treated as a pattern.  In
2902   this case, we quote the string specially for the globbing code.  If
2903   SPECIAL is 2, this is an rhs argument for the =~ operator, and should
2904   be quoted appropriately for regcomp/regexec.  The caller is responsible
2905   for removing the backslashes if the unquoted word is needed later. */
2906char *
2907cond_expand_word (w, special)
2908     WORD_DESC *w;
2909     int special;
2910{
2911  char *r, *p;
2912  WORD_LIST *l;
2913  int qflags;
2914
2915  if (w->word == 0 || w->word[0] == '\0')
2916    return ((char *)NULL);
2917
2918  l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
2919  if (l)
2920    {
2921      if (special == 0)
2922	{
2923	  dequote_list (l);
2924	  r = string_list (l);
2925	}
2926      else
2927	{
2928	  qflags = QGLOB_CVTNULL;
2929	  if (special == 2)
2930	    qflags |= QGLOB_REGEXP;
2931	  p = string_list (l);
2932	  r = quote_string_for_globbing (p, qflags);
2933	  free (p);
2934	}
2935      dispose_words (l);
2936    }
2937  else
2938    r = (char *)NULL;
2939
2940  return r;
2941}
2942#endif
2943
2944/* Call expand_word_internal to expand W and handle error returns.
2945   A convenience function for functions that don't want to handle
2946   any errors or free any memory before aborting. */
2947static WORD_LIST *
2948call_expand_word_internal (w, q, i, c, e)
2949     WORD_DESC *w;
2950     int q, i, *c, *e;
2951{
2952  WORD_LIST *result;
2953
2954  result = expand_word_internal (w, q, i, c, e);
2955  if (result == &expand_word_error || result == &expand_word_fatal)
2956    {
2957      /* By convention, each time this error is returned, w->word has
2958	 already been freed (it sometimes may not be in the fatal case,
2959	 but that doesn't result in a memory leak because we're going
2960	 to exit in most cases). */
2961      w->word = (char *)NULL;
2962      last_command_exit_value = EXECUTION_FAILURE;
2963      exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
2964      /* NOTREACHED */
2965    }
2966  else
2967    return (result);
2968}
2969
2970/* Perform parameter expansion, command substitution, and arithmetic
2971   expansion on STRING, as if it were a word.  Leave the result quoted. */
2972static WORD_LIST *
2973expand_string_internal (string, quoted)
2974     char *string;
2975     int quoted;
2976{
2977  WORD_DESC td;
2978  WORD_LIST *tresult;
2979
2980  if (string == 0 || *string == 0)
2981    return ((WORD_LIST *)NULL);
2982
2983  td.flags = 0;
2984  td.word = savestring (string);
2985
2986  tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
2987
2988  FREE (td.word);
2989  return (tresult);
2990}
2991
2992/* Expand STRING by performing parameter expansion, command substitution,
2993   and arithmetic expansion.  Dequote the resulting WORD_LIST before
2994   returning it, but do not perform word splitting.  The call to
2995   remove_quoted_nulls () is in here because word splitting normally
2996   takes care of quote removal. */
2997WORD_LIST *
2998expand_string_unsplit (string, quoted)
2999     char *string;
3000     int quoted;
3001{
3002  WORD_LIST *value;
3003
3004  if (string == 0 || *string == '\0')
3005    return ((WORD_LIST *)NULL);
3006
3007  expand_no_split_dollar_star = 1;
3008  value = expand_string_internal (string, quoted);
3009  expand_no_split_dollar_star = 0;
3010
3011  if (value)
3012    {
3013      if (value->word)
3014	{
3015	  remove_quoted_nulls (value->word->word);
3016	  value->word->flags &= ~W_HASQUOTEDNULL;
3017	}
3018      dequote_list (value);
3019    }
3020  return (value);
3021}
3022
3023/* Expand the rhs of an assignment statement */
3024WORD_LIST *
3025expand_string_assignment (string, quoted)
3026     char *string;
3027     int quoted;
3028{
3029  WORD_DESC td;
3030  WORD_LIST *value;
3031
3032  if (string == 0 || *string == '\0')
3033    return ((WORD_LIST *)NULL);
3034
3035  expand_no_split_dollar_star = 1;
3036
3037  td.flags = W_ASSIGNRHS;
3038  td.word = savestring (string);
3039  value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3040  FREE (td.word);
3041
3042  expand_no_split_dollar_star = 0;
3043
3044  if (value)
3045    {
3046      if (value->word)
3047	{
3048	  remove_quoted_nulls (value->word->word);
3049	  value->word->flags &= ~W_HASQUOTEDNULL;
3050	}
3051      dequote_list (value);
3052    }
3053  return (value);
3054}
3055
3056
3057/* Expand one of the PS? prompt strings. This is a sort of combination of
3058   expand_string_unsplit and expand_string_internal, but returns the
3059   passed string when an error occurs.  Might want to trap other calls
3060   to jump_to_top_level here so we don't endlessly loop. */
3061WORD_LIST *
3062expand_prompt_string (string, quoted, wflags)
3063     char *string;
3064     int quoted;
3065     int wflags;
3066{
3067  WORD_LIST *value;
3068  WORD_DESC td;
3069
3070  if (string == 0 || *string == 0)
3071    return ((WORD_LIST *)NULL);
3072
3073  td.flags = wflags;
3074  td.word = savestring (string);
3075
3076  no_longjmp_on_fatal_error = 1;
3077  value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3078  no_longjmp_on_fatal_error = 0;
3079
3080  if (value == &expand_word_error || value == &expand_word_fatal)
3081    {
3082      value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
3083      return value;
3084    }
3085  FREE (td.word);
3086  if (value)
3087    {
3088      if (value->word)
3089	{
3090	  remove_quoted_nulls (value->word->word);
3091	  value->word->flags &= ~W_HASQUOTEDNULL;
3092	}
3093      dequote_list (value);
3094    }
3095  return (value);
3096}
3097
3098/* Expand STRING just as if you were expanding a word, but do not dequote
3099   the resultant WORD_LIST.  This is called only from within this file,
3100   and is used to correctly preserve quoted characters when expanding
3101   things like ${1+"$@"}.  This does parameter expansion, command
3102   substitution, arithmetic expansion, and word splitting. */
3103static WORD_LIST *
3104expand_string_leave_quoted (string, quoted)
3105     char *string;
3106     int quoted;
3107{
3108  WORD_LIST *tlist;
3109  WORD_LIST *tresult;
3110
3111  if (string == 0 || *string == '\0')
3112    return ((WORD_LIST *)NULL);
3113
3114  tlist = expand_string_internal (string, quoted);
3115
3116  if (tlist)
3117    {
3118      tresult = word_list_split (tlist);
3119      dispose_words (tlist);
3120      return (tresult);
3121    }
3122  return ((WORD_LIST *)NULL);
3123}
3124
3125/* This does not perform word splitting or dequote the WORD_LIST
3126   it returns. */
3127static WORD_LIST *
3128expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at)
3129     char *string;
3130     int quoted, *dollar_at_p, *has_dollar_at;
3131{
3132  WORD_DESC td;
3133  WORD_LIST *tresult;
3134
3135  if (string == 0 || *string == '\0')
3136    return (WORD_LIST *)NULL;
3137
3138  td.flags = 0;
3139  td.word = string;
3140  tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at);
3141  return (tresult);
3142}
3143
3144/* Expand STRING just as if you were expanding a word.  This also returns
3145   a list of words.  Note that filename globbing is *NOT* done for word
3146   or string expansion, just when the shell is expanding a command.  This
3147   does parameter expansion, command substitution, arithmetic expansion,
3148   and word splitting.  Dequote the resultant WORD_LIST before returning. */
3149WORD_LIST *
3150expand_string (string, quoted)
3151     char *string;
3152     int quoted;
3153{
3154  WORD_LIST *result;
3155
3156  if (string == 0 || *string == '\0')
3157    return ((WORD_LIST *)NULL);
3158
3159  result = expand_string_leave_quoted (string, quoted);
3160  return (result ? dequote_list (result) : result);
3161}
3162
3163/***************************************************
3164 *						   *
3165 *	Functions to handle quoting chars	   *
3166 *						   *
3167 ***************************************************/
3168
3169/* Conventions:
3170
3171     A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
3172     The parser passes CTLNUL as CTLESC CTLNUL. */
3173
3174/* Quote escape characters in string s, but no other characters.  This is
3175   used to protect CTLESC and CTLNUL in variable values from the rest of
3176   the word expansion process after the variable is expanded (word splitting
3177   and filename generation).  If IFS is null, we quote spaces as well, just
3178   in case we split on spaces later (in the case of unquoted $@, we will
3179   eventually attempt to split the entire word on spaces).  Corresponding
3180   code exists in dequote_escapes.  Even if we don't end up splitting on
3181   spaces, quoting spaces is not a problem.  This should never be called on
3182   a string that is quoted with single or double quotes or part of a here
3183   document (effectively double-quoted). */
3184char *
3185quote_escapes (string)
3186     char *string;
3187{
3188  register char *s, *t;
3189  size_t slen;
3190  char *result, *send;
3191  int quote_spaces, skip_ctlesc, skip_ctlnul;
3192  DECLARE_MBSTATE;
3193
3194  slen = strlen (string);
3195  send = string + slen;
3196
3197  quote_spaces = (ifs_value && *ifs_value == 0);
3198
3199  for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
3200    skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
3201
3202  t = result = (char *)xmalloc ((slen * 2) + 1);
3203  s = string;
3204
3205  while (*s)
3206    {
3207      if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
3208	*t++ = CTLESC;
3209      COPY_CHAR_P (t, s, send);
3210    }
3211  *t = '\0';
3212  return (result);
3213}
3214
3215static WORD_LIST *
3216list_quote_escapes (list)
3217     WORD_LIST *list;
3218{
3219  register WORD_LIST *w;
3220  char *t;
3221
3222  for (w = list; w; w = w->next)
3223    {
3224      t = w->word->word;
3225      w->word->word = quote_escapes (t);
3226      free (t);
3227    }
3228  return list;
3229}
3230
3231/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
3232
3233   The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
3234   This is necessary to make unquoted CTLESC and CTLNUL characters in the
3235   data stream pass through properly.
3236
3237   We need to remove doubled CTLESC characters inside quoted strings before
3238   quoting the entire string, so we do not double the number of CTLESC
3239   characters.
3240
3241   Also used by parts of the pattern substitution code. */
3242char *
3243dequote_escapes (string)
3244     char *string;
3245{
3246  register char *s, *t, *s1;
3247  size_t slen;
3248  char *result, *send;
3249  int quote_spaces;
3250  DECLARE_MBSTATE;
3251
3252  if (string == 0)
3253    return string;
3254
3255  slen = strlen (string);
3256  send = string + slen;
3257
3258  t = result = (char *)xmalloc (slen + 1);
3259
3260  if (strchr (string, CTLESC) == 0)
3261    return (strcpy (result, string));
3262
3263  quote_spaces = (ifs_value && *ifs_value == 0);
3264
3265  s = string;
3266  while (*s)
3267    {
3268      if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
3269	{
3270	  s++;
3271	  if (*s == '\0')
3272	    break;
3273	}
3274      COPY_CHAR_P (t, s, send);
3275    }
3276  *t = '\0';
3277  return result;
3278}
3279
3280/* Return a new string with the quoted representation of character C.
3281   This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
3282   set in any resultant WORD_DESC where this value is the word. */
3283static char *
3284make_quoted_char (c)
3285     int c;
3286{
3287  char *temp;
3288
3289  temp = (char *)xmalloc (3);
3290  if (c == 0)
3291    {
3292      temp[0] = CTLNUL;
3293      temp[1] = '\0';
3294    }
3295  else
3296    {
3297      temp[0] = CTLESC;
3298      temp[1] = c;
3299      temp[2] = '\0';
3300    }
3301  return (temp);
3302}
3303
3304/* Quote STRING, returning a new string.  This turns "" into QUOTED_NULL, so
3305   the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
3306   this value is the word. */
3307char *
3308quote_string (string)
3309     char *string;
3310{
3311  register char *t;
3312  size_t slen;
3313  char *result, *send;
3314
3315  if (*string == 0)
3316    {
3317      result = (char *)xmalloc (2);
3318      result[0] = CTLNUL;
3319      result[1] = '\0';
3320    }
3321  else
3322    {
3323      DECLARE_MBSTATE;
3324
3325      slen = strlen (string);
3326      send = string + slen;
3327
3328      result = (char *)xmalloc ((slen * 2) + 1);
3329
3330      for (t = result; string < send; )
3331	{
3332	  *t++ = CTLESC;
3333	  COPY_CHAR_P (t, string, send);
3334	}
3335      *t = '\0';
3336    }
3337  return (result);
3338}
3339
3340/* De-quote quoted characters in STRING. */
3341char *
3342dequote_string (string)
3343     char *string;
3344{
3345  register char *s, *t;
3346  size_t slen;
3347  char *result, *send;
3348  DECLARE_MBSTATE;
3349
3350  slen = strlen (string);
3351
3352  t = result = (char *)xmalloc (slen + 1);
3353
3354  if (QUOTED_NULL (string))
3355    {
3356      result[0] = '\0';
3357      return (result);
3358    }
3359
3360  /* If no character in the string can be quoted, don't bother examining
3361     each character.  Just return a copy of the string passed to us. */
3362  if (strchr (string, CTLESC) == NULL)
3363    return (strcpy (result, string));
3364
3365  send = string + slen;
3366  s = string;
3367  while (*s)
3368    {
3369      if (*s == CTLESC)
3370	{
3371	  s++;
3372	  if (*s == '\0')
3373	    break;
3374	}
3375      COPY_CHAR_P (t, s, send);
3376    }
3377
3378  *t = '\0';
3379  return (result);
3380}
3381
3382/* Quote the entire WORD_LIST list. */
3383static WORD_LIST *
3384quote_list (list)
3385     WORD_LIST *list;
3386{
3387  register WORD_LIST *w;
3388  char *t;
3389
3390  for (w = list; w; w = w->next)
3391    {
3392      t = w->word->word;
3393      w->word->word = quote_string (t);
3394      if (*t == 0)
3395	w->word->flags |= W_HASQUOTEDNULL;	/* XXX - turn on W_HASQUOTEDNULL here? */
3396      w->word->flags |= W_QUOTED;
3397      free (t);
3398    }
3399  return list;
3400}
3401
3402/* De-quote quoted characters in each word in LIST. */
3403WORD_LIST *
3404dequote_list (list)
3405     WORD_LIST *list;
3406{
3407  register char *s;
3408  register WORD_LIST *tlist;
3409
3410  for (tlist = list; tlist; tlist = tlist->next)
3411    {
3412      s = dequote_string (tlist->word->word);
3413      if (QUOTED_NULL (tlist->word->word))
3414	tlist->word->flags &= ~W_HASQUOTEDNULL;
3415      free (tlist->word->word);
3416      tlist->word->word = s;
3417    }
3418  return list;
3419}
3420
3421/* Remove CTLESC protecting a CTLESC or CTLNUL in place.  Return the passed
3422   string. */
3423char *
3424remove_quoted_escapes (string)
3425     char *string;
3426{
3427  char *t;
3428
3429  if (string)
3430    {
3431      t = dequote_escapes (string);
3432      strcpy (string, t);
3433      free (t);
3434    }
3435
3436  return (string);
3437}
3438
3439/* Perform quoted null character removal on STRING.  We don't allow any
3440   quoted null characters in the middle or at the ends of strings because
3441   of how expand_word_internal works.  remove_quoted_nulls () turns
3442   STRING into an empty string iff it only consists of a quoted null,
3443   and removes all unquoted CTLNUL characters. */
3444char *
3445remove_quoted_nulls (string)
3446     char *string;
3447{
3448  register size_t slen;
3449  register int i, j, prev_i;
3450  DECLARE_MBSTATE;
3451
3452  if (strchr (string, CTLNUL) == 0)		/* XXX */
3453    return string;				/* XXX */
3454
3455  slen = strlen (string);
3456  i = j = 0;
3457
3458  while (i < slen)
3459    {
3460      if (string[i] == CTLESC)
3461	{
3462	  /* Old code had j++, but we cannot assume that i == j at this
3463	     point -- what if a CTLNUL has already been removed from the
3464	     string?  We don't want to drop the CTLESC or recopy characters
3465	     that we've already copied down. */
3466	  i++; string[j++] = CTLESC;
3467	  if (i == slen)
3468	    break;
3469	}
3470      else if (string[i] == CTLNUL)
3471	i++;
3472
3473      prev_i = i;
3474      ADVANCE_CHAR (string, slen, i);
3475      if (j < prev_i)
3476	{
3477	  do string[j++] = string[prev_i++]; while (prev_i < i);
3478	}
3479      else
3480	j = i;
3481    }
3482  string[j] = '\0';
3483
3484  return (string);
3485}
3486
3487/* Perform quoted null character removal on each element of LIST.
3488   This modifies LIST. */
3489void
3490word_list_remove_quoted_nulls (list)
3491     WORD_LIST *list;
3492{
3493  register WORD_LIST *t;
3494
3495  for (t = list; t; t = t->next)
3496    {
3497      remove_quoted_nulls (t->word->word);
3498      t->word->flags &= ~W_HASQUOTEDNULL;
3499    }
3500}
3501
3502/* **************************************************************** */
3503/*								    */
3504/*	   Functions for Matching and Removing Patterns		    */
3505/*								    */
3506/* **************************************************************** */
3507
3508#if defined (HANDLE_MULTIBYTE)
3509#if 0 /* Currently unused */
3510static unsigned char *
3511mb_getcharlens (string, len)
3512     char *string;
3513     int len;
3514{
3515  int i, offset, last;
3516  unsigned char *ret;
3517  char *p;
3518  DECLARE_MBSTATE;
3519
3520  i = offset = 0;
3521  last = 0;
3522  ret = (unsigned char *)xmalloc (len);
3523  memset (ret, 0, len);
3524  while (string[last])
3525    {
3526      ADVANCE_CHAR (string, len, offset);
3527      ret[last] = offset - last;
3528      last = offset;
3529    }
3530  return ret;
3531}
3532#endif
3533#endif
3534
3535/* Remove the portion of PARAM matched by PATTERN according to OP, where OP
3536   can have one of 4 values:
3537	RP_LONG_LEFT	remove longest matching portion at start of PARAM
3538	RP_SHORT_LEFT	remove shortest matching portion at start of PARAM
3539	RP_LONG_RIGHT	remove longest matching portion at end of PARAM
3540	RP_SHORT_RIGHT	remove shortest matching portion at end of PARAM
3541*/
3542
3543#define RP_LONG_LEFT	1
3544#define RP_SHORT_LEFT	2
3545#define RP_LONG_RIGHT	3
3546#define RP_SHORT_RIGHT	4
3547
3548static char *
3549remove_upattern (param, pattern, op)
3550     char *param, *pattern;
3551     int op;
3552{
3553  register int len;
3554  register char *end;
3555  register char *p, *ret, c;
3556
3557  len = STRLEN (param);
3558  end = param + len;
3559
3560  switch (op)
3561    {
3562      case RP_LONG_LEFT:	/* remove longest match at start */
3563	for (p = end; p >= param; p--)
3564	  {
3565	    c = *p; *p = '\0';
3566	    if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3567	      {
3568		*p = c;
3569		return (savestring (p));
3570	      }
3571	    *p = c;
3572
3573	  }
3574	break;
3575
3576      case RP_SHORT_LEFT:	/* remove shortest match at start */
3577	for (p = param; p <= end; p++)
3578	  {
3579	    c = *p; *p = '\0';
3580	    if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3581	      {
3582		*p = c;
3583		return (savestring (p));
3584	      }
3585	    *p = c;
3586	  }
3587	break;
3588
3589      case RP_LONG_RIGHT:	/* remove longest match at end */
3590	for (p = param; p <= end; p++)
3591	  {
3592	    if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3593	      {
3594		c = *p; *p = '\0';
3595		ret = savestring (param);
3596		*p = c;
3597		return (ret);
3598	      }
3599	  }
3600	break;
3601
3602      case RP_SHORT_RIGHT:	/* remove shortest match at end */
3603	for (p = end; p >= param; p--)
3604	  {
3605	    if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3606	      {
3607		c = *p; *p = '\0';
3608		ret = savestring (param);
3609		*p = c;
3610		return (ret);
3611	      }
3612	  }
3613	break;
3614    }
3615
3616  return (savestring (param));	/* no match, return original string */
3617}
3618
3619#if defined (HANDLE_MULTIBYTE)
3620static wchar_t *
3621remove_wpattern (wparam, wstrlen, wpattern, op)
3622     wchar_t *wparam;
3623     size_t wstrlen;
3624     wchar_t *wpattern;
3625     int op;
3626{
3627  wchar_t wc, *ret;
3628  int n;
3629
3630  switch (op)
3631    {
3632      case RP_LONG_LEFT:	/* remove longest match at start */
3633        for (n = wstrlen; n >= 0; n--)
3634	  {
3635	    wc = wparam[n]; wparam[n] = L'\0';
3636	    if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3637	      {
3638		wparam[n] = wc;
3639		return (wcsdup (wparam + n));
3640	      }
3641	    wparam[n] = wc;
3642	  }
3643	break;
3644
3645      case RP_SHORT_LEFT:	/* remove shortest match at start */
3646	for (n = 0; n <= wstrlen; n++)
3647	  {
3648	    wc = wparam[n]; wparam[n] = L'\0';
3649	    if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3650	      {
3651		wparam[n] = wc;
3652		return (wcsdup (wparam + n));
3653	      }
3654	    wparam[n] = wc;
3655	  }
3656	break;
3657
3658      case RP_LONG_RIGHT:	/* remove longest match at end */
3659        for (n = 0; n <= wstrlen; n++)
3660	  {
3661	    if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3662	      {
3663		wc = wparam[n]; wparam[n] = L'\0';
3664		ret = wcsdup (wparam);
3665		wparam[n] = wc;
3666		return (ret);
3667	      }
3668	  }
3669	break;
3670
3671      case RP_SHORT_RIGHT:	/* remove shortest match at end */
3672	for (n = wstrlen; n >= 0; n--)
3673	  {
3674	    if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3675	      {
3676		wc = wparam[n]; wparam[n] = L'\0';
3677		ret = wcsdup (wparam);
3678		wparam[n] = wc;
3679		return (ret);
3680	      }
3681	  }
3682	break;
3683    }
3684
3685  return (wcsdup (wparam));	/* no match, return original string */
3686}
3687#endif /* HANDLE_MULTIBYTE */
3688
3689static char *
3690remove_pattern (param, pattern, op)
3691     char *param, *pattern;
3692     int op;
3693{
3694  if (param == NULL)
3695    return (param);
3696  if (*param == '\0' || pattern == NULL || *pattern == '\0')	/* minor optimization */
3697    return (savestring (param));
3698
3699#if defined (HANDLE_MULTIBYTE)
3700  if (MB_CUR_MAX > 1)
3701    {
3702      wchar_t *ret, *oret;
3703      size_t n;
3704      wchar_t *wparam, *wpattern;
3705      mbstate_t ps;
3706      char *xret;
3707
3708      n = xdupmbstowcs (&wpattern, NULL, pattern);
3709      if (n == (size_t)-1)
3710	return (remove_upattern (param, pattern, op));
3711      n = xdupmbstowcs (&wparam, NULL, param);
3712      if (n == (size_t)-1)
3713	{
3714	  free (wpattern);
3715	  return (remove_upattern (param, pattern, op));
3716	}
3717      oret = ret = remove_wpattern (wparam, n, wpattern, op);
3718
3719      free (wparam);
3720      free (wpattern);
3721
3722      n = strlen (param);
3723      xret = (char *)xmalloc (n + 1);
3724      memset (&ps, '\0', sizeof (mbstate_t));
3725      n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
3726      xret[n] = '\0';		/* just to make sure */
3727      free (oret);
3728      return xret;
3729    }
3730  else
3731#endif
3732    return (remove_upattern (param, pattern, op));
3733}
3734
3735/* Return 1 of the first character of STRING could match the first
3736   character of pattern PAT.  Used to avoid n2 calls to strmatch(). */
3737static int
3738match_pattern_char (pat, string)
3739     char *pat, *string;
3740{
3741  char c;
3742
3743  if (*string == 0)
3744    return (0);
3745
3746  switch (c = *pat++)
3747    {
3748    default:
3749      return (*string == c);
3750    case '\\':
3751      return (*string == *pat);
3752    case '?':
3753      return (*pat == LPAREN ? 1 : (*string != '\0'));
3754    case '*':
3755      return (1);
3756    case '+':
3757    case '!':
3758    case '@':
3759      return (*pat == LPAREN ? 1 : (*string == c));
3760    case '[':
3761      return (*string != '\0');
3762    }
3763}
3764
3765/* Match PAT anywhere in STRING and return the match boundaries.
3766   This returns 1 in case of a successful match, 0 otherwise.  SP
3767   and EP are pointers into the string where the match begins and
3768   ends, respectively.  MTYPE controls what kind of match is attempted.
3769   MATCH_BEG and MATCH_END anchor the match at the beginning and end
3770   of the string, respectively.  The longest match is returned. */
3771static int
3772match_upattern (string, pat, mtype, sp, ep)
3773     char *string, *pat;
3774     int mtype;
3775     char **sp, **ep;
3776{
3777  int c, len;
3778  register char *p, *p1, *npat;
3779  char *end;
3780
3781  /* If the pattern doesn't match anywhere in the string, go ahead and
3782     short-circuit right away.  A minor optimization, saves a bunch of
3783     unnecessary calls to strmatch (up to N calls for a string of N
3784     characters) if the match is unsuccessful.  To preserve the semantics
3785     of the substring matches below, we make sure that the pattern has
3786     `*' as first and last character, making a new pattern if necessary. */
3787  /* XXX - check this later if I ever implement `**' with special meaning,
3788     since this will potentially result in `**' at the beginning or end */
3789  len = STRLEN (pat);
3790  if (pat[0] != '*' || (pat[0] == '*' && pat[1] == '(' && extended_glob) || pat[len - 1] != '*')	/*)*/
3791    {
3792      p = npat = (char *)xmalloc (len + 3);
3793      p1 = pat;
3794      if (*p1 != '*' || (*p1 == '*' && p1[1] == '(' && extended_glob))	/*)*/
3795	*p++ = '*';
3796      while (*p1)
3797	*p++ = *p1++;
3798      if (p1[-1] != '*' || p[-2] == '\\')
3799	*p++ = '*';
3800      *p = '\0';
3801    }
3802  else
3803    npat = pat;
3804  c = strmatch (npat, string, FNMATCH_EXTFLAG);
3805  if (npat != pat)
3806    free (npat);
3807  if (c == FNM_NOMATCH)
3808    return (0);
3809
3810  len = STRLEN (string);
3811  end = string + len;
3812
3813  switch (mtype)
3814    {
3815    case MATCH_ANY:
3816      for (p = string; p <= end; p++)
3817	{
3818	  if (match_pattern_char (pat, p))
3819	    {
3820	      for (p1 = end; p1 >= p; p1--)
3821		{
3822		  c = *p1; *p1 = '\0';
3823		  if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
3824		    {
3825		      *p1 = c;
3826		      *sp = p;
3827		      *ep = p1;
3828		      return 1;
3829		    }
3830		  *p1 = c;
3831		}
3832	    }
3833	}
3834
3835      return (0);
3836
3837    case MATCH_BEG:
3838      if (match_pattern_char (pat, string) == 0)
3839	return (0);
3840
3841      for (p = end; p >= string; p--)
3842	{
3843	  c = *p; *p = '\0';
3844	  if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0)
3845	    {
3846	      *p = c;
3847	      *sp = string;
3848	      *ep = p;
3849	      return 1;
3850	    }
3851	  *p = c;
3852	}
3853
3854      return (0);
3855
3856    case MATCH_END:
3857      for (p = string; p <= end; p++)
3858	{
3859	  if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
3860	    {
3861	      *sp = p;
3862	      *ep = end;
3863	      return 1;
3864	    }
3865
3866	}
3867
3868      return (0);
3869    }
3870
3871  return (0);
3872}
3873
3874#if defined (HANDLE_MULTIBYTE)
3875/* Return 1 of the first character of WSTRING could match the first
3876   character of pattern WPAT.  Wide character version. */
3877static int
3878match_pattern_wchar (wpat, wstring)
3879     wchar_t *wpat, *wstring;
3880{
3881  wchar_t wc;
3882
3883  if (*wstring == 0)
3884    return (0);
3885
3886  switch (wc = *wpat++)
3887    {
3888    default:
3889      return (*wstring == wc);
3890    case L'\\':
3891      return (*wstring == *wpat);
3892    case L'?':
3893      return (*wpat == LPAREN ? 1 : (*wstring != L'\0'));
3894    case L'*':
3895      return (1);
3896    case L'+':
3897    case L'!':
3898    case L'@':
3899      return (*wpat == LPAREN ? 1 : (*wstring == wc));
3900    case L'[':
3901      return (*wstring != L'\0');
3902    }
3903}
3904
3905/* Match WPAT anywhere in WSTRING and return the match boundaries.
3906   This returns 1 in case of a successful match, 0 otherwise.  Wide
3907   character version. */
3908static int
3909match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
3910     wchar_t *wstring;
3911     char **indices;
3912     size_t wstrlen;
3913     wchar_t *wpat;
3914     int mtype;
3915     char **sp, **ep;
3916{
3917  wchar_t wc, *wp, *nwpat, *wp1;
3918  int len;
3919#if 0
3920  size_t n, n1;	/* Apple's gcc seems to miscompile this badly */
3921#else
3922  int n, n1;
3923#endif
3924
3925  /* If the pattern doesn't match anywhere in the string, go ahead and
3926     short-circuit right away.  A minor optimization, saves a bunch of
3927     unnecessary calls to strmatch (up to N calls for a string of N
3928     characters) if the match is unsuccessful.  To preserve the semantics
3929     of the substring matches below, we make sure that the pattern has
3930     `*' as first and last character, making a new pattern if necessary. */
3931  /* XXX - check this later if I ever implement `**' with special meaning,
3932     since this will potentially result in `**' at the beginning or end */
3933  len = wcslen (wpat);
3934  if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == L'(' && extended_glob) || wpat[len - 1] != L'*')	/*)*/
3935    {
3936      wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
3937      wp1 = wpat;
3938      if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == '(' && extended_glob))	/*)*/
3939	*wp++ = L'*';
3940      while (*wp1 != L'\0')
3941	*wp++ = *wp1++;
3942      if (wp1[-1] != L'*' || wp1[-2] == L'\\')
3943        *wp++ = L'*';
3944      *wp = '\0';
3945    }
3946  else
3947    nwpat = wpat;
3948  len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG);
3949  if (nwpat != wpat)
3950    free (nwpat);
3951  if (len == FNM_NOMATCH)
3952    return (0);
3953
3954  switch (mtype)
3955    {
3956    case MATCH_ANY:
3957      for (n = 0; n <= wstrlen; n++)
3958	{
3959	  if (match_pattern_wchar (wpat, wstring + n))
3960	    {
3961	      for (n1 = wstrlen; n1 >= n; n1--)
3962		{
3963		  wc = wstring[n1]; wstring[n1] = L'\0';
3964		  if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
3965		    {
3966		      wstring[n1] = wc;
3967		      *sp = indices[n];
3968		      *ep = indices[n1];
3969		      return 1;
3970		    }
3971		  wstring[n1] = wc;
3972		}
3973	    }
3974	}
3975
3976      return (0);
3977
3978    case MATCH_BEG:
3979      if (match_pattern_wchar (wpat, wstring) == 0)
3980	return (0);
3981
3982      for (n = wstrlen; n >= 0; n--)
3983	{
3984	  wc = wstring[n]; wstring[n] = L'\0';
3985	  if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0)
3986	    {
3987	      wstring[n] = wc;
3988	      *sp = indices[0];
3989	      *ep = indices[n];
3990	      return 1;
3991	    }
3992	  wstring[n] = wc;
3993	}
3994
3995      return (0);
3996
3997    case MATCH_END:
3998      for (n = 0; n <= wstrlen; n++)
3999	{
4000	  if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
4001	    {
4002	      *sp = indices[n];
4003	      *ep = indices[wstrlen];
4004	      return 1;
4005	    }
4006	}
4007
4008      return (0);
4009    }
4010
4011  return (0);
4012}
4013#endif /* HANDLE_MULTIBYTE */
4014
4015static int
4016match_pattern (string, pat, mtype, sp, ep)
4017     char *string, *pat;
4018     int mtype;
4019     char **sp, **ep;
4020{
4021#if defined (HANDLE_MULTIBYTE)
4022  int ret;
4023  size_t n;
4024  wchar_t *wstring, *wpat;
4025  char **indices;
4026#endif
4027
4028  if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
4029    return (0);
4030
4031#if defined (HANDLE_MULTIBYTE)
4032  if (MB_CUR_MAX > 1)
4033    {
4034      n = xdupmbstowcs (&wpat, NULL, pat);
4035      if (n == (size_t)-1)
4036	return (match_upattern (string, pat, mtype, sp, ep));
4037      n = xdupmbstowcs (&wstring, &indices, string);
4038      if (n == (size_t)-1)
4039	{
4040	  free (wpat);
4041	  return (match_upattern (string, pat, mtype, sp, ep));
4042	}
4043      ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
4044
4045      free (wpat);
4046      free (wstring);
4047      free (indices);
4048
4049      return (ret);
4050    }
4051  else
4052#endif
4053    return (match_upattern (string, pat, mtype, sp, ep));
4054}
4055
4056static int
4057getpatspec (c, value)
4058     int c;
4059     char *value;
4060{
4061  if (c == '#')
4062    return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
4063  else	/* c == '%' */
4064    return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
4065}
4066
4067/* Posix.2 says that the WORD should be run through tilde expansion,
4068   parameter expansion, command substitution and arithmetic expansion.
4069   This leaves the result quoted, so quote_string_for_globbing () has
4070   to be called to fix it up for strmatch ().  If QUOTED is non-zero,
4071   it means that the entire expression was enclosed in double quotes.
4072   This means that quoting characters in the pattern do not make any
4073   special pattern characters quoted.  For example, the `*' in the
4074   following retains its special meaning: "${foo#'*'}". */
4075static char *
4076getpattern (value, quoted, expandpat)
4077     char *value;
4078     int quoted, expandpat;
4079{
4080  char *pat, *tword;
4081  WORD_LIST *l;
4082#if 0
4083  int i;
4084#endif
4085  /* There is a problem here:  how to handle single or double quotes in the
4086     pattern string when the whole expression is between double quotes?
4087     POSIX.2 says that enclosing double quotes do not cause the pattern to
4088     be quoted, but does that leave us a problem with @ and array[@] and their
4089     expansions inside a pattern? */
4090#if 0
4091  if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
4092    {
4093      i = 0;
4094      pat = string_extract_double_quoted (tword, &i, 1);
4095      free (tword);
4096      tword = pat;
4097    }
4098#endif
4099
4100  /* expand_string_for_rhs () leaves WORD quoted and does not perform
4101     word splitting. */
4102  l = *value ? expand_string_for_rhs (value,
4103				      (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
4104				      (int *)NULL, (int *)NULL)
4105	     : (WORD_LIST *)0;
4106  pat = string_list (l);
4107  dispose_words (l);
4108  if (pat)
4109    {
4110      tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
4111      free (pat);
4112      pat = tword;
4113    }
4114  return (pat);
4115}
4116
4117#if 0
4118/* Handle removing a pattern from a string as a result of ${name%[%]value}
4119   or ${name#[#]value}. */
4120static char *
4121variable_remove_pattern (value, pattern, patspec, quoted)
4122     char *value, *pattern;
4123     int patspec, quoted;
4124{
4125  char *tword;
4126
4127  tword = remove_pattern (value, pattern, patspec);
4128
4129  return (tword);
4130}
4131#endif
4132
4133static char *
4134list_remove_pattern (list, pattern, patspec, itype, quoted)
4135     WORD_LIST *list;
4136     char *pattern;
4137     int patspec, itype, quoted;
4138{
4139  WORD_LIST *new, *l;
4140  WORD_DESC *w;
4141  char *tword;
4142
4143  for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
4144    {
4145      tword = remove_pattern (l->word->word, pattern, patspec);
4146      w = alloc_word_desc ();
4147      w->word = tword ? tword : savestring ("");
4148      new = make_word_list (w, new);
4149    }
4150
4151  l = REVERSE_LIST (new, WORD_LIST *);
4152  tword = string_list_pos_params (itype, l, quoted);
4153  dispose_words (l);
4154
4155  return (tword);
4156}
4157
4158static char *
4159parameter_list_remove_pattern (itype, pattern, patspec, quoted)
4160     int itype;
4161     char *pattern;
4162     int patspec, quoted;
4163{
4164  char *ret;
4165  WORD_LIST *list;
4166
4167  list = list_rest_of_args ();
4168  if (list == 0)
4169    return ((char *)NULL);
4170  ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
4171  dispose_words (list);
4172  return (ret);
4173}
4174
4175#if defined (ARRAY_VARS)
4176static char *
4177array_remove_pattern (var, pattern, patspec, varname, quoted)
4178     SHELL_VAR *var;
4179     char *pattern;
4180     int patspec;
4181     char *varname;	/* so we can figure out how it's indexed */
4182     int quoted;
4183{
4184  ARRAY *a;
4185  HASH_TABLE *h;
4186  int itype;
4187  char *ret;
4188  WORD_LIST *list;
4189  SHELL_VAR *v;
4190
4191  /* compute itype from varname here */
4192  v = array_variable_part (varname, &ret, 0);
4193  itype = ret[0];
4194
4195  a = (v && array_p (v)) ? array_cell (v) : 0;
4196  h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
4197
4198  list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
4199  if (list == 0)
4200   return ((char *)NULL);
4201  ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
4202  dispose_words (list);
4203
4204  return ret;
4205}
4206#endif /* ARRAY_VARS */
4207
4208static char *
4209parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted)
4210     char *varname, *value, *patstr;
4211     int rtype, quoted;
4212{
4213  int vtype, patspec, starsub;
4214  char *temp1, *val, *pattern;
4215  SHELL_VAR *v;
4216
4217  if (value == 0)
4218    return ((char *)NULL);
4219
4220  this_command_name = varname;
4221
4222  vtype = get_var_and_type (varname, value, quoted, &v, &val);
4223  if (vtype == -1)
4224    return ((char *)NULL);
4225
4226  starsub = vtype & VT_STARSUB;
4227  vtype &= ~VT_STARSUB;
4228
4229  patspec = getpatspec (rtype, patstr);
4230  if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
4231    patstr++;
4232
4233  /* Need to pass getpattern newly-allocated memory in case of expansion --
4234     the expansion code will free the passed string on an error. */
4235  temp1 = savestring (patstr);
4236  pattern = getpattern (temp1, quoted, 1);
4237  free (temp1);
4238
4239  temp1 = (char *)NULL;		/* shut up gcc */
4240  switch (vtype)
4241    {
4242    case VT_VARIABLE:
4243    case VT_ARRAYMEMBER:
4244      temp1 = remove_pattern (val, pattern, patspec);
4245      if (vtype == VT_VARIABLE)
4246	FREE (val);
4247      if (temp1)
4248	{
4249	  val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4250			? quote_string (temp1)
4251			: quote_escapes (temp1);
4252	  free (temp1);
4253	  temp1 = val;
4254	}
4255      break;
4256#if defined (ARRAY_VARS)
4257    case VT_ARRAYVAR:
4258      temp1 = array_remove_pattern (v, pattern, patspec, varname, quoted);
4259      if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4260	{
4261	  val = quote_escapes (temp1);
4262	  free (temp1);
4263	  temp1 = val;
4264	}
4265      break;
4266#endif
4267    case VT_POSPARMS:
4268      temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
4269      if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4270	{
4271	  val = quote_escapes (temp1);
4272	  free (temp1);
4273	  temp1 = val;
4274	}
4275      break;
4276    }
4277
4278  FREE (pattern);
4279  return temp1;
4280}
4281
4282/*******************************************
4283 *					   *
4284 *	Functions to expand WORD_DESCs	   *
4285 *					   *
4286 *******************************************/
4287
4288/* Expand WORD, performing word splitting on the result.  This does
4289   parameter expansion, command substitution, arithmetic expansion,
4290   word splitting, and quote removal. */
4291
4292WORD_LIST *
4293expand_word (word, quoted)
4294     WORD_DESC *word;
4295     int quoted;
4296{
4297  WORD_LIST *result, *tresult;
4298
4299  tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4300  result = word_list_split (tresult);
4301  dispose_words (tresult);
4302  return (result ? dequote_list (result) : result);
4303}
4304
4305/* Expand WORD, but do not perform word splitting on the result.  This
4306   does parameter expansion, command substitution, arithmetic expansion,
4307   and quote removal. */
4308WORD_LIST *
4309expand_word_unsplit (word, quoted)
4310     WORD_DESC *word;
4311     int quoted;
4312{
4313  WORD_LIST *result;
4314
4315  expand_no_split_dollar_star = 1;
4316  result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4317  expand_no_split_dollar_star = 0;
4318
4319  return (result ? dequote_list (result) : result);
4320}
4321
4322/* Perform shell expansions on WORD, but do not perform word splitting or
4323   quote removal on the result. */
4324WORD_LIST *
4325expand_word_leave_quoted (word, quoted)
4326     WORD_DESC *word;
4327     int quoted;
4328{
4329  return (call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL));
4330}
4331
4332#if defined (PROCESS_SUBSTITUTION)
4333
4334/*****************************************************************/
4335/*								 */
4336/*		    Hacking Process Substitution		 */
4337/*								 */
4338/*****************************************************************/
4339
4340#if !defined (HAVE_DEV_FD)
4341/* Named pipes must be removed explicitly with `unlink'.  This keeps a list
4342   of FIFOs the shell has open.  unlink_fifo_list will walk the list and
4343   unlink all of them. add_fifo_list adds the name of an open FIFO to the
4344   list.  NFIFO is a count of the number of FIFOs in the list. */
4345#define FIFO_INCR 20
4346
4347struct temp_fifo {
4348  char *file;
4349  pid_t proc;
4350};
4351
4352static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
4353static int nfifo;
4354static int fifo_list_size;
4355
4356static void
4357add_fifo_list (pathname)
4358     char *pathname;
4359{
4360  if (nfifo >= fifo_list_size - 1)
4361    {
4362      fifo_list_size += FIFO_INCR;
4363      fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
4364				fifo_list_size * sizeof (struct temp_fifo));
4365    }
4366
4367  fifo_list[nfifo].file = savestring (pathname);
4368  nfifo++;
4369}
4370
4371void
4372unlink_fifo_list ()
4373{
4374  int saved, i, j;
4375
4376  if (nfifo == 0)
4377    return;
4378
4379  for (i = saved = 0; i < nfifo; i++)
4380    {
4381      if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1))
4382	{
4383	  unlink (fifo_list[i].file);
4384	  free (fifo_list[i].file);
4385	  fifo_list[i].file = (char *)NULL;
4386	  fifo_list[i].proc = -1;
4387	}
4388      else
4389	saved++;
4390    }
4391
4392  /* If we didn't remove some of the FIFOs, compact the list. */
4393  if (saved)
4394    {
4395      for (i = j = 0; i < nfifo; i++)
4396	if (fifo_list[i].file)
4397	  {
4398	    fifo_list[j].file = fifo_list[i].file;
4399	    fifo_list[j].proc = fifo_list[i].proc;
4400	    j++;
4401	  }
4402      nfifo = j;
4403    }
4404  else
4405    nfifo = 0;
4406}
4407
4408int
4409fifos_pending ()
4410{
4411  return nfifo;
4412}
4413
4414static char *
4415make_named_pipe ()
4416{
4417  char *tname;
4418
4419  tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
4420  if (mkfifo (tname, 0600) < 0)
4421    {
4422      free (tname);
4423      return ((char *)NULL);
4424    }
4425
4426  add_fifo_list (tname);
4427  return (tname);
4428}
4429
4430#else /* HAVE_DEV_FD */
4431
4432/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
4433   has open to children.  NFDS is a count of the number of bits currently
4434   set in DEV_FD_LIST.  TOTFDS is a count of the highest possible number
4435   of open files. */
4436static char *dev_fd_list = (char *)NULL;
4437static int nfds;
4438static int totfds;	/* The highest possible number of open files. */
4439
4440static void
4441add_fifo_list (fd)
4442     int fd;
4443{
4444  if (!dev_fd_list || fd >= totfds)
4445    {
4446      int ofds;
4447
4448      ofds = totfds;
4449      totfds = getdtablesize ();
4450      if (totfds < 0 || totfds > 256)
4451	totfds = 256;
4452      if (fd >= totfds)
4453	totfds = fd + 2;
4454
4455      dev_fd_list = (char *)xrealloc (dev_fd_list, totfds);
4456      memset (dev_fd_list + ofds, '\0', totfds - ofds);
4457    }
4458
4459  dev_fd_list[fd] = 1;
4460  nfds++;
4461}
4462
4463int
4464fifos_pending ()
4465{
4466  return 0;	/* used for cleanup; not needed with /dev/fd */
4467}
4468
4469void
4470unlink_fifo_list ()
4471{
4472  register int i;
4473
4474  if (nfds == 0)
4475    return;
4476
4477  for (i = 0; nfds && i < totfds; i++)
4478    if (dev_fd_list[i])
4479      {
4480	close (i);
4481	dev_fd_list[i] = 0;
4482	nfds--;
4483      }
4484
4485  nfds = 0;
4486}
4487
4488#if defined (NOTDEF)
4489print_dev_fd_list ()
4490{
4491  register int i;
4492
4493  fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
4494  fflush (stderr);
4495
4496  for (i = 0; i < totfds; i++)
4497    {
4498      if (dev_fd_list[i])
4499	fprintf (stderr, " %d", i);
4500    }
4501  fprintf (stderr, "\n");
4502}
4503#endif /* NOTDEF */
4504
4505static char *
4506make_dev_fd_filename (fd)
4507     int fd;
4508{
4509  char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
4510
4511  ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
4512
4513  strcpy (ret, DEV_FD_PREFIX);
4514  p = inttostr (fd, intbuf, sizeof (intbuf));
4515  strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
4516
4517  add_fifo_list (fd);
4518  return (ret);
4519}
4520
4521#endif /* HAVE_DEV_FD */
4522
4523/* Return a filename that will open a connection to the process defined by
4524   executing STRING.  HAVE_DEV_FD, if defined, means open a pipe and return
4525   a filename in /dev/fd corresponding to a descriptor that is one of the
4526   ends of the pipe.  If not defined, we use named pipes on systems that have
4527   them.  Systems without /dev/fd and named pipes are out of luck.
4528
4529   OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
4530   use the read end of the pipe and dup that file descriptor to fd 0 in
4531   the child.  If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
4532   writing or use the write end of the pipe in the child, and dup that
4533   file descriptor to fd 1 in the child.  The parent does the opposite. */
4534
4535static char *
4536process_substitute (string, open_for_read_in_child)
4537     char *string;
4538     int open_for_read_in_child;
4539{
4540  char *pathname;
4541  int fd, result;
4542  pid_t old_pid, pid;
4543#if defined (HAVE_DEV_FD)
4544  int parent_pipe_fd, child_pipe_fd;
4545  int fildes[2];
4546#endif /* HAVE_DEV_FD */
4547#if defined (JOB_CONTROL)
4548  pid_t old_pipeline_pgrp;
4549#endif
4550
4551  if (!string || !*string || wordexp_only)
4552    return ((char *)NULL);
4553
4554#if !defined (HAVE_DEV_FD)
4555  pathname = make_named_pipe ();
4556#else /* HAVE_DEV_FD */
4557  if (pipe (fildes) < 0)
4558    {
4559      sys_error (_("cannot make pipe for process substitution"));
4560      return ((char *)NULL);
4561    }
4562  /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
4563     the pipe in the parent, otherwise the read end. */
4564  parent_pipe_fd = fildes[open_for_read_in_child];
4565  child_pipe_fd = fildes[1 - open_for_read_in_child];
4566  /* Move the parent end of the pipe to some high file descriptor, to
4567     avoid clashes with FDs used by the script. */
4568  parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
4569
4570  pathname = make_dev_fd_filename (parent_pipe_fd);
4571#endif /* HAVE_DEV_FD */
4572
4573  if (pathname == 0)
4574    {
4575      sys_error (_("cannot make pipe for process substitution"));
4576      return ((char *)NULL);
4577    }
4578
4579  old_pid = last_made_pid;
4580
4581#if defined (JOB_CONTROL)
4582  old_pipeline_pgrp = pipeline_pgrp;
4583  pipeline_pgrp = shell_pgrp;
4584  save_pipeline (1);
4585#endif /* JOB_CONTROL */
4586
4587  pid = make_child ((char *)NULL, 1);
4588  if (pid == 0)
4589    {
4590      reset_terminating_signals ();	/* XXX */
4591      free_pushed_string_input ();
4592      /* Cancel traps, in trap.c. */
4593      restore_original_signals ();
4594      setup_async_signals ();
4595      subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB;
4596    }
4597
4598#if defined (JOB_CONTROL)
4599  set_sigchld_handler ();
4600  stop_making_children ();
4601  /* XXX - should we only do this in the parent? (as in command subst) */
4602  pipeline_pgrp = old_pipeline_pgrp;
4603#endif /* JOB_CONTROL */
4604
4605  if (pid < 0)
4606    {
4607      sys_error (_("cannot make child for process substitution"));
4608      free (pathname);
4609#if defined (HAVE_DEV_FD)
4610      close (parent_pipe_fd);
4611      close (child_pipe_fd);
4612#endif /* HAVE_DEV_FD */
4613      return ((char *)NULL);
4614    }
4615
4616  if (pid > 0)
4617    {
4618#if defined (JOB_CONTROL)
4619      restore_pipeline (1);
4620#endif
4621
4622#if !defined (HAVE_DEV_FD)
4623      fifo_list[nfifo-1].proc = pid;
4624#endif
4625
4626      last_made_pid = old_pid;
4627
4628#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
4629      close_pgrp_pipe ();
4630#endif /* JOB_CONTROL && PGRP_PIPE */
4631
4632#if defined (HAVE_DEV_FD)
4633      close (child_pipe_fd);
4634#endif /* HAVE_DEV_FD */
4635
4636      return (pathname);
4637    }
4638
4639  set_sigint_handler ();
4640
4641#if defined (JOB_CONTROL)
4642  set_job_control (0);
4643#endif /* JOB_CONTROL */
4644
4645#if !defined (HAVE_DEV_FD)
4646  /* Open the named pipe in the child. */
4647  fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY);
4648  if (fd < 0)
4649    {
4650      /* Two separate strings for ease of translation. */
4651      if (open_for_read_in_child)
4652	sys_error (_("cannot open named pipe %s for reading"), pathname);
4653      else
4654	sys_error (_("cannot open named pipe %s for writing"), pathname);
4655
4656      exit (127);
4657    }
4658  if (open_for_read_in_child)
4659    {
4660      if (sh_unset_nodelay_mode (fd) < 0)
4661	{
4662	  sys_error (_("cannot reset nodelay mode for fd %d"), fd);
4663	  exit (127);
4664	}
4665    }
4666#else /* HAVE_DEV_FD */
4667  fd = child_pipe_fd;
4668#endif /* HAVE_DEV_FD */
4669
4670  if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
4671    {
4672      sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
4673	open_for_read_in_child ? 0 : 1);
4674      exit (127);
4675    }
4676
4677  if (fd != (open_for_read_in_child ? 0 : 1))
4678    close (fd);
4679
4680  /* Need to close any files that this process has open to pipes inherited
4681     from its parent. */
4682  if (current_fds_to_close)
4683    {
4684      close_fd_bitmap (current_fds_to_close);
4685      current_fds_to_close = (struct fd_bitmap *)NULL;
4686    }
4687
4688#if defined (HAVE_DEV_FD)
4689  /* Make sure we close the parent's end of the pipe and clear the slot
4690     in the fd list so it is not closed later, if reallocated by, for
4691     instance, pipe(2). */
4692  close (parent_pipe_fd);
4693  dev_fd_list[parent_pipe_fd] = 0;
4694#endif /* HAVE_DEV_FD */
4695
4696  result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
4697
4698#if !defined (HAVE_DEV_FD)
4699  /* Make sure we close the named pipe in the child before we exit. */
4700  close (open_for_read_in_child ? 0 : 1);
4701#endif /* !HAVE_DEV_FD */
4702
4703  exit (result);
4704  /*NOTREACHED*/
4705}
4706#endif /* PROCESS_SUBSTITUTION */
4707
4708/***********************************/
4709/*				   */
4710/*	Command Substitution	   */
4711/*				   */
4712/***********************************/
4713
4714static char *
4715read_comsub (fd, quoted, rflag)
4716     int fd, quoted;
4717     int *rflag;
4718{
4719  char *istring, buf[128], *bufp, *s;
4720  int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul;
4721  ssize_t bufn;
4722
4723  istring = (char *)NULL;
4724  istring_index = istring_size = bufn = tflag = 0;
4725
4726  for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
4727    skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
4728
4729#ifdef __CYGWIN__
4730  setmode (fd, O_TEXT);		/* we don't want CR/LF, we want Unix-style */
4731#endif
4732
4733  /* Read the output of the command through the pipe.  This may need to be
4734     changed to understand multibyte characters in the future. */
4735  while (1)
4736    {
4737      if (fd < 0)
4738	break;
4739      if (--bufn <= 0)
4740	{
4741	  bufn = zread (fd, buf, sizeof (buf));
4742	  if (bufn <= 0)
4743	    break;
4744	  bufp = buf;
4745	}
4746      c = *bufp++;
4747
4748      if (c == 0)
4749	{
4750#if 0
4751	  internal_warning ("read_comsub: ignored null byte in input");
4752#endif
4753	  continue;
4754	}
4755
4756      /* Add the character to ISTRING, possibly after resizing it. */
4757      RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
4758
4759      /* This is essentially quote_string inline */
4760      if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
4761	istring[istring_index++] = CTLESC;
4762      /* Escape CTLESC and CTLNUL in the output to protect those characters
4763	 from the rest of the word expansions (word splitting and globbing.)
4764	 This is essentially quote_escapes inline. */
4765      else if (skip_ctlesc == 0 && c == CTLESC)
4766	{
4767	  tflag |= W_HASCTLESC;
4768	  istring[istring_index++] = CTLESC;
4769	}
4770      else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
4771	istring[istring_index++] = CTLESC;
4772
4773      istring[istring_index++] = c;
4774
4775#if 0
4776#if defined (__CYGWIN__)
4777      if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r')
4778	{
4779	  istring_index--;
4780	  istring[istring_index - 1] = '\n';
4781	}
4782#endif
4783#endif
4784    }
4785
4786  if (istring)
4787    istring[istring_index] = '\0';
4788
4789  /* If we read no output, just return now and save ourselves some
4790     trouble. */
4791  if (istring_index == 0)
4792    {
4793      FREE (istring);
4794      if (rflag)
4795	*rflag = tflag;
4796      return (char *)NULL;
4797    }
4798
4799  /* Strip trailing newlines from the output of the command. */
4800  if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4801    {
4802      while (istring_index > 0)
4803	{
4804	  if (istring[istring_index - 1] == '\n')
4805	    {
4806	      --istring_index;
4807
4808	      /* If the newline was quoted, remove the quoting char. */
4809	      if (istring[istring_index - 1] == CTLESC)
4810		--istring_index;
4811	    }
4812	  else
4813	    break;
4814	}
4815      istring[istring_index] = '\0';
4816    }
4817  else
4818    strip_trailing (istring, istring_index - 1, 1);
4819
4820  if (rflag)
4821    *rflag = tflag;
4822  return istring;
4823}
4824
4825/* Perform command substitution on STRING.  This returns a WORD_DESC * with the
4826   contained string possibly quoted. */
4827WORD_DESC *
4828command_substitute (string, quoted)
4829     char *string;
4830     int quoted;
4831{
4832  pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
4833  char *istring;
4834  int result, fildes[2], function_value, pflags, rc, tflag;
4835  WORD_DESC *ret;
4836
4837  istring = (char *)NULL;
4838
4839  /* Don't fork () if there is no need to.  In the case of no command to
4840     run, just return NULL. */
4841  if (!string || !*string || (string[0] == '\n' && !string[1]))
4842    return ((WORD_DESC *)NULL);
4843
4844  if (wordexp_only && read_but_dont_execute)
4845    {
4846      last_command_exit_value = 125;
4847      jump_to_top_level (EXITPROG);
4848    }
4849
4850  /* We're making the assumption here that the command substitution will
4851     eventually run a command from the file system.  Since we'll run
4852     maybe_make_export_env in this subshell before executing that command,
4853     the parent shell and any other shells it starts will have to remake
4854     the environment.  If we make it before we fork, other shells won't
4855     have to.  Don't bother if we have any temporary variable assignments,
4856     though, because the export environment will be remade after this
4857     command completes anyway, but do it if all the words to be expanded
4858     are variable assignments. */
4859  if (subst_assign_varlist == 0 || garglist == 0)
4860    maybe_make_export_env ();	/* XXX */
4861
4862  /* Flags to pass to parse_and_execute() */
4863  pflags = interactive ? SEVAL_RESETLINE : 0;
4864
4865  /* Pipe the output of executing STRING into the current shell. */
4866  if (pipe (fildes) < 0)
4867    {
4868      sys_error (_("cannot make pipe for command substitution"));
4869      goto error_exit;
4870    }
4871
4872  old_pid = last_made_pid;
4873#if defined (JOB_CONTROL)
4874  old_pipeline_pgrp = pipeline_pgrp;
4875  /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */
4876  if ((subshell_environment & SUBSHELL_PIPE) == 0)
4877    pipeline_pgrp = shell_pgrp;
4878  cleanup_the_pipeline ();
4879#endif /* JOB_CONTROL */
4880
4881  old_async_pid = last_asynchronous_pid;
4882  pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC);
4883  last_asynchronous_pid = old_async_pid;
4884
4885  if (pid == 0)
4886    /* Reset the signal handlers in the child, but don't free the
4887       trap strings. */
4888    reset_signal_handlers ();
4889
4890#if defined (JOB_CONTROL)
4891  /* XXX DO THIS ONLY IN PARENT ? XXX */
4892  set_sigchld_handler ();
4893  stop_making_children ();
4894  if (pid != 0)
4895    pipeline_pgrp = old_pipeline_pgrp;
4896#else
4897  stop_making_children ();
4898#endif /* JOB_CONTROL */
4899
4900  if (pid < 0)
4901    {
4902      sys_error (_("cannot make child for command substitution"));
4903    error_exit:
4904
4905      FREE (istring);
4906      close (fildes[0]);
4907      close (fildes[1]);
4908      return ((WORD_DESC *)NULL);
4909    }
4910
4911  if (pid == 0)
4912    {
4913      set_sigint_handler ();	/* XXX */
4914
4915      free_pushed_string_input ();
4916
4917      if (dup2 (fildes[1], 1) < 0)
4918	{
4919	  sys_error (_("command_substitute: cannot duplicate pipe as fd 1"));
4920	  exit (EXECUTION_FAILURE);
4921	}
4922
4923      /* If standard output is closed in the parent shell
4924	 (such as after `exec >&-'), file descriptor 1 will be
4925	 the lowest available file descriptor, and end up in
4926	 fildes[0].  This can happen for stdin and stderr as well,
4927	 but stdout is more important -- it will cause no output
4928	 to be generated from this command. */
4929      if ((fildes[1] != fileno (stdin)) &&
4930	  (fildes[1] != fileno (stdout)) &&
4931	  (fildes[1] != fileno (stderr)))
4932	close (fildes[1]);
4933
4934      if ((fildes[0] != fileno (stdin)) &&
4935	  (fildes[0] != fileno (stdout)) &&
4936	  (fildes[0] != fileno (stderr)))
4937	close (fildes[0]);
4938
4939      /* The currently executing shell is not interactive. */
4940      interactive = 0;
4941
4942      /* This is a subshell environment. */
4943      subshell_environment |= SUBSHELL_COMSUB;
4944
4945      /* When not in POSIX mode, command substitution does not inherit
4946	 the -e flag. */
4947      if (posixly_correct == 0)
4948	exit_immediately_on_error = 0;
4949
4950      remove_quoted_escapes (string);
4951
4952      startup_state = 2;	/* see if we can avoid a fork */
4953      /* Give command substitution a place to jump back to on failure,
4954	 so we don't go back up to main (). */
4955      result = setjmp (top_level);
4956
4957      /* If we're running a command substitution inside a shell function,
4958	 trap `return' so we don't return from the function in the subshell
4959	 and go off to never-never land. */
4960      if (result == 0 && return_catch_flag)
4961	function_value = setjmp (return_catch);
4962      else
4963	function_value = 0;
4964
4965      if (result == ERREXIT)
4966	rc = last_command_exit_value;
4967      else if (result == EXITPROG)
4968	rc = last_command_exit_value;
4969      else if (result)
4970	rc = EXECUTION_FAILURE;
4971      else if (function_value)
4972	rc = return_catch_value;
4973      else
4974	{
4975	  subshell_level++;
4976	  rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
4977	  subshell_level--;
4978	}
4979
4980      last_command_exit_value = rc;
4981      rc = run_exit_trap ();
4982#if defined (PROCESS_SUBSTITUTION)
4983      unlink_fifo_list ();
4984#endif
4985      exit (rc);
4986    }
4987  else
4988    {
4989#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
4990      close_pgrp_pipe ();
4991#endif /* JOB_CONTROL && PGRP_PIPE */
4992
4993      close (fildes[1]);
4994
4995      tflag = 0;
4996      istring = read_comsub (fildes[0], quoted, &tflag);
4997
4998      close (fildes[0]);
4999
5000      current_command_subst_pid = pid;
5001      last_command_exit_value = wait_for (pid);
5002      last_command_subst_pid = pid;
5003      last_made_pid = old_pid;
5004
5005#if defined (JOB_CONTROL)
5006      /* If last_command_exit_value > 128, then the substituted command
5007	 was terminated by a signal.  If that signal was SIGINT, then send
5008	 SIGINT to ourselves.  This will break out of loops, for instance. */
5009      if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
5010	kill (getpid (), SIGINT);
5011
5012      /* wait_for gives the terminal back to shell_pgrp.  If some other
5013	 process group should have it, give it away to that group here.
5014	 pipeline_pgrp is non-zero only while we are constructing a
5015	 pipline, so what we are concerned about is whether or not that
5016	 pipeline was started in the background.  A pipeline started in
5017	 the background should never get the tty back here. */
5018#if 0
5019      if (interactive && pipeline_pgrp != (pid_t)0 && pipeline_pgrp != last_asynchronous_pid)
5020#else
5021      if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0)
5022#endif
5023	give_terminal_to (pipeline_pgrp, 0);
5024#endif /* JOB_CONTROL */
5025
5026      ret = alloc_word_desc ();
5027      ret->word = istring;
5028      ret->flags = tflag;
5029
5030      return ret;
5031    }
5032}
5033
5034/********************************************************
5035 *							*
5036 *	Utility functions for parameter expansion	*
5037 *							*
5038 ********************************************************/
5039
5040#if defined (ARRAY_VARS)
5041
5042static arrayind_t
5043array_length_reference (s)
5044     char *s;
5045{
5046  int len;
5047  arrayind_t ind;
5048  char *akey;
5049  char *t, c;
5050  ARRAY *array;
5051  SHELL_VAR *var;
5052
5053  var = array_variable_part (s, &t, &len);
5054
5055  /* If unbound variables should generate an error, report one and return
5056     failure. */
5057  if ((var == 0 || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
5058    {
5059      c = *--t;
5060      *t = '\0';
5061      err_unboundvar (s);
5062      *t = c;
5063      return (-1);
5064    }
5065  else if (var == 0)
5066    return 0;
5067
5068  /* We support a couple of expansions for variables that are not arrays.
5069     We'll return the length of the value for v[0], and 1 for v[@] or
5070     v[*].  Return 0 for everything else. */
5071
5072  array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
5073
5074  if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
5075    {
5076      if (assoc_p (var))
5077	return (assoc_num_elements (assoc_cell (var)));
5078      else if (array_p (var))
5079	return (array_num_elements (array));
5080      else
5081	return 1;
5082    }
5083
5084  if (assoc_p (var))
5085    {
5086      t[len - 1] = '\0';
5087      akey = expand_assignment_string_to_string (t, 0);	/* [ */
5088      t[len - 1] = ']';
5089      if (akey == 0 || *akey == 0)
5090	{
5091	  err_badarraysub (t);
5092	  return (-1);
5093	}
5094      t = assoc_reference (assoc_cell (var), akey);
5095    }
5096  else
5097    {
5098      ind = array_expand_index (t, len);
5099      if (ind < 0)
5100	{
5101	  err_badarraysub (t);
5102	  return (-1);
5103	}
5104      if (array_p (var))
5105	t = array_reference (array, ind);
5106      else
5107	t = (ind == 0) ? value_cell (var) : (char *)NULL;
5108    }
5109
5110  len = MB_STRLEN (t);
5111  return (len);
5112}
5113#endif /* ARRAY_VARS */
5114
5115static int
5116valid_brace_expansion_word (name, var_is_special)
5117     char *name;
5118     int var_is_special;
5119{
5120  if (DIGIT (*name) && all_digits (name))
5121    return 1;
5122  else if (var_is_special)
5123    return 1;
5124#if defined (ARRAY_VARS)
5125  else if (valid_array_reference (name))
5126    return 1;
5127#endif /* ARRAY_VARS */
5128  else if (legal_identifier (name))
5129    return 1;
5130  else
5131    return 0;
5132}
5133
5134static int
5135chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at)
5136     char *name;
5137     int quoted;
5138     int *quoted_dollar_atp, *contains_dollar_at;
5139{
5140  char *temp1;
5141
5142  if (name == 0)
5143    {
5144      if (quoted_dollar_atp)
5145	*quoted_dollar_atp = 0;
5146      if (contains_dollar_at)
5147	*contains_dollar_at = 0;
5148      return 0;
5149    }
5150
5151  /* check for $@ and $* */
5152  if (name[0] == '@' && name[1] == 0)
5153    {
5154      if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5155	*quoted_dollar_atp = 1;
5156      if (contains_dollar_at)
5157	*contains_dollar_at = 1;
5158      return 1;
5159    }
5160  else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
5161    {
5162      if (contains_dollar_at)
5163	*contains_dollar_at = 1;
5164      return 1;
5165    }
5166
5167  /* Now check for ${array[@]} and ${array[*]} */
5168#if defined (ARRAY_VARS)
5169  else if (valid_array_reference (name))
5170    {
5171      temp1 = xstrchr (name, '[');
5172      if (temp1 && temp1[1] == '@' && temp1[2] == ']')
5173	{
5174	  if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5175	    *quoted_dollar_atp = 1;
5176	  if (contains_dollar_at)
5177	    *contains_dollar_at = 1;
5178	  return 1;
5179	}	/* [ */
5180      /* ${array[*]}, when unquoted, should be treated like ${array[@]},
5181	 which should result in separate words even when IFS is unset. */
5182      if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0)
5183	{
5184	  if (contains_dollar_at)
5185	    *contains_dollar_at = 1;
5186	  return 1;
5187	}
5188    }
5189#endif
5190  return 0;
5191}
5192
5193/* Parameter expand NAME, and return a new string which is the expansion,
5194   or NULL if there was no expansion.
5195   VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
5196   the shell, e.g., "@", "$", "*", etc.  QUOTED, if non-zero, means that
5197   NAME was found inside of a double-quoted expression. */
5198static WORD_DESC *
5199parameter_brace_expand_word (name, var_is_special, quoted, pflags)
5200     char *name;
5201     int var_is_special, quoted, pflags;
5202{
5203  WORD_DESC *ret;
5204  char *temp, *tt;
5205  intmax_t arg_index;
5206  SHELL_VAR *var;
5207  int atype, rflags;
5208
5209  ret = 0;
5210  temp = 0;
5211  rflags = 0;
5212
5213  /* Handle multiple digit arguments, as in ${11}. */
5214  if (legal_number (name, &arg_index))
5215    {
5216      tt = get_dollar_var_value (arg_index);
5217      if (tt)
5218 	temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5219 		  ? quote_string (tt)
5220 		  : quote_escapes (tt);
5221      else
5222        temp = (char *)NULL;
5223      FREE (tt);
5224    }
5225  else if (var_is_special)      /* ${@} */
5226    {
5227      int sindex;
5228      tt = (char *)xmalloc (2 + strlen (name));
5229      tt[sindex = 0] = '$';
5230      strcpy (tt + 1, name);
5231
5232      ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
5233			  (int *)NULL, (int *)NULL, pflags);
5234      free (tt);
5235    }
5236#if defined (ARRAY_VARS)
5237  else if (valid_array_reference (name))
5238    {
5239      temp = array_value (name, quoted, &atype);
5240      if (atype == 0 && temp)
5241 	temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5242 		  ? quote_string (temp)
5243 		  : quote_escapes (temp);
5244      else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5245	rflags |= W_HASQUOTEDNULL;
5246    }
5247#endif
5248  else if (var = find_variable (name))
5249    {
5250      if (var_isset (var) && invisible_p (var) == 0)
5251	{
5252#if defined (ARRAY_VARS)
5253	  if (assoc_p (var))
5254	    temp = assoc_reference (assoc_cell (var), "0");
5255	  else if (array_p (var))
5256	    temp = array_reference (array_cell (var), 0);
5257	  else
5258	    temp = value_cell (var);
5259#else
5260	  temp = value_cell (var);
5261#endif
5262
5263	  if (temp)
5264	    temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5265		      ? quote_string (temp)
5266		      : quote_escapes (temp);
5267	}
5268      else
5269	temp = (char *)NULL;
5270    }
5271  else
5272    temp = (char *)NULL;
5273
5274  if (ret == 0)
5275    {
5276      ret = alloc_word_desc ();
5277      ret->word = temp;
5278      ret->flags |= rflags;
5279    }
5280  return ret;
5281}
5282
5283/* Expand an indirect reference to a variable: ${!NAME} expands to the
5284   value of the variable whose name is the value of NAME. */
5285static WORD_DESC *
5286parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at)
5287     char *name;
5288     int var_is_special, quoted;
5289     int *quoted_dollar_atp, *contains_dollar_at;
5290{
5291  char *temp, *t;
5292  WORD_DESC *w;
5293
5294  w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND);
5295  t = w->word;
5296  /* Have to dequote here if necessary */
5297  if (t)
5298    {
5299      temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
5300		? dequote_string (t)
5301		: dequote_escapes (t);
5302      free (t);
5303      t = temp;
5304    }
5305  dispose_word_desc (w);
5306
5307  chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at);
5308  if (t == 0)
5309    return (WORD_DESC *)NULL;
5310
5311  w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0);
5312  free (t);
5313
5314  return w;
5315}
5316
5317/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
5318   depending on the value of C, the separating character.  C can be one of
5319   "-", "+", or "=".  QUOTED is true if the entire brace expression occurs
5320   between double quotes. */
5321static WORD_DESC *
5322parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
5323     char *name, *value;
5324     int c, quoted, *qdollaratp, *hasdollarat;
5325{
5326  WORD_DESC *w;
5327  WORD_LIST *l;
5328  char *t, *t1, *temp;
5329  int hasdol;
5330
5331  /* If the entire expression is between double quotes, we want to treat
5332     the value as a double-quoted string, with the exception that we strip
5333     embedded unescaped double quotes (for sh backwards compatibility). */
5334  if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
5335    {
5336      hasdol = 0;
5337      temp = string_extract_double_quoted (value, &hasdol, 1);
5338    }
5339  else
5340    temp = value;
5341
5342  w = alloc_word_desc ();
5343  hasdol = 0;
5344  /* XXX was 0 not quoted */
5345  l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL)
5346	    : (WORD_LIST *)0;
5347  if (hasdollarat)
5348    *hasdollarat = hasdol || (l && l->next);
5349  if (temp != value)
5350    free (temp);
5351  if (l)
5352    {
5353      /* The expansion of TEMP returned something.  We need to treat things
5354	  slightly differently if HASDOL is non-zero.  If we have "$@", the
5355	  individual words have already been quoted.  We need to turn them
5356	  into a string with the words separated by the first character of
5357	  $IFS without any additional quoting, so string_list_dollar_at won't
5358	  do the right thing.  We use string_list_dollar_star instead. */
5359      temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l);
5360
5361      /* If l->next is not null, we know that TEMP contained "$@", since that
5362	 is the only expansion that creates more than one word. */
5363      if (qdollaratp && ((hasdol && quoted) || l->next))
5364	*qdollaratp = 1;
5365      dispose_words (l);
5366    }
5367  else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol)
5368    {
5369      /* The brace expansion occurred between double quotes and there was
5370	 a $@ in TEMP.  It does not matter if the $@ is quoted, as long as
5371	 it does not expand to anything.  In this case, we want to return
5372	 a quoted empty string. */
5373      temp = make_quoted_char ('\0');
5374      w->flags |= W_HASQUOTEDNULL;
5375    }
5376  else
5377    temp = (char *)NULL;
5378
5379  if (c == '-' || c == '+')
5380    {
5381      w->word = temp;
5382      return w;
5383    }
5384
5385  /* c == '=' */
5386  t = temp ? savestring (temp) : savestring ("");
5387  t1 = dequote_string (t);
5388  free (t);
5389#if defined (ARRAY_VARS)
5390  if (valid_array_reference (name))
5391    assign_array_element (name, t1, 0);
5392  else
5393#endif /* ARRAY_VARS */
5394  bind_variable (name, t1, 0);
5395  free (t1);
5396
5397  w->word = temp;
5398  return w;
5399}
5400
5401/* Deal with the right hand side of a ${name:?value} expansion in the case
5402   that NAME is null or not set.  If VALUE is non-null it is expanded and
5403   used as the error message to print, otherwise a standard message is
5404   printed. */
5405static void
5406parameter_brace_expand_error (name, value)
5407     char *name, *value;
5408{
5409  WORD_LIST *l;
5410  char *temp;
5411
5412  if (value && *value)
5413    {
5414      l = expand_string (value, 0);
5415      temp =  string_list (l);
5416      report_error ("%s: %s", name, temp ? temp : "");	/* XXX was value not "" */
5417      FREE (temp);
5418      dispose_words (l);
5419    }
5420  else
5421    report_error (_("%s: parameter null or not set"), name);
5422
5423  /* Free the data we have allocated during this expansion, since we
5424     are about to longjmp out. */
5425  free (name);
5426  FREE (value);
5427}
5428
5429/* Return 1 if NAME is something for which parameter_brace_expand_length is
5430   OK to do. */
5431static int
5432valid_length_expression (name)
5433     char *name;
5434{
5435  return (name[1] == '\0' ||					/* ${#} */
5436	  ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') ||  /* special param */
5437	  (DIGIT (name[1]) && all_digits (name + 1)) ||	/* ${#11} */
5438#if defined (ARRAY_VARS)
5439	  valid_array_reference (name + 1) ||			/* ${#a[7]} */
5440#endif
5441	  legal_identifier (name + 1));				/* ${#PS1} */
5442}
5443
5444#if defined (HANDLE_MULTIBYTE)
5445size_t
5446mbstrlen (s)
5447     const char *s;
5448{
5449  size_t clen, nc;
5450  mbstate_t mbs, mbsbak;
5451
5452  nc = 0;
5453  memset (&mbs, 0, sizeof (mbs));
5454  mbsbak = mbs;
5455  while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0)
5456    {
5457      if (MB_INVALIDCH(clen))
5458        {
5459	  clen = 1;	/* assume single byte */
5460	  mbs = mbsbak;
5461        }
5462
5463      s += clen;
5464      nc++;
5465      mbsbak = mbs;
5466    }
5467  return nc;
5468}
5469#endif
5470
5471
5472/* Handle the parameter brace expansion that requires us to return the
5473   length of a parameter. */
5474static intmax_t
5475parameter_brace_expand_length (name)
5476     char *name;
5477{
5478  char *t, *newname;
5479  intmax_t number, arg_index;
5480  WORD_LIST *list;
5481#if defined (ARRAY_VARS)
5482  SHELL_VAR *var;
5483#endif
5484
5485  if (name[1] == '\0')			/* ${#} */
5486    number = number_of_args ();
5487  else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0')	/* ${#@}, ${#*} */
5488    number = number_of_args ();
5489  else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
5490    {
5491      /* Take the lengths of some of the shell's special parameters. */
5492      switch (name[1])
5493	{
5494	case '-':
5495	  t = which_set_flags ();
5496	  break;
5497	case '?':
5498	  t = itos (last_command_exit_value);
5499	  break;
5500	case '$':
5501	  t = itos (dollar_dollar_pid);
5502	  break;
5503	case '!':
5504	  if (last_asynchronous_pid == NO_PID)
5505	    t = (char *)NULL;
5506	  else
5507	    t = itos (last_asynchronous_pid);
5508	  break;
5509	case '#':
5510	  t = itos (number_of_args ());
5511	  break;
5512	}
5513      number = STRLEN (t);
5514      FREE (t);
5515    }
5516#if defined (ARRAY_VARS)
5517  else if (valid_array_reference (name + 1))
5518    number = array_length_reference (name + 1);
5519#endif /* ARRAY_VARS */
5520  else
5521    {
5522      number = 0;
5523
5524      if (legal_number (name + 1, &arg_index))		/* ${#1} */
5525	{
5526	  t = get_dollar_var_value (arg_index);
5527	  number = MB_STRLEN (t);
5528	  FREE (t);
5529	}
5530#if defined (ARRAY_VARS)
5531      else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
5532	{
5533	  if (assoc_p (var))
5534	    t = assoc_reference (assoc_cell (var), "0");
5535	  else
5536	    t = array_reference (array_cell (var), 0);
5537	  number = MB_STRLEN (t);
5538	}
5539#endif
5540      else				/* ${#PS1} */
5541	{
5542	  newname = savestring (name);
5543	  newname[0] = '$';
5544	  list = expand_string (newname, Q_DOUBLE_QUOTES);
5545	  t = list ? string_list (list) : (char *)NULL;
5546	  free (newname);
5547	  if (list)
5548	    dispose_words (list);
5549
5550	  number = MB_STRLEN (t);
5551	  FREE (t);
5552	}
5553    }
5554
5555  return (number);
5556}
5557
5558/* Skip characters in SUBSTR until DELIM.  SUBSTR is an arithmetic expression,
5559   so we do some ad-hoc parsing of an arithmetic expression to find
5560   the first DELIM, instead of using strchr(3).  Two rules:
5561	1.  If the substring contains a `(', read until closing `)'.
5562	2.  If the substring contains a `?', read past one `:' for each `?'.
5563*/
5564
5565static char *
5566skiparith (substr, delim)
5567     char *substr;
5568     int delim;
5569{
5570  size_t sublen;
5571  int skipcol, pcount, i;
5572  DECLARE_MBSTATE;
5573
5574  sublen = strlen (substr);
5575  i = skipcol = pcount = 0;
5576  while (substr[i])
5577    {
5578      /* Balance parens */
5579      if (substr[i] == LPAREN)
5580	{
5581	  pcount++;
5582	  i++;
5583	  continue;
5584	}
5585      if (substr[i] == RPAREN && pcount)
5586	{
5587	  pcount--;
5588	  i++;
5589	  continue;
5590	}
5591      if (pcount)
5592	{
5593	  ADVANCE_CHAR (substr, sublen, i);
5594	  continue;
5595	}
5596
5597      /* Skip one `:' for each `?' */
5598      if (substr[i] == ':' && skipcol)
5599	{
5600	  skipcol--;
5601	  i++;
5602	  continue;
5603	}
5604      if (substr[i] == delim)
5605	break;
5606      if (substr[i] == '?')
5607	{
5608	  skipcol++;
5609	  i++;
5610	  continue;
5611	}
5612      ADVANCE_CHAR (substr, sublen, i);
5613    }
5614
5615  return (substr + i);
5616}
5617
5618/* Verify and limit the start and end of the desired substring.  If
5619   VTYPE == 0, a regular shell variable is being used; if it is 1,
5620   then the positional parameters are being used; if it is 2, then
5621   VALUE is really a pointer to an array variable that should be used.
5622   Return value is 1 if both values were OK, 0 if there was a problem
5623   with an invalid expression, or -1 if the values were out of range. */
5624static int
5625verify_substring_values (v, value, substr, vtype, e1p, e2p)
5626     SHELL_VAR *v;
5627     char *value, *substr;
5628     int vtype;
5629     intmax_t *e1p, *e2p;
5630{
5631  char *t, *temp1, *temp2;
5632  arrayind_t len;
5633  int expok;
5634#if defined (ARRAY_VARS)
5635 ARRAY *a;
5636 HASH_TABLE *h;
5637#endif
5638
5639  /* duplicate behavior of strchr(3) */
5640  t = skiparith (substr, ':');
5641  if (*t && *t == ':')
5642    *t = '\0';
5643  else
5644    t = (char *)0;
5645
5646  temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES);
5647  *e1p = evalexp (temp1, &expok);
5648  free (temp1);
5649  if (expok == 0)
5650    return (0);
5651
5652  len = -1;	/* paranoia */
5653  switch (vtype)
5654    {
5655    case VT_VARIABLE:
5656    case VT_ARRAYMEMBER:
5657      len = MB_STRLEN (value);
5658      break;
5659    case VT_POSPARMS:
5660      len = number_of_args () + 1;
5661      if (*e1p == 0)
5662	len++;		/* add one arg if counting from $0 */
5663      break;
5664#if defined (ARRAY_VARS)
5665    case VT_ARRAYVAR:
5666      /* For arrays, the first value deals with array indices.  Negative
5667	 offsets count from one past the array's maximum index.  Associative
5668	 arrays treat the number of elements as the maximum index. */
5669      if (assoc_p (v))
5670	{
5671	  h = assoc_cell (v);
5672	  len = assoc_num_elements (h) + (*e1p < 0);
5673	}
5674      else
5675	{
5676	  a = (ARRAY *)value;
5677	  len = array_max_index (a) + (*e1p < 0);	/* arrays index from 0 to n - 1 */
5678	}
5679      break;
5680#endif
5681    }
5682
5683  if (len == -1)	/* paranoia */
5684    return -1;
5685
5686  if (*e1p < 0)		/* negative offsets count from end */
5687    *e1p += len;
5688
5689  if (*e1p > len || *e1p < 0)
5690    return (-1);
5691
5692#if defined (ARRAY_VARS)
5693  /* For arrays, the second offset deals with the number of elements. */
5694  if (vtype == VT_ARRAYVAR)
5695    len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
5696#endif
5697
5698  if (t)
5699    {
5700      t++;
5701      temp2 = savestring (t);
5702      temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
5703      free (temp2);
5704      t[-1] = ':';
5705      *e2p = evalexp (temp1, &expok);
5706      free (temp1);
5707      if (expok == 0)
5708	return (0);
5709      if (*e2p < 0)
5710	{
5711	  internal_error (_("%s: substring expression < 0"), t);
5712	  return (0);
5713	}
5714#if defined (ARRAY_VARS)
5715      /* In order to deal with sparse arrays, push the intelligence about how
5716	 to deal with the number of elements desired down to the array-
5717	 specific functions.  */
5718      if (vtype != VT_ARRAYVAR)
5719#endif
5720	{
5721	  *e2p += *e1p;		/* want E2 chars starting at E1 */
5722	  if (*e2p > len)
5723	    *e2p = len;
5724	}
5725    }
5726  else
5727    *e2p = len;
5728
5729  return (1);
5730}
5731
5732/* Return the type of variable specified by VARNAME (simple variable,
5733   positional param, or array variable).  Also return the value specified
5734   by VARNAME (value of a variable or a reference to an array element).
5735   If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
5736   characters in the value are quoted with CTLESC and takes appropriate
5737   steps.  For convenience, *VALP is set to the dequoted VALUE. */
5738static int
5739get_var_and_type (varname, value, quoted, varp, valp)
5740     char *varname, *value;
5741     int quoted;
5742     SHELL_VAR **varp;
5743     char **valp;
5744{
5745  int vtype;
5746  char *temp;
5747#if defined (ARRAY_VARS)
5748  SHELL_VAR *v;
5749#endif
5750
5751  /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
5752  vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0';
5753  if (vtype == VT_POSPARMS && varname[0] == '*')
5754    vtype |= VT_STARSUB;
5755  *varp = (SHELL_VAR *)NULL;
5756
5757#if defined (ARRAY_VARS)
5758  if (valid_array_reference (varname))
5759    {
5760      v = array_variable_part (varname, &temp, (int *)0);
5761      if (v && (array_p (v) || assoc_p (v)))
5762	{ /* [ */
5763	  if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
5764	    {
5765	      /* Callers have to differentiate betwen indexed and associative */
5766	      vtype = VT_ARRAYVAR;
5767	      if (temp[0] == '*')
5768		vtype |= VT_STARSUB;
5769	      *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
5770	    }
5771	  else
5772	    {
5773	      vtype = VT_ARRAYMEMBER;
5774	      *valp = array_value (varname, 1, (int *)NULL);
5775	    }
5776	  *varp = v;
5777	}
5778      else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']'))
5779	{
5780	  vtype = VT_VARIABLE;
5781	  *varp = v;
5782	  if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
5783	    *valp = dequote_string (value);
5784	  else
5785	    *valp = dequote_escapes (value);
5786	}
5787      else
5788	{
5789	  vtype = VT_ARRAYMEMBER;
5790	  *varp = v;
5791	  *valp = array_value (varname, 1, (int *)NULL);
5792	}
5793    }
5794  else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
5795    {
5796      vtype = VT_ARRAYMEMBER;
5797      *varp = v;
5798      *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
5799    }
5800  else
5801#endif
5802    {
5803      if (value && vtype == VT_VARIABLE)
5804	{
5805	  if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
5806	    *valp = dequote_string (value);
5807	  else
5808	    *valp = dequote_escapes (value);
5809	}
5810      else
5811	*valp = value;
5812    }
5813
5814  return vtype;
5815}
5816
5817/******************************************************/
5818/*						      */
5819/* Functions to extract substrings of variable values */
5820/*						      */
5821/******************************************************/
5822
5823#if defined (HANDLE_MULTIBYTE)
5824/* Character-oriented rather than strictly byte-oriented substrings.  S and
5825   E, rather being strict indices into STRING, indicate character (possibly
5826   multibyte character) positions that require calculation.
5827   Used by the ${param:offset[:length]} expansion. */
5828static char *
5829mb_substring (string, s, e)
5830     char *string;
5831     int s, e;
5832{
5833  char *tt;
5834  int start, stop, i, slen;
5835  DECLARE_MBSTATE;
5836
5837  start = 0;
5838  /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
5839  slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
5840
5841  i = s;
5842  while (string[start] && i--)
5843    ADVANCE_CHAR (string, slen, start);
5844  stop = start;
5845  i = e - s;
5846  while (string[stop] && i--)
5847    ADVANCE_CHAR (string, slen, stop);
5848  tt = substring (string, start, stop);
5849  return tt;
5850}
5851#endif
5852
5853/* Process a variable substring expansion: ${name:e1[:e2]}.  If VARNAME
5854   is `@', use the positional parameters; otherwise, use the value of
5855   VARNAME.  If VARNAME is an array variable, use the array elements. */
5856
5857static char *
5858parameter_brace_substring (varname, value, substr, quoted)
5859     char *varname, *value, *substr;
5860     int quoted;
5861{
5862  intmax_t e1, e2;
5863  int vtype, r, starsub;
5864  char *temp, *val, *tt, *oname;
5865  SHELL_VAR *v;
5866
5867  if (value == 0)
5868    return ((char *)NULL);
5869
5870  oname = this_command_name;
5871  this_command_name = varname;
5872
5873  vtype = get_var_and_type (varname, value, quoted, &v, &val);
5874  if (vtype == -1)
5875    {
5876      this_command_name = oname;
5877      return ((char *)NULL);
5878    }
5879
5880  starsub = vtype & VT_STARSUB;
5881  vtype &= ~VT_STARSUB;
5882
5883  r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
5884  this_command_name = oname;
5885  if (r <= 0)
5886    return ((r == 0) ? &expand_param_error : (char *)NULL);
5887
5888  switch (vtype)
5889    {
5890    case VT_VARIABLE:
5891    case VT_ARRAYMEMBER:
5892#if defined (HANDLE_MULTIBYTE)
5893      if (MB_CUR_MAX > 1)
5894	tt = mb_substring (val, e1, e2);
5895      else
5896#endif
5897      tt = substring (val, e1, e2);
5898
5899      if (vtype == VT_VARIABLE)
5900	FREE (val);
5901      if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
5902	temp = quote_string (tt);
5903      else
5904	temp = tt ? quote_escapes (tt) : (char *)NULL;
5905      FREE (tt);
5906      break;
5907    case VT_POSPARMS:
5908      tt = pos_params (varname, e1, e2, quoted);
5909      if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
5910	{
5911	  temp = tt ? quote_escapes (tt) : (char *)NULL;
5912	  FREE (tt);
5913	}
5914      else
5915	temp = tt;
5916      break;
5917#if defined (ARRAY_VARS)
5918    case VT_ARRAYVAR:
5919      if (assoc_p (v))
5920	/* we convert to list and take first e2 elements starting at e1th
5921	   element -- officially undefined for now */
5922	temp = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted);
5923      else
5924      /* We want E2 to be the number of elements desired (arrays can be sparse,
5925	 so verify_substring_values just returns the numbers specified and we
5926	 rely on array_subrange to understand how to deal with them). */
5927	temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
5928      /* array_subrange now calls array_quote_escapes as appropriate, so the
5929	 caller no longer needs to. */
5930      break;
5931#endif
5932    default:
5933      temp = (char *)NULL;
5934    }
5935
5936  return temp;
5937}
5938
5939/****************************************************************/
5940/*								*/
5941/* Functions to perform pattern substitution on variable values */
5942/*								*/
5943/****************************************************************/
5944
5945char *
5946pat_subst (string, pat, rep, mflags)
5947     char *string, *pat, *rep;
5948     int mflags;
5949{
5950  char *ret, *s, *e, *str;
5951  int rsize, rptr, l, replen, mtype;
5952
5953  mtype = mflags & MATCH_TYPEMASK;
5954
5955  /* Special cases:
5956   * 	1.  A null pattern with mtype == MATCH_BEG means to prefix STRING
5957   *	    with REP and return the result.
5958   *	2.  A null pattern with mtype == MATCH_END means to append REP to
5959   *	    STRING and return the result.
5960   */
5961  if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
5962    {
5963      replen = STRLEN (rep);
5964      l = strlen (string);
5965      ret = (char *)xmalloc (replen + l + 2);
5966      if (replen == 0)
5967	strcpy (ret, string);
5968      else if (mtype == MATCH_BEG)
5969	{
5970	  strcpy (ret, rep);
5971	  strcpy (ret + replen, string);
5972	}
5973      else
5974	{
5975	  strcpy (ret, string);
5976	  strcpy (ret + l, rep);
5977	}
5978      return (ret);
5979    }
5980
5981  ret = (char *)xmalloc (rsize = 64);
5982  ret[0] = '\0';
5983
5984  for (replen = STRLEN (rep), rptr = 0, str = string;;)
5985    {
5986      if (match_pattern (str, pat, mtype, &s, &e) == 0)
5987	break;
5988      l = s - str;
5989      RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64);
5990
5991      /* OK, now copy the leading unmatched portion of the string (from
5992	 str to s) to ret starting at rptr (the current offset).  Then copy
5993	 the replacement string at ret + rptr + (s - str).  Increment
5994	 rptr (if necessary) and str and go on. */
5995      if (l)
5996	{
5997	  strncpy (ret + rptr, str, l);
5998	  rptr += l;
5999	}
6000      if (replen)
6001	{
6002	  strncpy (ret + rptr, rep, replen);
6003	  rptr += replen;
6004	}
6005      str = e;		/* e == end of match */
6006
6007      if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
6008	break;
6009
6010      if (s == e)
6011	e++, str++;		/* avoid infinite recursion on zero-length match */
6012    }
6013
6014  /* Now copy the unmatched portion of the input string */
6015  if (*str)
6016    {
6017      RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
6018      strcpy (ret + rptr, str);
6019    }
6020  else
6021    ret[rptr] = '\0';
6022
6023  return ret;
6024}
6025
6026/* Do pattern match and replacement on the positional parameters. */
6027static char *
6028pos_params_pat_subst (string, pat, rep, mflags)
6029     char *string, *pat, *rep;
6030     int mflags;
6031{
6032  WORD_LIST *save, *params;
6033  WORD_DESC *w;
6034  char *ret;
6035  int pchar, qflags;
6036
6037  save = params = list_rest_of_args ();
6038  if (save == 0)
6039    return ((char *)NULL);
6040
6041  for ( ; params; params = params->next)
6042    {
6043      ret = pat_subst (params->word->word, pat, rep, mflags);
6044      w = alloc_word_desc ();
6045      w->word = ret ? ret : savestring ("");
6046      dispose_word (params->word);
6047      params->word = w;
6048    }
6049
6050  pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6051  qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6052
6053#if 0
6054  if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
6055    ret = string_list_dollar_star (quote_list (save));
6056  else if ((mflags & MATCH_STARSUB) == MATCH_STARSUB)
6057    ret = string_list_dollar_star (save);
6058  else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED)
6059    ret = string_list_dollar_at (save, qflags);
6060  else
6061    ret = string_list_dollar_star (save);
6062#else
6063  ret = string_list_pos_params (pchar, save, qflags);
6064#endif
6065
6066  dispose_words (save);
6067
6068  return (ret);
6069}
6070
6071/* Perform pattern substitution on VALUE, which is the expansion of
6072   VARNAME.  PATSUB is an expression supplying the pattern to match
6073   and the string to substitute.  QUOTED is a flags word containing
6074   the type of quoting currently in effect. */
6075static char *
6076parameter_brace_patsub (varname, value, patsub, quoted)
6077     char *varname, *value, *patsub;
6078     int quoted;
6079{
6080  int vtype, mflags, starsub, delim;
6081  char *val, *temp, *pat, *rep, *p, *lpatsub, *tt;
6082  SHELL_VAR *v;
6083
6084  if (value == 0)
6085    return ((char *)NULL);
6086
6087  this_command_name = varname;
6088
6089  vtype = get_var_and_type (varname, value, quoted, &v, &val);
6090  if (vtype == -1)
6091    return ((char *)NULL);
6092
6093  starsub = vtype & VT_STARSUB;
6094  vtype &= ~VT_STARSUB;
6095
6096  mflags = 0;
6097  if (patsub && *patsub == '/')
6098    {
6099      mflags |= MATCH_GLOBREP;
6100      patsub++;
6101    }
6102
6103  /* Malloc this because expand_string_if_necessary or one of the expansion
6104     functions in its call chain may free it on a substitution error. */
6105  lpatsub = savestring (patsub);
6106
6107  if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6108    mflags |= MATCH_QUOTED;
6109
6110  if (starsub)
6111    mflags |= MATCH_STARSUB;
6112
6113  /* If the pattern starts with a `/', make sure we skip over it when looking
6114     for the replacement delimiter. */
6115#if 0
6116  if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL))
6117    *rep++ = '\0';
6118  else
6119    rep = (char *)NULL;
6120#else
6121  delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
6122  if (lpatsub[delim] == '/')
6123    {
6124      lpatsub[delim] = 0;
6125      rep = lpatsub + delim + 1;
6126    }
6127  else
6128    rep = (char *)NULL;
6129#endif
6130
6131  if (rep && *rep == '\0')
6132    rep = (char *)NULL;
6133
6134  /* Perform the same expansions on the pattern as performed by the
6135     pattern removal expansions. */
6136  pat = getpattern (lpatsub, quoted, 1);
6137
6138  if (rep)
6139    {
6140      if ((mflags & MATCH_QUOTED) == 0)
6141	rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
6142      else
6143	rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
6144    }
6145
6146  /* ksh93 doesn't allow the match specifier to be a part of the expanded
6147     pattern.  This is an extension.  Make sure we don't anchor the pattern
6148     at the beginning or end of the string if we're doing global replacement,
6149     though. */
6150  p = pat;
6151  if (mflags & MATCH_GLOBREP)
6152    mflags |= MATCH_ANY;
6153  else if (pat && pat[0] == '#')
6154    {
6155      mflags |= MATCH_BEG;
6156      p++;
6157    }
6158  else if (pat && pat[0] == '%')
6159    {
6160      mflags |= MATCH_END;
6161      p++;
6162    }
6163  else
6164    mflags |= MATCH_ANY;
6165
6166  /* OK, we now want to substitute REP for PAT in VAL.  If
6167     flags & MATCH_GLOBREP is non-zero, the substitution is done
6168     everywhere, otherwise only the first occurrence of PAT is
6169     replaced.  The pattern matching code doesn't understand
6170     CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
6171     values passed in (VT_VARIABLE) so the pattern substitution
6172     code works right.  We need to requote special chars after
6173     we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
6174     other cases if QUOTED == 0, since the posparams and arrays
6175     indexed by * or @ do special things when QUOTED != 0. */
6176
6177  switch (vtype)
6178    {
6179    case VT_VARIABLE:
6180    case VT_ARRAYMEMBER:
6181      temp = pat_subst (val, p, rep, mflags);
6182      if (vtype == VT_VARIABLE)
6183	FREE (val);
6184      if (temp)
6185	{
6186	  tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
6187	  free (temp);
6188	  temp = tt;
6189	}
6190      break;
6191    case VT_POSPARMS:
6192      temp = pos_params_pat_subst (val, p, rep, mflags);
6193      if (temp && (mflags & MATCH_QUOTED) == 0)
6194	{
6195	  tt = quote_escapes (temp);
6196	  free (temp);
6197	  temp = tt;
6198	}
6199      break;
6200#if defined (ARRAY_VARS)
6201    case VT_ARRAYVAR:
6202      temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags)
6203			 : array_patsub (array_cell (v), p, rep, mflags);
6204      /* Don't call quote_escapes anymore; array_patsub calls
6205	 array_quote_escapes as appropriate before adding the
6206	 space separators; ditto for assoc_patsub. */
6207      break;
6208#endif
6209    }
6210
6211  FREE (pat);
6212  FREE (rep);
6213  free (lpatsub);
6214
6215  return temp;
6216}
6217
6218/****************************************************************/
6219/*								*/
6220/*   Functions to perform case modification on variable values  */
6221/*								*/
6222/****************************************************************/
6223
6224/* Do case modification on the positional parameters. */
6225
6226static char *
6227pos_params_modcase (string, pat, modop, mflags)
6228     char *string, *pat;
6229     int modop;
6230     int mflags;
6231{
6232  WORD_LIST *save, *params;
6233  WORD_DESC *w;
6234  char *ret;
6235  int pchar, qflags;
6236
6237  save = params = list_rest_of_args ();
6238  if (save == 0)
6239    return ((char *)NULL);
6240
6241  for ( ; params; params = params->next)
6242    {
6243      ret = sh_modcase (params->word->word, pat, modop);
6244      w = alloc_word_desc ();
6245      w->word = ret ? ret : savestring ("");
6246      dispose_word (params->word);
6247      params->word = w;
6248    }
6249
6250  pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6251  qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6252
6253  ret = string_list_pos_params (pchar, save, qflags);
6254  dispose_words (save);
6255
6256  return (ret);
6257}
6258
6259/* Perform case modification on VALUE, which is the expansion of
6260   VARNAME.  MODSPEC is an expression supplying the type of modification
6261   to perform.  QUOTED is a flags word containing the type of quoting
6262   currently in effect. */
6263static char *
6264parameter_brace_casemod (varname, value, modspec, patspec, quoted)
6265     char *varname, *value;
6266     int modspec;
6267     char *patspec;
6268     int quoted;
6269{
6270  int vtype, starsub, modop, mflags, x;
6271  char *val, *temp, *pat, *p, *lpat, *tt;
6272  SHELL_VAR *v;
6273
6274  if (value == 0)
6275    return ((char *)NULL);
6276
6277  this_command_name = varname;
6278
6279  vtype = get_var_and_type (varname, value, quoted, &v, &val);
6280  if (vtype == -1)
6281    return ((char *)NULL);
6282
6283  starsub = vtype & VT_STARSUB;
6284  vtype &= ~VT_STARSUB;
6285
6286  modop = 0;
6287  mflags = 0;
6288  if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6289    mflags |= MATCH_QUOTED;
6290  if (starsub)
6291    mflags |= MATCH_STARSUB;
6292
6293  p = patspec;
6294  if (modspec == '^')
6295    {
6296      x = p && p[0] == modspec;
6297      modop = x ? CASE_UPPER : CASE_UPFIRST;
6298      p += x;
6299    }
6300  else if (modspec == ',')
6301    {
6302      x = p && p[0] == modspec;
6303      modop = x ? CASE_LOWER : CASE_LOWFIRST;
6304      p += x;
6305    }
6306  else if (modspec == '~')
6307    {
6308      x = p && p[0] == modspec;
6309      modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
6310      p += x;
6311    }
6312
6313  lpat = p ? savestring (p) : 0;
6314  /* Perform the same expansions on the pattern as performed by the
6315     pattern removal expansions.  FOR LATER */
6316  pat = lpat ? getpattern (lpat, quoted, 1) : 0;
6317
6318  /* OK, now we do the case modification. */
6319  switch (vtype)
6320    {
6321    case VT_VARIABLE:
6322    case VT_ARRAYMEMBER:
6323      temp = sh_modcase (val, pat, modop);
6324      if (vtype == VT_VARIABLE)
6325	FREE (val);
6326      if (temp)
6327	{
6328	  tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
6329	  free (temp);
6330	  temp = tt;
6331	}
6332      break;
6333
6334    case VT_POSPARMS:
6335      temp = pos_params_modcase (val, pat, modop, mflags);
6336      if (temp && (mflags & MATCH_QUOTED)  == 0)
6337	{
6338	  tt = quote_escapes (temp);
6339	  free (temp);
6340	  temp = tt;
6341	}
6342      break;
6343
6344#if defined (ARRAY_VARS)
6345    case VT_ARRAYVAR:
6346      temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
6347			 : array_modcase (array_cell (v), pat, modop, mflags);
6348      /* Don't call quote_escapes; array_modcase calls array_quote_escapes
6349	 as appropriate before adding the space separators; ditto for
6350	 assoc_modcase. */
6351      break;
6352#endif
6353    }
6354
6355  FREE (pat);
6356  free (lpat);
6357
6358  return temp;
6359}
6360
6361/* Check for unbalanced parens in S, which is the contents of $(( ... )).  If
6362   any occur, this must be a nested command substitution, so return 0.
6363   Otherwise, return 1.  A valid arithmetic expression must always have a
6364   ( before a matching ), so any cases where there are more right parens
6365   means that this must not be an arithmetic expression, though the parser
6366   will not accept it without a balanced total number of parens. */
6367static int
6368chk_arithsub (s, len)
6369     const char *s;
6370     int len;
6371{
6372  int i, count;
6373  DECLARE_MBSTATE;
6374
6375  i = count = 0;
6376  while (i < len)
6377    {
6378      if (s[i] == '(')
6379	count++;
6380      else if (s[i] == ')')
6381	{
6382	  count--;
6383	  if (count < 0)
6384	    return 0;
6385	}
6386
6387      switch (s[i])
6388	{
6389	default:
6390	  ADVANCE_CHAR (s, len, i);
6391	  break;
6392
6393	case '\\':
6394	  i++;
6395	  if (s[i])
6396	    ADVANCE_CHAR (s, len, i);
6397	  break;
6398
6399	case '\'':
6400	  i = skip_single_quoted (s, len, ++i);
6401	  break;
6402
6403	case '"':
6404	  i = skip_double_quoted ((char *)s, len, ++i);
6405	  break;
6406	}
6407    }
6408
6409  return (count == 0);
6410}
6411
6412/****************************************************************/
6413/*								*/
6414/*	Functions to perform parameter expansion on a string	*/
6415/*								*/
6416/****************************************************************/
6417
6418/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
6419static WORD_DESC *
6420parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at)
6421     char *string;
6422     int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at;
6423{
6424  int check_nullness, var_is_set, var_is_null, var_is_special;
6425  int want_substring, want_indir, want_patsub, want_casemod;
6426  char *name, *value, *temp, *temp1;
6427  WORD_DESC *tdesc, *ret;
6428  int t_index, sindex, c, tflag, modspec;
6429  intmax_t number;
6430
6431  temp = temp1 = value = (char *)NULL;
6432  var_is_set = var_is_null = var_is_special = check_nullness = 0;
6433  want_substring = want_indir = want_patsub = want_casemod = 0;
6434
6435  sindex = *indexp;
6436  t_index = ++sindex;
6437  /* ${#var} doesn't have any of the other parameter expansions on it. */
6438  if (string[t_index] == '#' && legal_variable_starter (string[t_index+1]))		/* {{ */
6439    name = string_extract (string, &t_index, "}", SX_VARNAME);
6440  else
6441#if defined (CASEMOD_EXPANSIONS)
6442    /* To enable case-toggling expansions using the `~' operator character
6443       change the 1 to 0. */
6444#  if defined (CASEMOD_CAPCASE)
6445    name = string_extract (string, &t_index, "#%^,~:-=?+/}", SX_VARNAME);
6446#  else
6447    name = string_extract (string, &t_index, "#%^,:-=?+/}", SX_VARNAME);
6448#  endif /* CASEMOD_CAPCASE */
6449#else
6450    name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME);
6451#endif /* CASEMOD_EXPANSIONS */
6452
6453  ret = 0;
6454  tflag = 0;
6455
6456  /* If the name really consists of a special variable, then make sure
6457     that we have the entire name.  We don't allow indirect references
6458     to special variables except `#', `?', `@' and `*'. */
6459  if ((sindex == t_index &&
6460	(string[t_index] == '-' ||
6461	 string[t_index] == '?' ||
6462	 string[t_index] == '#')) ||
6463      (sindex == t_index - 1 && string[sindex] == '!' &&
6464	(string[t_index] == '#' ||
6465	 string[t_index] == '?' ||
6466	 string[t_index] == '@' ||
6467	 string[t_index] == '*')))
6468    {
6469      t_index++;
6470      free (name);
6471      temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
6472      name = (char *)xmalloc (3 + (strlen (temp1)));
6473      *name = string[sindex];
6474      if (string[sindex] == '!')
6475	{
6476	  /* indirect reference of $#, $?, $@, or $* */
6477	  name[1] = string[sindex + 1];
6478	  strcpy (name + 2, temp1);
6479	}
6480      else
6481	strcpy (name + 1, temp1);
6482      free (temp1);
6483    }
6484  sindex = t_index;
6485
6486  /* Find out what character ended the variable name.  Then
6487     do the appropriate thing. */
6488  if (c = string[sindex])
6489    sindex++;
6490
6491  /* If c is followed by one of the valid parameter expansion
6492     characters, move past it as normal.  If not, assume that
6493     a substring specification is being given, and do not move
6494     past it. */
6495  if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
6496    {
6497      check_nullness++;
6498      if (c = string[sindex])
6499	sindex++;
6500    }
6501  else if (c == ':' && string[sindex] != RBRACE)
6502    want_substring = 1;
6503  else if (c == '/' && string[sindex] != RBRACE)
6504    want_patsub = 1;
6505#if defined (CASEMOD_EXPANSIONS)
6506  else if (c == '^' || c == ',' || c == '~')
6507    {
6508      modspec = c;
6509      want_casemod = 1;
6510    }
6511#endif
6512
6513  /* Catch the valid and invalid brace expressions that made it through the
6514     tests above. */
6515  /* ${#-} is a valid expansion and means to take the length of $-.
6516     Similarly for ${#?} and ${##}... */
6517  if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
6518	VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
6519    {
6520      name = (char *)xrealloc (name, 3);
6521      name[1] = c;
6522      name[2] = '\0';
6523      c = string[sindex++];
6524    }
6525
6526  /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
6527  if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
6528	member (c, "%:=+/") && string[sindex] == RBRACE)
6529    {
6530      temp = (char *)NULL;
6531      goto bad_substitution;
6532    }
6533
6534  /* Indirect expansion begins with a `!'.  A valid indirect expansion is
6535     either a variable name, one of the positional parameters or a special
6536     variable that expands to one of the positional parameters. */
6537  want_indir = *name == '!' &&
6538    (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
6539					|| VALID_INDIR_PARAM (name[1]));
6540
6541  /* Determine the value of this variable. */
6542
6543  /* Check for special variables, directly referenced. */
6544  if (SPECIAL_VAR (name, want_indir))
6545    var_is_special++;
6546
6547  /* Check for special expansion things, like the length of a parameter */
6548  if (*name == '#' && name[1])
6549    {
6550      /* If we are not pointing at the character just after the
6551	 closing brace, then we haven't gotten all of the name.
6552	 Since it begins with a special character, this is a bad
6553	 substitution.  Also check NAME for validity before trying
6554	 to go on. */
6555      if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
6556	{
6557	  temp = (char *)NULL;
6558	  goto bad_substitution;
6559	}
6560
6561      number = parameter_brace_expand_length (name);
6562      free (name);
6563
6564      *indexp = sindex;
6565      if (number < 0)
6566        return (&expand_wdesc_error);
6567      else
6568	{
6569	  ret = alloc_word_desc ();
6570	  ret->word = itos (number);
6571	  return ret;
6572	}
6573    }
6574
6575  /* ${@} is identical to $@. */
6576  if (name[0] == '@' && name[1] == '\0')
6577    {
6578      if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
6579	*quoted_dollar_atp = 1;
6580
6581      if (contains_dollar_at)
6582	*contains_dollar_at = 1;
6583    }
6584
6585  /* Process ${!PREFIX*} expansion. */
6586  if (want_indir && string[sindex - 1] == RBRACE &&
6587      (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
6588      legal_variable_starter ((unsigned char) name[1]))
6589    {
6590      char **x;
6591      WORD_LIST *xlist;
6592
6593      temp1 = savestring (name + 1);
6594      number = strlen (temp1);
6595      temp1[number - 1] = '\0';
6596      x = all_variables_matching_prefix (temp1);
6597      xlist = strvec_to_word_list (x, 0, 0);
6598      if (string[sindex - 2] == '*')
6599	temp = string_list_dollar_star (xlist);
6600      else
6601	{
6602	  temp = string_list_dollar_at (xlist, quoted);
6603	  if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
6604	    *quoted_dollar_atp = 1;
6605	  if (contains_dollar_at)
6606	    *contains_dollar_at = 1;
6607	}
6608      free (x);
6609      dispose_words (xlist);
6610      free (temp1);
6611      *indexp = sindex;
6612
6613      ret = alloc_word_desc ();
6614      ret->word = temp;
6615      return ret;
6616    }
6617
6618#if defined (ARRAY_VARS)
6619  /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */
6620  if (want_indir && string[sindex - 1] == RBRACE &&
6621      string[sindex - 2] == ']' && valid_array_reference (name+1))
6622    {
6623      char *x, *x1;
6624
6625      temp1 = savestring (name + 1);
6626      x = array_variable_name (temp1, &x1, (int *)0);	/* [ */
6627      FREE (x);
6628      if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']')
6629	{
6630	  temp = array_keys (temp1, quoted);	/* handles assoc vars too */
6631	  if (x1[0] == '@')
6632	    {
6633	      if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
6634		*quoted_dollar_atp = 1;
6635	      if (contains_dollar_at)
6636		*contains_dollar_at = 1;
6637	    }
6638
6639	  free (temp1);
6640	  *indexp = sindex;
6641
6642	  ret = alloc_word_desc ();
6643	  ret->word = temp;
6644	  return ret;
6645	}
6646
6647      free (temp1);
6648    }
6649#endif /* ARRAY_VARS */
6650
6651  /* Make sure that NAME is valid before trying to go on. */
6652  if (valid_brace_expansion_word (want_indir ? name + 1 : name,
6653					var_is_special) == 0)
6654    {
6655      temp = (char *)NULL;
6656      goto bad_substitution;
6657    }
6658
6659  if (want_indir)
6660    tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
6661  else
6662    tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND);
6663
6664  if (tdesc)
6665    {
6666      temp = tdesc->word;
6667      tflag = tdesc->flags;
6668      dispose_word_desc (tdesc);
6669    }
6670  else
6671    temp = (char  *)0;
6672
6673#if defined (ARRAY_VARS)
6674  if (valid_array_reference (name))
6675    chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at);
6676#endif
6677
6678  var_is_set = temp != (char *)0;
6679  var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
6680
6681  /* Get the rest of the stuff inside the braces. */
6682  if (c && c != RBRACE)
6683    {
6684      /* Extract the contents of the ${ ... } expansion
6685	 according to the Posix.2 rules. */
6686      value = extract_dollar_brace_string (string, &sindex, quoted, 0);
6687      if (string[sindex] == RBRACE)
6688	sindex++;
6689      else
6690	goto bad_substitution;
6691    }
6692  else
6693    value = (char *)NULL;
6694
6695  *indexp = sindex;
6696
6697  /* If this is a substring spec, process it and add the result. */
6698  if (want_substring)
6699    {
6700      temp1 = parameter_brace_substring (name, temp, value, quoted);
6701      FREE (name);
6702      FREE (value);
6703      FREE (temp);
6704
6705      if (temp1 == &expand_param_error)
6706	return (&expand_wdesc_error);
6707      else if (temp1 == &expand_param_fatal)
6708	return (&expand_wdesc_fatal);
6709
6710      ret = alloc_word_desc ();
6711      ret->word = temp1;
6712      if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
6713	ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
6714      return ret;
6715    }
6716  else if (want_patsub)
6717    {
6718      temp1 = parameter_brace_patsub (name, temp, value, quoted);
6719      FREE (name);
6720      FREE (value);
6721      FREE (temp);
6722
6723      if (temp1 == &expand_param_error)
6724	return (&expand_wdesc_error);
6725      else if (temp1 == &expand_param_fatal)
6726	return (&expand_wdesc_fatal);
6727
6728      ret = alloc_word_desc ();
6729      ret->word = temp1;
6730      ret = alloc_word_desc ();
6731      ret->word = temp1;
6732      if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
6733	ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
6734      return ret;
6735    }
6736#if defined (CASEMOD_EXPANSIONS)
6737  else if (want_casemod)
6738    {
6739      temp1 = parameter_brace_casemod (name, temp, modspec, value, quoted);
6740      FREE (name);
6741      FREE (value);
6742      FREE (temp);
6743
6744      if (temp1 == &expand_param_error)
6745	return (&expand_wdesc_error);
6746      else if (temp1 == &expand_param_fatal)
6747	return (&expand_wdesc_fatal);
6748
6749      ret = alloc_word_desc ();
6750      ret->word = temp1;
6751      if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
6752	ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
6753      return ret;
6754    }
6755#endif
6756
6757  /* Do the right thing based on which character ended the variable name. */
6758  switch (c)
6759    {
6760    default:
6761    case '\0':
6762    bad_substitution:
6763      report_error (_("%s: bad substitution"), string ? string : "??");
6764      FREE (value);
6765      FREE (temp);
6766      free (name);
6767      return &expand_wdesc_error;
6768
6769    case RBRACE:
6770      if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
6771	{
6772	  last_command_exit_value = EXECUTION_FAILURE;
6773	  err_unboundvar (name);
6774	  FREE (value);
6775	  FREE (temp);
6776	  free (name);
6777	  return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
6778	}
6779      break;
6780
6781    case '#':	/* ${param#[#]pattern} */
6782    case '%':	/* ${param%[%]pattern} */
6783      if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
6784	{
6785	  FREE (value);
6786	  break;
6787	}
6788      temp1 = parameter_brace_remove_pattern (name, temp, value, c, quoted);
6789      free (temp);
6790      free (value);
6791
6792      ret = alloc_word_desc ();
6793      ret->word = temp1;
6794      if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
6795	ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
6796      return ret;
6797
6798    case '-':
6799    case '=':
6800    case '?':
6801    case '+':
6802      if (var_is_set && var_is_null == 0)
6803	{
6804	  /* If the operator is `+', we don't want the value of the named
6805	     variable for anything, just the value of the right hand side. */
6806
6807	  if (c == '+')
6808	    {
6809	      /* XXX -- if we're double-quoted and the named variable is "$@",
6810			we want to turn off any special handling of "$@" --
6811			we're not using it, so whatever is on the rhs applies. */
6812	      if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
6813		*quoted_dollar_atp = 0;
6814	      if (contains_dollar_at)
6815		*contains_dollar_at = 0;
6816
6817	      FREE (temp);
6818	      if (value)
6819		{
6820		  ret = parameter_brace_expand_rhs (name, value, c,
6821						    quoted,
6822						    quoted_dollar_atp,
6823						    contains_dollar_at);
6824		  /* XXX - fix up later, esp. noting presence of
6825			   W_HASQUOTEDNULL in ret->flags */
6826		  free (value);
6827		}
6828	      else
6829		temp = (char *)NULL;
6830	    }
6831	  else
6832	    {
6833	      FREE (value);
6834	    }
6835	  /* Otherwise do nothing; just use the value in TEMP. */
6836	}
6837      else	/* VAR not set or VAR is NULL. */
6838	{
6839	  FREE (temp);
6840	  temp = (char *)NULL;
6841	  if (c == '=' && var_is_special)
6842	    {
6843	      report_error (_("$%s: cannot assign in this way"), name);
6844	      free (name);
6845	      free (value);
6846	      return &expand_wdesc_error;
6847	    }
6848	  else if (c == '?')
6849	    {
6850	      parameter_brace_expand_error (name, value);
6851	      return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
6852	    }
6853	  else if (c != '+')
6854	    {
6855	      /* XXX -- if we're double-quoted and the named variable is "$@",
6856			we want to turn off any special handling of "$@" --
6857			we're not using it, so whatever is on the rhs applies. */
6858	      if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
6859		*quoted_dollar_atp = 0;
6860	      if (contains_dollar_at)
6861		*contains_dollar_at = 0;
6862
6863	      ret = parameter_brace_expand_rhs (name, value, c, quoted,
6864						quoted_dollar_atp,
6865						contains_dollar_at);
6866	      /* XXX - fix up later, esp. noting presence of
6867		       W_HASQUOTEDNULL in tdesc->flags */
6868	    }
6869	  free (value);
6870	}
6871
6872      break;
6873    }
6874  free (name);
6875
6876  if (ret == 0)
6877    {
6878      ret = alloc_word_desc ();
6879      ret->flags = tflag;
6880      ret->word = temp;
6881    }
6882  return (ret);
6883}
6884
6885/* Expand a single ${xxx} expansion.  The braces are optional.  When
6886   the braces are used, parameter_brace_expand() does the work,
6887   possibly calling param_expand recursively. */
6888static WORD_DESC *
6889param_expand (string, sindex, quoted, expanded_something,
6890	      contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
6891	      pflags)
6892     char *string;
6893     int *sindex, quoted, *expanded_something, *contains_dollar_at;
6894     int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
6895{
6896  char *temp, *temp1, uerror[3];
6897  int zindex, t_index, expok;
6898  unsigned char c;
6899  intmax_t number;
6900  SHELL_VAR *var;
6901  WORD_LIST *list;
6902  WORD_DESC *tdesc, *ret;
6903  int tflag;
6904
6905  zindex = *sindex;
6906  c = string[++zindex];
6907
6908  temp = (char *)NULL;
6909  ret = tdesc = (WORD_DESC *)NULL;
6910  tflag = 0;
6911
6912  /* Do simple cases first. Switch on what follows '$'. */
6913  switch (c)
6914    {
6915    /* $0 .. $9? */
6916    case '0':
6917    case '1':
6918    case '2':
6919    case '3':
6920    case '4':
6921    case '5':
6922    case '6':
6923    case '7':
6924    case '8':
6925    case '9':
6926      temp1 = dollar_vars[TODIGIT (c)];
6927      if (unbound_vars_is_error && temp1 == (char *)NULL)
6928	{
6929	  uerror[0] = '$';
6930	  uerror[1] = c;
6931	  uerror[2] = '\0';
6932	  err_unboundvar (uerror);
6933	  last_command_exit_value = EXECUTION_FAILURE;
6934	  return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
6935	}
6936      if (temp1)
6937	temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
6938		  ? quote_string (temp1)
6939		  : quote_escapes (temp1);
6940      else
6941	temp = (char *)NULL;
6942
6943      break;
6944
6945    /* $$ -- pid of the invoking shell. */
6946    case '$':
6947      temp = itos (dollar_dollar_pid);
6948      break;
6949
6950    /* $# -- number of positional parameters. */
6951    case '#':
6952      temp = itos (number_of_args ());
6953      break;
6954
6955    /* $? -- return value of the last synchronous command. */
6956    case '?':
6957      temp = itos (last_command_exit_value);
6958      break;
6959
6960    /* $- -- flags supplied to the shell on invocation or by `set'. */
6961    case '-':
6962      temp = which_set_flags ();
6963      break;
6964
6965      /* $! -- Pid of the last asynchronous command. */
6966    case '!':
6967      /* If no asynchronous pids have been created, expand to nothing.
6968	 If `set -u' has been executed, and no async processes have
6969	 been created, this is an expansion error. */
6970      if (last_asynchronous_pid == NO_PID)
6971	{
6972	  if (expanded_something)
6973	    *expanded_something = 0;
6974	  temp = (char *)NULL;
6975	  if (unbound_vars_is_error)
6976	    {
6977	      uerror[0] = '$';
6978	      uerror[1] = c;
6979	      uerror[2] = '\0';
6980	      err_unboundvar (uerror);
6981	      last_command_exit_value = EXECUTION_FAILURE;
6982	      return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
6983	    }
6984	}
6985      else
6986	temp = itos (last_asynchronous_pid);
6987      break;
6988
6989    /* The only difference between this and $@ is when the arg is quoted. */
6990    case '*':		/* `$*' */
6991      list = list_rest_of_args ();
6992
6993#if 0
6994      /* According to austin-group posix proposal by Geoff Clare in
6995	 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
6996
6997 	"The shell shall write a message to standard error and
6998 	 immediately exit when it tries to expand an unset parameter
6999 	 other than the '@' and '*' special parameters."
7000      */
7001
7002      if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
7003	{
7004	  uerror[0] = '$';
7005	  uerror[1] = '*';
7006	  uerror[2] = '\0';
7007	  last_command_exit_value = EXECUTION_FAILURE;
7008	  err_unboundvar (uerror);
7009	  return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7010	}
7011#endif
7012
7013      /* If there are no command-line arguments, this should just
7014	 disappear if there are other characters in the expansion,
7015	 even if it's quoted. */
7016      if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
7017	temp = (char *)NULL;
7018      else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7019	{
7020	  /* If we have "$*" we want to make a string of the positional
7021	     parameters, separated by the first character of $IFS, and
7022	     quote the whole string, including the separators.  If IFS
7023	     is unset, the parameters are separated by ' '; if $IFS is
7024	     null, the parameters are concatenated. */
7025	  temp = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (list) : string_list (list);
7026	  temp1 = quote_string (temp);
7027	  if (*temp == 0)
7028	    tflag |= W_HASQUOTEDNULL;
7029	  free (temp);
7030	  temp = temp1;
7031	}
7032      else
7033	{
7034	  /* We check whether or not we're eventually going to split $* here,
7035	     for example when IFS is empty and we are processing the rhs of
7036	     an assignment statement.  In that case, we don't separate the
7037	     arguments at all.  Otherwise, if the $* is not quoted it is
7038	     identical to $@ */
7039#if 1
7040#  if defined (HANDLE_MULTIBYTE)
7041	  if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
7042#  else
7043	  if (expand_no_split_dollar_star && ifs_firstc == 0)
7044#  endif
7045	    temp = string_list_dollar_star (list);
7046	  else
7047	    temp = string_list_dollar_at (list, quoted);
7048#else
7049	  temp = string_list_dollar_at (list, quoted);
7050#endif
7051	  if (expand_no_split_dollar_star == 0 && contains_dollar_at)
7052	    *contains_dollar_at = 1;
7053	}
7054
7055      dispose_words (list);
7056      break;
7057
7058    /* When we have "$@" what we want is "$1" "$2" "$3" ... This
7059       means that we have to turn quoting off after we split into
7060       the individually quoted arguments so that the final split
7061       on the first character of $IFS is still done.  */
7062    case '@':		/* `$@' */
7063      list = list_rest_of_args ();
7064
7065#if 0
7066      /* According to austin-group posix proposal by Geoff Clare in
7067	 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
7068
7069 	"The shell shall write a message to standard error and
7070 	 immediately exit when it tries to expand an unset parameter
7071 	 other than the '@' and '*' special parameters."
7072      */
7073
7074      if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
7075	{
7076	  uerror[0] = '$';
7077	  uerror[1] = '@';
7078	  uerror[2] = '\0';
7079	  last_command_exit_value = EXECUTION_FAILURE;
7080	  err_unboundvar (uerror);
7081	  return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7082	}
7083#endif
7084
7085      /* We want to flag the fact that we saw this.  We can't turn
7086	 off quoting entirely, because other characters in the
7087	 string might need it (consider "\"$@\""), but we need some
7088	 way to signal that the final split on the first character
7089	 of $IFS should be done, even though QUOTED is 1. */
7090      if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7091	*quoted_dollar_at_p = 1;
7092      if (contains_dollar_at)
7093	*contains_dollar_at = 1;
7094
7095      /* We want to separate the positional parameters with the first
7096	 character of $IFS in case $IFS is something other than a space.
7097	 We also want to make sure that splitting is done no matter what --
7098	 according to POSIX.2, this expands to a list of the positional
7099	 parameters no matter what IFS is set to. */
7100      temp = string_list_dollar_at (list, quoted);
7101
7102      dispose_words (list);
7103      break;
7104
7105    case LBRACE:
7106      tdesc = parameter_brace_expand (string, &zindex, quoted,
7107				      quoted_dollar_at_p,
7108				      contains_dollar_at);
7109
7110      if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
7111	return (tdesc);
7112      temp = tdesc ? tdesc->word : (char *)0;
7113
7114      /* XXX */
7115      /* Quoted nulls should be removed if there is anything else
7116	 in the string. */
7117      /* Note that we saw the quoted null so we can add one back at
7118	 the end of this function if there are no other characters
7119	 in the string, discard TEMP, and go on.  The exception to
7120	 this is when we have "${@}" and $1 is '', since $@ needs
7121	 special handling. */
7122      if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
7123	{
7124	  if (had_quoted_null_p)
7125	    *had_quoted_null_p = 1;
7126	  if (*quoted_dollar_at_p == 0)
7127	    {
7128	      free (temp);
7129	      tdesc->word = temp = (char *)NULL;
7130	    }
7131
7132	}
7133
7134      ret = tdesc;
7135      goto return0;
7136
7137    /* Do command or arithmetic substitution. */
7138    case LPAREN:
7139      /* We have to extract the contents of this paren substitution. */
7140      t_index = zindex + 1;
7141      temp = extract_command_subst (string, &t_index, 0);
7142      zindex = t_index;
7143
7144      /* For Posix.2-style `$(( ))' arithmetic substitution,
7145	 extract the expression and pass it to the evaluator. */
7146      if (temp && *temp == LPAREN)
7147	{
7148	  char *temp2;
7149	  temp1 = temp + 1;
7150	  temp2 = savestring (temp1);
7151	  t_index = strlen (temp2) - 1;
7152
7153	  if (temp2[t_index] != RPAREN)
7154	    {
7155	      free (temp2);
7156	      goto comsub;
7157	    }
7158
7159	  /* Cut off ending `)' */
7160	  temp2[t_index] = '\0';
7161
7162	  if (chk_arithsub (temp2, t_index) == 0)
7163	    {
7164	      free (temp2);
7165	      goto comsub;
7166	    }
7167
7168	  /* Expand variables found inside the expression. */
7169	  temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
7170	  free (temp2);
7171
7172arithsub:
7173	  /* No error messages. */
7174	  this_command_name = (char *)NULL;
7175	  number = evalexp (temp1, &expok);
7176	  free (temp);
7177	  free (temp1);
7178	  if (expok == 0)
7179	    {
7180	      if (interactive_shell == 0 && posixly_correct)
7181		{
7182		  last_command_exit_value = EXECUTION_FAILURE;
7183		  return (&expand_wdesc_fatal);
7184		}
7185	      else
7186		return (&expand_wdesc_error);
7187	    }
7188	  temp = itos (number);
7189	  break;
7190	}
7191
7192comsub:
7193      if (pflags & PF_NOCOMSUB)
7194	/* we need zindex+1 because string[zindex] == RPAREN */
7195	temp1 = substring (string, *sindex, zindex+1);
7196      else
7197	{
7198	  tdesc = command_substitute (temp, quoted);
7199	  temp1 = tdesc ? tdesc->word : (char *)NULL;
7200	  if (tdesc)
7201	    dispose_word_desc (tdesc);
7202	}
7203      FREE (temp);
7204      temp = temp1;
7205      break;
7206
7207    /* Do POSIX.2d9-style arithmetic substitution.  This will probably go
7208       away in a future bash release. */
7209    case '[':
7210      /* Extract the contents of this arithmetic substitution. */
7211      t_index = zindex + 1;
7212      temp = extract_arithmetic_subst (string, &t_index);
7213      zindex = t_index;
7214      if (temp == 0)
7215	{
7216	  temp = savestring (string);
7217	  if (expanded_something)
7218	    *expanded_something = 0;
7219	  goto return0;
7220	}
7221
7222       /* Do initial variable expansion. */
7223      temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES);
7224
7225      goto arithsub;
7226
7227    default:
7228      /* Find the variable in VARIABLE_LIST. */
7229      temp = (char *)NULL;
7230
7231      for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
7232	;
7233      temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
7234
7235      /* If this isn't a variable name, then just output the `$'. */
7236      if (temp1 == 0 || *temp1 == '\0')
7237	{
7238	  FREE (temp1);
7239	  temp = (char *)xmalloc (2);
7240	  temp[0] = '$';
7241	  temp[1] = '\0';
7242	  if (expanded_something)
7243	    *expanded_something = 0;
7244	  goto return0;
7245	}
7246
7247      /* If the variable exists, return its value cell. */
7248      var = find_variable (temp1);
7249
7250      if (var && invisible_p (var) == 0 && var_isset (var))
7251	{
7252#if defined (ARRAY_VARS)
7253	  if (assoc_p (var) || array_p (var))
7254	    {
7255	      temp = array_p (var) ? array_reference (array_cell (var), 0)
7256				   : assoc_reference (assoc_cell (var), "0");
7257	      if (temp)
7258		temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7259			  ? quote_string (temp)
7260			  : quote_escapes (temp);
7261	      else if (unbound_vars_is_error)
7262		goto unbound_variable;
7263	    }
7264	  else
7265#endif
7266	    {
7267	      temp = value_cell (var);
7268
7269	      temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7270			? quote_string (temp)
7271			: quote_escapes (temp);
7272	    }
7273
7274	  free (temp1);
7275
7276	  goto return0;
7277	}
7278
7279      temp = (char *)NULL;
7280
7281unbound_variable:
7282      if (unbound_vars_is_error)
7283	err_unboundvar (temp1);
7284      else
7285	{
7286	  free (temp1);
7287	  goto return0;
7288	}
7289
7290      free (temp1);
7291      last_command_exit_value = EXECUTION_FAILURE;
7292      return ((unbound_vars_is_error && interactive_shell == 0)
7293		? &expand_wdesc_fatal
7294		: &expand_wdesc_error);
7295    }
7296
7297  if (string[zindex])
7298    zindex++;
7299
7300return0:
7301  *sindex = zindex;
7302
7303  if (ret == 0)
7304    {
7305      ret = alloc_word_desc ();
7306      ret->flags = tflag;	/* XXX */
7307      ret->word = temp;
7308    }
7309  return ret;
7310}
7311
7312/* Make a word list which is the result of parameter and variable
7313   expansion, command substitution, arithmetic substitution, and
7314   quote removal of WORD.  Return a pointer to a WORD_LIST which is
7315   the result of the expansion.  If WORD contains a null word, the
7316   word list returned is also null.
7317
7318   QUOTED contains flag values defined in shell.h.
7319
7320   ISEXP is used to tell expand_word_internal that the word should be
7321   treated as the result of an expansion.  This has implications for
7322   how IFS characters in the word are treated.
7323
7324   CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
7325   they point to an integer value which receives information about expansion.
7326   CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
7327   EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
7328   else zero.
7329
7330   This only does word splitting in the case of $@ expansion.  In that
7331   case, we split on ' '. */
7332
7333/* Values for the local variable quoted_state. */
7334#define UNQUOTED	 0
7335#define PARTIALLY_QUOTED 1
7336#define WHOLLY_QUOTED    2
7337
7338static WORD_LIST *
7339expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
7340     WORD_DESC *word;
7341     int quoted, isexp;
7342     int *contains_dollar_at;
7343     int *expanded_something;
7344{
7345  WORD_LIST *list;
7346  WORD_DESC *tword;
7347
7348  /* The intermediate string that we build while expanding. */
7349  char *istring;
7350
7351  /* The current size of the above object. */
7352  int istring_size;
7353
7354  /* Index into ISTRING. */
7355  int istring_index;
7356
7357  /* Temporary string storage. */
7358  char *temp, *temp1;
7359
7360  /* The text of WORD. */
7361  register char *string;
7362
7363  /* The size of STRING. */
7364  size_t string_size;
7365
7366  /* The index into STRING. */
7367  int sindex;
7368
7369  /* This gets 1 if we see a $@ while quoted. */
7370  int quoted_dollar_at;
7371
7372  /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
7373     whether WORD contains no quoting characters, a partially quoted
7374     string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
7375  int quoted_state;
7376
7377  /* State flags */
7378  int had_quoted_null;
7379  int has_dollar_at;
7380  int tflag;
7381
7382  int assignoff;		/* If assignment, offset of `=' */
7383
7384  register unsigned char c;	/* Current character. */
7385  int t_index;			/* For calls to string_extract_xxx. */
7386
7387  char twochars[2];
7388
7389  DECLARE_MBSTATE;
7390
7391  istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
7392  istring[istring_index = 0] = '\0';
7393  quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
7394  quoted_state = UNQUOTED;
7395
7396  string = word->word;
7397  if (string == 0)
7398    goto finished_with_string;
7399  /* Don't need the string length for the SADD... and COPY_ macros unless
7400     multibyte characters are possible. */
7401  string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1;
7402
7403  if (contains_dollar_at)
7404    *contains_dollar_at = 0;
7405
7406  assignoff = -1;
7407
7408  /* Begin the expansion. */
7409
7410  for (sindex = 0; ;)
7411    {
7412      c = string[sindex];
7413
7414      /* Case on toplevel character. */
7415      switch (c)
7416	{
7417	case '\0':
7418	  goto finished_with_string;
7419
7420	case CTLESC:
7421	  sindex++;
7422#if HANDLE_MULTIBYTE
7423	  if (MB_CUR_MAX > 1 && string[sindex])
7424	    {
7425	      SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7426	    }
7427	  else
7428#endif
7429	    {
7430	      temp = (char *)xmalloc (3);
7431	      temp[0] = CTLESC;
7432	      temp[1] = c = string[sindex];
7433	      temp[2] = '\0';
7434	    }
7435
7436dollar_add_string:
7437	  if (string[sindex])
7438	    sindex++;
7439
7440add_string:
7441	  if (temp)
7442	    {
7443	      istring = sub_append_string (temp, istring, &istring_index, &istring_size);
7444	      temp = (char *)0;
7445	    }
7446
7447	  break;
7448
7449#if defined (PROCESS_SUBSTITUTION)
7450	  /* Process substitution. */
7451	case '<':
7452	case '>':
7453	  {
7454	    if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || posixly_correct)
7455	      {
7456		sindex--;	/* add_character: label increments sindex */
7457		goto add_character;
7458	      }
7459	    else
7460	      t_index = sindex + 1; /* skip past both '<' and LPAREN */
7461
7462	    temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/
7463	    sindex = t_index;
7464
7465	    /* If the process substitution specification is `<()', we want to
7466	       open the pipe for writing in the child and produce output; if
7467	       it is `>()', we want to open the pipe for reading in the child
7468	       and consume input. */
7469	    temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
7470
7471	    FREE (temp1);
7472
7473	    goto dollar_add_string;
7474	  }
7475#endif /* PROCESS_SUBSTITUTION */
7476
7477	case '=':
7478	  /* Posix.2 section 3.6.1 says that tildes following `=' in words
7479	     which are not assignment statements are not expanded.  If the
7480	     shell isn't in posix mode, though, we perform tilde expansion
7481	     on `likely candidate' unquoted assignment statements (flags
7482	     include W_ASSIGNMENT but not W_QUOTED).  A likely candidate
7483	     contains an unquoted :~ or =~.  Something to think about: we
7484	     now have a flag that says  to perform tilde expansion on arguments
7485	     to `assignment builtins' like declare and export that look like
7486	     assignment statements.  We now do tilde expansion on such words
7487	     even in POSIX mode. */
7488	  if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
7489	    {
7490	      if (isexp == 0 && isifs (c))
7491		goto add_ifs_character;
7492	      else
7493		goto add_character;
7494	    }
7495	  /* If we're not in posix mode or forcing assignment-statement tilde
7496	     expansion, note where the `=' appears in the word and prepare to
7497	     do tilde expansion following the first `='. */
7498	  if ((word->flags & W_ASSIGNMENT) &&
7499	      (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
7500	      assignoff == -1 && sindex > 0)
7501	    assignoff = sindex;
7502	  if (sindex == assignoff && string[sindex+1] == '~')	/* XXX */
7503	    word->flags |= W_ITILDE;
7504#if 0
7505	  else if ((word->flags & W_ASSIGNMENT) &&
7506		   (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
7507		   string[sindex+1] == '~')
7508	    word->flags |= W_ITILDE;
7509#endif
7510	  if (isexp == 0 && isifs (c))
7511	    goto add_ifs_character;
7512	  else
7513	    goto add_character;
7514
7515	case ':':
7516	  if (word->flags & W_NOTILDE)
7517	    {
7518	      if (isexp == 0 && isifs (c))
7519		goto add_ifs_character;
7520	      else
7521		goto add_character;
7522	    }
7523
7524	  if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) &&
7525	      string[sindex+1] == '~')
7526	    word->flags |= W_ITILDE;
7527
7528	  if (isexp == 0 && isifs (c))
7529	    goto add_ifs_character;
7530	  else
7531	    goto add_character;
7532
7533	case '~':
7534	  /* If the word isn't supposed to be tilde expanded, or we're not
7535	     at the start of a word or after an unquoted : or = in an
7536	     assignment statement, we don't do tilde expansion. */
7537	  if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
7538	      (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
7539	      (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7540	    {
7541	      word->flags &= ~W_ITILDE;
7542	      if (isexp == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
7543		goto add_ifs_character;
7544	      else
7545		goto add_character;
7546	    }
7547
7548	  if (word->flags & W_ASSIGNRHS)
7549	    tflag = 2;
7550	  else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
7551	    tflag = 1;
7552	  else
7553	    tflag = 0;
7554
7555	  temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
7556
7557	  word->flags &= ~W_ITILDE;
7558
7559	  if (temp && *temp && t_index > 0)
7560	    {
7561	      temp1 = bash_tilde_expand (temp, tflag);
7562	      if  (temp1 && *temp1 == '~' && STREQ (temp, temp1))
7563		{
7564		  FREE (temp);
7565		  FREE (temp1);
7566		  goto add_character;		/* tilde expansion failed */
7567		}
7568	      free (temp);
7569	      temp = temp1;
7570	      sindex += t_index;
7571	      goto add_quoted_string;		/* XXX was add_string */
7572	    }
7573	  else
7574	    {
7575	      FREE (temp);
7576	      goto add_character;
7577	    }
7578
7579	case '$':
7580	  if (expanded_something)
7581	    *expanded_something = 1;
7582
7583	  has_dollar_at = 0;
7584	  tword = param_expand (string, &sindex, quoted, expanded_something,
7585			       &has_dollar_at, &quoted_dollar_at,
7586			       &had_quoted_null,
7587			       (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0);
7588
7589	  if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
7590	    {
7591	      free (string);
7592	      free (istring);
7593	      return ((tword == &expand_wdesc_error) ? &expand_word_error
7594						     : &expand_word_fatal);
7595	    }
7596	  if (contains_dollar_at && has_dollar_at)
7597	    *contains_dollar_at = 1;
7598
7599	  if (tword && (tword->flags & W_HASQUOTEDNULL))
7600	    had_quoted_null = 1;
7601
7602	  temp = tword->word;
7603	  dispose_word_desc (tword);
7604
7605	  goto add_string;
7606	  break;
7607
7608	case '`':		/* Backquoted command substitution. */
7609	  {
7610	    t_index = sindex++;
7611
7612	    temp = string_extract (string, &sindex, "`", SX_REQMATCH);
7613	    /* The test of sindex against t_index is to allow bare instances of
7614	       ` to pass through, for backwards compatibility. */
7615	    if (temp == &extract_string_error || temp == &extract_string_fatal)
7616	      {
7617		if (sindex - 1 == t_index)
7618		  {
7619		    sindex = t_index;
7620		    goto add_character;
7621		  }
7622		report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
7623		free (string);
7624		free (istring);
7625		return ((temp == &extract_string_error) ? &expand_word_error
7626							: &expand_word_fatal);
7627	      }
7628
7629	    if (expanded_something)
7630	      *expanded_something = 1;
7631
7632	    if (word->flags & W_NOCOMSUB)
7633	      /* sindex + 1 because string[sindex] == '`' */
7634	      temp1 = substring (string, t_index, sindex + 1);
7635	    else
7636	      {
7637		de_backslash (temp);
7638		tword = command_substitute (temp, quoted);
7639		temp1 = tword ? tword->word : (char *)NULL;
7640		if (tword)
7641		  dispose_word_desc (tword);
7642	      }
7643	    FREE (temp);
7644	    temp = temp1;
7645	    goto dollar_add_string;
7646	  }
7647
7648	case '\\':
7649	  if (string[sindex + 1] == '\n')
7650	    {
7651	      sindex += 2;
7652	      continue;
7653	    }
7654
7655	  c = string[++sindex];
7656
7657	  if (quoted & Q_HERE_DOCUMENT)
7658	    tflag = CBSHDOC;
7659	  else if (quoted & Q_DOUBLE_QUOTES)
7660	    tflag = CBSDQUOTE;
7661	  else
7662	    tflag = 0;
7663
7664	  if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
7665	    {
7666	      SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
7667	    }
7668	  else if (c == 0)
7669	    {
7670	      c = CTLNUL;
7671	      sindex--;		/* add_character: label increments sindex */
7672	      goto add_character;
7673	    }
7674	  else
7675	    {
7676	      SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
7677	    }
7678
7679	  sindex++;
7680add_twochars:
7681	  /* BEFORE jumping here, we need to increment sindex if appropriate */
7682	  RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
7683				  DEFAULT_ARRAY_SIZE);
7684	  istring[istring_index++] = twochars[0];
7685	  istring[istring_index++] = twochars[1];
7686	  istring[istring_index] = '\0';
7687
7688	  break;
7689
7690	case '"':
7691#if 0
7692	  if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
7693#else
7694	  if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7695#endif
7696	    goto add_character;
7697
7698	  t_index = ++sindex;
7699	  temp = string_extract_double_quoted (string, &sindex, 0);
7700
7701	  /* If the quotes surrounded the entire string, then the
7702	     whole word was quoted. */
7703	  quoted_state = (t_index == 1 && string[sindex] == '\0')
7704			    ? WHOLLY_QUOTED
7705			    : PARTIALLY_QUOTED;
7706
7707	  if (temp && *temp)
7708	    {
7709	      tword = alloc_word_desc ();
7710	      tword->word = temp;
7711
7712	      temp = (char *)NULL;
7713
7714	      has_dollar_at = 0;
7715	      /* Need to get W_HASQUOTEDNULL flag through this function. */
7716	      list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL);
7717
7718	      if (list == &expand_word_error || list == &expand_word_fatal)
7719		{
7720		  free (istring);
7721		  free (string);
7722		  /* expand_word_internal has already freed temp_word->word
7723		     for us because of the way it prints error messages. */
7724		  tword->word = (char *)NULL;
7725		  dispose_word (tword);
7726		  return list;
7727		}
7728
7729	      dispose_word (tword);
7730
7731	      /* "$@" (a double-quoted dollar-at) expands into nothing,
7732		 not even a NULL word, when there are no positional
7733		 parameters. */
7734	      if (list == 0 && has_dollar_at)
7735		{
7736		  quoted_dollar_at++;
7737		  break;
7738		}
7739
7740	      /* If we get "$@", we know we have expanded something, so we
7741		 need to remember it for the final split on $IFS.  This is
7742		 a special case; it's the only case where a quoted string
7743		 can expand into more than one word.  It's going to come back
7744		 from the above call to expand_word_internal as a list with
7745		 a single word, in which all characters are quoted and
7746		 separated by blanks.  What we want to do is to turn it back
7747		 into a list for the next piece of code. */
7748	      if (list)
7749		dequote_list (list);
7750
7751	      if (list && list->word && (list->word->flags & W_HASQUOTEDNULL))
7752		had_quoted_null = 1;
7753
7754	      if (has_dollar_at)
7755		{
7756		  quoted_dollar_at++;
7757		  if (contains_dollar_at)
7758		    *contains_dollar_at = 1;
7759		  if (expanded_something)
7760		    *expanded_something = 1;
7761		}
7762	    }
7763	  else
7764	    {
7765	      /* What we have is "".  This is a minor optimization. */
7766	      FREE (temp);
7767	      list = (WORD_LIST *)NULL;
7768	    }
7769
7770	  /* The code above *might* return a list (consider the case of "$@",
7771	     where it returns "$1", "$2", etc.).  We can't throw away the
7772	     rest of the list, and we have to make sure each word gets added
7773	     as quoted.  We test on tresult->next:  if it is non-NULL, we
7774	     quote the whole list, save it to a string with string_list, and
7775	     add that string. We don't need to quote the results of this
7776	     (and it would be wrong, since that would quote the separators
7777	     as well), so we go directly to add_string. */
7778	  if (list)
7779	    {
7780	      if (list->next)
7781		{
7782		  /* Testing quoted_dollar_at makes sure that "$@" is
7783		     split correctly when $IFS does not contain a space. */
7784		  temp = quoted_dollar_at
7785				? string_list_dollar_at (list, Q_DOUBLE_QUOTES)
7786				: string_list (quote_list (list));
7787		  dispose_words (list);
7788		  goto add_string;
7789		}
7790	      else
7791		{
7792		  temp = savestring (list->word->word);
7793		  tflag = list->word->flags;
7794		  dispose_words (list);
7795
7796		  /* If the string is not a quoted null string, we want
7797		     to remove any embedded unquoted CTLNUL characters.
7798		     We do not want to turn quoted null strings back into
7799		     the empty string, though.  We do this because we
7800		     want to remove any quoted nulls from expansions that
7801		     contain other characters.  For example, if we have
7802		     x"$*"y or "x$*y" and there are no positional parameters,
7803		     the $* should expand into nothing. */
7804		  /* We use the W_HASQUOTEDNULL flag to differentiate the
7805		     cases:  a quoted null character as above and when
7806		     CTLNUL is contained in the (non-null) expansion
7807		     of some variable.  We use the had_quoted_null flag to
7808		     pass the value through this function to its caller. */
7809		  if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
7810		    remove_quoted_nulls (temp);	/* XXX */
7811		}
7812	    }
7813	  else
7814	    temp = (char *)NULL;
7815
7816	  /* We do not want to add quoted nulls to strings that are only
7817	     partially quoted; we can throw them away. */
7818	  if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
7819	    continue;
7820
7821	add_quoted_string:
7822
7823	  if (temp)
7824	    {
7825	      temp1 = temp;
7826	      temp = quote_string (temp);
7827	      free (temp1);
7828	      goto add_string;
7829	    }
7830	  else
7831	    {
7832	      /* Add NULL arg. */
7833	      c = CTLNUL;
7834	      sindex--;		/* add_character: label increments sindex */
7835	      goto add_character;
7836	    }
7837
7838	  /* break; */
7839
7840	case '\'':
7841#if 0
7842	  if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
7843#else
7844	  if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7845#endif
7846	    goto add_character;
7847
7848	  t_index = ++sindex;
7849	  temp = string_extract_single_quoted (string, &sindex);
7850
7851	  /* If the entire STRING was surrounded by single quotes,
7852	     then the string is wholly quoted. */
7853	  quoted_state = (t_index == 1 && string[sindex] == '\0')
7854			    ? WHOLLY_QUOTED
7855			    : PARTIALLY_QUOTED;
7856
7857	  /* If all we had was '', it is a null expansion. */
7858	  if (*temp == '\0')
7859	    {
7860	      free (temp);
7861	      temp = (char *)NULL;
7862	    }
7863	  else
7864	    remove_quoted_escapes (temp);	/* ??? */
7865
7866	  /* We do not want to add quoted nulls to strings that are only
7867	     partially quoted; such nulls are discarded. */
7868	  if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
7869	    continue;
7870
7871	  /* If we have a quoted null expansion, add a quoted NULL to istring. */
7872	  if (temp == 0)
7873	    {
7874	      c = CTLNUL;
7875	      sindex--;		/* add_character: label increments sindex */
7876	      goto add_character;
7877	    }
7878	  else
7879	    goto add_quoted_string;
7880
7881	  /* break; */
7882
7883	default:
7884	  /* This is the fix for " $@ " */
7885	add_ifs_character:
7886	  if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c)))
7887	    {
7888	      if (string[sindex])	/* from old goto dollar_add_string */
7889		sindex++;
7890	      if (c == 0)
7891		{
7892		  c = CTLNUL;
7893		  goto add_character;
7894		}
7895	      else
7896		{
7897#if HANDLE_MULTIBYTE
7898		  if (MB_CUR_MAX > 1)
7899		    sindex--;
7900
7901		  if (MB_CUR_MAX > 1)
7902		    {
7903		      SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7904		    }
7905		  else
7906#endif
7907		    {
7908		      twochars[0] = CTLESC;
7909		      twochars[1] = c;
7910		      goto add_twochars;
7911		    }
7912		}
7913	    }
7914
7915	  SADD_MBCHAR (temp, string, sindex, string_size);
7916
7917	add_character:
7918	  RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
7919				  DEFAULT_ARRAY_SIZE);
7920	  istring[istring_index++] = c;
7921	  istring[istring_index] = '\0';
7922
7923	  /* Next character. */
7924	  sindex++;
7925	}
7926    }
7927
7928finished_with_string:
7929  /* OK, we're ready to return.  If we have a quoted string, and
7930     quoted_dollar_at is not set, we do no splitting at all; otherwise
7931     we split on ' '.  The routines that call this will handle what to
7932     do if nothing has been expanded. */
7933
7934  /* Partially and wholly quoted strings which expand to the empty
7935     string are retained as an empty arguments.  Unquoted strings
7936     which expand to the empty string are discarded.  The single
7937     exception is the case of expanding "$@" when there are no
7938     positional parameters.  In that case, we discard the expansion. */
7939
7940  /* Because of how the code that handles "" and '' in partially
7941     quoted strings works, we need to make ISTRING into a QUOTED_NULL
7942     if we saw quoting characters, but the expansion was empty.
7943     "" and '' are tossed away before we get to this point when
7944     processing partially quoted strings.  This makes "" and $xxx""
7945     equivalent when xxx is unset.  We also look to see whether we
7946     saw a quoted null from a ${} expansion and add one back if we
7947     need to. */
7948
7949  /* If we expand to nothing and there were no single or double quotes
7950     in the word, we throw it away.  Otherwise, we return a NULL word.
7951     The single exception is for $@ surrounded by double quotes when
7952     there are no positional parameters.  In that case, we also throw
7953     the word away. */
7954
7955  if (*istring == '\0')
7956    {
7957      if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
7958	{
7959	  istring[0] = CTLNUL;
7960	  istring[1] = '\0';
7961	  tword = make_bare_word (istring);
7962	  tword->flags |= W_HASQUOTEDNULL;		/* XXX */
7963	  list = make_word_list (tword, (WORD_LIST *)NULL);
7964	  if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7965	    tword->flags |= W_QUOTED;
7966	}
7967      /* According to sh, ksh, and Posix.2, if a word expands into nothing
7968	 and a double-quoted "$@" appears anywhere in it, then the entire
7969	 word is removed. */
7970      else  if (quoted_state == UNQUOTED || quoted_dollar_at)
7971	list = (WORD_LIST *)NULL;
7972#if 0
7973      else
7974	{
7975	  tword = make_bare_word (istring);
7976	  if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7977	    tword->flags |= W_QUOTED;
7978	  list = make_word_list (tword, (WORD_LIST *)NULL);
7979	}
7980#else
7981      else
7982	list = (WORD_LIST *)NULL;
7983#endif
7984    }
7985  else if (word->flags & W_NOSPLIT)
7986    {
7987      tword = make_bare_word (istring);
7988      if (word->flags & W_ASSIGNMENT)
7989	tword->flags |= W_ASSIGNMENT;	/* XXX */
7990      if (word->flags & W_COMPASSIGN)
7991	tword->flags |= W_COMPASSIGN;	/* XXX */
7992      if (word->flags & W_NOGLOB)
7993	tword->flags |= W_NOGLOB;	/* XXX */
7994      if (word->flags & W_NOEXPAND)
7995	tword->flags |= W_NOEXPAND;	/* XXX */
7996      if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7997	tword->flags |= W_QUOTED;
7998      if (had_quoted_null)
7999	tword->flags |= W_HASQUOTEDNULL;
8000      list = make_word_list (tword, (WORD_LIST *)NULL);
8001    }
8002  else
8003    {
8004      char *ifs_chars;
8005
8006      ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
8007
8008      /* If we have $@, we need to split the results no matter what.  If
8009	 IFS is unset or NULL, string_list_dollar_at has separated the
8010	 positional parameters with a space, so we split on space (we have
8011	 set ifs_chars to " \t\n" above if ifs is unset).  If IFS is set,
8012	 string_list_dollar_at has separated the positional parameters
8013	 with the first character of $IFS, so we split on $IFS. */
8014      if (has_dollar_at && ifs_chars)
8015	list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
8016      else
8017	{
8018	  tword = make_bare_word (istring);
8019	  if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
8020	    tword->flags |= W_QUOTED;
8021	  if (word->flags & W_ASSIGNMENT)
8022	    tword->flags |= W_ASSIGNMENT;
8023	  if (word->flags & W_COMPASSIGN)
8024	    tword->flags |= W_COMPASSIGN;
8025	  if (word->flags & W_NOGLOB)
8026	    tword->flags |= W_NOGLOB;
8027	  if (word->flags & W_NOEXPAND)
8028	    tword->flags |= W_NOEXPAND;
8029	  if (had_quoted_null)
8030	    tword->flags |= W_HASQUOTEDNULL;	/* XXX */
8031	  list = make_word_list (tword, (WORD_LIST *)NULL);
8032	}
8033    }
8034
8035  free (istring);
8036  return (list);
8037}
8038
8039/* **************************************************************** */
8040/*								    */
8041/*		   Functions for Quote Removal			    */
8042/*								    */
8043/* **************************************************************** */
8044
8045/* Perform quote removal on STRING.  If QUOTED > 0, assume we are obeying the
8046   backslash quoting rules for within double quotes or a here document. */
8047char *
8048string_quote_removal (string, quoted)
8049     char *string;
8050     int quoted;
8051{
8052  size_t slen;
8053  char *r, *result_string, *temp, *send;
8054  int sindex, tindex, dquote;
8055  unsigned char c;
8056  DECLARE_MBSTATE;
8057
8058  /* The result can be no longer than the original string. */
8059  slen = strlen (string);
8060  send = string + slen;
8061
8062  r = result_string = (char *)xmalloc (slen + 1);
8063
8064  for (dquote = sindex = 0; c = string[sindex];)
8065    {
8066      switch (c)
8067	{
8068	case '\\':
8069	  c = string[++sindex];
8070	  if (c == 0)
8071	    {
8072	      *r++ = '\\';
8073	      break;
8074	    }
8075	  if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
8076	    *r++ = '\\';
8077	  /* FALLTHROUGH */
8078
8079	default:
8080	  SCOPY_CHAR_M (r, string, send, sindex);
8081	  break;
8082
8083	case '\'':
8084	  if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
8085	    {
8086	      *r++ = c;
8087	      sindex++;
8088	      break;
8089	    }
8090	  tindex = sindex + 1;
8091	  temp = string_extract_single_quoted (string, &tindex);
8092	  if (temp)
8093	    {
8094	      strcpy (r, temp);
8095	      r += strlen (r);
8096	      free (temp);
8097	    }
8098	  sindex = tindex;
8099	  break;
8100
8101	case '"':
8102	  dquote = 1 - dquote;
8103	  sindex++;
8104	  break;
8105	}
8106    }
8107    *r = '\0';
8108    return (result_string);
8109}
8110
8111#if 0
8112/* UNUSED */
8113/* Perform quote removal on word WORD.  This allocates and returns a new
8114   WORD_DESC *. */
8115WORD_DESC *
8116word_quote_removal (word, quoted)
8117     WORD_DESC *word;
8118     int quoted;
8119{
8120  WORD_DESC *w;
8121  char *t;
8122
8123  t = string_quote_removal (word->word, quoted);
8124  w = alloc_word_desc ();
8125  w->word = t ? t : savestring ("");
8126  return (w);
8127}
8128
8129/* Perform quote removal on all words in LIST.  If QUOTED is non-zero,
8130   the members of the list are treated as if they are surrounded by
8131   double quotes.  Return a new list, or NULL if LIST is NULL. */
8132WORD_LIST *
8133word_list_quote_removal (list, quoted)
8134     WORD_LIST *list;
8135     int quoted;
8136{
8137  WORD_LIST *result, *t, *tresult, *e;
8138
8139  for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
8140    {
8141      tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
8142#if 0
8143      result = (WORD_LIST *) list_append (result, tresult);
8144#else
8145      if (result == 0)
8146	result = e = tresult;
8147      else
8148	{
8149	  e->next = tresult;
8150	  while (e->next)
8151	    e = e->next;
8152	}
8153#endif
8154    }
8155  return (result);
8156}
8157#endif
8158
8159/*******************************************
8160 *					   *
8161 *    Functions to perform word splitting  *
8162 *					   *
8163 *******************************************/
8164
8165void
8166setifs (v)
8167     SHELL_VAR *v;
8168{
8169  char *t;
8170  unsigned char uc;
8171
8172  ifs_var = v;
8173  ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
8174
8175  /* Should really merge ifs_cmap with sh_syntaxtab.  XXX - doesn't yet
8176     handle multibyte chars in IFS */
8177  memset (ifs_cmap, '\0', sizeof (ifs_cmap));
8178  for (t = ifs_value ; t && *t; t++)
8179    {
8180      uc = *t;
8181      ifs_cmap[uc] = 1;
8182    }
8183
8184#if defined (HANDLE_MULTIBYTE)
8185  if (ifs_value == 0)
8186    {
8187      ifs_firstc[0] = '\0';
8188      ifs_firstc_len = 1;
8189    }
8190  else
8191    {
8192      size_t ifs_len;
8193      ifs_len = strnlen (ifs_value, MB_CUR_MAX);
8194      ifs_firstc_len = MBLEN (ifs_value, ifs_len);
8195      if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
8196	{
8197	  ifs_firstc[0] = ifs_value[0];
8198	  ifs_firstc[1] = '\0';
8199	  ifs_firstc_len = 1;
8200	}
8201      else
8202	memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
8203    }
8204#else
8205  ifs_firstc = ifs_value ? *ifs_value : 0;
8206#endif
8207}
8208
8209char *
8210getifs ()
8211{
8212  return ifs_value;
8213}
8214
8215/* This splits a single word into a WORD LIST on $IFS, but only if the word
8216   is not quoted.  list_string () performs quote removal for us, even if we
8217   don't do any splitting. */
8218WORD_LIST *
8219word_split (w, ifs_chars)
8220     WORD_DESC *w;
8221     char *ifs_chars;
8222{
8223  WORD_LIST *result;
8224
8225  if (w)
8226    {
8227      char *xifs;
8228
8229      xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
8230      result = list_string (w->word, xifs, w->flags & W_QUOTED);
8231    }
8232  else
8233    result = (WORD_LIST *)NULL;
8234
8235  return (result);
8236}
8237
8238/* Perform word splitting on LIST and return the RESULT.  It is possible
8239   to return (WORD_LIST *)NULL. */
8240static WORD_LIST *
8241word_list_split (list)
8242     WORD_LIST *list;
8243{
8244  WORD_LIST *result, *t, *tresult, *e;
8245
8246  for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
8247    {
8248      tresult = word_split (t->word, ifs_value);
8249      if (result == 0)
8250        result = e = tresult;
8251      else
8252	{
8253	  e->next = tresult;
8254	  while (e->next)
8255	    e = e->next;
8256	}
8257    }
8258  return (result);
8259}
8260
8261/**************************************************
8262 * 						  *
8263 *    Functions to expand an entire WORD_LIST	  *
8264 *						  *
8265 **************************************************/
8266
8267/* Do any word-expansion-specific cleanup and jump to top_level */
8268static void
8269exp_jump_to_top_level (v)
8270     int v;
8271{
8272  set_pipestatus_from_exit (last_command_exit_value);
8273
8274  /* Cleanup code goes here. */
8275  expand_no_split_dollar_star = 0;	/* XXX */
8276  expanding_redir = 0;
8277  assigning_in_environment = 0;
8278
8279  if (parse_and_execute_level == 0)
8280    top_level_cleanup ();			/* from sig.c */
8281
8282  jump_to_top_level (v);
8283}
8284
8285/* Put NLIST (which is a WORD_LIST * of only one element) at the front of
8286   ELIST, and set ELIST to the new list. */
8287#define PREPEND_LIST(nlist, elist) \
8288	do { nlist->next = elist; elist = nlist; } while (0)
8289
8290/* Separate out any initial variable assignments from TLIST.  If set -k has
8291   been executed, remove all assignment statements from TLIST.  Initial
8292   variable assignments and other environment assignments are placed
8293   on SUBST_ASSIGN_VARLIST. */
8294static WORD_LIST *
8295separate_out_assignments (tlist)
8296     WORD_LIST *tlist;
8297{
8298  register WORD_LIST *vp, *lp;
8299
8300  if (!tlist)
8301    return ((WORD_LIST *)NULL);
8302
8303  if (subst_assign_varlist)
8304    dispose_words (subst_assign_varlist);	/* Clean up after previous error */
8305
8306  subst_assign_varlist = (WORD_LIST *)NULL;
8307  vp = lp = tlist;
8308
8309  /* Separate out variable assignments at the start of the command.
8310     Loop invariant: vp->next == lp
8311     Loop postcondition:
8312	lp = list of words left after assignment statements skipped
8313	tlist = original list of words
8314  */
8315  while (lp && (lp->word->flags & W_ASSIGNMENT))
8316    {
8317      vp = lp;
8318      lp = lp->next;
8319    }
8320
8321  /* If lp != tlist, we have some initial assignment statements.
8322     We make SUBST_ASSIGN_VARLIST point to the list of assignment
8323     words and TLIST point to the remaining words.  */
8324  if (lp != tlist)
8325    {
8326      subst_assign_varlist = tlist;
8327      /* ASSERT(vp->next == lp); */
8328      vp->next = (WORD_LIST *)NULL;	/* terminate variable list */
8329      tlist = lp;			/* remainder of word list */
8330    }
8331
8332  /* vp == end of variable list */
8333  /* tlist == remainder of original word list without variable assignments */
8334  if (!tlist)
8335    /* All the words in tlist were assignment statements */
8336    return ((WORD_LIST *)NULL);
8337
8338  /* ASSERT(tlist != NULL); */
8339  /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
8340
8341  /* If the -k option is in effect, we need to go through the remaining
8342     words, separate out the assignment words, and place them on
8343     SUBST_ASSIGN_VARLIST. */
8344  if (place_keywords_in_env)
8345    {
8346      WORD_LIST *tp;	/* tp == running pointer into tlist */
8347
8348      tp = tlist;
8349      lp = tlist->next;
8350
8351      /* Loop Invariant: tp->next == lp */
8352      /* Loop postcondition: tlist == word list without assignment statements */
8353      while (lp)
8354	{
8355	  if (lp->word->flags & W_ASSIGNMENT)
8356	    {
8357	      /* Found an assignment statement, add this word to end of
8358		 subst_assign_varlist (vp). */
8359	      if (!subst_assign_varlist)
8360		subst_assign_varlist = vp = lp;
8361	      else
8362		{
8363		  vp->next = lp;
8364		  vp = lp;
8365		}
8366
8367	      /* Remove the word pointed to by LP from TLIST. */
8368	      tp->next = lp->next;
8369	      /* ASSERT(vp == lp); */
8370	      lp->next = (WORD_LIST *)NULL;
8371	      lp = tp->next;
8372	    }
8373	  else
8374	    {
8375	      tp = lp;
8376	      lp = lp->next;
8377	    }
8378	}
8379    }
8380  return (tlist);
8381}
8382
8383#define WEXP_VARASSIGN	0x001
8384#define WEXP_BRACEEXP	0x002
8385#define WEXP_TILDEEXP	0x004
8386#define WEXP_PARAMEXP	0x008
8387#define WEXP_PATHEXP	0x010
8388
8389/* All of the expansions, including variable assignments at the start of
8390   the list. */
8391#define WEXP_ALL	(WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
8392
8393/* All of the expansions except variable assignments at the start of
8394   the list. */
8395#define WEXP_NOVARS	(WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
8396
8397/* All of the `shell expansions': brace expansion, tilde expansion, parameter
8398   expansion, command substitution, arithmetic expansion, word splitting, and
8399   quote removal. */
8400#define WEXP_SHELLEXP	(WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
8401
8402/* Take the list of words in LIST and do the various substitutions.  Return
8403   a new list of words which is the expanded list, and without things like
8404   variable assignments. */
8405
8406WORD_LIST *
8407expand_words (list)
8408     WORD_LIST *list;
8409{
8410  return (expand_word_list_internal (list, WEXP_ALL));
8411}
8412
8413/* Same as expand_words (), but doesn't hack variable or environment
8414   variables. */
8415WORD_LIST *
8416expand_words_no_vars (list)
8417     WORD_LIST *list;
8418{
8419  return (expand_word_list_internal (list, WEXP_NOVARS));
8420}
8421
8422WORD_LIST *
8423expand_words_shellexp (list)
8424     WORD_LIST *list;
8425{
8426  return (expand_word_list_internal (list, WEXP_SHELLEXP));
8427}
8428
8429static WORD_LIST *
8430glob_expand_word_list (tlist, eflags)
8431     WORD_LIST *tlist;
8432     int eflags;
8433{
8434  char **glob_array, *temp_string;
8435  register int glob_index;
8436  WORD_LIST *glob_list, *output_list, *disposables, *next;
8437  WORD_DESC *tword;
8438
8439  output_list = disposables = (WORD_LIST *)NULL;
8440  glob_array = (char **)NULL;
8441  while (tlist)
8442    {
8443      /* For each word, either globbing is attempted or the word is
8444	 added to orig_list.  If globbing succeeds, the results are
8445	 added to orig_list and the word (tlist) is added to the list
8446	 of disposable words.  If globbing fails and failed glob
8447	 expansions are left unchanged (the shell default), the
8448	 original word is added to orig_list.  If globbing fails and
8449	 failed glob expansions are removed, the original word is
8450	 added to the list of disposable words.  orig_list ends up
8451	 in reverse order and requires a call to REVERSE_LIST to
8452	 be set right.  After all words are examined, the disposable
8453	 words are freed. */
8454      next = tlist->next;
8455
8456      /* If the word isn't an assignment and contains an unquoted
8457	 pattern matching character, then glob it. */
8458      if ((tlist->word->flags & W_NOGLOB) == 0 &&
8459	  unquoted_glob_pattern_p (tlist->word->word))
8460	{
8461	  glob_array = shell_glob_filename (tlist->word->word);
8462
8463	  /* Handle error cases.
8464	     I don't think we should report errors like "No such file
8465	     or directory".  However, I would like to report errors
8466	     like "Read failed". */
8467
8468	  if (glob_array == 0 || GLOB_FAILED (glob_array))
8469	    {
8470	      glob_array = (char **)xmalloc (sizeof (char *));
8471	      glob_array[0] = (char *)NULL;
8472	    }
8473
8474	  /* Dequote the current word in case we have to use it. */
8475	  if (glob_array[0] == NULL)
8476	    {
8477	      temp_string = dequote_string (tlist->word->word);
8478	      free (tlist->word->word);
8479	      tlist->word->word = temp_string;
8480	    }
8481
8482	  /* Make the array into a word list. */
8483	  glob_list = (WORD_LIST *)NULL;
8484	  for (glob_index = 0; glob_array[glob_index]; glob_index++)
8485	    {
8486	      tword = make_bare_word (glob_array[glob_index]);
8487	      tword->flags |= W_GLOBEXP;	/* XXX */
8488	      glob_list = make_word_list (tword, glob_list);
8489	    }
8490
8491	  if (glob_list)
8492	    {
8493	      output_list = (WORD_LIST *)list_append (glob_list, output_list);
8494	      PREPEND_LIST (tlist, disposables);
8495	    }
8496	  else if (fail_glob_expansion != 0)
8497	    {
8498	      report_error (_("no match: %s"), tlist->word->word);
8499	      exp_jump_to_top_level (DISCARD);
8500	    }
8501	  else if (allow_null_glob_expansion == 0)
8502	    {
8503	      /* Failed glob expressions are left unchanged. */
8504	      PREPEND_LIST (tlist, output_list);
8505	    }
8506	  else
8507	    {
8508	      /* Failed glob expressions are removed. */
8509	      PREPEND_LIST (tlist, disposables);
8510	    }
8511	}
8512      else
8513	{
8514	  /* Dequote the string. */
8515	  temp_string = dequote_string (tlist->word->word);
8516	  free (tlist->word->word);
8517	  tlist->word->word = temp_string;
8518	  PREPEND_LIST (tlist, output_list);
8519	}
8520
8521      strvec_dispose (glob_array);
8522      glob_array = (char **)NULL;
8523
8524      tlist = next;
8525    }
8526
8527  if (disposables)
8528    dispose_words (disposables);
8529
8530  if (output_list)
8531    output_list = REVERSE_LIST (output_list, WORD_LIST *);
8532
8533  return (output_list);
8534}
8535
8536#if defined (BRACE_EXPANSION)
8537static WORD_LIST *
8538brace_expand_word_list (tlist, eflags)
8539     WORD_LIST *tlist;
8540     int eflags;
8541{
8542  register char **expansions;
8543  char *temp_string;
8544  WORD_LIST *disposables, *output_list, *next;
8545  WORD_DESC *w;
8546  int eindex;
8547
8548  for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
8549    {
8550      next = tlist->next;
8551
8552      /* Only do brace expansion if the word has a brace character.  If
8553	 not, just add the word list element to BRACES and continue.  In
8554	 the common case, at least when running shell scripts, this will
8555	 degenerate to a bunch of calls to `xstrchr', and then what is
8556	 basically a reversal of TLIST into BRACES, which is corrected
8557	 by a call to REVERSE_LIST () on BRACES when the end of TLIST
8558	 is reached. */
8559      if (xstrchr (tlist->word->word, LBRACE))
8560	{
8561	  expansions = brace_expand (tlist->word->word);
8562
8563	  for (eindex = 0; temp_string = expansions[eindex]; eindex++)
8564	    {
8565	      w = make_word (temp_string);
8566	      /* If brace expansion didn't change the word, preserve
8567		 the flags.  We may want to preserve the flags
8568		 unconditionally someday -- XXX */
8569	      if (STREQ (temp_string, tlist->word->word))
8570		w->flags = tlist->word->flags;
8571	      output_list = make_word_list (w, output_list);
8572	      free (expansions[eindex]);
8573	    }
8574	  free (expansions);
8575
8576	  /* Add TLIST to the list of words to be freed after brace
8577	     expansion has been performed. */
8578	  PREPEND_LIST (tlist, disposables);
8579	}
8580      else
8581	PREPEND_LIST (tlist, output_list);
8582    }
8583
8584  if (disposables)
8585    dispose_words (disposables);
8586
8587  if (output_list)
8588    output_list = REVERSE_LIST (output_list, WORD_LIST *);
8589
8590  return (output_list);
8591}
8592#endif
8593
8594#if defined (ARRAY_VARS)
8595/* Take WORD, a compound associative array assignment, and internally run
8596   'declare -A w', where W is the variable name portion of WORD. */
8597static int
8598make_internal_declare (word, option)
8599     char *word;
8600     char *option;
8601{
8602  int t;
8603  WORD_LIST *wl;
8604  WORD_DESC *w;
8605
8606  w = make_word (word);
8607
8608  t = assignment (w->word, 0);
8609  w->word[t] = '\0';
8610
8611  wl = make_word_list (w, (WORD_LIST *)NULL);
8612  wl = make_word_list (make_word (option), wl);
8613
8614  return (declare_builtin (wl));
8615}
8616#endif
8617
8618static WORD_LIST *
8619shell_expand_word_list (tlist, eflags)
8620     WORD_LIST *tlist;
8621     int eflags;
8622{
8623  WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list;
8624  int expanded_something, has_dollar_at;
8625  char *temp_string;
8626
8627  /* We do tilde expansion all the time.  This is what 1003.2 says. */
8628  new_list = (WORD_LIST *)NULL;
8629  for (orig_list = tlist; tlist; tlist = next)
8630    {
8631      temp_string = tlist->word->word;
8632
8633      next = tlist->next;
8634
8635#if defined (ARRAY_VARS)
8636      /* If this is a compound array assignment to a builtin that accepts
8637         such assignments (e.g., `declare'), take the assignment and perform
8638         it separately, handling the semantics of declarations inside shell
8639         functions.  This avoids the double-evaluation of such arguments,
8640         because `declare' does some evaluation of compound assignments on
8641         its own. */
8642      if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
8643	{
8644	  int t;
8645
8646	  if (tlist->word->flags & W_ASSIGNASSOC)
8647	    make_internal_declare (tlist->word->word, "-A");
8648
8649	  t = do_word_assignment (tlist->word);
8650	  if (t == 0)
8651	    {
8652	      last_command_exit_value = EXECUTION_FAILURE;
8653	      exp_jump_to_top_level (DISCARD);
8654	    }
8655
8656	  /* Now transform the word as ksh93 appears to do and go on */
8657	  t = assignment (tlist->word->word, 0);
8658	  tlist->word->word[t] = '\0';
8659	  tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC);
8660	}
8661#endif
8662
8663      expanded_something = 0;
8664      expanded = expand_word_internal
8665	(tlist->word, 0, 0, &has_dollar_at, &expanded_something);
8666
8667      if (expanded == &expand_word_error || expanded == &expand_word_fatal)
8668	{
8669	  /* By convention, each time this error is returned,
8670	     tlist->word->word has already been freed. */
8671	  tlist->word->word = (char *)NULL;
8672
8673	  /* Dispose our copy of the original list. */
8674	  dispose_words (orig_list);
8675	  /* Dispose the new list we're building. */
8676	  dispose_words (new_list);
8677
8678	  last_command_exit_value = EXECUTION_FAILURE;
8679	  if (expanded == &expand_word_error)
8680	    exp_jump_to_top_level (DISCARD);
8681	  else
8682	    exp_jump_to_top_level (FORCE_EOF);
8683	}
8684
8685      /* Don't split words marked W_NOSPLIT. */
8686      if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
8687	{
8688	  temp_list = word_list_split (expanded);
8689	  dispose_words (expanded);
8690	}
8691      else
8692	{
8693	  /* If no parameter expansion, command substitution, process
8694	     substitution, or arithmetic substitution took place, then
8695	     do not do word splitting.  We still have to remove quoted
8696	     null characters from the result. */
8697	  word_list_remove_quoted_nulls (expanded);
8698	  temp_list = expanded;
8699	}
8700
8701      expanded = REVERSE_LIST (temp_list, WORD_LIST *);
8702      new_list = (WORD_LIST *)list_append (expanded, new_list);
8703    }
8704
8705  if (orig_list)
8706    dispose_words (orig_list);
8707
8708  if (new_list)
8709    new_list = REVERSE_LIST (new_list, WORD_LIST *);
8710
8711  return (new_list);
8712}
8713
8714/* The workhorse for expand_words () and expand_words_no_vars ().
8715   First arg is LIST, a WORD_LIST of words.
8716   Second arg EFLAGS is a flags word controlling which expansions are
8717   performed.
8718
8719   This does all of the substitutions: brace expansion, tilde expansion,
8720   parameter expansion, command substitution, arithmetic expansion,
8721   process substitution, word splitting, and pathname expansion, according
8722   to the bits set in EFLAGS.  Words with the W_QUOTED or W_NOSPLIT bits
8723   set, or for which no expansion is done, do not undergo word splitting.
8724   Words with the W_NOGLOB bit set do not undergo pathname expansion. */
8725static WORD_LIST *
8726expand_word_list_internal (list, eflags)
8727     WORD_LIST *list;
8728     int eflags;
8729{
8730  WORD_LIST *new_list, *temp_list;
8731  int tint;
8732
8733  if (list == 0)
8734    return ((WORD_LIST *)NULL);
8735
8736  garglist = new_list = copy_word_list (list);
8737  if (eflags & WEXP_VARASSIGN)
8738    {
8739      garglist = new_list = separate_out_assignments (new_list);
8740      if (new_list == 0)
8741	{
8742	  if (subst_assign_varlist)
8743	    {
8744	      /* All the words were variable assignments, so they are placed
8745		 into the shell's environment. */
8746	      for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
8747		{
8748		  this_command_name = (char *)NULL;	/* no arithmetic errors */
8749		  tint = do_word_assignment (temp_list->word);
8750		  /* Variable assignment errors in non-interactive shells
8751		     running in Posix.2 mode cause the shell to exit. */
8752		  if (tint == 0)
8753		    {
8754		      last_command_exit_value = EXECUTION_FAILURE;
8755		      if (interactive_shell == 0 && posixly_correct)
8756			exp_jump_to_top_level (FORCE_EOF);
8757		      else
8758			exp_jump_to_top_level (DISCARD);
8759		    }
8760		}
8761	      dispose_words (subst_assign_varlist);
8762	      subst_assign_varlist = (WORD_LIST *)NULL;
8763	    }
8764	  return ((WORD_LIST *)NULL);
8765	}
8766    }
8767
8768  /* Begin expanding the words that remain.  The expansions take place on
8769     things that aren't really variable assignments. */
8770
8771#if defined (BRACE_EXPANSION)
8772  /* Do brace expansion on this word if there are any brace characters
8773     in the string. */
8774  if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
8775    new_list = brace_expand_word_list (new_list, eflags);
8776#endif /* BRACE_EXPANSION */
8777
8778  /* Perform the `normal' shell expansions: tilde expansion, parameter and
8779     variable substitution, command substitution, arithmetic expansion,
8780     and word splitting. */
8781  new_list = shell_expand_word_list (new_list, eflags);
8782
8783  /* Okay, we're almost done.  Now let's just do some filename
8784     globbing. */
8785  if (new_list)
8786    {
8787      if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
8788	/* Glob expand the word list unless globbing has been disabled. */
8789	new_list = glob_expand_word_list (new_list, eflags);
8790      else
8791	/* Dequote the words, because we're not performing globbing. */
8792	new_list = dequote_list (new_list);
8793    }
8794
8795  if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
8796    {
8797      sh_wassign_func_t *assign_func;
8798
8799      /* If the remainder of the words expand to nothing, Posix.2 requires
8800	 that the variable and environment assignments affect the shell's
8801	 environment. */
8802      assign_func = new_list ? assign_in_env : do_word_assignment;
8803      tempenv_assign_error = 0;
8804
8805      for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
8806	{
8807	  this_command_name = (char *)NULL;
8808	  assigning_in_environment = (assign_func == assign_in_env);
8809	  tint = (*assign_func) (temp_list->word);
8810	  assigning_in_environment = 0;
8811	  /* Variable assignment errors in non-interactive shells running
8812	     in Posix.2 mode cause the shell to exit. */
8813	  if (tint == 0)
8814	    {
8815	      if (assign_func == do_word_assignment)
8816		{
8817		  last_command_exit_value = EXECUTION_FAILURE;
8818		  if (interactive_shell == 0 && posixly_correct)
8819		    exp_jump_to_top_level (FORCE_EOF);
8820		  else
8821		    exp_jump_to_top_level (DISCARD);
8822		}
8823	      else
8824		tempenv_assign_error++;
8825	    }
8826	}
8827
8828      dispose_words (subst_assign_varlist);
8829      subst_assign_varlist = (WORD_LIST *)NULL;
8830    }
8831
8832#if 0
8833  tint = list_length (new_list) + 1;
8834  RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
8835  for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next)
8836    glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0';
8837  glob_argv_flags[tint] = '\0';
8838#endif
8839
8840  return (new_list);
8841}
8842