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