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