commit bash-20051123 snapshot
[platform/upstream/bash.git] / subst.c.save1
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           temp = (xstrchr (temp, '~') && unquoted_member ('~', temp))
2168                         ? bash_tilde_expand (temp, 2)
2169                         : savestring (temp);
2170
2171           value = expand_string_if_necessary (temp, 0, expand_string_assignment);
2172           free (temp);
2173         }
2174       else
2175         value = savestring (temp);
2176     }
2177
2178   if (value == 0)
2179     {
2180       value = (char *)xmalloc (1);
2181       value[0] = '\0';
2182     }
2183
2184   if (echo_command_at_execute)
2185      xtrace_print_assignment (name, value, assign_list, 1);
2186
2187 #define ASSIGN_RETURN(r)        do { FREE (value); free (name); return (r); } while (0)
2188
2189 #if defined (ARRAY_VARS)
2190   if (t = xstrchr (name, '['))  /*]*/
2191     {
2192       if (assign_list)
2193         {
2194           report_error (_("%s: cannot assign list to array member"), name);
2195           ASSIGN_RETURN (0);
2196         }
2197       entry = assign_array_element (name, value);
2198       if (entry == 0)
2199         ASSIGN_RETURN (0);
2200     }
2201   else if (assign_list)
2202     entry = assign_array_from_string (name, value);
2203   else
2204 #endif /* ARRAY_VARS */
2205   entry = bind_variable (name, value);
2206
2207   stupidly_hack_special_variables (name);
2208
2209   if (entry)
2210     VUNSETATTR (entry, att_invisible);
2211
2212   /* Return 1 if the assignment seems to have been performed correctly. */
2213   ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0);
2214 }
2215
2216 /* Perform the assignment statement in STRING, and expand the
2217    right side by doing command and parameter expansion. */
2218 int
2219 do_assignment (string)
2220      const char *string;
2221 {
2222   return do_assignment_internal (string, 1);
2223 }
2224
2225 /* Given STRING, an assignment string, get the value of the right side
2226    of the `=', and bind it to the left side.  Do not do command and
2227    parameter substitution on the right hand side. */
2228 int
2229 do_assignment_no_expand (string)
2230      const char *string;
2231 {
2232   return do_assignment_internal (string, 0);
2233 }
2234
2235 /***************************************************
2236  *                                                 *
2237  *  Functions to manage the positional parameters  *
2238  *                                                 *
2239  ***************************************************/
2240
2241 /* Return the word list that corresponds to `$*'. */
2242 WORD_LIST *
2243 list_rest_of_args ()
2244 {
2245   register WORD_LIST *list, *args;
2246   int i;
2247
2248   /* Break out of the loop as soon as one of the dollar variables is null. */
2249   for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
2250     list = make_word_list (make_bare_word (dollar_vars[i]), list);
2251
2252   for (args = rest_of_args; args; args = args->next)
2253     list = make_word_list (make_bare_word (args->word->word), list);
2254
2255   return (REVERSE_LIST (list, WORD_LIST *));
2256 }
2257
2258 int
2259 number_of_args ()
2260 {
2261   register WORD_LIST *list;
2262   int n;
2263
2264   for (n = 0; n < 9 && dollar_vars[n+1]; n++)
2265     ;
2266   for (list = rest_of_args; list; list = list->next)
2267     n++;
2268   return n;
2269 }
2270
2271 /* Return the value of a positional parameter.  This handles values > 10. */
2272 char *
2273 get_dollar_var_value (ind)
2274      intmax_t ind;
2275 {
2276   char *temp;
2277   WORD_LIST *p;
2278
2279   if (ind < 10)
2280     temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
2281   else  /* We want something like ${11} */
2282     {
2283       ind -= 10;
2284       for (p = rest_of_args; p && ind--; p = p->next)
2285         ;
2286       temp = p ? savestring (p->word->word) : (char *)NULL;
2287     }
2288   return (temp);
2289 }
2290
2291 /* Make a single large string out of the dollar digit variables,
2292    and the rest_of_args.  If DOLLAR_STAR is 1, then obey the special
2293    case of "$*" with respect to IFS. */
2294 char *
2295 string_rest_of_args (dollar_star)
2296      int dollar_star;
2297 {
2298   register WORD_LIST *list;
2299   char *string;
2300
2301   list = list_rest_of_args ();
2302   string = dollar_star ? string_list_dollar_star (list) : string_list (list);
2303   dispose_words (list);
2304   return (string);
2305 }
2306
2307 /* Return a string containing the positional parameters from START to
2308    END, inclusive.  If STRING[0] == '*', we obey the rules for $*,
2309    which only makes a difference if QUOTED is non-zero.  If QUOTED includes
2310    Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise
2311    no quoting chars are added. */
2312 static char *
2313 pos_params (string, start, end, quoted)
2314      char *string;
2315      int start, end, quoted;
2316 {
2317   WORD_LIST *save, *params, *h, *t;
2318   char *ret;
2319   int i;
2320
2321   /* see if we can short-circuit.  if start == end, we want 0 parameters. */
2322   if (start == end)
2323     return ((char *)NULL);
2324
2325   save = params = list_rest_of_args ();
2326   if (save == 0)
2327     return ((char *)NULL);
2328
2329   for (i = 1; params && i < start; i++)
2330     params = params->next;
2331   if (params == 0)
2332     return ((char *)NULL);
2333   for (h = t = params; params && i < end; i++)
2334     {
2335       t = params;
2336       params = params->next;
2337     }
2338
2339   t->next = (WORD_LIST *)NULL;
2340   if (string[0] == '*')
2341 #if 0
2342     ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (quote_list (h)) : string_list (h);
2343 #else
2344     {
2345       if (quoted & Q_DOUBLE_QUOTES)
2346         ret = string_list_dollar_star (quote_list (h));
2347       else if (quoted & Q_HERE_DOCUMENT)
2348         ret = string_list (quote_list (h));
2349       else
2350         ret = string_list (h);
2351     }
2352 #endif
2353   else
2354     ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h);
2355   if (t != params)
2356     t->next = params;
2357
2358   dispose_words (save);
2359   return (ret);
2360 }
2361
2362 /******************************************************************/
2363 /*                                                                */
2364 /*      Functions to expand strings to strings or WORD_LISTs      */
2365 /*                                                                */
2366 /******************************************************************/
2367
2368 #if defined (PROCESS_SUBSTITUTION)
2369 #define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC)
2370 #else
2371 #define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC)
2372 #endif
2373
2374 /* If there are any characters in STRING that require full expansion,
2375    then call FUNC to expand STRING; otherwise just perform quote
2376    removal if necessary.  This returns a new string. */
2377 static char *
2378 expand_string_if_necessary (string, quoted, func)
2379      char *string;
2380      int quoted;
2381      EXPFUNC *func;
2382 {
2383   WORD_LIST *list;
2384   size_t slen;
2385   int i, saw_quote;
2386   char *ret;
2387   DECLARE_MBSTATE;
2388
2389   slen = strlen (string);
2390   i = saw_quote = 0;
2391   while (string[i])
2392     {
2393       if (EXP_CHAR (string[i]))
2394         break;
2395       else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
2396         saw_quote = 1;
2397       ADVANCE_CHAR (string, slen, i);
2398     }
2399
2400   if (string[i])
2401     {
2402       list = (*func) (string, quoted);
2403       if (list)
2404         {
2405           ret = string_list (list);
2406           dispose_words (list);
2407         }
2408       else
2409         ret = (char *)NULL;
2410     }
2411   else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
2412     ret = string_quote_removal (string, quoted);
2413   else
2414     ret = savestring (string);
2415
2416   return ret;
2417 }
2418
2419 static inline char *
2420 expand_string_to_string_internal (string, quoted, func)
2421      char *string;
2422      int quoted;
2423      EXPFUNC *func;
2424 {
2425   WORD_LIST *list;
2426   char *ret;
2427
2428   if (string == 0 || *string == '\0')
2429     return ((char *)NULL);
2430
2431   list = (*func) (string, quoted);
2432   if (list)
2433     {
2434       ret = string_list (list);
2435       dispose_words (list);
2436     }
2437   else
2438     ret = (char *)NULL;
2439
2440   return (ret);
2441 }
2442
2443 char *
2444 expand_string_to_string (string, quoted)
2445      char *string;
2446      int quoted;
2447 {
2448   return (expand_string_to_string_internal (string, quoted, expand_string));
2449 }
2450
2451 char *
2452 expand_string_unsplit_to_string (string, quoted)
2453      char *string;
2454      int quoted;
2455 {
2456   return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
2457 }
2458
2459 #if defined (COND_COMMAND)
2460 /* Just remove backslashes in STRING.  Returns a new string. */
2461 char *
2462 remove_backslashes (string)
2463      char *string;
2464 {
2465   char *r, *ret, *s;
2466
2467   r = ret = (char *)xmalloc (strlen (string) + 1);
2468   for (s = string; s && *s; )
2469     {
2470       if (*s == '\\')
2471         s++;
2472       if (*s == 0)
2473         break;
2474       *r++ = *s++;
2475     }
2476   *r = '\0';
2477   return ret;
2478 }
2479
2480 /* This needs better error handling. */
2481 /* Expand W for use as an argument to a unary or binary operator in a
2482    [[...]] expression.  If SPECIAL is nonzero, this is the rhs argument
2483    to the != or == operator, and should be treated as a pattern.  In
2484    this case, we quote the string specially for the globbing code.  The
2485    caller is responsible for removing the backslashes if the unquoted
2486    words is needed later. */   
2487 char *
2488 cond_expand_word (w, special)
2489      WORD_DESC *w;
2490      int special;
2491 {
2492   char *r, *p;
2493   WORD_LIST *l;
2494
2495   if (w->word == 0 || w->word[0] == '\0')
2496     return ((char *)NULL);
2497
2498   if (xstrchr (w->word, '~') && unquoted_member ('~', w->word))
2499     {
2500       p = bash_tilde_expand (w->word, 0);
2501       free (w->word);
2502       w->word = p;
2503     }
2504
2505   l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
2506   if (l)
2507     {
2508       if (special == 0)
2509         {
2510           dequote_list (l);
2511           r = string_list (l);
2512         }
2513       else
2514         {
2515           p = string_list (l);
2516           r = quote_string_for_globbing (p, QGLOB_CVTNULL);
2517           free (p);
2518         }
2519       dispose_words (l);
2520     }
2521   else
2522     r = (char *)NULL;
2523
2524   return r;
2525 }
2526 #endif
2527
2528 /* Call expand_word_internal to expand W and handle error returns.
2529    A convenience function for functions that don't want to handle
2530    any errors or free any memory before aborting. */
2531 static WORD_LIST *
2532 call_expand_word_internal (w, q, i, c, e)
2533      WORD_DESC *w;
2534      int q, i, *c, *e;
2535 {
2536   WORD_LIST *result;
2537
2538   result = expand_word_internal (w, q, i, c, e);
2539   if (result == &expand_word_error || result == &expand_word_fatal)
2540     {
2541       /* By convention, each time this error is returned, w->word has
2542          already been freed (it sometimes may not be in the fatal case,
2543          but that doesn't result in a memory leak because we're going
2544          to exit in most cases). */
2545       w->word = (char *)NULL;
2546       last_command_exit_value = EXECUTION_FAILURE;
2547       exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
2548       /* NOTREACHED */
2549     }
2550   else
2551     return (result);
2552 }
2553
2554 /* Perform parameter expansion, command substitution, and arithmetic
2555    expansion on STRING, as if it were a word.  Leave the result quoted. */
2556 static WORD_LIST *
2557 expand_string_internal (string, quoted)
2558      char *string;
2559      int quoted;
2560 {
2561   WORD_DESC td;
2562   WORD_LIST *tresult;
2563
2564   if (string == 0 || *string == 0)
2565     return ((WORD_LIST *)NULL);
2566
2567   td.flags = 0;
2568   td.word = savestring (string);
2569
2570   tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
2571
2572   FREE (td.word);
2573   return (tresult);
2574 }
2575
2576 /* Expand STRING by performing parameter expansion, command substitution,
2577    and arithmetic expansion.  Dequote the resulting WORD_LIST before
2578    returning it, but do not perform word splitting.  The call to
2579    remove_quoted_nulls () is in here because word splitting normally
2580    takes care of quote removal. */
2581 WORD_LIST *
2582 expand_string_unsplit (string, quoted)
2583      char *string;
2584      int quoted;
2585 {
2586   WORD_LIST *value;
2587
2588   if (string == 0 || *string == '\0')
2589     return ((WORD_LIST *)NULL);
2590
2591   expand_no_split_dollar_star = 1;
2592   value = expand_string_internal (string, quoted);
2593   expand_no_split_dollar_star = 0;
2594
2595   if (value)
2596     {
2597       if (value->word)
2598         remove_quoted_nulls (value->word->word);
2599       dequote_list (value);
2600     }
2601   return (value);
2602 }
2603
2604 /* Expand the rhs of an assignment statement */
2605 WORD_LIST *
2606 expand_string_assignment (string, quoted)
2607      char *string;
2608      int quoted;
2609 {
2610   WORD_DESC td;
2611   WORD_LIST *value;
2612
2613   if (string == 0 || *string == '\0')
2614     return ((WORD_LIST *)NULL);
2615
2616   expand_no_split_dollar_star = 1;
2617
2618   td.flags = W_ASSIGNRHS;
2619   td.word = savestring (string);
2620   value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
2621   FREE (td.word);
2622
2623   expand_no_split_dollar_star = 0;
2624
2625   if (value)
2626     {
2627       if (value->word)
2628         remove_quoted_nulls (value->word->word);
2629       dequote_list (value);
2630     }
2631   return (value);
2632 }
2633
2634
2635 /* Expand one of the PS? prompt strings. This is a sort of combination of
2636    expand_string_unsplit and expand_string_internal, but returns the
2637    passed string when an error occurs.  Might want to trap other calls
2638    to jump_to_top_level here so we don't endlessly loop. */
2639 WORD_LIST *
2640 expand_prompt_string (string, quoted)
2641      char *string;
2642      int quoted;
2643 {
2644   WORD_LIST *value;
2645   WORD_DESC td;
2646
2647   if (string == 0 || *string == 0)
2648     return ((WORD_LIST *)NULL);
2649
2650   td.flags = 0;
2651   td.word = savestring (string);
2652
2653   no_longjmp_on_fatal_error = 1;
2654   value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
2655   no_longjmp_on_fatal_error = 0;
2656
2657   if (value == &expand_word_error || value == &expand_word_fatal)
2658     {
2659       value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
2660       return value;
2661     }
2662   FREE (td.word);
2663   if (value)
2664     {
2665       if (value->word)
2666         remove_quoted_nulls (value->word->word);
2667       dequote_list (value);
2668     }
2669   return (value);
2670 }
2671
2672 /* Expand STRING just as if you were expanding a word, but do not dequote
2673    the resultant WORD_LIST.  This is called only from within this file,
2674    and is used to correctly preserve quoted characters when expanding
2675    things like ${1+"$@"}.  This does parameter expansion, command
2676    substitution, arithmetic expansion, and word splitting. */
2677 static WORD_LIST *
2678 expand_string_leave_quoted (string, quoted)
2679      char *string;
2680      int quoted;
2681 {
2682   WORD_LIST *tlist;
2683   WORD_LIST *tresult;
2684
2685   if (string == 0 || *string == '\0')
2686     return ((WORD_LIST *)NULL);
2687
2688   tlist = expand_string_internal (string, quoted);
2689
2690   if (tlist)
2691     {
2692       tresult = word_list_split (tlist);
2693       dispose_words (tlist);
2694       return (tresult);
2695     }
2696   return ((WORD_LIST *)NULL);
2697 }
2698
2699 /* This does not perform word splitting or dequote the WORD_LIST
2700    it returns. */
2701 static WORD_LIST *
2702 expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at)
2703      char *string;
2704      int quoted, *dollar_at_p, *has_dollar_at;
2705 {
2706   WORD_DESC td;
2707   WORD_LIST *tresult;
2708
2709   if (string == 0 || *string == '\0')
2710     return (WORD_LIST *)NULL;
2711
2712   td.flags = 0;
2713   td.word = string;
2714   tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at);
2715   return (tresult);
2716 }
2717
2718 /* Expand STRING just as if you were expanding a word.  This also returns
2719    a list of words.  Note that filename globbing is *NOT* done for word
2720    or string expansion, just when the shell is expanding a command.  This
2721    does parameter expansion, command substitution, arithmetic expansion,
2722    and word splitting.  Dequote the resultant WORD_LIST before returning. */
2723 WORD_LIST *
2724 expand_string (string, quoted)
2725      char *string;
2726      int quoted;
2727 {
2728   WORD_LIST *result;
2729
2730   if (string == 0 || *string == '\0')
2731     return ((WORD_LIST *)NULL);
2732
2733   result = expand_string_leave_quoted (string, quoted);
2734   return (result ? dequote_list (result) : result);
2735 }
2736
2737 /***************************************************
2738  *                                                 *
2739  *      Functions to handle quoting chars          *
2740  *                                                 *
2741  ***************************************************/
2742
2743 /* Conventions:
2744
2745      A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
2746      The parser passes CTLNUL as CTLESC CTLNUL. */
2747
2748 /* Quote escape characters in string s, but no other characters.  This is
2749    used to protect CTLESC and CTLNUL in variable values from the rest of
2750    the word expansion process after the variable is expanded. */
2751 char *
2752 quote_escapes (string)
2753      char *string;
2754 {
2755   register char *s, *t;
2756   size_t slen;
2757   char *result, *send;
2758   DECLARE_MBSTATE; 
2759
2760   slen = strlen (string);
2761   send = string + slen;
2762
2763   t = result = (char *)xmalloc ((slen * 2) + 1);
2764   s = string;
2765
2766   while (*s)
2767     {
2768       if (*s == CTLESC || *s == CTLNUL)
2769         *t++ = CTLESC;
2770       COPY_CHAR_P (t, s, send);
2771     }
2772   *t = '\0';
2773   return (result);
2774 }
2775
2776 static WORD_LIST *
2777 list_quote_escapes (list)
2778      WORD_LIST *list;
2779 {
2780   register WORD_LIST *w;
2781   char *t;
2782
2783   for (w = list; w; w = w->next)
2784     {
2785       t = w->word->word;
2786       w->word->word = quote_escapes (t);
2787       free (t);
2788     }
2789   return list;
2790 }
2791
2792 /* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
2793
2794    The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
2795    This is necessary to make unquoted CTLESC and CTLNUL characters in the
2796    data stream pass through properly.
2797
2798    We need to remove doubled CTLESC characters inside quoted strings before
2799    quoting the entire string, so we do not double the number of CTLESC
2800    characters.
2801
2802    Also used by parts of the pattern substitution code. */
2803 static char *
2804 dequote_escapes (string)
2805      char *string;
2806 {
2807   register char *s, *t;
2808   size_t slen;
2809   char *result, *send;
2810   DECLARE_MBSTATE;
2811
2812   if (string == 0)
2813     return string;
2814
2815   slen = strlen (string);
2816   send = string + slen;
2817
2818   t = result = (char *)xmalloc (slen + 1);
2819   s = string;
2820
2821   if (strchr (string, CTLESC) == 0)
2822     return (strcpy (result, s));
2823
2824   while (*s)
2825     {
2826       if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL))
2827         {
2828           s++;
2829           if (*s == '\0')
2830             break;
2831         }
2832       COPY_CHAR_P (t, s, send);
2833     }
2834   *t = '\0';
2835   return result;
2836 }
2837
2838 /* Return a new string with the quoted representation of character C. */
2839 static char *
2840 make_quoted_char (c)
2841      int c;
2842 {
2843   char *temp;
2844
2845   temp = (char *)xmalloc (3);
2846   if (c == 0)
2847     {
2848       temp[0] = CTLNUL;
2849       temp[1] = '\0';
2850     }
2851   else
2852     {
2853       temp[0] = CTLESC;
2854       temp[1] = c;
2855       temp[2] = '\0';
2856     }
2857   return (temp);
2858 }
2859
2860 /* Quote STRING.  Return a new string. */
2861 char *
2862 quote_string (string)
2863      char *string;
2864 {
2865   register char *t;
2866   size_t slen;
2867   char *result, *send;
2868
2869   if (*string == 0)
2870     {
2871       result = (char *)xmalloc (2);
2872       result[0] = CTLNUL;
2873       result[1] = '\0';
2874     }
2875   else
2876     {
2877       DECLARE_MBSTATE;
2878
2879       slen = strlen (string);
2880       send = string + slen;
2881
2882       result = (char *)xmalloc ((slen * 2) + 1);
2883
2884       for (t = result; string < send; )
2885         {
2886           *t++ = CTLESC;
2887           COPY_CHAR_P (t, string, send);
2888         }
2889       *t = '\0';
2890     }
2891   return (result);
2892 }
2893
2894 /* De-quoted quoted characters in STRING. */
2895 char *
2896 dequote_string (string)
2897      char *string;
2898 {
2899   register char *s, *t;
2900   size_t slen;
2901   char *result, *send;
2902   DECLARE_MBSTATE;
2903
2904   slen = strlen (string);
2905
2906   t = result = (char *)xmalloc (slen + 1);
2907
2908   if (QUOTED_NULL (string))
2909     {
2910       result[0] = '\0';
2911       return (result);
2912     }
2913
2914   /* If no character in the string can be quoted, don't bother examining
2915      each character.  Just return a copy of the string passed to us. */
2916   if (strchr (string, CTLESC) == NULL)
2917     return (strcpy (result, string));
2918
2919   send = string + slen;
2920   s = string;
2921   while (*s)
2922     {
2923       if (*s == CTLESC)
2924         {
2925           s++;
2926           if (*s == '\0')
2927             break;
2928         }
2929       COPY_CHAR_P (t, s, send);
2930     }
2931
2932   *t = '\0';
2933   return (result);
2934 }
2935
2936 /* Quote the entire WORD_LIST list. */
2937 static WORD_LIST *
2938 quote_list (list)
2939      WORD_LIST *list;
2940 {
2941   register WORD_LIST *w;
2942   char *t;
2943
2944   for (w = list; w; w = w->next)
2945     {
2946       t = w->word->word;
2947       w->word->word = quote_string (t);
2948       free (t);
2949       w->word->flags |= W_QUOTED;
2950     }
2951   return list;
2952 }
2953
2954 static WORD_LIST *
2955 dequote_list (list)
2956      WORD_LIST *list;
2957 {
2958   register char *s;
2959   register WORD_LIST *tlist;
2960
2961   for (tlist = list; tlist; tlist = tlist->next)
2962     {
2963       s = dequote_string (tlist->word->word);
2964       free (tlist->word->word);
2965       tlist->word->word = s;
2966     }
2967   return list;
2968 }
2969
2970 /* Remove CTLESC protecting a CTLESC or CTLNUL in place.  Return the passed
2971    string. */
2972 static char *
2973 remove_quoted_escapes (string)
2974      char *string;
2975 {
2976   char *t;
2977
2978   if (string)
2979     {
2980       t = dequote_escapes (string);
2981       strcpy (string, t);
2982       free (t);
2983     }
2984
2985   return (string);
2986 }
2987
2988 /* Perform quoted null character removal on STRING.  We don't allow any
2989    quoted null characters in the middle or at the ends of strings because
2990    of how expand_word_internal works.  remove_quoted_nulls () turns
2991    STRING into an empty string iff it only consists of a quoted null,
2992    and removes all unquoted CTLNUL characters. */
2993 static char *
2994 remove_quoted_nulls (string)
2995      char *string;
2996 {
2997   register size_t slen;
2998   register int i, j, prev_i;
2999   DECLARE_MBSTATE;
3000
3001   if (strchr (string, CTLNUL) == 0)             /* XXX */
3002     return string;                              /* XXX */
3003
3004   slen = strlen (string);
3005   i = j = 0;
3006
3007   while (i < slen)
3008     {
3009       if (string[i] == CTLESC)
3010         {
3011           /* Old code had j++, but we cannot assume that i == j at this
3012              point -- what if a CTLNUL has already been removed from the
3013              string?  We don't want to drop the CTLESC or recopy characters
3014              that we've already copied down. */
3015           i++; string[j++] = CTLESC;
3016           if (i == slen)
3017             break;
3018         }
3019       else if (string[i] == CTLNUL)
3020         i++;
3021
3022       prev_i = i;
3023       ADVANCE_CHAR (string, slen, i);
3024       if (j < prev_i)
3025         {
3026           do string[j++] = string[prev_i++]; while (prev_i < i);
3027         }
3028       else
3029         j = i;
3030     }
3031   string[j] = '\0';
3032
3033   return (string);
3034 }
3035
3036 /* Perform quoted null character removal on each element of LIST.
3037    This modifies LIST. */
3038 void
3039 word_list_remove_quoted_nulls (list)
3040      WORD_LIST *list;
3041 {
3042   register WORD_LIST *t;
3043
3044   for (t = list; t; t = t->next)
3045     remove_quoted_nulls (t->word->word);
3046 }
3047
3048 /* **************************************************************** */
3049 /*                                                                  */
3050 /*         Functions for Matching and Removing Patterns             */
3051 /*                                                                  */
3052 /* **************************************************************** */
3053
3054 #if defined (HANDLE_MULTIBYTE)
3055 #if 0 /* Currently unused */
3056 static unsigned char *
3057 mb_getcharlens (string, len)
3058      char *string;
3059      int len;
3060 {
3061   int i, offset, last;
3062   unsigned char *ret;
3063   char *p;
3064   DECLARE_MBSTATE;
3065
3066   i = offset = 0;
3067   last = 0;
3068   ret = (unsigned char *)xmalloc (len);
3069   memset (ret, 0, len);
3070   while (string[last])
3071     {
3072       ADVANCE_CHAR (string, len, offset);
3073       ret[last] = offset - last;
3074       last = offset;
3075     }
3076   return ret;
3077 }
3078 #endif
3079 #endif
3080
3081 /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
3082    can have one of 4 values:
3083         RP_LONG_LEFT    remove longest matching portion at start of PARAM
3084         RP_SHORT_LEFT   remove shortest matching portion at start of PARAM
3085         RP_LONG_RIGHT   remove longest matching portion at end of PARAM
3086         RP_SHORT_RIGHT  remove shortest matching portion at end of PARAM
3087 */
3088
3089 #define RP_LONG_LEFT    1
3090 #define RP_SHORT_LEFT   2
3091 #define RP_LONG_RIGHT   3
3092 #define RP_SHORT_RIGHT  4
3093
3094 static char *
3095 remove_upattern (param, pattern, op)
3096      char *param, *pattern;
3097      int op;
3098 {
3099   register int len;
3100   register char *end;
3101   register char *p, *ret, c;
3102
3103   len = STRLEN (param);
3104   end = param + len;
3105
3106   switch (op)
3107     {
3108       case RP_LONG_LEFT:        /* remove longest match at start */
3109         for (p = end; p >= param; p--)
3110           {
3111             c = *p; *p = '\0';
3112             if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3113               {
3114                 *p = c;
3115                 return (savestring (p));
3116               }
3117             *p = c;
3118
3119           }
3120         break;
3121
3122       case RP_SHORT_LEFT:       /* remove shortest match at start */
3123         for (p = param; p <= end; p++)
3124           {
3125             c = *p; *p = '\0';
3126             if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3127               {
3128                 *p = c;
3129                 return (savestring (p));
3130               }
3131             *p = c;
3132           }
3133         break;
3134
3135       case RP_LONG_RIGHT:       /* remove longest match at end */
3136         for (p = param; p <= end; p++)
3137           {
3138             if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3139               {
3140                 c = *p; *p = '\0';
3141                 ret = savestring (param);
3142                 *p = c;
3143                 return (ret);
3144               }
3145           }
3146         break;
3147
3148       case RP_SHORT_RIGHT:      /* remove shortest match at end */
3149         for (p = end; p >= param; p--)
3150           {
3151             if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3152               {
3153                 c = *p; *p = '\0';
3154                 ret = savestring (param);
3155                 *p = c;
3156                 return (ret);
3157               }
3158           }
3159         break;
3160     }
3161
3162   return (savestring (param));  /* no match, return original string */
3163 }
3164
3165 #if defined (HANDLE_MULTIBYTE)
3166
3167 #if !defined (HAVE_WCSDUP)
3168 static wchar_t *
3169 wcsdup (ws)
3170      wchar_t *ws;
3171 {
3172   wchar_t *ret;
3173   size_t len;
3174
3175   len = wcslen (ws);
3176   ret = xmalloc ((len + 1) * sizeof (wchar_t));
3177   if (ret == 0)
3178     return ret;
3179   return (wcscpy (ret, ws));
3180 }
3181 #endif /* !HAVE_WCSDUP */
3182
3183 static wchar_t *
3184 remove_wpattern (wparam, wstrlen, wpattern, op)
3185      wchar_t *wparam;
3186      size_t wstrlen;
3187      wchar_t *wpattern;
3188      int op;
3189 {
3190   wchar_t wc;
3191   int n, n1;
3192   wchar_t *ret;
3193
3194   switch (op)
3195     {
3196       case RP_LONG_LEFT:        /* remove longest match at start */
3197         for (n = wstrlen; n >= 0; n--)
3198           {
3199             wc = wparam[n]; wparam[n] = L'\0';
3200             if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3201               {
3202                 wparam[n] = wc;
3203                 return (wcsdup (wparam + n));
3204               }
3205             wparam[n] = wc;
3206           }
3207         break;
3208
3209       case RP_SHORT_LEFT:       /* remove shortest match at start */
3210         for (n = 0; n <= wstrlen; n++)
3211           {
3212             wc = wparam[n]; wparam[n] = L'\0';
3213             if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3214               {
3215                 wparam[n] = wc;
3216                 return (wcsdup (wparam + n));
3217               }
3218             wparam[n] = wc;
3219           }
3220         break;
3221
3222       case RP_LONG_RIGHT:       /* remove longest match at end */
3223         for (n = 0; n <= wstrlen; n++)
3224           {
3225             if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3226               {
3227                 wc = wparam[n]; wparam[n] = L'\0';
3228                 ret = wcsdup (wparam);
3229                 wparam[n] = wc;
3230                 return (ret);
3231               }
3232           }
3233         break;
3234
3235       case RP_SHORT_RIGHT:      /* remove shortest match at end */
3236         for (n = wstrlen; n >= 0; n--)
3237           {
3238             if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3239               {
3240                 wc = wparam[n]; wparam[n] = L'\0';
3241                 ret = wcsdup (wparam);
3242                 wparam[n] = wc;
3243                 return (ret);
3244               }
3245           }
3246         break;
3247     }
3248
3249   return (wcsdup (wparam));     /* no match, return original string */
3250 }
3251 #endif /* HANDLE_MULTIBYTE */
3252
3253 static char *
3254 remove_pattern (param, pattern, op)
3255      char *param, *pattern;
3256      int op;
3257 {
3258   if (param == NULL)
3259     return (param);
3260   if (*param == '\0' || pattern == NULL || *pattern == '\0')    /* minor optimization */
3261     return (savestring (param));
3262
3263 #if defined (HANDLE_MULTIBYTE)
3264   if (MB_CUR_MAX > 1)
3265     {
3266       wchar_t *ret, *oret;
3267       size_t n;
3268       wchar_t *wparam, *wpattern;
3269       mbstate_t ps;
3270       char *xret;
3271
3272       n = xdupmbstowcs (&wpattern, NULL, pattern);
3273       if (n == (size_t)-1)
3274         return (remove_upattern (param, pattern, op));
3275       n = xdupmbstowcs (&wparam, NULL, param);
3276       if (n == (size_t)-1)
3277         {
3278           free (wpattern);
3279           return (remove_upattern (param, pattern, op));
3280         }
3281       oret = ret = remove_wpattern (wparam, n, wpattern, op);
3282
3283       free (wparam);
3284       free (wpattern);
3285
3286       n = strlen (param);
3287       xret = xmalloc (n + 1);
3288       memset (&ps, '\0', sizeof (mbstate_t));
3289       n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
3290       xret[n] = '\0';           /* just to make sure */
3291       free (oret);
3292       return xret;      
3293     }
3294   else
3295 #endif
3296     return (remove_upattern (param, pattern, op));
3297 }
3298
3299 /* Return 1 of the first character of STRING could match the first
3300    character of pattern PAT.  Used to avoid n2 calls to strmatch(). */
3301 static int
3302 match_pattern_char (pat, string)
3303      char *pat, *string;
3304 {
3305   char c;
3306
3307   if (*string == 0)
3308     return (0);
3309
3310   switch (c = *pat++)
3311     {
3312     default:
3313       return (*string == c);
3314     case '\\':
3315       return (*string == *pat);
3316     case '?':
3317       return (*pat == LPAREN ? 1 : (*string != '\0'));
3318     case '*':
3319       return (1);
3320     case '+':
3321     case '!':
3322     case '@':
3323       return (*pat == LPAREN ? 1 : (*string == c));
3324     case '[':
3325       return (*string != '\0');
3326     }
3327 }
3328
3329 /* Match PAT anywhere in STRING and return the match boundaries.
3330    This returns 1 in case of a successful match, 0 otherwise.  SP
3331    and EP are pointers into the string where the match begins and
3332    ends, respectively.  MTYPE controls what kind of match is attempted.
3333    MATCH_BEG and MATCH_END anchor the match at the beginning and end
3334    of the string, respectively.  The longest match is returned. */
3335 static int
3336 match_upattern (string, pat, mtype, sp, ep)
3337      char *string, *pat;
3338      int mtype;
3339      char **sp, **ep;
3340 {
3341   int c, len;
3342   register char *p, *p1;
3343   char *end;
3344
3345   len = STRLEN (string);
3346   end = string + len;
3347
3348   switch (mtype)
3349     {
3350     case MATCH_ANY:
3351       for (p = string; p <= end; p++)
3352         {
3353           if (match_pattern_char (pat, p))
3354             {
3355               for (p1 = end; p1 >= p; p1--)
3356                 {
3357                   c = *p1; *p1 = '\0';
3358                   if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
3359                     {
3360                       *p1 = c;
3361                       *sp = p;
3362                       *ep = p1;
3363                       return 1;
3364                     }
3365                   *p1 = c;
3366                 }
3367             }
3368         }
3369
3370       return (0);
3371
3372     case MATCH_BEG:
3373       if (match_pattern_char (pat, string) == 0)
3374         return (0);
3375
3376       for (p = end; p >= string; p--)
3377         {
3378           c = *p; *p = '\0';
3379           if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0)
3380             {
3381               *p = c;
3382               *sp = string;
3383               *ep = p;
3384               return 1;
3385             }
3386           *p = c;
3387         }
3388
3389       return (0);
3390
3391     case MATCH_END:
3392       for (p = string; p <= end; p++)
3393         {
3394           if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
3395             {
3396               *sp = p;
3397               *ep = end;
3398               return 1;
3399             }
3400
3401         }
3402
3403       return (0);
3404     }
3405
3406   return (0);
3407 }
3408
3409 #if defined (HANDLE_MULTIBYTE)
3410 /* Return 1 of the first character of WSTRING could match the first
3411    character of pattern WPAT.  Wide character version. */
3412 static int
3413 match_pattern_wchar (wpat, wstring)
3414      wchar_t *wpat, *wstring;
3415 {
3416   wchar_t wc;
3417
3418   if (*wstring == 0)
3419     return (0);
3420
3421   switch (wc = *wpat++)
3422     {
3423     default:
3424       return (*wstring == wc);
3425     case L'\\':
3426       return (*wstring == *wpat);
3427     case L'?':
3428       return (*wpat == LPAREN ? 1 : (*wstring != L'\0'));
3429     case L'*':
3430       return (1);
3431     case L'+':
3432     case L'!':
3433     case L'@':
3434       return (*wpat == LPAREN ? 1 : (*wstring == wc));
3435     case L'[':
3436       return (*wstring != L'\0');
3437     }
3438 }
3439
3440 /* Match WPAT anywhere in WSTRING and return the match boundaries.
3441    This returns 1 in case of a successful match, 0 otherwise.  Wide
3442    character version. */
3443 static int
3444 match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
3445      wchar_t *wstring;
3446      char **indices;
3447      size_t wstrlen;
3448      wchar_t *wpat;
3449      int mtype;
3450      char **sp, **ep;
3451 {
3452   wchar_t wc;
3453   int len;
3454 #if 0
3455   size_t n, n1; /* Apple's gcc seems to miscompile this badly */
3456 #else
3457   int n, n1;
3458 #endif
3459
3460   switch (mtype)
3461     {
3462     case MATCH_ANY:
3463       for (n = 0; n <= wstrlen; n++)
3464         {
3465           if (match_pattern_wchar (wpat, wstring + n))
3466             {
3467               for (n1 = wstrlen; n1 >= n; n1--)
3468                 {
3469                   wc = wstring[n1]; wstring[n1] = L'\0';
3470                   if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
3471                     {
3472                       wstring[n1] = wc;
3473                       *sp = indices[n];
3474                       *ep = indices[n1];
3475                       return 1;
3476                     }
3477                   wstring[n1] = wc;
3478                 }
3479             }
3480         }
3481
3482       return (0);
3483
3484     case MATCH_BEG:
3485       if (match_pattern_wchar (wpat, wstring) == 0)
3486         return (0);
3487
3488       for (n = wstrlen; n >= 0; n--)
3489         {
3490           wc = wstring[n]; wstring[n] = L'\0';
3491           if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0)
3492             {
3493               wstring[n] = wc;
3494               *sp = indices[0];
3495               *ep = indices[n];
3496               return 1;
3497             }
3498           wstring[n] = wc;
3499         }
3500
3501       return (0);
3502
3503     case MATCH_END:
3504       for (n = 0; n <= wstrlen; n++)
3505         {
3506           if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
3507             {
3508               *sp = indices[n];
3509               *ep = indices[wstrlen];
3510               return 1;
3511             }
3512         }
3513
3514       return (0);
3515     }
3516
3517   return (0);
3518 }
3519 #endif /* HANDLE_MULTIBYTE */
3520
3521 static int
3522 match_pattern (string, pat, mtype, sp, ep)
3523      char *string, *pat;
3524      int mtype;
3525      char **sp, **ep;
3526 {
3527 #if defined (HANDLE_MULTIBYTE)
3528   int ret;
3529   size_t n;
3530   wchar_t *wstring, *wpat;
3531   char **indices;
3532 #endif
3533
3534   if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
3535     return (0);
3536
3537 #if defined (HANDLE_MULTIBYTE)
3538   if (MB_CUR_MAX > 1)
3539     {
3540       n = xdupmbstowcs (&wpat, NULL, pat);
3541       if (n == (size_t)-1)
3542         return (match_upattern (string, pat, mtype, sp, ep));
3543       n = xdupmbstowcs (&wstring, &indices, string);
3544       if (n == (size_t)-1)
3545         {
3546           free (wpat);
3547           return (match_upattern (string, pat, mtype, sp, ep));
3548         }
3549       ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
3550
3551       free (wpat);
3552       free (wstring);
3553       free (indices);
3554
3555       return (ret);
3556     }
3557   else
3558 #endif
3559     return (match_upattern (string, pat, mtype, sp, ep));
3560 }
3561
3562 static int
3563 getpatspec (c, value)
3564      int c;
3565      char *value;
3566 {
3567   if (c == '#')
3568     return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
3569   else  /* c == '%' */
3570     return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
3571 }
3572
3573 /* Posix.2 says that the WORD should be run through tilde expansion,
3574    parameter expansion, command substitution and arithmetic expansion.
3575    This leaves the result quoted, so quote_string_for_globbing () has
3576    to be called to fix it up for strmatch ().  If QUOTED is non-zero,
3577    it means that the entire expression was enclosed in double quotes.
3578    This means that quoting characters in the pattern do not make any
3579    special pattern characters quoted.  For example, the `*' in the
3580    following retains its special meaning: "${foo#'*'}". */
3581 static char *
3582 getpattern (value, quoted, expandpat)
3583      char *value;
3584      int quoted, expandpat;
3585 {
3586   char *pat, *tword;
3587   WORD_LIST *l;
3588   int i;
3589
3590   tword = xstrchr (value, '~') ? bash_tilde_expand (value, 0) : savestring (value);
3591
3592   /* There is a problem here:  how to handle single or double quotes in the
3593      pattern string when the whole expression is between double quotes?
3594      POSIX.2 says that enclosing double quotes do not cause the pattern to
3595      be quoted, but does that leave us a problem with @ and array[@] and their
3596      expansions inside a pattern? */
3597 #if 0
3598   if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
3599     {
3600       i = 0;
3601       pat = string_extract_double_quoted (tword, &i, 1);
3602       free (tword);
3603       tword = pat;
3604     }
3605 #endif
3606
3607   /* expand_string_for_rhs () leaves WORD quoted and does not perform
3608      word splitting. */
3609   l = *tword ? expand_string_for_rhs (tword,
3610                                       (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
3611                                       (int *)NULL, (int *)NULL)
3612              : (WORD_LIST *)0;
3613   free (tword);
3614   pat = string_list (l);
3615   dispose_words (l);
3616   if (pat)
3617     {
3618       tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
3619       free (pat);
3620       pat = tword;
3621     }
3622   return (pat);
3623 }
3624
3625 #if 0
3626 /* Handle removing a pattern from a string as a result of ${name%[%]value}
3627    or ${name#[#]value}. */
3628 static char *
3629 variable_remove_pattern (value, pattern, patspec, quoted)
3630      char *value, *pattern;
3631      int patspec, quoted;
3632 {
3633   char *tword;
3634
3635   tword = remove_pattern (value, pattern, patspec);
3636
3637   return (tword);
3638 }
3639 #endif
3640
3641 static char *
3642 list_remove_pattern (list, pattern, patspec, itype, quoted)
3643      WORD_LIST *list;
3644      char *pattern;
3645      int patspec, itype, quoted;
3646 {
3647   WORD_LIST *new, *l;
3648   WORD_DESC *w;
3649   char *tword;
3650
3651   for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
3652     {
3653       tword = remove_pattern (l->word->word, pattern, patspec);
3654       w = make_bare_word (tword);
3655       FREE (tword);
3656       new = make_word_list (w, new);
3657     }
3658
3659   l = REVERSE_LIST (new, WORD_LIST *);
3660   if (itype == '*')
3661 #if 0
3662     tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l);
3663 #else
3664     tword = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (l) : string_list (l);
3665 #endif
3666   else
3667     tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l);
3668
3669   dispose_words (l);
3670   return (tword);
3671 }
3672
3673 static char *
3674 parameter_list_remove_pattern (itype, pattern, patspec, quoted)
3675      int itype;
3676      char *pattern;
3677      int patspec, quoted;
3678 {
3679   char *ret;
3680   WORD_LIST *list;
3681
3682   list = list_rest_of_args ();
3683   if (list == 0)
3684     return ((char *)NULL);
3685   ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
3686   dispose_words (list);
3687   return (ret);
3688 }
3689
3690 #if defined (ARRAY_VARS)
3691 static char *
3692 array_remove_pattern (a, pattern, patspec, varname, quoted)
3693      ARRAY *a;
3694      char *pattern;
3695      int patspec;
3696      char *varname;     /* so we can figure out how it's indexed */
3697      int quoted;
3698 {
3699   int itype;
3700   char *ret;
3701   WORD_LIST *list;
3702   SHELL_VAR *v;
3703
3704   /* compute itype from varname here */
3705   v = array_variable_part (varname, &ret, 0);
3706   itype = ret[0];
3707
3708   list = array_to_word_list (a);
3709   if (list == 0)
3710    return ((char *)NULL);
3711   ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
3712   dispose_words (list);
3713
3714   return ret;
3715 }
3716 #endif /* ARRAY_VARS */
3717
3718 static char *
3719 parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted)
3720      char *varname, *value, *patstr;
3721      int rtype, quoted;
3722 {
3723   int vtype, patspec, starsub;
3724   char *temp1, *val, *pattern;
3725   SHELL_VAR *v;
3726
3727   if (value == 0)
3728     return ((char *)NULL);
3729
3730   this_command_name = varname;
3731
3732   vtype = get_var_and_type (varname, value, quoted, &v, &val);
3733   if (vtype == -1)
3734     return ((char *)NULL);
3735
3736   starsub = vtype & VT_STARSUB;
3737   vtype &= ~VT_STARSUB;
3738
3739   patspec = getpatspec (rtype, patstr);
3740   if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
3741     patstr++;
3742
3743   pattern = getpattern (patstr, quoted, 1);
3744
3745   temp1 = (char *)NULL;         /* shut up gcc */
3746   switch (vtype)
3747     {
3748     case VT_VARIABLE:
3749     case VT_ARRAYMEMBER:
3750       temp1 = remove_pattern (val, pattern, patspec);
3751       if (vtype == VT_VARIABLE)
3752         FREE (val);
3753       if (temp1)
3754         {
3755           val = quote_escapes (temp1);
3756           free (temp1);
3757           temp1 = val;
3758         }
3759       break;
3760 #if defined (ARRAY_VARS)
3761     case VT_ARRAYVAR:
3762       temp1 = array_remove_pattern (array_cell (v), pattern, patspec, varname, quoted);
3763       if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3764         {
3765           val = quote_escapes (temp1);
3766           free (temp1);
3767           temp1 = val;
3768         }
3769       break;
3770 #endif
3771     case VT_POSPARMS:
3772       temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
3773       if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3774         {
3775           val = quote_escapes (temp1);
3776           free (temp1);
3777           temp1 = val;
3778         }
3779       break;
3780     }
3781
3782   FREE (pattern);
3783   return temp1;
3784 }    
3785
3786 /*******************************************
3787  *                                         *
3788  *      Functions to expand WORD_DESCs     *
3789  *                                         *
3790  *******************************************/
3791
3792 /* Expand WORD, performing word splitting on the result.  This does
3793    parameter expansion, command substitution, arithmetic expansion,
3794    word splitting, and quote removal. */
3795
3796 WORD_LIST *
3797 expand_word (word, quoted)
3798      WORD_DESC *word;
3799      int quoted;
3800 {
3801   WORD_LIST *result, *tresult;
3802
3803   tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
3804   result = word_list_split (tresult);
3805   dispose_words (tresult);
3806   return (result ? dequote_list (result) : result);
3807 }
3808
3809 /* Expand WORD, but do not perform word splitting on the result.  This
3810    does parameter expansion, command substitution, arithmetic expansion,
3811    and quote removal. */
3812 WORD_LIST *
3813 expand_word_unsplit (word, quoted)
3814      WORD_DESC *word;
3815      int quoted;
3816 {
3817   WORD_LIST *result;
3818
3819   expand_no_split_dollar_star = 1;
3820   result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
3821   expand_no_split_dollar_star = 0;
3822
3823   return (result ? dequote_list (result) : result);
3824 }
3825
3826 /* Perform shell expansions on WORD, but do not perform word splitting or
3827    quote removal on the result. */
3828 WORD_LIST *
3829 expand_word_leave_quoted (word, quoted)
3830      WORD_DESC *word;
3831      int quoted;
3832 {
3833   return (call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL));
3834 }
3835
3836 #if defined (PROCESS_SUBSTITUTION)
3837
3838 /*****************************************************************/
3839 /*                                                               */
3840 /*                  Hacking Process Substitution                 */
3841 /*                                                               */
3842 /*****************************************************************/
3843
3844 #if !defined (HAVE_DEV_FD)
3845 /* Named pipes must be removed explicitly with `unlink'.  This keeps a list
3846    of FIFOs the shell has open.  unlink_fifo_list will walk the list and
3847    unlink all of them. add_fifo_list adds the name of an open FIFO to the
3848    list.  NFIFO is a count of the number of FIFOs in the list. */
3849 #define FIFO_INCR 20
3850
3851 struct temp_fifo {
3852   char *file;
3853   pid_t proc;
3854 };
3855
3856 static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
3857 static int nfifo;
3858 static int fifo_list_size;
3859
3860 static void
3861 add_fifo_list (pathname)
3862      char *pathname;
3863 {
3864   if (nfifo >= fifo_list_size - 1)
3865     {
3866       fifo_list_size += FIFO_INCR;
3867       fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
3868                                 fifo_list_size * sizeof (struct temp_fifo));
3869     }
3870
3871   fifo_list[nfifo].file = savestring (pathname);
3872   nfifo++;
3873 }
3874
3875 void
3876 unlink_fifo_list ()
3877 {
3878   int saved, i, j;
3879
3880   if (nfifo == 0)
3881     return;
3882
3883   for (i = saved = 0; i < nfifo; i++)
3884     {
3885       if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1))
3886         {
3887           unlink (fifo_list[i].file);
3888           free (fifo_list[i].file);
3889           fifo_list[i].file = (char *)NULL;
3890           fifo_list[i].proc = -1;
3891         }
3892       else
3893         saved++;
3894     }
3895
3896   /* If we didn't remove some of the FIFOs, compact the list. */
3897   if (saved)
3898     {
3899       for (i = j = 0; i < nfifo; i++)
3900         if (fifo_list[i].file)
3901           {
3902             fifo_list[j].file = fifo_list[i].file;
3903             fifo_list[j].proc = fifo_list[i].proc;
3904             j++;
3905           }
3906       nfifo = j;
3907     }
3908   else
3909     nfifo = 0;
3910 }
3911
3912 static char *
3913 make_named_pipe ()
3914 {
3915   char *tname;
3916
3917   tname = sh_mktmpname ("sh-np", MT_USERANDOM);
3918   if (mkfifo (tname, 0600) < 0)
3919     {
3920       free (tname);
3921       return ((char *)NULL);
3922     }
3923
3924   add_fifo_list (tname);
3925   return (tname);
3926 }
3927
3928 #else /* HAVE_DEV_FD */
3929
3930 /* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
3931    has open to children.  NFDS is a count of the number of bits currently
3932    set in DEV_FD_LIST.  TOTFDS is a count of the highest possible number
3933    of open files. */
3934 static char *dev_fd_list = (char *)NULL;
3935 static int nfds;
3936 static int totfds;      /* The highest possible number of open files. */
3937
3938 static void
3939 add_fifo_list (fd)
3940      int fd;
3941 {
3942   if (!dev_fd_list || fd >= totfds)
3943     {
3944       int ofds;
3945
3946       ofds = totfds;
3947       totfds = getdtablesize ();
3948       if (totfds < 0 || totfds > 256)
3949         totfds = 256;
3950       if (fd > totfds)
3951         totfds = fd + 2;
3952
3953       dev_fd_list = (char *)xrealloc (dev_fd_list, totfds);
3954       memset (dev_fd_list + ofds, '\0', totfds - ofds);
3955     }
3956
3957   dev_fd_list[fd] = 1;
3958   nfds++;
3959 }
3960
3961 void
3962 unlink_fifo_list ()
3963 {
3964   register int i;
3965
3966   if (nfds == 0)
3967     return;
3968
3969   for (i = 0; nfds && i < totfds; i++)
3970     if (dev_fd_list[i])
3971       {
3972         close (i);
3973         dev_fd_list[i] = 0;
3974         nfds--;
3975       }
3976
3977   nfds = 0;
3978 }
3979
3980 #if defined (NOTDEF)
3981 print_dev_fd_list ()
3982 {
3983   register int i;
3984
3985   fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
3986   fflush (stderr);
3987
3988   for (i = 0; i < totfds; i++)
3989     {
3990       if (dev_fd_list[i])
3991         fprintf (stderr, " %d", i);
3992     }
3993   fprintf (stderr, "\n");
3994 }
3995 #endif /* NOTDEF */
3996
3997 static char *
3998 make_dev_fd_filename (fd)
3999      int fd;
4000 {
4001   char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
4002
4003   ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 4);
4004
4005   strcpy (ret, DEV_FD_PREFIX);
4006   p = inttostr (fd, intbuf, sizeof (intbuf));
4007   strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
4008
4009   add_fifo_list (fd);
4010   return (ret);
4011 }
4012
4013 #endif /* HAVE_DEV_FD */
4014
4015 /* Return a filename that will open a connection to the process defined by
4016    executing STRING.  HAVE_DEV_FD, if defined, means open a pipe and return
4017    a filename in /dev/fd corresponding to a descriptor that is one of the
4018    ends of the pipe.  If not defined, we use named pipes on systems that have
4019    them.  Systems without /dev/fd and named pipes are out of luck.
4020
4021    OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
4022    use the read end of the pipe and dup that file descriptor to fd 0 in
4023    the child.  If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
4024    writing or use the write end of the pipe in the child, and dup that
4025    file descriptor to fd 1 in the child.  The parent does the opposite. */
4026
4027 static char *
4028 process_substitute (string, open_for_read_in_child)
4029      char *string;
4030      int open_for_read_in_child;
4031 {
4032   char *pathname;
4033   int fd, result;
4034   pid_t old_pid, pid;
4035 #if defined (HAVE_DEV_FD)
4036   int parent_pipe_fd, child_pipe_fd;
4037   int fildes[2];
4038 #endif /* HAVE_DEV_FD */
4039 #if defined (JOB_CONTROL)
4040   pid_t old_pipeline_pgrp;
4041 #endif
4042
4043   if (!string || !*string || wordexp_only)
4044     return ((char *)NULL);
4045
4046 #if !defined (HAVE_DEV_FD)
4047   pathname = make_named_pipe ();
4048 #else /* HAVE_DEV_FD */
4049   if (pipe (fildes) < 0)
4050     {
4051       sys_error (_("cannot make pipe for process substitution"));
4052       return ((char *)NULL);
4053     }
4054   /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
4055      the pipe in the parent, otherwise the read end. */
4056   parent_pipe_fd = fildes[open_for_read_in_child];
4057   child_pipe_fd = fildes[1 - open_for_read_in_child];
4058   /* Move the parent end of the pipe to some high file descriptor, to
4059      avoid clashes with FDs used by the script. */
4060   parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
4061
4062   pathname = make_dev_fd_filename (parent_pipe_fd);
4063 #endif /* HAVE_DEV_FD */
4064
4065   if (!pathname)
4066     {
4067       sys_error (_("cannot make pipe for process substitution"));
4068       return ((char *)NULL);
4069     }
4070
4071   old_pid = last_made_pid;
4072
4073 #if defined (JOB_CONTROL)
4074   old_pipeline_pgrp = pipeline_pgrp;
4075   pipeline_pgrp = shell_pgrp;
4076   save_pipeline (1);
4077 #endif /* JOB_CONTROL */
4078
4079   pid = make_child ((char *)NULL, 1);
4080   if (pid == 0)
4081     {
4082       reset_terminating_signals ();     /* XXX */
4083       free_pushed_string_input ();
4084       /* Cancel traps, in trap.c. */
4085       restore_original_signals ();
4086       setup_async_signals ();
4087       subshell_environment |= SUBSHELL_COMSUB;
4088     }
4089
4090 #if defined (JOB_CONTROL)
4091   set_sigchld_handler ();
4092   stop_making_children ();
4093   pipeline_pgrp = old_pipeline_pgrp;
4094 #endif /* JOB_CONTROL */
4095
4096   if (pid < 0)
4097     {
4098       sys_error (_("cannot make child for process substitution"));
4099       free (pathname);
4100 #if defined (HAVE_DEV_FD)
4101       close (parent_pipe_fd);
4102       close (child_pipe_fd);
4103 #endif /* HAVE_DEV_FD */
4104       return ((char *)NULL);
4105     }
4106
4107   if (pid > 0)
4108     {
4109 #if defined (JOB_CONTROL)
4110       restore_pipeline (1);
4111 #endif
4112
4113 #if !defined (HAVE_DEV_FD)
4114       fifo_list[nfifo-1].proc = pid;
4115 #endif
4116
4117       last_made_pid = old_pid;
4118
4119 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
4120       close_pgrp_pipe ();
4121 #endif /* JOB_CONTROL && PGRP_PIPE */
4122
4123 #if defined (HAVE_DEV_FD)
4124       close (child_pipe_fd);
4125 #endif /* HAVE_DEV_FD */
4126
4127       return (pathname);
4128     }
4129
4130   set_sigint_handler ();
4131
4132 #if defined (JOB_CONTROL)
4133   set_job_control (0);
4134 #endif /* JOB_CONTROL */
4135
4136 #if !defined (HAVE_DEV_FD)
4137   /* Open the named pipe in the child. */
4138   fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY);
4139   if (fd < 0)
4140     {
4141       /* Two separate strings for ease of translation. */
4142       if (open_for_read_in_child)
4143         sys_error (_("cannot open named pipe %s for reading"), pathname);
4144       else
4145         sys_error (_("cannot open named pipe %s for writing"), pathname);
4146
4147       exit (127);
4148     }
4149   if (open_for_read_in_child)
4150     {
4151       if (sh_unset_nodelay_mode (fd) < 0)
4152         {
4153           sys_error (_("cannout reset nodelay mode for fd %d"), fd);
4154           exit (127);
4155         }
4156     }
4157 #else /* HAVE_DEV_FD */
4158   fd = child_pipe_fd;
4159 #endif /* HAVE_DEV_FD */
4160
4161   if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
4162     {
4163       sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
4164         open_for_read_in_child ? 0 : 1);
4165       exit (127);
4166     }
4167
4168   if (fd != (open_for_read_in_child ? 0 : 1))
4169     close (fd);
4170
4171   /* Need to close any files that this process has open to pipes inherited
4172      from its parent. */
4173   if (current_fds_to_close)
4174     {
4175       close_fd_bitmap (current_fds_to_close);
4176       current_fds_to_close = (struct fd_bitmap *)NULL;
4177     }
4178
4179 #if defined (HAVE_DEV_FD)
4180   /* Make sure we close the parent's end of the pipe and clear the slot
4181      in the fd list so it is not closed later, if reallocated by, for
4182      instance, pipe(2). */
4183   close (parent_pipe_fd);
4184   dev_fd_list[parent_pipe_fd] = 0;
4185 #endif /* HAVE_DEV_FD */
4186
4187   result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
4188
4189 #if !defined (HAVE_DEV_FD)
4190   /* Make sure we close the named pipe in the child before we exit. */
4191   close (open_for_read_in_child ? 0 : 1);
4192 #endif /* !HAVE_DEV_FD */
4193
4194   exit (result);
4195   /*NOTREACHED*/
4196 }
4197 #endif /* PROCESS_SUBSTITUTION */
4198
4199 /***********************************/
4200 /*                                 */
4201 /*      Command Substitution       */
4202 /*                                 */
4203 /***********************************/
4204
4205 static char *
4206 read_comsub (fd, quoted)
4207      int fd, quoted;
4208 {
4209   char *istring, buf[128], *bufp;
4210   int istring_index, istring_size, c;
4211   ssize_t bufn;
4212
4213   istring = (char *)NULL;
4214   istring_index = istring_size = bufn = 0;
4215
4216 #ifdef __CYGWIN__
4217   setmode (fd, O_TEXT);         /* we don't want CR/LF, we want Unix-style */
4218 #endif
4219
4220   /* Read the output of the command through the pipe. */
4221   while (1)
4222     {
4223       if (fd < 0)
4224         break;
4225       if (--bufn <= 0)
4226         {
4227           bufn = zread (fd, buf, sizeof (buf));
4228           if (bufn <= 0) 
4229             break;
4230           bufp = buf;
4231         }
4232       c = *bufp++;
4233
4234       if (c == 0)
4235         {
4236 #if 0
4237           internal_warning ("read_comsub: ignored null byte in input");
4238 #endif
4239           continue;
4240         }
4241
4242       /* Add the character to ISTRING, possibly after resizing it. */
4243       RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
4244
4245       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL)
4246         istring[istring_index++] = CTLESC;
4247
4248       istring[istring_index++] = c;
4249
4250 #if 0
4251 #if defined (__CYGWIN__)
4252       if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r')
4253         {
4254           istring_index--;
4255           istring[istring_index - 1] = '\n';
4256         }
4257 #endif
4258 #endif
4259     }
4260
4261   if (istring)
4262     istring[istring_index] = '\0';
4263
4264   /* If we read no output, just return now and save ourselves some
4265      trouble. */
4266   if (istring_index == 0)
4267     {
4268       FREE (istring);
4269       return (char *)NULL;
4270     }
4271
4272   /* Strip trailing newlines from the output of the command. */
4273   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4274     {
4275       while (istring_index > 0)
4276         {
4277           if (istring[istring_index - 1] == '\n')
4278             {
4279               --istring_index;
4280
4281               /* If the newline was quoted, remove the quoting char. */
4282               if (istring[istring_index - 1] == CTLESC)
4283                 --istring_index;
4284             }
4285           else
4286             break;
4287         }
4288       istring[istring_index] = '\0';
4289     }
4290   else
4291     strip_trailing (istring, istring_index - 1, 1);
4292
4293   return istring;
4294 }
4295
4296 /* Perform command substitution on STRING.  This returns a string,
4297    possibly quoted. */
4298 char *
4299 command_substitute (string, quoted)
4300      char *string;
4301      int quoted;
4302 {
4303   pid_t pid, old_pid, old_pipeline_pgrp;
4304   char *istring;
4305   int result, fildes[2], function_value, pflags, rc;
4306
4307   istring = (char *)NULL;
4308
4309   /* Don't fork () if there is no need to.  In the case of no command to
4310      run, just return NULL. */
4311   if (!string || !*string || (string[0] == '\n' && !string[1]))
4312     return ((char *)NULL);
4313
4314   if (wordexp_only && read_but_dont_execute)
4315     {
4316       last_command_exit_value = 125;
4317       jump_to_top_level (EXITPROG);
4318     }
4319
4320   /* We're making the assumption here that the command substitution will
4321      eventually run a command from the file system.  Since we'll run
4322      maybe_make_export_env in this subshell before executing that command,
4323      the parent shell and any other shells it starts will have to remake
4324      the environment.  If we make it before we fork, other shells won't
4325      have to.  Don't bother if we have any temporary variable assignments,
4326      though, because the export environment will be remade after this
4327      command completes anyway, but do it if all the words to be expanded
4328      are variable assignments. */
4329   if (subst_assign_varlist == 0 || garglist == 0)
4330     maybe_make_export_env ();   /* XXX */
4331
4332   /* Flags to pass to parse_and_execute() */
4333   pflags = interactive ? SEVAL_RESETLINE : 0;
4334
4335   /* Pipe the output of executing STRING into the current shell. */
4336   if (pipe (fildes) < 0)
4337     {
4338       sys_error (_("cannot make pipe for command substitution"));
4339       goto error_exit;
4340     }
4341
4342   old_pid = last_made_pid;
4343 #if defined (JOB_CONTROL)
4344   old_pipeline_pgrp = pipeline_pgrp;
4345   /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */
4346   if ((subshell_environment & SUBSHELL_PIPE) == 0)
4347     pipeline_pgrp = shell_pgrp;
4348   cleanup_the_pipeline ();
4349 #endif
4350
4351   pid = make_child ((char *)NULL, 0);
4352   if (pid == 0)
4353     /* Reset the signal handlers in the child, but don't free the
4354        trap strings. */
4355     reset_signal_handlers ();
4356
4357 #if defined (JOB_CONTROL)
4358   set_sigchld_handler ();
4359   stop_making_children ();
4360   pipeline_pgrp = old_pipeline_pgrp;
4361 #else
4362   stop_making_children ();
4363 #endif /* JOB_CONTROL */
4364
4365   if (pid < 0)
4366     {
4367       sys_error (_("cannot make child for command substitution"));
4368     error_exit:
4369
4370       FREE (istring);
4371       close (fildes[0]);
4372       close (fildes[1]);
4373       return ((char *)NULL);
4374     }
4375
4376   if (pid == 0)
4377     {
4378       set_sigint_handler ();    /* XXX */
4379
4380       free_pushed_string_input ();
4381
4382       if (dup2 (fildes[1], 1) < 0)
4383         {
4384           sys_error (_("command_substitute: cannot duplicate pipe as fd 1"));
4385           exit (EXECUTION_FAILURE);
4386         }
4387
4388       /* If standard output is closed in the parent shell
4389          (such as after `exec >&-'), file descriptor 1 will be
4390          the lowest available file descriptor, and end up in
4391          fildes[0].  This can happen for stdin and stderr as well,
4392          but stdout is more important -- it will cause no output
4393          to be generated from this command. */
4394       if ((fildes[1] != fileno (stdin)) &&
4395           (fildes[1] != fileno (stdout)) &&
4396           (fildes[1] != fileno (stderr)))
4397         close (fildes[1]);
4398
4399       if ((fildes[0] != fileno (stdin)) &&
4400           (fildes[0] != fileno (stdout)) &&
4401           (fildes[0] != fileno (stderr)))
4402         close (fildes[0]);
4403
4404       /* The currently executing shell is not interactive. */
4405       interactive = 0;
4406
4407       /* This is a subshell environment. */
4408       subshell_environment |= SUBSHELL_COMSUB;
4409
4410       /* When not in POSIX mode, command substitution does not inherit
4411          the -e flag. */
4412       if (posixly_correct == 0)
4413         exit_immediately_on_error = 0;
4414
4415       remove_quoted_escapes (string);
4416
4417       startup_state = 2;        /* see if we can avoid a fork */
4418       /* Give command substitution a place to jump back to on failure,
4419          so we don't go back up to main (). */
4420       result = setjmp (top_level);
4421
4422       /* If we're running a command substitution inside a shell function,
4423          trap `return' so we don't return from the function in the subshell
4424          and go off to never-never land. */
4425       if (result == 0 && return_catch_flag)
4426         function_value = setjmp (return_catch);
4427       else
4428         function_value = 0;
4429
4430       if (result == ERREXIT)
4431         rc = last_command_exit_value;
4432       else if (result == EXITPROG)
4433         rc = last_command_exit_value;
4434       else if (result)
4435         rc = EXECUTION_FAILURE;
4436       else if (function_value)
4437         rc = return_catch_value;
4438       else
4439         {
4440           subshell_level++;
4441           rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
4442           subshell_level--;
4443         }
4444
4445       last_command_exit_value = rc;
4446       rc = run_exit_trap ();
4447       exit (rc);
4448     }
4449   else
4450     {
4451 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
4452       close_pgrp_pipe ();
4453 #endif /* JOB_CONTROL && PGRP_PIPE */
4454
4455       close (fildes[1]);
4456
4457       istring = read_comsub (fildes[0], quoted);
4458
4459       close (fildes[0]);
4460
4461       current_command_subst_pid = pid;
4462       last_command_exit_value = wait_for (pid);
4463       last_command_subst_pid = pid;
4464       last_made_pid = old_pid;
4465
4466 #if defined (JOB_CONTROL)
4467       /* If last_command_exit_value > 128, then the substituted command
4468          was terminated by a signal.  If that signal was SIGINT, then send
4469          SIGINT to ourselves.  This will break out of loops, for instance. */
4470       if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
4471         kill (getpid (), SIGINT);
4472
4473       /* wait_for gives the terminal back to shell_pgrp.  If some other
4474          process group should have it, give it away to that group here.
4475          pipeline_pgrp is non-zero only while we are constructing a
4476          pipline, so what we are concerned about is whether or not that
4477          pipeline was started in the background.  A pipeline started in
4478          the background should never get the tty back here. */
4479 #if 0
4480       if (interactive && pipeline_pgrp != (pid_t)0 && pipeline_pgrp != last_asynchronous_pid)
4481 #else
4482       if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0)
4483 #endif
4484         give_terminal_to (pipeline_pgrp, 0);
4485 #endif /* JOB_CONTROL */
4486
4487       return (istring);
4488     }
4489 }
4490
4491 /********************************************************
4492  *                                                      *
4493  *      Utility functions for parameter expansion       *
4494  *                                                      *
4495  ********************************************************/
4496
4497 #if defined (ARRAY_VARS)
4498
4499 static arrayind_t
4500 array_length_reference (s)
4501      char *s;
4502 {
4503   int len;
4504   arrayind_t ind;
4505   char *t, c;
4506   ARRAY *array;
4507   SHELL_VAR *var;
4508
4509   var = array_variable_part (s, &t, &len);
4510
4511   /* If unbound variables should generate an error, report one and return
4512      failure. */
4513   if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error)
4514     {
4515       c = *--t;
4516       *t = '\0';
4517       err_unboundvar (s);
4518       *t = c;
4519       return (-1);
4520     }
4521   else if (var == 0)
4522     return 0;
4523
4524   /* We support a couple of expansions for variables that are not arrays.
4525      We'll return the length of the value for v[0], and 1 for v[@] or
4526      v[*].  Return 0 for everything else. */
4527
4528   array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
4529
4530   if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
4531     return (array_p (var) ? array_num_elements (array) : 1);
4532
4533   ind = array_expand_index (t, len);
4534   if (ind < 0)
4535     {
4536       err_badarraysub (t);
4537       return (-1);
4538     }
4539
4540   if (array_p (var))
4541     t = array_reference (array, ind);
4542   else
4543     t = (ind == 0) ? value_cell (var) : (char *)NULL;
4544
4545   len = STRLEN (t);
4546   return (len);
4547 }
4548 #endif /* ARRAY_VARS */
4549
4550 static int
4551 valid_brace_expansion_word (name, var_is_special)
4552      char *name;
4553      int var_is_special;
4554 {
4555   if (DIGIT (*name) && all_digits (name))
4556     return 1;
4557   else if (var_is_special)
4558     return 1;
4559 #if defined (ARRAY_VARS)
4560   else if (valid_array_reference (name))
4561     return 1;
4562 #endif /* ARRAY_VARS */
4563   else if (legal_identifier (name))
4564     return 1;
4565   else
4566     return 0;
4567 }
4568
4569 static int
4570 chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at)
4571      char *name;
4572      int quoted;
4573      int *quoted_dollar_atp, *contains_dollar_at;
4574 {
4575   char *temp1;
4576
4577   if (name == 0)
4578     {
4579       if (quoted_dollar_atp)
4580         *quoted_dollar_atp = 0;
4581       if (contains_dollar_at)
4582         *contains_dollar_at = 0;
4583       return 0;
4584     }
4585
4586   /* check for $@ and $* */
4587   if (name[0] == '@' && name[1] == 0)
4588     {
4589       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4590         *quoted_dollar_atp = 1;
4591       if (contains_dollar_at)
4592         *contains_dollar_at = 1;
4593       return 1;
4594     }
4595   else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
4596     {
4597       if (contains_dollar_at)
4598         *contains_dollar_at = 1;
4599       return 1;
4600     }
4601
4602   /* Now check for ${array[@]} and ${array[*]} */
4603 #if defined (ARRAY_VARS)
4604   else if (valid_array_reference (name))
4605     {
4606       temp1 = xstrchr (name, '[');
4607       if (temp1 && temp1[1] == '@' && temp1[2] == ']')
4608         {
4609           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4610             *quoted_dollar_atp = 1;
4611           if (contains_dollar_at)
4612             *contains_dollar_at = 1;
4613           return 1;
4614         }       /* [ */
4615       /* ${array[*]}, when unquoted, should be treated like ${array[@]},
4616          which should result in separate words even when IFS is unset. */
4617       if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0)
4618         {
4619           if (contains_dollar_at)
4620             *contains_dollar_at = 1;
4621           return 1;
4622         }
4623     }
4624 #endif
4625   return 0;
4626 }
4627
4628 /* Parameter expand NAME, and return a new string which is the expansion,
4629    or NULL if there was no expansion.
4630    VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
4631    the shell, e.g., "@", "$", "*", etc.  QUOTED, if non-zero, means that
4632    NAME was found inside of a double-quoted expression. */
4633 static char *
4634 parameter_brace_expand_word (name, var_is_special, quoted)
4635      char *name;
4636      int var_is_special, quoted;
4637 {
4638   char *temp, *tt;
4639   intmax_t arg_index;
4640   SHELL_VAR *var;
4641   int atype;
4642
4643   /* Handle multiple digit arguments, as in ${11}. */
4644   
4645   if (legal_number (name, &arg_index))
4646     {
4647       tt = get_dollar_var_value (arg_index);
4648       if (tt)
4649         temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
4650                   ? quote_string (tt)
4651                   : quote_escapes (tt);
4652       else
4653         temp = (char *)NULL;
4654       FREE (tt);
4655     }
4656   else if (var_is_special)      /* ${@} */
4657     {
4658       int sindex;
4659       tt = (char *)xmalloc (2 + strlen (name));
4660       tt[sindex = 0] = '$';
4661       strcpy (tt + 1, name);
4662
4663       temp = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
4664                            (int *)NULL, (int *)NULL, 0);
4665       free (tt);
4666     }
4667 #if defined (ARRAY_VARS)
4668   else if (valid_array_reference (name))
4669     {
4670       temp = array_value (name, quoted, &atype);
4671       if (atype == 0 && temp)
4672         temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
4673                   ? quote_string (temp)
4674                   : quote_escapes (temp);
4675     }
4676 #endif
4677   else if (var = find_variable (name))
4678     {
4679       if (var_isset (var) && invisible_p (var) == 0)
4680         {
4681 #if defined (ARRAY_VARS)
4682           temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var);
4683 #else
4684           temp = value_cell (var);
4685 #endif
4686
4687           if (temp)
4688             temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
4689                       ? quote_string (temp)
4690                       : quote_escapes (temp);
4691         }
4692       else
4693         temp = (char *)NULL;
4694     }
4695   else
4696     temp = (char *)NULL;
4697
4698   return (temp);
4699 }
4700
4701 /* Expand an indirect reference to a variable: ${!NAME} expands to the
4702    value of the variable whose name is the value of NAME. */
4703 static char *
4704 parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at)
4705      char *name;
4706      int var_is_special, quoted;
4707      int *quoted_dollar_atp, *contains_dollar_at;
4708 {
4709   char *temp, *t;
4710
4711   t = parameter_brace_expand_word (name, var_is_special, quoted);
4712   /* Have to dequote here if necessary */
4713   if (t)
4714     {
4715       temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
4716                 ? dequote_string (t)
4717                 : dequote_escapes (t);
4718       free (t);
4719       t = temp;
4720     }
4721   chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at);
4722   if (t == 0)
4723     return (t);
4724   temp = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted);
4725   free (t);
4726   return temp;
4727 }
4728
4729 /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
4730    depending on the value of C, the separating character.  C can be one of
4731    "-", "+", or "=".  QUOTED is true if the entire brace expression occurs
4732    between double quotes. */
4733 static char *
4734 parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
4735      char *name, *value;
4736      int c, quoted, *qdollaratp, *hasdollarat;
4737 {
4738   WORD_LIST *l;
4739   char *t, *t1, *temp;
4740   int hasdol;
4741
4742   /* XXX - Should we tilde expand in an assignment context if C is `='? */
4743   if (*value == '~')
4744     temp = bash_tilde_expand (value, 0);
4745   else if (xstrchr (value, '~')  && unquoted_substring ("=~", value))
4746     temp = bash_tilde_expand (value, 1);
4747   else
4748     temp = savestring (value);
4749
4750   /* If the entire expression is between double quotes, we want to treat
4751      the value as a double-quoted string, with the exception that we strip
4752      embedded unescaped double quotes. */
4753   if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *temp)
4754     {
4755       hasdol = 0;
4756       t = string_extract_double_quoted (temp, &hasdol, 1);
4757       free (temp);
4758       temp = t;
4759     }
4760
4761   hasdol = 0;
4762   /* XXX was 0 not quoted */
4763   l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL)
4764             : (WORD_LIST *)0;
4765   if (hasdollarat)
4766     *hasdollarat = hasdol || (l && l->next);
4767   free (temp);
4768   if (l)
4769     {
4770       /* The expansion of TEMP returned something.  We need to treat things
4771           slightly differently if HASDOL is non-zero.  If we have "$@", the
4772           individual words have already been quoted.  We need to turn them
4773           into a string with the words separated by the first character of
4774           $IFS without any additional quoting, so string_list_dollar_at won't
4775           do the right thing.  We use string_list_dollar_star instead. */
4776       temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l);
4777
4778       /* If l->next is not null, we know that TEMP contained "$@", since that
4779          is the only expansion that creates more than one word. */
4780       if (qdollaratp && ((hasdol && quoted) || l->next))
4781         *qdollaratp = 1;
4782       dispose_words (l);
4783     }
4784   else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol)
4785     {
4786       /* The brace expansion occurred between double quotes and there was
4787          a $@ in TEMP.  It does not matter if the $@ is quoted, as long as
4788          it does not expand to anything.  In this case, we want to return
4789          a quoted empty string. */
4790       temp = (char *)xmalloc (2);
4791       temp[0] = CTLNUL;
4792       temp[1] = '\0';
4793     }
4794   else
4795     temp = (char *)NULL;
4796
4797   if (c == '-' || c == '+')
4798     return (temp);
4799
4800   /* c == '=' */
4801   t = temp ? savestring (temp) : savestring ("");
4802   t1 = dequote_string (t);
4803   free (t);
4804 #if defined (ARRAY_VARS)
4805   if (valid_array_reference (name))
4806     assign_array_element (name, t1);
4807   else
4808 #endif /* ARRAY_VARS */
4809   bind_variable (name, t1);
4810   free (t1);
4811   return (temp);
4812 }
4813
4814 /* Deal with the right hand side of a ${name:?value} expansion in the case
4815    that NAME is null or not set.  If VALUE is non-null it is expanded and
4816    used as the error message to print, otherwise a standard message is
4817    printed. */
4818 static void
4819 parameter_brace_expand_error (name, value)
4820      char *name, *value;
4821 {
4822   WORD_LIST *l;
4823   char *temp;
4824
4825   if (value && *value)
4826     {
4827       if (*value == '~')
4828         temp = bash_tilde_expand (value, 0);
4829       else if (xstrchr (value, '~')  && unquoted_substring ("=~", value))
4830         temp = bash_tilde_expand (value, 1);
4831       else
4832         temp = savestring (value);
4833
4834       l = expand_string (temp, 0);
4835       FREE (temp);
4836       temp =  string_list (l);
4837       report_error ("%s: %s", name, temp ? temp : "");  /* XXX was value not "" */
4838       FREE (temp);
4839       dispose_words (l);
4840     }
4841   else
4842     report_error (_("%s: parameter null or not set"), name);
4843
4844   /* Free the data we have allocated during this expansion, since we
4845      are about to longjmp out. */
4846   free (name);
4847   FREE (value);
4848 }
4849
4850 /* Return 1 if NAME is something for which parameter_brace_expand_length is
4851    OK to do. */
4852 static int
4853 valid_length_expression (name)
4854      char *name;
4855 {
4856   return (name[1] == '\0' ||                                    /* ${#} */
4857           ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') ||  /* special param */
4858           (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
4859 #if defined (ARRAY_VARS)
4860           valid_array_reference (name + 1) ||                   /* ${#a[7]} */
4861 #endif
4862           legal_identifier (name + 1));                         /* ${#PS1} */
4863 }
4864
4865 #if defined (HANDLE_MULTIBYTE)
4866 size_t
4867 mbstrlen (s)
4868      const char *s;
4869 {
4870   size_t clen, nc;
4871   mbstate_t mbs;
4872
4873   nc = 0;
4874   memset (&mbs, 0, sizeof (mbs));
4875   while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0 && (MB_INVALIDCH(clen) == 0))
4876     {
4877       s += clen;
4878       nc++;
4879     }
4880   return nc;
4881 }
4882 #endif
4883       
4884
4885 /* Handle the parameter brace expansion that requires us to return the
4886    length of a parameter. */
4887 static intmax_t
4888 parameter_brace_expand_length (name)
4889      char *name;
4890 {
4891   char *t, *newname;
4892   intmax_t number, arg_index;
4893   WORD_LIST *list;
4894 #if defined (ARRAY_VARS)
4895   SHELL_VAR *var;
4896 #endif
4897
4898   if (name[1] == '\0')                  /* ${#} */
4899     number = number_of_args ();
4900   else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0')       /* ${#@}, ${#*} */
4901     number = number_of_args ();
4902   else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
4903     {
4904       /* Take the lengths of some of the shell's special parameters. */
4905       switch (name[1])
4906         {
4907         case '-':
4908           t = which_set_flags ();
4909           break;
4910         case '?':
4911           t = itos (last_command_exit_value);
4912           break;
4913         case '$':
4914           t = itos (dollar_dollar_pid);
4915           break;
4916         case '!':
4917           if (last_asynchronous_pid == NO_PID)
4918             t = (char *)NULL;
4919           else
4920             t = itos (last_asynchronous_pid);
4921           break;
4922         case '#':
4923           t = itos (number_of_args ());
4924           break;
4925         }
4926       number = STRLEN (t);
4927       FREE (t);
4928     }
4929 #if defined (ARRAY_VARS)
4930   else if (valid_array_reference (name + 1))
4931     number = array_length_reference (name + 1);
4932 #endif /* ARRAY_VARS */
4933   else
4934     {
4935       number = 0;
4936
4937       if (legal_number (name + 1, &arg_index))          /* ${#1} */
4938         {
4939           t = get_dollar_var_value (arg_index);
4940           number = MB_STRLEN (t);
4941           FREE (t);
4942         }
4943 #if defined (ARRAY_VARS)
4944       else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && array_p (var))
4945         {
4946           t = array_reference (array_cell (var), 0);
4947           number = MB_STRLEN (t);
4948         }
4949 #endif
4950       else                              /* ${#PS1} */
4951         {
4952           newname = savestring (name);
4953           newname[0] = '$';
4954           list = expand_string (newname, Q_DOUBLE_QUOTES);
4955           t = list ? string_list (list) : (char *)NULL;
4956           free (newname);
4957           if (list)
4958             dispose_words (list);
4959
4960           number = MB_STRLEN (t);
4961           FREE (t);
4962         }
4963     }
4964
4965   return (number);
4966 }
4967
4968 /* Skip characters in SUBSTR until DELIM.  SUBSTR is an arithmetic expression,
4969    so we do some ad-hoc parsing of an arithmetic expression to find
4970    the first DELIM, instead of using strchr(3).  Two rules:
4971         1.  If the substring contains a `(', read until closing `)'.
4972         2.  If the substring contains a `?', read past one `:' for each `?'.
4973 */
4974
4975 static char *
4976 skiparith (substr, delim)
4977      char *substr;
4978      int delim;
4979 {
4980   size_t sublen;
4981   int skipcol, pcount, i;
4982   DECLARE_MBSTATE;
4983
4984   sublen = strlen (substr);
4985   i = skipcol = pcount = 0;
4986   while (substr[i])
4987     {
4988       /* Balance parens */
4989       if (substr[i] == LPAREN)
4990         {
4991           pcount++;
4992           i++;
4993           continue;
4994         }
4995       if (substr[i] == RPAREN && pcount)
4996         {
4997           pcount--;
4998           i++;
4999           continue;
5000         }
5001       if (pcount)
5002         {
5003           ADVANCE_CHAR (substr, sublen, i);
5004           continue;
5005         }
5006
5007       /* Skip one `:' for each `?' */
5008       if (substr[i] == ':' && skipcol)
5009         {
5010           skipcol--;
5011           i++;
5012           continue;
5013         }
5014       if (substr[i] == delim)
5015         break;
5016       if (substr[i] == '?')
5017         {
5018           skipcol++;
5019           i++;
5020           continue;
5021         }
5022       ADVANCE_CHAR (substr, sublen, i);
5023     }
5024
5025   return (substr + i);
5026 }
5027
5028 /* Verify and limit the start and end of the desired substring.  If
5029    VTYPE == 0, a regular shell variable is being used; if it is 1,
5030    then the positional parameters are being used; if it is 2, then
5031    VALUE is really a pointer to an array variable that should be used.
5032    Return value is 1 if both values were OK, 0 if there was a problem
5033    with an invalid expression, or -1 if the values were out of range. */
5034 static int
5035 verify_substring_values (value, substr, vtype, e1p, e2p)
5036      char *value, *substr;
5037      int vtype;
5038      intmax_t *e1p, *e2p;
5039 {
5040   char *t, *temp1, *temp2;
5041   arrayind_t len;
5042   int expok;
5043 #if defined (ARRAY_VARS)
5044  ARRAY *a;
5045 #endif
5046
5047   /* duplicate behavior of strchr(3) */
5048   t = skiparith (substr, ':');
5049   if (*t && *t == ':')
5050     *t = '\0';
5051   else
5052     t = (char *)0;
5053
5054   temp1 = expand_string_if_necessary (substr, Q_DOUBLE_QUOTES, expand_string);
5055   *e1p = evalexp (temp1, &expok);
5056   free (temp1);
5057   if (expok == 0)
5058     return (0);
5059
5060   len = -1;     /* paranoia */
5061   switch (vtype)
5062     {
5063     case VT_VARIABLE:
5064     case VT_ARRAYMEMBER:
5065       len = MB_STRLEN (value);
5066       break;
5067     case VT_POSPARMS:
5068       len = number_of_args () + 1;
5069       break;
5070 #if defined (ARRAY_VARS)
5071     case VT_ARRAYVAR:
5072       a = (ARRAY *)value;
5073       /* For arrays, the first value deals with array indices.  Negative
5074          offsets count from one past the array's maximum index. */
5075       len = array_max_index (a) + (*e1p < 0);   /* arrays index from 0 to n - 1 */
5076       break;
5077 #endif
5078     }
5079
5080   if (len == -1)        /* paranoia */
5081     return -1;
5082
5083   if (*e1p < 0)         /* negative offsets count from end */
5084     *e1p += len;
5085
5086   if (*e1p > len || *e1p < 0)
5087     return (-1);
5088
5089 #if defined (ARRAY_VARS)
5090   /* For arrays, the second offset deals with the number of elements. */
5091   if (vtype == VT_ARRAYVAR)
5092     len = array_num_elements (a);
5093 #endif
5094
5095   if (t)
5096     {
5097       t++;
5098       temp2 = savestring (t);
5099       temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string);
5100       free (temp2);
5101       t[-1] = ':';
5102       *e2p = evalexp (temp1, &expok);
5103       free (temp1);
5104       if (expok == 0)
5105         return (0);
5106       if (*e2p < 0)
5107         {
5108           internal_error (_("%s: substring expression < 0"), t);
5109           return (0);
5110         }
5111 #if defined (ARRAY_VARS)
5112       /* In order to deal with sparse arrays, push the intelligence about how
5113          to deal with the number of elements desired down to the array-
5114          specific functions.  */
5115       if (vtype != VT_ARRAYVAR)
5116 #endif
5117         {
5118           *e2p += *e1p;         /* want E2 chars starting at E1 */
5119           if (*e2p > len)
5120             *e2p = len;
5121         }
5122     }
5123   else
5124     *e2p = len;
5125
5126   return (1);
5127 }
5128
5129 /* Return the type of variable specified by VARNAME (simple variable,
5130    positional param, or array variable).  Also return the value specified
5131    by VARNAME (value of a variable or a reference to an array element).
5132    If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
5133    characters in the value are quoted with CTLESC and takes appropriate
5134    steps.  For convenience, *VALP is set to the dequoted VALUE. */
5135 static int
5136 get_var_and_type (varname, value, quoted, varp, valp)
5137      char *varname, *value;
5138      int quoted;
5139      SHELL_VAR **varp;
5140      char **valp;
5141 {
5142   int vtype;
5143   char *temp;
5144 #if defined (ARRAY_VARS)
5145   SHELL_VAR *v;
5146 #endif
5147
5148   /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
5149   vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0';
5150   if (vtype == VT_POSPARMS && varname[0] == '*')
5151     vtype |= VT_STARSUB;
5152   *varp = (SHELL_VAR *)NULL;
5153
5154 #if defined (ARRAY_VARS)
5155   if (valid_array_reference (varname))
5156     {
5157       v = array_variable_part (varname, &temp, (int *)0);
5158       if (v && array_p (v))
5159         { /* [ */
5160           if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
5161             {
5162               vtype = VT_ARRAYVAR;
5163               if (temp[0] == '*')
5164                 vtype |= VT_STARSUB;
5165               *valp = (char *)array_cell (v);
5166             }
5167           else
5168             {
5169               vtype = VT_ARRAYMEMBER;
5170               *valp = array_value (varname, 1, (int *)NULL);
5171             }
5172           *varp = v;
5173         }
5174       else
5175         return -1;
5176     }
5177   else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && array_p (v))
5178     {
5179       vtype = VT_ARRAYMEMBER;
5180       *varp = v;
5181       *valp = array_reference (array_cell (v), 0);
5182     }
5183   else
5184 #endif
5185 #if 1
5186     {
5187       if (value && vtype == VT_VARIABLE)
5188         {
5189           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
5190             *valp = dequote_string (value);
5191           else
5192             *valp = dequote_escapes (value);
5193         }
5194       else
5195         *valp = value;
5196     }
5197 #else
5198   *valp = (value && vtype == VT_VARIABLE) ? dequote_escapes (value) : value;
5199 #endif
5200
5201   return vtype;
5202 }
5203
5204 /******************************************************/
5205 /*                                                    */
5206 /* Functions to extract substrings of variable values */
5207 /*                                                    */
5208 /******************************************************/
5209
5210 #if defined (HANDLE_MULTIBYTE)
5211 /* Character-oriented rather than strictly byte-oriented substrings.  S and
5212    E, rather being strict indices into STRING, indicate character (possibly
5213    multibyte character) positions that require calculation.
5214    Used by the ${param:offset[:length]} expansion. */
5215 static char *
5216 mb_substring (string, s, e)
5217      char *string;
5218      int s, e;
5219 {
5220   char *tt;
5221   int start, stop, i, slen;
5222   DECLARE_MBSTATE;
5223
5224   start = 0;
5225   slen = STRLEN (string);
5226
5227   i = s;
5228   while (string[start] && i--)
5229     ADVANCE_CHAR (string, slen, start);
5230   stop = start;
5231   i = e - s;
5232   while (string[stop] && i--)
5233     ADVANCE_CHAR (string, slen, stop);
5234   tt = substring (string, start, stop);
5235   return tt;
5236 }
5237 #endif
5238   
5239 /* Process a variable substring expansion: ${name:e1[:e2]}.  If VARNAME
5240    is `@', use the positional parameters; otherwise, use the value of
5241    VARNAME.  If VARNAME is an array variable, use the array elements. */
5242
5243 static char *
5244 parameter_brace_substring (varname, value, substr, quoted)
5245      char *varname, *value, *substr;
5246      int quoted;
5247 {
5248   intmax_t e1, e2;
5249   int vtype, r, starsub;
5250   char *temp, *val, *tt;
5251   SHELL_VAR *v;
5252
5253   if (value == 0)
5254     return ((char *)NULL);
5255
5256   this_command_name = varname;
5257
5258   vtype = get_var_and_type (varname, value, quoted, &v, &val);
5259   if (vtype == -1)
5260     return ((char *)NULL);
5261
5262   starsub = vtype & VT_STARSUB;
5263   vtype &= ~VT_STARSUB;
5264
5265   r = verify_substring_values (val, substr, vtype, &e1, &e2);
5266   if (r <= 0)
5267     return ((r == 0) ? &expand_param_error : (char *)NULL);
5268
5269   switch (vtype)
5270     {
5271     case VT_VARIABLE:
5272     case VT_ARRAYMEMBER:
5273 #if defined (HANDLE_MULTIBYTE)
5274       if (MB_CUR_MAX > 1)
5275         tt = mb_substring (val, e1, e2);
5276       else
5277 #endif
5278       tt = substring (val, e1, e2);
5279
5280       if (vtype == VT_VARIABLE)
5281         FREE (val);
5282       if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
5283         temp = quote_string (tt);
5284       else
5285         temp = tt ? quote_escapes (tt) : (char *)NULL;
5286       FREE (tt);
5287       break;
5288     case VT_POSPARMS:
5289       tt = pos_params (varname, e1, e2, quoted);
5290       if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
5291         {
5292           temp = tt ? quote_escapes (tt) : (char *)NULL;
5293           FREE (tt);
5294         }
5295       else
5296         temp = tt;
5297       break;
5298 #if defined (ARRAY_VARS)
5299     case VT_ARRAYVAR:
5300       /* We want E2 to be the number of elements desired (arrays can be sparse,
5301          so verify_substring_values just returns the numbers specified and we
5302          rely on array_subrange to understand how to deal with them). */
5303       tt = array_subrange (array_cell (v), e1, e2, starsub, quoted);
5304       if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
5305         {
5306           temp = tt ? quote_escapes (tt) : (char *)NULL;
5307           FREE (tt);
5308         }
5309       else
5310         temp = tt;
5311       break;
5312 #endif
5313     default:
5314       temp = (char *)NULL;
5315     }
5316
5317   return temp;
5318 }
5319
5320 /****************************************************************/
5321 /*                                                              */
5322 /* Functions to perform pattern substitution on variable values */
5323 /*                                                              */
5324 /****************************************************************/
5325
5326 char *
5327 pat_subst (string, pat, rep, mflags)
5328      char *string, *pat, *rep;
5329      int mflags;
5330 {
5331   char *ret, *s, *e, *str;
5332   int rsize, rptr, l, replen, mtype;
5333
5334   mtype = mflags & MATCH_TYPEMASK;
5335
5336   /* Special cases:
5337    *    1.  A null pattern with mtype == MATCH_BEG means to prefix STRING
5338    *        with REP and return the result.
5339    *    2.  A null pattern with mtype == MATCH_END means to append REP to
5340    *        STRING and return the result.
5341    */
5342   if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
5343     {
5344       replen = STRLEN (rep);
5345       l = strlen (string);
5346       ret = (char *)xmalloc (replen + l + 2);
5347       if (replen == 0)
5348         strcpy (ret, string);
5349       else if (mtype == MATCH_BEG)
5350         {
5351           strcpy (ret, rep);
5352           strcpy (ret + replen, string);
5353         }
5354       else
5355         {
5356           strcpy (ret, string);
5357           strcpy (ret + l, rep);
5358         }
5359       return (ret);
5360     }
5361
5362   ret = (char *)xmalloc (rsize = 64);
5363   ret[0] = '\0';
5364
5365   for (replen = STRLEN (rep), rptr = 0, str = string;;)
5366     {
5367       if (match_pattern (str, pat, mtype, &s, &e) == 0)
5368         break;
5369       l = s - str;
5370       RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64);
5371
5372       /* OK, now copy the leading unmatched portion of the string (from
5373          str to s) to ret starting at rptr (the current offset).  Then copy
5374          the replacement string at ret + rptr + (s - str).  Increment
5375          rptr (if necessary) and str and go on. */
5376       if (l)
5377         {
5378           strncpy (ret + rptr, str, l);
5379           rptr += l;
5380         }
5381       if (replen)
5382         {
5383           strncpy (ret + rptr, rep, replen);
5384           rptr += replen;
5385         }
5386       str = e;          /* e == end of match */
5387
5388       if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
5389         break;
5390
5391       if (s == e)
5392         e++, str++;             /* avoid infinite recursion on zero-length match */
5393     }
5394
5395   /* Now copy the unmatched portion of the input string */
5396   if (*str)
5397     {
5398       RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
5399       strcpy (ret + rptr, str);
5400     }
5401   else
5402     ret[rptr] = '\0';
5403
5404   return ret;
5405 }
5406
5407 /* Do pattern match and replacement on the positional parameters. */
5408 static char *
5409 pos_params_pat_subst (string, pat, rep, mflags)
5410      char *string, *pat, *rep;
5411      int mflags;
5412 {
5413   WORD_LIST *save, *params;
5414   WORD_DESC *w;
5415   char *ret, *tt;
5416
5417   save = params = list_rest_of_args ();
5418   if (save == 0)
5419     return ((char *)NULL);
5420
5421   for ( ; params; params = params->next)
5422     {
5423       ret = pat_subst (params->word->word, pat, rep, mflags);
5424       w = make_bare_word (ret);
5425       dispose_word (params->word);
5426       params->word = w;
5427       FREE (ret);
5428     }
5429
5430   if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
5431     ret = string_list_dollar_star (quote_list (save));
5432   else
5433     ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save);
5434   dispose_words (save);
5435
5436   return (ret);
5437 }
5438
5439 /* Perform pattern substitution on VALUE, which is the expansion of
5440    VARNAME.  PATSUB is an expression supplying the pattern to match
5441    and the string to substitute.  QUOTED is a flags word containing
5442    the type of quoting currently in effect. */
5443 static char *
5444 parameter_brace_patsub (varname, value, patsub, quoted)
5445      char *varname, *value, *patsub;
5446      int quoted;
5447 {
5448   int vtype, mflags, starsub;
5449   char *val, *temp, *pat, *rep, *p, *lpatsub, *tt;
5450   SHELL_VAR *v;
5451
5452   if (value == 0)
5453     return ((char *)NULL);
5454
5455   this_command_name = varname;
5456
5457   vtype = get_var_and_type (varname, value, quoted, &v, &val);
5458   if (vtype == -1)
5459     return ((char *)NULL);
5460
5461   starsub = vtype & VT_STARSUB;
5462   vtype &= ~VT_STARSUB;
5463
5464   mflags = 0;
5465   if (*patsub == '/')
5466     {
5467       mflags |= MATCH_GLOBREP;
5468       patsub++;
5469     }
5470
5471   /* Malloc this because expand_string_if_necessary or one of the expansion
5472      functions in its call chain may free it on a substitution error. */
5473   lpatsub = savestring (patsub);
5474
5475   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5476     mflags |= MATCH_QUOTED;
5477
5478   if (starsub)
5479     mflags |= MATCH_STARSUB;
5480
5481   if (rep = quoted_strchr (lpatsub, '/', ST_BACKSL))
5482     *rep++ = '\0';
5483   else
5484     rep = (char *)NULL;
5485
5486   if (rep && *rep == '\0')
5487     rep = (char *)NULL;
5488
5489 #if 0
5490   /* Expand PAT and REP for command, variable and parameter, arithmetic,
5491      and process substitution.  Also perform quote removal.  Do not
5492      perform word splitting or filename generation. */
5493   pat = expand_string_if_necessary (lpatsub, (quoted & ~Q_DOUBLE_QUOTES), expand_string_unsplit);
5494 #else
5495   /* Perform the same expansions on the pattern as performed by the
5496      pattern removal expansions. */
5497   pat = getpattern (lpatsub, quoted, 1);
5498 #endif
5499
5500   if (rep)
5501     {
5502       if ((mflags & MATCH_QUOTED) == 0)
5503         rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
5504       else
5505         rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
5506     }
5507
5508   p = pat;
5509   if (pat && pat[0] == '#')
5510     {
5511       mflags |= MATCH_BEG;
5512       p++;
5513     }
5514   else if (pat && pat[0] == '%')
5515     {
5516       mflags |= MATCH_END;
5517       p++;
5518     }
5519   else
5520     mflags |= MATCH_ANY;
5521
5522   /* OK, we now want to substitute REP for PAT in VAL.  If
5523      flags & MATCH_GLOBREP is non-zero, the substitution is done
5524      everywhere, otherwise only the first occurrence of PAT is
5525      replaced.  The pattern matching code doesn't understand
5526      CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
5527      values passed in (VT_VARIABLE) so the pattern substitution
5528      code works right.  We need to requote special chars after
5529      we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
5530      other cases if QUOTED == 0, since the posparams and arrays
5531      indexed by * or @ do special things when QUOTED != 0. */
5532
5533   switch (vtype)
5534     {
5535     case VT_VARIABLE:
5536     case VT_ARRAYMEMBER:
5537       temp = pat_subst (val, p, rep, mflags);
5538       if (vtype == VT_VARIABLE)
5539         FREE (val);
5540       if (temp)
5541         {
5542           tt = quote_escapes (temp);
5543           free (temp);
5544           temp = tt;
5545         }
5546       break;
5547     case VT_POSPARMS:
5548       temp = pos_params_pat_subst (val, p, rep, mflags);
5549       if (temp && (mflags & MATCH_QUOTED) == 0)
5550         {
5551           tt = quote_escapes (temp);
5552           free (temp);
5553           temp = tt;
5554         }
5555       break;
5556 #if defined (ARRAY_VARS)
5557     case VT_ARRAYVAR:
5558       temp = array_patsub (array_cell (v), p, rep, mflags);
5559       if (temp && (mflags & MATCH_QUOTED) == 0)
5560         {
5561           tt = quote_escapes (temp);
5562           free (temp);
5563           temp = tt;
5564         }
5565       break;
5566 #endif
5567     }
5568
5569   FREE (pat);
5570   FREE (rep);
5571   free (lpatsub);
5572
5573   return temp;
5574 }
5575
5576 /****************************************************************/
5577 /*                                                              */
5578 /*      Functions to perform parameter expansion on a string    */
5579 /*                                                              */
5580 /****************************************************************/
5581
5582 /* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */
5583 static char *
5584 parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at)
5585      char *string;
5586      int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at;
5587 {
5588   int check_nullness, var_is_set, var_is_null, var_is_special;
5589   int want_substring, want_indir, want_patsub;
5590   char *name, *value, *temp, *temp1;
5591   int t_index, sindex, c;
5592   intmax_t number;
5593
5594   value = (char *)NULL;
5595   var_is_set = var_is_null = var_is_special = check_nullness = 0;
5596   want_substring = want_indir = want_patsub = 0;
5597
5598   sindex = *indexp;
5599   t_index = ++sindex;
5600   name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME);
5601
5602   /* If the name really consists of a special variable, then make sure
5603      that we have the entire name.  We don't allow indirect references
5604      to special variables except `#', `?', `@' and `*'. */
5605   if ((sindex == t_index &&
5606         (string[t_index] == '-' ||
5607          string[t_index] == '?' ||
5608          string[t_index] == '#')) ||
5609       (sindex == t_index - 1 && string[sindex] == '!' &&
5610         (string[t_index] == '#' ||
5611          string[t_index] == '?' ||
5612          string[t_index] == '@' ||
5613          string[t_index] == '*')))
5614     {
5615       t_index++;
5616       free (name);
5617       temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
5618       name = (char *)xmalloc (3 + (strlen (temp1)));
5619       *name = string[sindex];
5620       if (string[sindex] == '!')
5621         {
5622           /* indirect reference of $#, $?, $@, or $* */
5623           name[1] = string[sindex + 1];
5624           strcpy (name + 2, temp1);
5625         }
5626       else      
5627         strcpy (name + 1, temp1);
5628       free (temp1);
5629     }
5630   sindex = t_index;
5631
5632   /* Find out what character ended the variable name.  Then
5633      do the appropriate thing. */
5634   if (c = string[sindex])
5635     sindex++;
5636
5637   /* If c is followed by one of the valid parameter expansion
5638      characters, move past it as normal.  If not, assume that
5639      a substring specification is being given, and do not move
5640      past it. */
5641   if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
5642     {
5643       check_nullness++;
5644       if (c = string[sindex])
5645         sindex++;
5646     }
5647   else if (c == ':' && string[sindex] != RBRACE)
5648     want_substring = 1;
5649   else if (c == '/' && string[sindex] != RBRACE)
5650     want_patsub = 1;
5651
5652   /* Catch the valid and invalid brace expressions that made it through the
5653      tests above. */
5654   /* ${#-} is a valid expansion and means to take the length of $-.
5655      Similarly for ${#?} and ${##}... */
5656   if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
5657         VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
5658     {
5659       name = (char *)xrealloc (name, 3);
5660       name[1] = c;
5661       name[2] = '\0';
5662       c = string[sindex++];
5663     }
5664
5665   /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
5666   if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
5667         member (c, "%:=+/") && string[sindex] == RBRACE)
5668     {
5669       temp = (char *)NULL;
5670       goto bad_substitution;
5671     }
5672
5673   /* Indirect expansion begins with a `!'.  A valid indirect expansion is
5674      either a variable name, one of the positional parameters or a special
5675      variable that expands to one of the positional parameters. */
5676   want_indir = *name == '!' &&
5677     (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
5678                                         || VALID_INDIR_PARAM (name[1]));
5679
5680   /* Determine the value of this variable. */
5681
5682   /* Check for special variables, directly referenced. */
5683   if (SPECIAL_VAR (name, want_indir))
5684     var_is_special++;
5685
5686   /* Check for special expansion things, like the length of a parameter */
5687   if (*name == '#' && name[1])
5688     {
5689       /* If we are not pointing at the character just after the
5690          closing brace, then we haven't gotten all of the name.
5691          Since it begins with a special character, this is a bad
5692          substitution.  Also check NAME for validity before trying
5693          to go on. */
5694       if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
5695         {
5696           temp = (char *)NULL;
5697           goto bad_substitution;
5698         }
5699
5700       number = parameter_brace_expand_length (name);
5701       free (name);
5702
5703       *indexp = sindex;
5704       return ((number < 0) ? &expand_param_error : itos (number));
5705     }
5706
5707   /* ${@} is identical to $@. */
5708   if (name[0] == '@' && name[1] == '\0')
5709     {
5710       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5711         *quoted_dollar_atp = 1;
5712
5713       if (contains_dollar_at)
5714         *contains_dollar_at = 1;
5715     }
5716
5717   /* Process ${!PREFIX*} expansion. */
5718   if (want_indir && string[sindex - 1] == RBRACE &&
5719       (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
5720       legal_variable_starter ((unsigned char) name[1]))
5721     {
5722       char **x;
5723       WORD_LIST *xlist;
5724
5725       temp1 = savestring (name + 1);
5726       number = strlen (temp1);
5727       temp1[number - 1] = '\0';
5728       x = all_variables_matching_prefix (temp1);
5729       xlist = strvec_to_word_list (x, 0, 0);
5730       if (string[sindex - 2] == '*')
5731         temp = string_list_dollar_star (xlist);
5732       else
5733         {
5734           temp = string_list_dollar_at (xlist, quoted);
5735           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5736             *quoted_dollar_atp = 1;
5737           if (contains_dollar_at)
5738             *contains_dollar_at = 1;
5739         }
5740       free (x);
5741       free (xlist);
5742       free (temp1);
5743       *indexp = sindex;
5744       return (temp);
5745     }
5746
5747 #if defined (ARRAY_VARS)      
5748   /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */
5749   if (want_indir && string[sindex - 1] == RBRACE &&
5750       string[sindex - 2] == ']' && valid_array_reference (name+1))
5751     {
5752       char *x, *x1;
5753
5754       temp1 = savestring (name + 1);
5755       x = array_variable_name (temp1, &x1, (int *)0);   /* [ */
5756       FREE (x);
5757       if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']')
5758         {
5759           temp = array_keys (temp1, quoted);
5760           if (x1[0] == '@')
5761             {
5762               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5763                 *quoted_dollar_atp = 1;
5764               if (contains_dollar_at)
5765                 *contains_dollar_at = 1;
5766             }       
5767
5768           free (temp1);
5769           *indexp = sindex;
5770           return (temp);
5771         }
5772
5773       free (temp1);
5774     }
5775 #endif /* ARRAY_VARS */
5776       
5777   /* Make sure that NAME is valid before trying to go on. */
5778   if (valid_brace_expansion_word (want_indir ? name + 1 : name,
5779                                         var_is_special) == 0)
5780     {
5781       temp = (char *)NULL;
5782       goto bad_substitution;
5783     }
5784
5785   if (want_indir)
5786     temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
5787   else
5788     temp = parameter_brace_expand_word (name, var_is_special, quoted);
5789
5790 #if defined (ARRAY_VARS)
5791   if (valid_array_reference (name))
5792     chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at);
5793 #endif
5794
5795   var_is_set = temp != (char *)0;
5796   var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
5797
5798   /* Get the rest of the stuff inside the braces. */
5799   if (c && c != RBRACE)
5800     {
5801       /* Extract the contents of the ${ ... } expansion
5802          according to the Posix.2 rules. */
5803       value = extract_dollar_brace_string (string, &sindex, quoted, 0);
5804       if (string[sindex] == RBRACE)
5805         sindex++;
5806       else
5807         goto bad_substitution;
5808     }
5809   else
5810     value = (char *)NULL;
5811
5812   *indexp = sindex;
5813
5814   /* If this is a substring spec, process it and add the result. */
5815   if (want_substring)
5816     {
5817       temp1 = parameter_brace_substring (name, temp, value, quoted);
5818       FREE (name);
5819       FREE (value);
5820       FREE (temp);
5821       return (temp1);
5822     }
5823   else if (want_patsub)
5824     {
5825       temp1 = parameter_brace_patsub (name, temp, value, quoted);
5826       FREE (name);
5827       FREE (value);
5828       FREE (temp);
5829       return (temp1);
5830     }
5831
5832   /* Do the right thing based on which character ended the variable name. */
5833   switch (c)
5834     {
5835     default:
5836     case '\0':
5837     bad_substitution:
5838       report_error (_("%s: bad substitution"), string ? string : "??");
5839       FREE (value);
5840       FREE (temp);
5841       free (name);
5842       return &expand_param_error;
5843
5844     case RBRACE:
5845       if (var_is_set == 0 && unbound_vars_is_error)
5846         {
5847           err_unboundvar (name);
5848           FREE (value);
5849           FREE (temp);
5850           free (name);
5851           last_command_exit_value = EXECUTION_FAILURE;
5852           return (interactive_shell ? &expand_param_error : &expand_param_fatal);
5853         }
5854       break;
5855
5856     case '#':   /* ${param#[#]pattern} */
5857     case '%':   /* ${param%[%]pattern} */
5858       if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
5859         {
5860           FREE (value);
5861           break;
5862         }
5863       temp1 = parameter_brace_remove_pattern (name, temp, value, c, quoted);
5864       free (temp);
5865       free (value);
5866       temp = temp1;
5867       break;
5868
5869     case '-':
5870     case '=':
5871     case '?':
5872     case '+':
5873       if (var_is_set && var_is_null == 0)
5874         {
5875           /* If the operator is `+', we don't want the value of the named
5876              variable for anything, just the value of the right hand side. */
5877
5878           if (c == '+')
5879             {
5880               /* XXX -- if we're double-quoted and the named variable is "$@",
5881                         we want to turn off any special handling of "$@" --
5882                         we're not using it, so whatever is on the rhs applies. */
5883               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5884                 *quoted_dollar_atp = 0;
5885               if (contains_dollar_at)
5886                 *contains_dollar_at = 0;
5887
5888               FREE (temp);
5889               if (value)
5890                 {
5891                   temp = parameter_brace_expand_rhs (name, value, c,
5892                                                      quoted,
5893                                                      quoted_dollar_atp,
5894                                                      contains_dollar_at);
5895                   free (value);
5896                 }
5897               else
5898                 temp = (char *)NULL;
5899             }
5900           else
5901             {
5902               FREE (value);
5903             }
5904           /* Otherwise do nothing; just use the value in TEMP. */
5905         }
5906       else      /* VAR not set or VAR is NULL. */
5907         {
5908           FREE (temp);
5909           temp = (char *)NULL;
5910           if (c == '=' && var_is_special)
5911             {
5912               report_error (_("$%s: cannot assign in this way"), name);
5913               free (name);
5914               free (value);
5915               return &expand_param_error;
5916             }
5917           else if (c == '?')
5918             {
5919               parameter_brace_expand_error (name, value);
5920               return (interactive_shell ? &expand_param_error : &expand_param_fatal);
5921             }
5922           else if (c != '+')
5923             {
5924               /* XXX -- if we're double-quoted and the named variable is "$@",
5925                         we want to turn off any special handling of "$@" --
5926                         we're not using it, so whatever is on the rhs applies. */
5927               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5928                 *quoted_dollar_atp = 0;
5929               if (contains_dollar_at)
5930                 *contains_dollar_at = 0;
5931
5932               temp = parameter_brace_expand_rhs (name, value, c, quoted,
5933                                                  quoted_dollar_atp,
5934                                                  contains_dollar_at);
5935             }
5936           free (value);
5937         }
5938
5939       break;
5940     }
5941   free (name);
5942   return (temp);
5943 }
5944
5945 /* Expand a single ${xxx} expansion.  The braces are optional.  When
5946    the braces are used, parameter_brace_expand() does the work,
5947    possibly calling param_expand recursively. */
5948 static char *
5949 param_expand (string, sindex, quoted, expanded_something,
5950               contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
5951               pflags)
5952      char *string;
5953      int *sindex, quoted, *expanded_something, *contains_dollar_at;
5954      int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
5955 {
5956   char *temp, *temp1, uerror[3];
5957   int zindex, t_index, expok;
5958   unsigned char c;
5959   intmax_t number;
5960   SHELL_VAR *var;
5961   WORD_LIST *list;
5962
5963   zindex = *sindex;
5964   c = string[++zindex];
5965
5966   temp = (char *)NULL;
5967
5968   /* Do simple cases first. Switch on what follows '$'. */
5969   switch (c)
5970     {
5971     /* $0 .. $9? */
5972     case '0':
5973     case '1':
5974     case '2':
5975     case '3':
5976     case '4':
5977     case '5':
5978     case '6':
5979     case '7':
5980     case '8':
5981     case '9':
5982       temp1 = dollar_vars[TODIGIT (c)];
5983       if (unbound_vars_is_error && temp1 == (char *)NULL)
5984         {
5985           uerror[0] = '$';
5986           uerror[1] = c;
5987           uerror[2] = '\0';
5988           err_unboundvar (uerror);
5989           last_command_exit_value = EXECUTION_FAILURE;
5990           return (interactive_shell ? &expand_param_error : &expand_param_fatal);
5991         }
5992 #if 1
5993       if (temp1)
5994         temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
5995                   ? quote_string (temp1)
5996                   : quote_escapes (temp1);
5997       else
5998         temp = (char *)NULL;
5999 #else
6000       temp = temp1 ? quote_escapes (temp1) : (char *)NULL;
6001 #endif
6002       break;
6003
6004     /* $$ -- pid of the invoking shell. */
6005     case '$':
6006       temp = itos (dollar_dollar_pid);
6007       break;
6008
6009     /* $# -- number of positional parameters. */
6010     case '#':
6011       temp = itos (number_of_args ());
6012       break;
6013
6014     /* $? -- return value of the last synchronous command. */
6015     case '?':
6016       temp = itos (last_command_exit_value);
6017       break;
6018
6019     /* $- -- flags supplied to the shell on invocation or by `set'. */
6020     case '-':
6021       temp = which_set_flags ();
6022       break;
6023
6024       /* $! -- Pid of the last asynchronous command. */
6025     case '!':
6026       /* If no asynchronous pids have been created, expand to nothing.
6027          If `set -u' has been executed, and no async processes have
6028          been created, this is an expansion error. */
6029       if (last_asynchronous_pid == NO_PID)
6030         {
6031           if (expanded_something)
6032             *expanded_something = 0;
6033           temp = (char *)NULL;
6034           if (unbound_vars_is_error)
6035             {
6036               uerror[0] = '$';
6037               uerror[1] = c;
6038               uerror[2] = '\0';
6039               err_unboundvar (uerror);
6040               last_command_exit_value = EXECUTION_FAILURE;
6041               return (interactive_shell ? &expand_param_error : &expand_param_fatal);
6042             }
6043         }
6044       else
6045         temp = itos (last_asynchronous_pid);
6046       break;
6047
6048     /* The only difference between this and $@ is when the arg is quoted. */
6049     case '*':           /* `$*' */
6050       list = list_rest_of_args ();
6051
6052       /* If there are no command-line arguments, this should just
6053          disappear if there are other characters in the expansion,
6054          even if it's quoted. */
6055       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
6056         temp = (char *)NULL;
6057       else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6058         {
6059           /* If we have "$*" we want to make a string of the positional
6060              parameters, separated by the first character of $IFS, and
6061              quote the whole string, including the separators.  If IFS
6062              is unset, the parameters are separated by ' '; if $IFS is
6063              null, the parameters are concatenated. */
6064 #if 0
6065           temp = string_list_dollar_star (list);
6066 #else
6067           temp = (quoted & Q_DOUBLE_QUOTES) ? string_list_dollar_star (list) : string_list (list);
6068 #endif
6069           temp1 = quote_string (temp);
6070           free (temp);
6071           temp = temp1;
6072         }
6073       else
6074         {
6075           /* If the $* is not quoted it is identical to $@ */
6076           temp = string_list_dollar_at (list, quoted);
6077           if (expand_no_split_dollar_star == 0 && contains_dollar_at)
6078             *contains_dollar_at = 1;
6079         }
6080
6081       dispose_words (list);
6082       break;
6083
6084     /* When we have "$@" what we want is "$1" "$2" "$3" ... This
6085        means that we have to turn quoting off after we split into
6086        the individually quoted arguments so that the final split
6087        on the first character of $IFS is still done.  */
6088     case '@':           /* `$@' */
6089       list = list_rest_of_args ();
6090
6091       /* We want to flag the fact that we saw this.  We can't turn
6092          off quoting entirely, because other characters in the
6093          string might need it (consider "\"$@\""), but we need some
6094          way to signal that the final split on the first character
6095          of $IFS should be done, even though QUOTED is 1. */
6096       if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
6097         *quoted_dollar_at_p = 1;
6098       if (contains_dollar_at)
6099         *contains_dollar_at = 1;
6100
6101       /* We want to separate the positional parameters with the first
6102          character of $IFS in case $IFS is something other than a space.
6103          We also want to make sure that splitting is done no matter what --
6104          according to POSIX.2, this expands to a list of the positional
6105          parameters no matter what IFS is set to. */
6106       temp = string_list_dollar_at (list, quoted);
6107
6108       dispose_words (list);
6109       break;
6110
6111     case LBRACE:
6112       temp = parameter_brace_expand (string, &zindex, quoted,
6113                                      quoted_dollar_at_p,
6114                                      contains_dollar_at);
6115       if (temp == &expand_param_error || temp == &expand_param_fatal)
6116         return (temp);
6117
6118       /* XXX */
6119       /* Quoted nulls should be removed if there is anything else
6120          in the string. */
6121       /* Note that we saw the quoted null so we can add one back at
6122          the end of this function if there are no other characters
6123          in the string, discard TEMP, and go on.  The exception to
6124          this is when we have "${@}" and $1 is '', since $@ needs
6125          special handling. */
6126       if (temp && QUOTED_NULL (temp))
6127         {
6128           if (had_quoted_null_p)
6129             *had_quoted_null_p = 1;
6130           if (*quoted_dollar_at_p == 0)
6131             {
6132               free (temp);
6133               temp = (char *)NULL;
6134             }
6135             
6136         }
6137
6138       goto return0;
6139
6140     /* Do command or arithmetic substitution. */
6141     case LPAREN:
6142       /* We have to extract the contents of this paren substitution. */
6143       t_index = zindex + 1;
6144       temp = extract_command_subst (string, &t_index);
6145       zindex = t_index;
6146
6147       /* For Posix.2-style `$(( ))' arithmetic substitution,
6148          extract the expression and pass it to the evaluator. */
6149       if (temp && *temp == LPAREN)
6150         {
6151           char *temp2;
6152           temp1 = temp + 1;
6153           temp2 = savestring (temp1);
6154           t_index = strlen (temp2) - 1;
6155
6156           if (temp2[t_index] != RPAREN)
6157             {
6158               free (temp2);
6159               goto comsub;
6160             }
6161
6162           /* Cut off ending `)' */
6163           temp2[t_index] = '\0';
6164
6165           /* Expand variables found inside the expression. */
6166           temp1 = expand_string_if_necessary (temp2, Q_DOUBLE_QUOTES, expand_string);
6167           free (temp2);
6168
6169 arithsub:
6170           /* No error messages. */
6171           this_command_name = (char *)NULL;
6172           number = evalexp (temp1, &expok);
6173           free (temp);
6174           free (temp1);
6175           if (expok == 0)
6176             {
6177               if (interactive_shell == 0 && posixly_correct)
6178                 {
6179                   last_command_exit_value = EXECUTION_FAILURE;
6180                   return (&expand_param_fatal);
6181                 }
6182               else
6183                 return (&expand_param_error);
6184             }
6185           temp = itos (number);
6186           break;
6187         }
6188
6189 comsub:
6190       if (pflags & PF_NOCOMSUB)
6191         /* we need zindex+1 because string[zindex] == RPAREN */
6192         temp1 = substring (string, *sindex, zindex+1);
6193       else
6194         temp1 = command_substitute (temp, quoted);
6195       FREE (temp);
6196       temp = temp1;
6197       break;
6198
6199     /* Do POSIX.2d9-style arithmetic substitution.  This will probably go
6200        away in a future bash release. */
6201     case '[':
6202       /* Extract the contents of this arithmetic substitution. */
6203       t_index = zindex + 1;
6204       temp = extract_arithmetic_subst (string, &t_index);
6205       zindex = t_index;
6206
6207        /* Do initial variable expansion. */
6208       temp1 = expand_string_if_necessary (temp, Q_DOUBLE_QUOTES, expand_string);
6209
6210       goto arithsub;
6211
6212     default:
6213       /* Find the variable in VARIABLE_LIST. */
6214       temp = (char *)NULL;
6215
6216       for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
6217         ;
6218       temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
6219
6220       /* If this isn't a variable name, then just output the `$'. */
6221       if (temp1 == 0 || *temp1 == '\0')
6222         {
6223           FREE (temp1);
6224           temp = (char *)xmalloc (2);
6225           temp[0] = '$';
6226           temp[1] = '\0';
6227           if (expanded_something)
6228             *expanded_something = 0;
6229           goto return0;
6230         }
6231
6232       /* If the variable exists, return its value cell. */
6233       var = find_variable (temp1);
6234
6235       if (var && invisible_p (var) == 0 && var_isset (var))
6236         {
6237 #if defined (ARRAY_VARS)
6238           if (array_p (var))
6239             {
6240               temp = array_reference (array_cell (var), 0);
6241               if (temp)
6242                 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
6243                           ? quote_string (temp)
6244                           : quote_escapes (temp);
6245               else if (unbound_vars_is_error)
6246                 goto unbound_variable;
6247             }
6248           else
6249 #endif
6250             {
6251               temp = value_cell (var);
6252
6253               temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
6254                         ? quote_string (temp)
6255                         : quote_escapes (temp);
6256             }
6257
6258           free (temp1);
6259
6260           goto return0;
6261         }
6262
6263       temp = (char *)NULL;
6264
6265 unbound_variable:
6266       if (unbound_vars_is_error)
6267         err_unboundvar (temp1);
6268       else
6269         {
6270           free (temp1);
6271           goto return0;
6272         }
6273
6274       free (temp1);
6275       last_command_exit_value = EXECUTION_FAILURE;
6276       return ((unbound_vars_is_error && interactive_shell == 0)
6277                 ? &expand_param_fatal
6278                 : &expand_param_error);
6279     }
6280
6281   if (string[zindex])
6282     zindex++;
6283
6284 return0:
6285   *sindex = zindex;
6286   return (temp);
6287 }
6288
6289 /* Make a word list which is the result of parameter and variable
6290    expansion, command substitution, arithmetic substitution, and
6291    quote removal of WORD.  Return a pointer to a WORD_LIST which is
6292    the result of the expansion.  If WORD contains a null word, the
6293    word list returned is also null.
6294
6295    QUOTED contains flag values defined in shell.h.
6296
6297    ISEXP is used to tell expand_word_internal that the word should be
6298    treated as the result of an expansion.  This has implications for
6299    how IFS characters in the word are treated.
6300
6301    CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
6302    they point to an integer value which receives information about expansion.
6303    CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
6304    EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
6305    else zero.
6306
6307    This only does word splitting in the case of $@ expansion.  In that
6308    case, we split on ' '. */
6309
6310 /* Values for the local variable quoted_state. */
6311 #define UNQUOTED         0
6312 #define PARTIALLY_QUOTED 1
6313 #define WHOLLY_QUOTED    2
6314
6315 static WORD_LIST *
6316 expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
6317      WORD_DESC *word;
6318      int quoted, isexp;
6319      int *contains_dollar_at;
6320      int *expanded_something;
6321 {
6322   WORD_LIST *list;
6323   WORD_DESC *tword;
6324
6325   /* The intermediate string that we build while expanding. */
6326   char *istring;
6327
6328   /* The current size of the above object. */
6329   int istring_size;
6330
6331   /* Index into ISTRING. */
6332   int istring_index;
6333
6334   /* Temporary string storage. */
6335   char *temp, *temp1;
6336
6337   /* The text of WORD. */
6338   register char *string;
6339
6340   /* The size of STRING. */
6341   size_t string_size;
6342
6343   /* The index into STRING. */
6344   int sindex;
6345
6346   /* This gets 1 if we see a $@ while quoted. */
6347   int quoted_dollar_at;
6348
6349   /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
6350      whether WORD contains no quoting characters, a partially quoted
6351      string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
6352   int quoted_state;
6353
6354   /* State flags */
6355   int had_quoted_null;
6356   int has_dollar_at;
6357   int tflag;
6358
6359   register unsigned char c;     /* Current character. */
6360   int t_index;                  /* For calls to string_extract_xxx. */
6361
6362   char twochars[2];
6363
6364   DECLARE_MBSTATE;
6365
6366   istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
6367   istring[istring_index = 0] = '\0';
6368   quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
6369   quoted_state = UNQUOTED;
6370
6371   string = word->word;
6372   if (string == 0)
6373     goto finished_with_string;
6374   string_size = strlen (string);
6375
6376   if (contains_dollar_at)
6377     *contains_dollar_at = 0;
6378
6379   /* Begin the expansion. */
6380
6381   for (sindex = 0; ;)
6382     {
6383       c = string[sindex];
6384
6385       /* Case on toplevel character. */
6386       switch (c)
6387         {
6388         case '\0':
6389           goto finished_with_string;
6390
6391         case CTLESC:
6392           sindex++;
6393 #if HANDLE_MULTIBYTE
6394           if (MB_CUR_MAX > 1 && string[sindex])
6395             {
6396               SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
6397             }
6398           else
6399 #endif
6400             {
6401               temp = (char *)xmalloc (3);
6402               temp[0] = CTLESC;
6403               temp[1] = c = string[sindex];
6404               temp[2] = '\0';
6405             }
6406
6407 dollar_add_string:
6408           if (string[sindex])
6409             sindex++;
6410
6411 add_string:
6412           if (temp)
6413             {
6414               istring = sub_append_string (temp, istring, &istring_index, &istring_size);
6415               temp = (char *)0;
6416             }
6417
6418           break;
6419
6420 #if defined (PROCESS_SUBSTITUTION)
6421           /* Process substitution. */
6422         case '<':
6423         case '>':
6424           {
6425             if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct)
6426               {
6427                 sindex--;       /* add_character: label increments sindex */
6428                 goto add_character;
6429               }
6430             else
6431               t_index = sindex + 1; /* skip past both '<' and LPAREN */
6432
6433             temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/
6434             sindex = t_index;
6435
6436             /* If the process substitution specification is `<()', we want to
6437                open the pipe for writing in the child and produce output; if
6438                it is `>()', we want to open the pipe for reading in the child
6439                and consume input. */
6440             temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
6441
6442             FREE (temp1);
6443
6444             goto dollar_add_string;
6445           }
6446 #endif /* PROCESS_SUBSTITUTION */
6447
6448         case '$':
6449           if (expanded_something)
6450             *expanded_something = 1;
6451
6452           has_dollar_at = 0;
6453           temp = param_expand (string, &sindex, quoted, expanded_something,
6454                                &has_dollar_at, &quoted_dollar_at,
6455                                &had_quoted_null,
6456                                (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0);
6457
6458           if (temp == &expand_param_error || temp == &expand_param_fatal)
6459             {
6460               free (string);
6461               free (istring);
6462               return ((temp == &expand_param_error) ? &expand_word_error
6463                                                     : &expand_word_fatal);
6464             }
6465           if (contains_dollar_at && has_dollar_at)
6466             *contains_dollar_at = 1;
6467           goto add_string;
6468           break;
6469
6470         case '`':               /* Backquoted command substitution. */
6471           {
6472             t_index = sindex++;
6473
6474             if (expanded_something)
6475               *expanded_something = 1;
6476
6477             temp = string_extract (string, &sindex, "`", 0);
6478             if (word->flags & W_NOCOMSUB)
6479               /* sindex + 1 because string[sindex] == '`' */
6480               temp1 = substring (string, t_index, sindex + 1);
6481             else
6482               {
6483                 de_backslash (temp);
6484                 temp1 = command_substitute (temp, quoted);
6485               }
6486             FREE (temp);
6487             temp = temp1;
6488             goto dollar_add_string;
6489           }
6490
6491         case '\\':
6492           if (string[sindex + 1] == '\n')
6493             {
6494               sindex += 2;
6495               continue;
6496             }
6497
6498           c = string[++sindex];
6499
6500           if (quoted & Q_HERE_DOCUMENT)
6501             tflag = CBSHDOC;
6502           else if (quoted & Q_DOUBLE_QUOTES)
6503             tflag = CBSDQUOTE;
6504           else
6505             tflag = 0;
6506
6507           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
6508             {
6509               SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
6510             }
6511           else if (c == 0)
6512             {
6513               c = CTLNUL;
6514               sindex--;         /* add_character: label increments sindex */
6515               goto add_character;
6516             }
6517           else
6518             {
6519               SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
6520             }
6521
6522           sindex++;
6523 add_twochars:
6524           /* BEFORE jumping here, we need to increment sindex if appropriate */
6525           RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
6526                                   DEFAULT_ARRAY_SIZE);
6527           istring[istring_index++] = twochars[0];
6528           istring[istring_index++] = twochars[1];
6529           istring[istring_index] = '\0';
6530
6531           break;
6532
6533         case '"':
6534 #if 0
6535           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE))
6536 #else
6537           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6538 #endif
6539             goto add_character;
6540
6541           t_index = ++sindex;
6542           temp = string_extract_double_quoted (string, &sindex, 0);
6543
6544           /* If the quotes surrounded the entire string, then the
6545              whole word was quoted. */
6546           quoted_state = (t_index == 1 && string[sindex] == '\0')
6547                             ? WHOLLY_QUOTED
6548                             : PARTIALLY_QUOTED;
6549
6550           if (temp && *temp)
6551             {
6552               tword = make_word (temp);         /* XXX */
6553               free (temp);
6554               temp = (char *)NULL;
6555
6556               has_dollar_at = 0;
6557               list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL);
6558
6559               if (list == &expand_word_error || list == &expand_word_fatal)
6560                 {
6561                   free (istring);
6562                   free (string);
6563                   /* expand_word_internal has already freed temp_word->word
6564                      for us because of the way it prints error messages. */
6565                   tword->word = (char *)NULL;
6566                   dispose_word (tword);
6567                   return list;
6568                 }
6569
6570               dispose_word (tword);
6571
6572               /* "$@" (a double-quoted dollar-at) expands into nothing,
6573                  not even a NULL word, when there are no positional
6574                  parameters. */
6575               if (list == 0 && has_dollar_at)
6576                 {
6577                   quoted_dollar_at++;
6578                   break;
6579                 }
6580
6581               /* If we get "$@", we know we have expanded something, so we
6582                  need to remember it for the final split on $IFS.  This is
6583                  a special case; it's the only case where a quoted string
6584                  can expand into more than one word.  It's going to come back
6585                  from the above call to expand_word_internal as a list with
6586                  a single word, in which all characters are quoted and
6587                  separated by blanks.  What we want to do is to turn it back
6588                  into a list for the next piece of code. */
6589               if (list)
6590                 dequote_list (list);
6591
6592               if (has_dollar_at)
6593                 {
6594                   quoted_dollar_at++;
6595                   if (contains_dollar_at)
6596                     *contains_dollar_at = 1;
6597                   if (expanded_something)
6598                     *expanded_something = 1;
6599                 }
6600             }
6601           else
6602             {
6603               /* What we have is "".  This is a minor optimization. */
6604               FREE (temp);
6605               list = (WORD_LIST *)NULL;
6606             }
6607
6608           /* The code above *might* return a list (consider the case of "$@",
6609              where it returns "$1", "$2", etc.).  We can't throw away the
6610              rest of the list, and we have to make sure each word gets added
6611              as quoted.  We test on tresult->next:  if it is non-NULL, we
6612              quote the whole list, save it to a string with string_list, and
6613              add that string. We don't need to quote the results of this
6614              (and it would be wrong, since that would quote the separators
6615              as well), so we go directly to add_string. */
6616           if (list)
6617             {
6618               if (list->next)
6619                 {
6620                   /* Testing quoted_dollar_at makes sure that "$@" is
6621                      split correctly when $IFS does not contain a space. */
6622                   temp = quoted_dollar_at
6623                                 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES)
6624                                 : string_list (quote_list (list));
6625                   dispose_words (list);
6626                   goto add_string;
6627                 }
6628               else
6629                 {
6630                   temp = savestring (list->word->word);
6631                   dispose_words (list);
6632 #if 1
6633                   /* If the string is not a quoted null string, we want
6634                      to remove any embedded unquoted CTLNUL characters.
6635                      We do not want to turn quoted null strings back into
6636                      the empty string, though.  We do this because we
6637                      want to remove any quoted nulls from expansions that
6638                      contain other characters.  For example, if we have
6639                      x"$*"y or "x$*y" and there are no positional parameters,
6640                      the $* should expand into nothing. */
6641                   /* HOWEVER, this fails if the string contains a literal
6642                      CTLNUL or CTLNUL is contained in the (non-null) expansion
6643                      of some variable.  I'm not sure what to do about this
6644                      yet.  There has to be some way to indicate the difference
6645                      between the two.  An auxiliary data structure might be
6646                      necessary. */
6647                   if (QUOTED_NULL (temp) == 0)
6648                     remove_quoted_nulls (temp); /* XXX */
6649 #endif
6650                 }
6651             }
6652           else
6653             temp = (char *)NULL;
6654
6655           /* We do not want to add quoted nulls to strings that are only
6656              partially quoted; we can throw them away. */
6657           if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
6658             continue;
6659
6660         add_quoted_string:
6661
6662           if (temp)
6663             {
6664               temp1 = temp;
6665               temp = quote_string (temp);
6666               free (temp1);
6667               goto add_string;
6668             }
6669           else
6670             {
6671               /* Add NULL arg. */
6672               c = CTLNUL;
6673               sindex--;         /* add_character: label increments sindex */
6674               goto add_character;
6675             }
6676
6677           /* break; */
6678
6679         case '\'':
6680 #if 0
6681           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_PATQUOTE))
6682 #else
6683           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6684 #endif
6685             goto add_character;
6686
6687           t_index = ++sindex;
6688           temp = string_extract_single_quoted (string, &sindex);
6689
6690           /* If the entire STRING was surrounded by single quotes,
6691              then the string is wholly quoted. */
6692           quoted_state = (t_index == 1 && string[sindex] == '\0')
6693                             ? WHOLLY_QUOTED
6694                             : PARTIALLY_QUOTED;
6695
6696           /* If all we had was '', it is a null expansion. */
6697           if (*temp == '\0')
6698             {
6699               free (temp);
6700               temp = (char *)NULL;
6701             }
6702           else
6703             remove_quoted_escapes (temp);       /* ??? */
6704
6705           /* We do not want to add quoted nulls to strings that are only
6706              partially quoted; such nulls are discarded. */
6707           if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
6708             continue;
6709
6710           /* If we have a quoted null expansion, add a quoted NULL to istring. */
6711           if (temp == 0)
6712             {
6713               c = CTLNUL;
6714               sindex--;         /* add_character: label increments sindex */
6715               goto add_character;
6716             }
6717           else
6718             goto add_quoted_string;
6719
6720           /* break; */
6721
6722         default:
6723           /* This is the fix for " $@ " */
6724           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c)))
6725             {
6726               if (string[sindex])       /* from old goto dollar_add_string */
6727                 sindex++;
6728               if (c == 0)
6729                 {
6730                   c = CTLNUL;
6731                   goto add_character;
6732                 }
6733               else
6734                 {
6735 #if HANDLE_MULTIBYTE
6736                   if (MB_CUR_MAX > 1)
6737                     sindex--;
6738
6739                   if (MB_CUR_MAX > 1)
6740                     {
6741                       SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
6742                     }
6743                   else
6744 #endif
6745                     {
6746                       twochars[0] = CTLESC;
6747                       twochars[1] = c;
6748                       goto add_twochars;
6749                     }
6750                 }
6751             }
6752
6753           SADD_MBCHAR (temp, string, sindex, string_size);
6754
6755         add_character:
6756           RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
6757                                   DEFAULT_ARRAY_SIZE);
6758           istring[istring_index++] = c;
6759           istring[istring_index] = '\0';
6760
6761           /* Next character. */
6762           sindex++;
6763         }
6764     }
6765
6766 finished_with_string:
6767   /* OK, we're ready to return.  If we have a quoted string, and
6768      quoted_dollar_at is not set, we do no splitting at all; otherwise
6769      we split on ' '.  The routines that call this will handle what to
6770      do if nothing has been expanded. */
6771
6772   /* Partially and wholly quoted strings which expand to the empty
6773      string are retained as an empty arguments.  Unquoted strings
6774      which expand to the empty string are discarded.  The single
6775      exception is the case of expanding "$@" when there are no
6776      positional parameters.  In that case, we discard the expansion. */
6777
6778   /* Because of how the code that handles "" and '' in partially
6779      quoted strings works, we need to make ISTRING into a QUOTED_NULL
6780      if we saw quoting characters, but the expansion was empty.
6781      "" and '' are tossed away before we get to this point when
6782      processing partially quoted strings.  This makes "" and $xxx""
6783      equivalent when xxx is unset.  We also look to see whether we
6784      saw a quoted null from a ${} expansion and add one back if we
6785      need to. */
6786
6787   /* If we expand to nothing and there were no single or double quotes
6788      in the word, we throw it away.  Otherwise, we return a NULL word.
6789      The single exception is for $@ surrounded by double quotes when
6790      there are no positional parameters.  In that case, we also throw
6791      the word away. */
6792
6793   if (*istring == '\0')
6794     {
6795       if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
6796         {
6797           istring[0] = CTLNUL;
6798           istring[1] = '\0';
6799           tword = make_bare_word (istring);
6800           list = make_word_list (tword, (WORD_LIST *)NULL);
6801           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6802             tword->flags |= W_QUOTED;
6803         }
6804       /* According to sh, ksh, and Posix.2, if a word expands into nothing
6805          and a double-quoted "$@" appears anywhere in it, then the entire
6806          word is removed. */
6807       else  if (quoted_state == UNQUOTED || quoted_dollar_at)
6808         list = (WORD_LIST *)NULL;
6809 #if 0
6810       else
6811         {
6812           tword = make_bare_word (istring);
6813           list = make_word_list (tword, (WORD_LIST *)NULL);
6814           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6815             tword->flags |= W_QUOTED;
6816         }
6817 #else
6818       else
6819         list = (WORD_LIST *)NULL;
6820 #endif
6821     }
6822   else if (word->flags & W_NOSPLIT)
6823     {
6824       tword = make_bare_word (istring);
6825       list = make_word_list (tword, (WORD_LIST *)NULL);
6826       if (word->flags & W_ASSIGNMENT)
6827         tword->flags |= W_ASSIGNMENT;   /* XXX */
6828       if (word->flags & W_NOGLOB)
6829         tword->flags |= W_NOGLOB;       /* XXX */
6830       if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6831         tword->flags |= W_QUOTED;
6832     }
6833   else
6834     {
6835       char *ifs_chars;
6836
6837       ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
6838
6839       /* If we have $@, we need to split the results no matter what.  If
6840          IFS is unset or NULL, string_list_dollar_at has separated the
6841          positional parameters with a space, so we split on space (we have
6842          set ifs_chars to " \t\n" above if ifs is unset).  If IFS is set,
6843          string_list_dollar_at has separated the positional parameters
6844          with the first character of $IFS, so we split on $IFS. */
6845       if (has_dollar_at && ifs_chars)
6846         list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
6847       else
6848         {
6849           tword = make_bare_word (istring);
6850           list = make_word_list (tword, (WORD_LIST *)NULL);
6851           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
6852             tword->flags |= W_QUOTED;
6853           if (word->flags & W_ASSIGNMENT)
6854             tword->flags |= W_ASSIGNMENT;
6855           if (word->flags & W_NOGLOB)
6856             tword->flags |= W_NOGLOB;
6857         }
6858     }
6859
6860   free (istring);
6861   return (list);
6862 }
6863
6864 /* **************************************************************** */
6865 /*                                                                  */
6866 /*                 Functions for Quote Removal                      */
6867 /*                                                                  */
6868 /* **************************************************************** */
6869
6870 /* Perform quote removal on STRING.  If QUOTED > 0, assume we are obeying the
6871    backslash quoting rules for within double quotes or a here document. */
6872 char *
6873 string_quote_removal (string, quoted)
6874      char *string;
6875      int quoted;
6876 {
6877   size_t slen;
6878   char *r, *result_string, *temp, *send;
6879   int sindex, tindex, dquote;
6880   unsigned char c;
6881   DECLARE_MBSTATE;
6882
6883   /* The result can be no longer than the original string. */
6884   slen = strlen (string);
6885   send = string + slen;
6886
6887   r = result_string = (char *)xmalloc (slen + 1);
6888
6889   for (dquote = sindex = 0; c = string[sindex];)
6890     {
6891       switch (c)
6892         {
6893         case '\\':
6894           c = string[++sindex];
6895           if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
6896             *r++ = '\\';
6897           /* FALLTHROUGH */
6898
6899         default:
6900           SCOPY_CHAR_M (r, string, send, sindex);
6901           break;
6902
6903         case '\'':
6904           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
6905             {
6906               *r++ = c;
6907               sindex++;
6908               break;
6909             }
6910           tindex = sindex + 1;
6911           temp = string_extract_single_quoted (string, &tindex);
6912           if (temp)
6913             {
6914               strcpy (r, temp);
6915               r += strlen (r);
6916               free (temp);
6917             }
6918           sindex = tindex;
6919           break;
6920
6921         case '"':
6922           dquote = 1 - dquote;
6923           sindex++;
6924           break;
6925         }
6926     }
6927     *r = '\0';
6928     return (result_string);
6929 }
6930
6931 #if 0
6932 /* UNUSED */
6933 /* Perform quote removal on word WORD.  This allocates and returns a new
6934    WORD_DESC *. */
6935 WORD_DESC *
6936 word_quote_removal (word, quoted)
6937      WORD_DESC *word;
6938      int quoted;
6939 {
6940   WORD_DESC *w;
6941   char *t;
6942
6943   t = string_quote_removal (word->word, quoted);
6944   w = make_bare_word (t);
6945   free (t);
6946   return (w);
6947 }
6948
6949 /* Perform quote removal on all words in LIST.  If QUOTED is non-zero,
6950    the members of the list are treated as if they are surrounded by
6951    double quotes.  Return a new list, or NULL if LIST is NULL. */
6952 WORD_LIST *
6953 word_list_quote_removal (list, quoted)
6954      WORD_LIST *list;
6955      int quoted;
6956 {
6957   WORD_LIST *result, *t, *tresult;
6958
6959   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
6960     {
6961       tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
6962       result = (WORD_LIST *) list_append (result, tresult);
6963     }
6964   return (result);
6965 }
6966 #endif
6967
6968 /*******************************************
6969  *                                         *
6970  *    Functions to perform word splitting  *
6971  *                                         *
6972  *******************************************/
6973
6974 void
6975 setifs (v)
6976      SHELL_VAR *v;
6977 {
6978   char *t;
6979   unsigned char uc;
6980
6981   ifs_var = v;
6982   ifs_value = v ? value_cell (v) : " \t\n";
6983
6984   /* Should really merge ifs_cmap with sh_syntaxtab.  XXX - doesn't yet
6985      handle multibyte chars in IFS */
6986   memset (ifs_cmap, '\0', sizeof (ifs_cmap));
6987   for (t = ifs_value ; t && *t; t++)
6988     {
6989       uc = *t;
6990       ifs_cmap[uc] = 1;
6991     }
6992
6993 #if defined (HANDLE_MULTIBYTE)
6994   if (ifs_value == 0)
6995     {
6996       ifs_firstc[0] = '\0';
6997       ifs_firstc_len = 1;
6998     }
6999   else
7000     {
7001       size_t ifs_len;
7002       ifs_len = strnlen (ifs_value, MB_CUR_MAX);
7003       ifs_firstc_len = MBLEN (ifs_value, ifs_len);
7004       if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
7005         {
7006           ifs_firstc[0] = ifs_value[0];
7007           ifs_firstc[1] = '\0';
7008           ifs_firstc_len = 1;
7009         }
7010       else
7011         memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
7012     }
7013 #else
7014   ifs_firstc = ifs_value ? *ifs_value : 0;
7015 #endif
7016 }
7017
7018 char *
7019 getifs ()
7020 {
7021   return ifs_value;
7022 }
7023
7024 /* This splits a single word into a WORD LIST on $IFS, but only if the word
7025    is not quoted.  list_string () performs quote removal for us, even if we
7026    don't do any splitting. */
7027 WORD_LIST *
7028 word_split (w, ifs_chars)
7029      WORD_DESC *w;
7030      char *ifs_chars;
7031 {
7032   WORD_LIST *result;
7033
7034   if (w)
7035     {
7036       char *xifs;
7037
7038       xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
7039       result = list_string (w->word, xifs, w->flags & W_QUOTED);
7040     }
7041   else
7042     result = (WORD_LIST *)NULL;
7043
7044   return (result);
7045 }
7046
7047 /* Perform word splitting on LIST and return the RESULT.  It is possible
7048    to return (WORD_LIST *)NULL. */
7049 static WORD_LIST *
7050 word_list_split (list)
7051      WORD_LIST *list;
7052 {
7053   WORD_LIST *result, *t, *tresult, *e;
7054
7055   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
7056     {
7057       tresult = word_split (t->word, ifs_value);
7058 #if 0
7059       result = (WORD_LIST *) list_append (result, tresult);
7060 #else
7061       if (result == 0)
7062         result = e = tresult;
7063       else
7064         {
7065           e->next = tresult;
7066           while (e->next)
7067             e = e->next;
7068         }
7069 #endif
7070     }
7071   return (result);
7072 }
7073
7074 /**************************************************
7075  *                                                *
7076  *    Functions to expand an entire WORD_LIST     *
7077  *                                                *
7078  **************************************************/
7079
7080 /* Do any word-expansion-specific cleanup and jump to top_level */
7081 static void
7082 exp_jump_to_top_level (v)
7083      int v;
7084 {
7085   /* Cleanup code goes here. */
7086   expand_no_split_dollar_star = 0;      /* XXX */
7087   expanding_redir = 0;
7088
7089   jump_to_top_level (v);
7090 }
7091
7092 /* Put NLIST (which is a WORD_LIST * of only one element) at the front of
7093    ELIST, and set ELIST to the new list. */
7094 #define PREPEND_LIST(nlist, elist) \
7095         do { nlist->next = elist; elist = nlist; } while (0)
7096
7097 /* Separate out any initial variable assignments from TLIST.  If set -k has
7098    been executed, remove all assignment statements from TLIST.  Initial
7099    variable assignments and other environment assignments are placed
7100    on SUBST_ASSIGN_VARLIST. */
7101 static WORD_LIST *
7102 separate_out_assignments (tlist)
7103      WORD_LIST *tlist;
7104 {
7105   register WORD_LIST *vp, *lp;
7106
7107   if (!tlist)
7108     return ((WORD_LIST *)NULL);
7109
7110   if (subst_assign_varlist)
7111     dispose_words (subst_assign_varlist);       /* Clean up after previous error */
7112
7113   subst_assign_varlist = (WORD_LIST *)NULL;
7114   vp = lp = tlist;
7115
7116   /* Separate out variable assignments at the start of the command.
7117      Loop invariant: vp->next == lp
7118      Loop postcondition:
7119         lp = list of words left after assignment statements skipped
7120         tlist = original list of words
7121   */
7122   while (lp && (lp->word->flags & W_ASSIGNMENT))
7123     {
7124       vp = lp;
7125       lp = lp->next;
7126     }
7127
7128   /* If lp != tlist, we have some initial assignment statements.
7129      We make SUBST_ASSIGN_VARLIST point to the list of assignment
7130      words and TLIST point to the remaining words.  */
7131   if (lp != tlist)
7132     {
7133       subst_assign_varlist = tlist;
7134       /* ASSERT(vp->next == lp); */
7135       vp->next = (WORD_LIST *)NULL;     /* terminate variable list */
7136       tlist = lp;                       /* remainder of word list */
7137     }
7138
7139   /* vp == end of variable list */
7140   /* tlist == remainder of original word list without variable assignments */
7141   if (!tlist)
7142     /* All the words in tlist were assignment statements */
7143     return ((WORD_LIST *)NULL);
7144
7145   /* ASSERT(tlist != NULL); */
7146   /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
7147
7148   /* If the -k option is in effect, we need to go through the remaining
7149      words, separate out the assignment words, and place them on
7150      SUBST_ASSIGN_VARLIST. */
7151   if (place_keywords_in_env)
7152     {
7153       WORD_LIST *tp;    /* tp == running pointer into tlist */
7154
7155       tp = tlist;
7156       lp = tlist->next;
7157
7158       /* Loop Invariant: tp->next == lp */
7159       /* Loop postcondition: tlist == word list without assignment statements */
7160       while (lp)
7161         {
7162           if (lp->word->flags & W_ASSIGNMENT)
7163             {
7164               /* Found an assignment statement, add this word to end of
7165                  subst_assign_varlist (vp). */
7166               if (!subst_assign_varlist)
7167                 subst_assign_varlist = vp = lp;
7168               else
7169                 {
7170                   vp->next = lp;
7171                   vp = lp;
7172                 }
7173
7174               /* Remove the word pointed to by LP from TLIST. */
7175               tp->next = lp->next;
7176               /* ASSERT(vp == lp); */
7177               lp->next = (WORD_LIST *)NULL;
7178               lp = tp->next;
7179             }
7180           else
7181             {
7182               tp = lp;
7183               lp = lp->next;
7184             }
7185         }
7186     }
7187   return (tlist);
7188 }
7189
7190 #define WEXP_VARASSIGN  0x001
7191 #define WEXP_BRACEEXP   0x002
7192 #define WEXP_TILDEEXP   0x004
7193 #define WEXP_PARAMEXP   0x008
7194 #define WEXP_PATHEXP    0x010
7195
7196 /* All of the expansions, including variable assignments at the start of
7197    the list. */
7198 #define WEXP_ALL        (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
7199
7200 /* All of the expansions except variable assignments at the start of
7201    the list. */
7202 #define WEXP_NOVARS     (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
7203
7204 /* All of the `shell expansions': brace expansion, tilde expansion, parameter
7205    expansion, command substitution, arithmetic expansion, word splitting, and
7206    quote removal. */
7207 #define WEXP_SHELLEXP   (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
7208
7209 /* Take the list of words in LIST and do the various substitutions.  Return
7210    a new list of words which is the expanded list, and without things like
7211    variable assignments. */
7212
7213 WORD_LIST *
7214 expand_words (list)
7215      WORD_LIST *list;
7216 {
7217   return (expand_word_list_internal (list, WEXP_ALL));
7218 }
7219
7220 /* Same as expand_words (), but doesn't hack variable or environment
7221    variables. */
7222 WORD_LIST *
7223 expand_words_no_vars (list)
7224      WORD_LIST *list;
7225 {
7226   return (expand_word_list_internal (list, WEXP_NOVARS));
7227 }
7228
7229 WORD_LIST *
7230 expand_words_shellexp (list)
7231      WORD_LIST *list;
7232 {
7233   return (expand_word_list_internal (list, WEXP_SHELLEXP));
7234 }
7235
7236 static WORD_LIST *
7237 glob_expand_word_list (tlist, eflags)
7238      WORD_LIST *tlist;
7239      int eflags;
7240 {
7241   char **glob_array, *temp_string;
7242   register int glob_index;
7243   WORD_LIST *glob_list, *output_list, *disposables, *next;
7244   WORD_DESC *tword;
7245
7246   output_list = disposables = (WORD_LIST *)NULL;
7247   glob_array = (char **)NULL;
7248   while (tlist)
7249     {
7250       /* For each word, either globbing is attempted or the word is
7251          added to orig_list.  If globbing succeeds, the results are
7252          added to orig_list and the word (tlist) is added to the list
7253          of disposable words.  If globbing fails and failed glob
7254          expansions are left unchanged (the shell default), the
7255          original word is added to orig_list.  If globbing fails and
7256          failed glob expansions are removed, the original word is
7257          added to the list of disposable words.  orig_list ends up
7258          in reverse order and requires a call to REVERSE_LIST to
7259          be set right.  After all words are examined, the disposable
7260          words are freed. */
7261       next = tlist->next;
7262
7263       /* If the word isn't an assignment and contains an unquoted
7264          pattern matching character, then glob it. */
7265       if ((tlist->word->flags & W_NOGLOB) == 0 &&
7266           unquoted_glob_pattern_p (tlist->word->word))
7267         {
7268           glob_array = shell_glob_filename (tlist->word->word);
7269
7270           /* Handle error cases.
7271              I don't think we should report errors like "No such file
7272              or directory".  However, I would like to report errors
7273              like "Read failed". */
7274
7275           if (glob_array == 0 || GLOB_FAILED (glob_array))
7276             {
7277               glob_array = (char **)xmalloc (sizeof (char *));
7278               glob_array[0] = (char *)NULL;
7279             }
7280
7281           /* Dequote the current word in case we have to use it. */
7282           if (glob_array[0] == NULL)
7283             {
7284               temp_string = dequote_string (tlist->word->word);
7285               free (tlist->word->word);
7286               tlist->word->word = temp_string;
7287             }
7288
7289           /* Make the array into a word list. */
7290           glob_list = (WORD_LIST *)NULL;
7291           for (glob_index = 0; glob_array[glob_index]; glob_index++)
7292             {
7293               tword = make_bare_word (glob_array[glob_index]);
7294               tword->flags |= W_GLOBEXP;        /* XXX */
7295               glob_list = make_word_list (tword, glob_list);
7296             }
7297
7298           if (glob_list)
7299             {
7300               output_list = (WORD_LIST *)list_append (glob_list, output_list);
7301               PREPEND_LIST (tlist, disposables);
7302             }
7303           else if (fail_glob_expansion != 0)
7304             {
7305               report_error (_("no match: %s"), tlist->word->word);
7306               jump_to_top_level (DISCARD);
7307             }
7308           else if (allow_null_glob_expansion == 0)
7309             {
7310               /* Failed glob expressions are left unchanged. */
7311               PREPEND_LIST (tlist, output_list);
7312             }
7313           else
7314             {
7315               /* Failed glob expressions are removed. */
7316               PREPEND_LIST (tlist, disposables);
7317             }
7318         }
7319       else
7320         {
7321           /* Dequote the string. */
7322           temp_string = dequote_string (tlist->word->word);
7323           free (tlist->word->word);
7324           tlist->word->word = temp_string;
7325           PREPEND_LIST (tlist, output_list);
7326         }
7327
7328       strvec_dispose (glob_array);
7329       glob_array = (char **)NULL;
7330
7331       tlist = next;
7332     }
7333
7334   if (disposables)
7335     dispose_words (disposables);
7336
7337   if (output_list)
7338     output_list = REVERSE_LIST (output_list, WORD_LIST *);
7339
7340   return (output_list);
7341 }
7342
7343 #if defined (BRACE_EXPANSION)
7344 static WORD_LIST *
7345 brace_expand_word_list (tlist, eflags)
7346      WORD_LIST *tlist;
7347      int eflags;
7348 {
7349   register char **expansions;
7350   char *temp_string;
7351   WORD_LIST *disposables, *output_list, *next;
7352   WORD_DESC *w;
7353   int eindex;
7354
7355   for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
7356     {
7357       next = tlist->next;
7358
7359       /* Only do brace expansion if the word has a brace character.  If
7360          not, just add the word list element to BRACES and continue.  In
7361          the common case, at least when running shell scripts, this will
7362          degenerate to a bunch of calls to `xstrchr', and then what is
7363          basically a reversal of TLIST into BRACES, which is corrected
7364          by a call to REVERSE_LIST () on BRACES when the end of TLIST
7365          is reached. */
7366       if (xstrchr (tlist->word->word, LBRACE))
7367         {
7368           expansions = brace_expand (tlist->word->word);
7369
7370           for (eindex = 0; temp_string = expansions[eindex]; eindex++)
7371             {
7372               w = make_word (temp_string);
7373               /* If brace expansion didn't change the word, preserve
7374                  the flags.  We may want to preserve the flags
7375                  unconditionally someday -- XXX */
7376               if (STREQ (temp_string, tlist->word->word))
7377                 w->flags = tlist->word->flags;
7378               output_list = make_word_list (w, output_list);
7379               free (expansions[eindex]);
7380             }
7381           free (expansions);
7382
7383           /* Add TLIST to the list of words to be freed after brace
7384              expansion has been performed. */
7385           PREPEND_LIST (tlist, disposables);
7386         }
7387       else
7388         PREPEND_LIST (tlist, output_list);
7389     }
7390
7391   if (disposables)
7392     dispose_words (disposables);
7393
7394   if (output_list)
7395     output_list = REVERSE_LIST (output_list, WORD_LIST *);
7396
7397   return (output_list);
7398 }
7399 #endif
7400
7401 static WORD_LIST *
7402 shell_expand_word_list (tlist, eflags)
7403      WORD_LIST *tlist;
7404      int eflags;
7405 {
7406   WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list;
7407   int expanded_something, has_dollar_at;
7408   char *temp_string;
7409
7410   /* We do tilde expansion all the time.  This is what 1003.2 says. */
7411   new_list = (WORD_LIST *)NULL;
7412   for (orig_list = tlist; tlist; tlist = next)
7413     {
7414       temp_string = tlist->word->word;
7415
7416       next = tlist->next;
7417
7418       /* Posix.2 section 3.6.1 says that tildes following `=' in words
7419          which are not assignment statements are not expanded.  If the
7420          shell isn't in posix mode, though, we perform tilde expansion
7421          on `likely candidate' unquoted assignment statements (flags
7422          include W_ASSIGNMENT but not W_QUOTED).  A likely candidate
7423          contains an unquoted :~ or =~.  Something to think about: we
7424          now have a flag that says  to perform tilde expansion on arguments
7425          to `assignment builtins' like declare and export that look like
7426          assignment statements.  We now do tilde expansion on such words
7427          even in POSIX mode. */
7428       if (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) &&
7429              (posixly_correct == 0 || (tlist->word->flags & W_TILDEEXP)) &&
7430              (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string)))
7431         {
7432           tlist->word->word = bash_tilde_expand (temp_string, 1);
7433           free (temp_string);
7434         }
7435       else if (temp_string[0] == '~')
7436         {
7437           tlist->word->word = bash_tilde_expand (temp_string, 0);
7438           free (temp_string);
7439         }
7440
7441       expanded_something = 0;
7442       expanded = expand_word_internal
7443         (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
7444
7445       if (expanded == &expand_word_error || expanded == &expand_word_fatal)
7446         {
7447           /* By convention, each time this error is returned,
7448              tlist->word->word has already been freed. */
7449           tlist->word->word = (char *)NULL;
7450
7451           /* Dispose our copy of the original list. */
7452           dispose_words (orig_list);
7453           /* Dispose the new list we're building. */
7454           dispose_words (new_list);
7455
7456           last_command_exit_value = EXECUTION_FAILURE;
7457           if (expanded == &expand_word_error)
7458             exp_jump_to_top_level (DISCARD);
7459           else
7460             exp_jump_to_top_level (FORCE_EOF);
7461         }
7462
7463       /* Don't split words marked W_NOSPLIT. */
7464       if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
7465         {
7466           temp_list = word_list_split (expanded);
7467           dispose_words (expanded);
7468         }
7469       else
7470         {
7471           /* If no parameter expansion, command substitution, process
7472              substitution, or arithmetic substitution took place, then
7473              do not do word splitting.  We still have to remove quoted
7474              null characters from the result. */
7475           word_list_remove_quoted_nulls (expanded);
7476           temp_list = expanded;
7477         }
7478
7479       expanded = REVERSE_LIST (temp_list, WORD_LIST *);
7480       new_list = (WORD_LIST *)list_append (expanded, new_list);
7481     }
7482
7483   if (orig_list)  
7484     dispose_words (orig_list);
7485
7486   if (new_list)
7487     new_list = REVERSE_LIST (new_list, WORD_LIST *);
7488
7489   return (new_list);
7490 }
7491
7492 /* The workhorse for expand_words () and expand_words_no_vars ().
7493    First arg is LIST, a WORD_LIST of words.
7494    Second arg EFLAGS is a flags word controlling which expansions are
7495    performed.
7496
7497    This does all of the substitutions: brace expansion, tilde expansion,
7498    parameter expansion, command substitution, arithmetic expansion,
7499    process substitution, word splitting, and pathname expansion, according
7500    to the bits set in EFLAGS.  Words with the W_QUOTED or W_NOSPLIT bits
7501    set, or for which no expansion is done, do not undergo word splitting.
7502    Words with the W_NOGLOB bit set do not undergo pathname expansion. */
7503 static WORD_LIST *
7504 expand_word_list_internal (list, eflags)
7505      WORD_LIST *list;
7506      int eflags;
7507 {
7508   WORD_LIST *new_list, *temp_list;
7509   int tint;
7510
7511   if (list == 0)
7512     return ((WORD_LIST *)NULL);
7513
7514   garglist = new_list = copy_word_list (list);
7515   if (eflags & WEXP_VARASSIGN)
7516     {
7517       garglist = new_list = separate_out_assignments (new_list);
7518       if (new_list == 0)
7519         {
7520           if (subst_assign_varlist)
7521             {
7522               /* All the words were variable assignments, so they are placed
7523                  into the shell's environment. */
7524               for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
7525                 {
7526                   this_command_name = (char *)NULL;     /* no arithmetic errors */
7527                   tint = do_assignment (temp_list->word->word);
7528                   /* Variable assignment errors in non-interactive shells
7529                      running in Posix.2 mode cause the shell to exit. */
7530                   if (tint == 0)
7531                     {
7532                       last_command_exit_value = EXECUTION_FAILURE;
7533                       if (interactive_shell == 0 && posixly_correct)
7534                         exp_jump_to_top_level (FORCE_EOF);
7535                       else
7536                         exp_jump_to_top_level (DISCARD);
7537                     }
7538                 }
7539               dispose_words (subst_assign_varlist);
7540               subst_assign_varlist = (WORD_LIST *)NULL;
7541             }
7542           return ((WORD_LIST *)NULL);
7543         }
7544     }
7545
7546   /* Begin expanding the words that remain.  The expansions take place on
7547      things that aren't really variable assignments. */
7548
7549 #if defined (BRACE_EXPANSION)
7550   /* Do brace expansion on this word if there are any brace characters
7551      in the string. */
7552   if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
7553     new_list = brace_expand_word_list (new_list, eflags);
7554 #endif /* BRACE_EXPANSION */
7555
7556   /* Perform the `normal' shell expansions: tilde expansion, parameter and
7557      variable substitution, command substitution, arithmetic expansion,
7558      and word splitting. */
7559   new_list = shell_expand_word_list (new_list, eflags);
7560
7561   /* Okay, we're almost done.  Now let's just do some filename
7562      globbing. */
7563   if (new_list)
7564     {
7565       if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
7566         /* Glob expand the word list unless globbing has been disabled. */
7567         new_list = glob_expand_word_list (new_list, eflags);
7568       else
7569         /* Dequote the words, because we're not performing globbing. */
7570         new_list = dequote_list (new_list);
7571     }
7572
7573   if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
7574     {
7575       sh_assign_func_t *assign_func;
7576
7577       /* If the remainder of the words expand to nothing, Posix.2 requires
7578          that the variable and environment assignments affect the shell's
7579          environment. */
7580       assign_func = new_list ? assign_in_env : do_assignment;
7581       tempenv_assign_error = 0;
7582
7583       for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
7584         {
7585           this_command_name = (char *)NULL;
7586           tint = (*assign_func) (temp_list->word->word);
7587           /* Variable assignment errors in non-interactive shells running
7588              in Posix.2 mode cause the shell to exit. */
7589           if (tint == 0)
7590             {
7591               if (assign_func == do_assignment)
7592                 {
7593                   last_command_exit_value = EXECUTION_FAILURE;
7594                   if (interactive_shell == 0 && posixly_correct)
7595                     exp_jump_to_top_level (FORCE_EOF);
7596                   else
7597                     exp_jump_to_top_level (DISCARD);
7598                 }
7599               else
7600                 tempenv_assign_error++;
7601             }
7602         }
7603
7604       dispose_words (subst_assign_varlist);
7605       subst_assign_varlist = (WORD_LIST *)NULL;
7606     }
7607
7608 #if 0
7609   tint = list_length (new_list) + 1;
7610   RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
7611   for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next)
7612     glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0';
7613   glob_argv_flags[tint] = '\0';
7614 #endif
7615
7616   return (new_list);
7617 }