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