Imported from ../bash-2.01.tar.gz.
[platform/upstream/bash.git] / subst.c
1 /* subst.c -- The part of the shell that does parameter, command, and
2    globbing substitutions. */
3
4 /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
5
6    This file is part of GNU Bash, the Bourne Again SHell.
7
8    Bash is free software; you can redistribute it and/or modify it under
9    the terms of the GNU General Public License as published by the Free
10    Software Foundation; either version 2, or (at your option) any later
11    version.
12
13    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14    WARRANTY; without even the implied warranty of MERCHANTABILITY or
15    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16    for more details.
17
18    You should have received a copy of the GNU General Public License along
19    with Bash; see the file COPYING.  If not, write to the Free Software
20    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22 #include "config.h"
23
24 #include "bashtypes.h"
25 #include <stdio.h>
26 #include <pwd.h>
27 #include <signal.h>
28 #include <errno.h>
29
30 #if defined (HAVE_UNISTD_H)
31 #  include <unistd.h>
32 #endif
33
34 #include "bashansi.h"
35 #include "posixstat.h"
36
37 #include "shell.h"
38 #include "flags.h"
39 #include "jobs.h"
40 #include "execute_cmd.h"
41 #include "filecntl.h"
42 #include "trap.h"
43 #include "pathexp.h"
44 #include "mailcheck.h"
45
46 #if !defined (HAVE_RESTARTABLE_SYSCALLS)        /* for getc_with_restart */
47 #include "input.h"
48 #endif
49
50 #include "builtins/getopt.h"
51 #include "builtins/common.h"
52
53 #if defined (READLINE)
54 #  include "bashline.h"
55 #  include <readline/readline.h>
56 #else
57 #  include <tilde/tilde.h>
58 #endif
59
60 #if defined (HISTORY)
61 #  include "bashhist.h"
62 #  include <readline/history.h>
63 #endif
64
65 #include <glob/fnmatch.h>
66
67 #if !defined (errno)
68 extern int errno;
69 #endif /* !errno */
70
71 /* The size that strings change by. */
72 #define DEFAULT_INITIAL_ARRAY_SIZE 112
73 #define DEFAULT_ARRAY_SIZE 128
74
75 /* Variable types. */
76 #define VT_VARIABLE     0
77 #define VT_POSPARMS     1
78 #define VT_ARRAYVAR     2
79 #define VT_ARRAYMEMBER  3
80
81 /* Flags for quoted_strchr */
82 #define ST_BACKSL       0x01
83 #define ST_CTLESC       0x02
84
85 /* How to quote character C. */
86 static char *make_quoted_char ();
87
88 /* Process ID of the last command executed within command substitution. */
89 pid_t last_command_subst_pid = NO_PID;
90
91 /* Extern functions and variables from different files. */
92 extern int last_command_exit_value, interactive, interactive_shell;
93 extern int subshell_environment, startup_state;
94 extern int dollar_dollar_pid;
95 extern int posixly_correct;
96 extern int eof_encountered, eof_encountered_limit, ignoreeof;
97 extern char *this_command_name;
98 extern struct fd_bitmap *current_fds_to_close;
99 #if defined (READLINE)
100 extern int no_line_editing;
101 extern int hostname_list_initialized;
102 #endif
103
104 extern void getopts_reset ();
105
106 /* Non-zero means to allow unmatched globbed filenames to expand to
107    a null file. */
108 int allow_null_glob_expansion;
109
110 /* Variables to keep track of which words in an expanded word list (the
111    output of expand_word_list_internal) are the result of globbing
112    expansions.  GLOB_ARGV_FLAGS is used by execute_cmd.c. */
113 char *glob_argv_flags;
114 static int glob_argv_flags_size;
115
116 static WORD_LIST expand_word_error, expand_word_fatal;
117 static char expand_param_error, expand_param_fatal;
118
119 static WORD_LIST *expand_string_internal ();
120 static WORD_LIST *expand_word_internal (), *expand_word_list_internal ();
121 static WORD_LIST *expand_string_leave_quoted ();
122 static WORD_LIST *expand_string_for_rhs ();
123 static WORD_LIST *word_list_split ();
124 static WORD_LIST *quote_list (), *dequote_list ();
125 static int unquoted_substring (), unquoted_member ();
126 static int do_assignment_internal ();
127 static char *string_extract_verbatim (), *string_extract ();
128 static char *string_extract_double_quoted (), *string_extract_single_quoted ();
129 static int skip_single_quoted (), skip_double_quoted ();
130 static char *extract_delimited_string ();
131 static char *extract_dollar_brace_string ();
132
133 /* **************************************************************** */
134 /*                                                                  */
135 /*                      Utility Functions                           */
136 /*                                                                  */
137 /* **************************************************************** */
138
139 /* Cons a new string from STRING starting at START and ending at END,
140    not including END. */
141 char *
142 substring (string, start, end)
143      char *string;
144      int start, end;
145 {
146   register int len;
147   register char *result;
148
149   len = end - start;
150   result = xmalloc (len + 1);
151   strncpy (result, string + start, len);
152   result[len] = '\0';
153   return (result);
154 }
155
156 static char *
157 quoted_substring (string, start, end)
158      char *string;
159      int start, end;
160 {
161   register int len, l;
162   register char *result, *s, *r;
163
164   len = end - start;
165
166   /* Move to string[start], skipping quoted characters. */
167   for (s = string, l = 0; *s && l < start; )
168     {
169       if (*s == CTLESC)
170         {
171           s++;
172           continue;
173         }
174       l++;
175       if (*s == 0)
176         break;
177     }
178
179   r = result = xmalloc (2*len + 1);      /* save room for quotes */
180
181   /* Copy LEN characters, including quote characters. */
182   s = string + l;
183   for (l = 0; l < len; s++)
184     {
185       if (*s == CTLESC)
186         *r++ = *s++;
187       *r++ = *s;
188       l++;
189       if (*s == 0)
190         break;
191     }
192   *r = '\0';
193   return result;
194 }
195
196 /* Find the first occurrence of character C in string S, obeying shell
197    quoting rules.  If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
198    characters are skipped.  If (FLAGS & ST_CTLESC) is non-zero, characters
199    escaped with CTLESC are skipped. */
200 static inline char *
201 quoted_strchr (s, c, flags)
202      char *s;
203      int c, flags;
204 {
205   register char *p;
206
207   for (p = s; *p; p++)
208     {
209       if (((flags & ST_BACKSL) && *p == '\\')
210             || ((flags & ST_CTLESC) && *p == CTLESC))
211         {
212           p++;
213           if (*p == '\0')
214             return ((char *)NULL);
215           continue;
216         }
217       else if (*p == c)
218         return p;
219     }
220   return ((char *)NULL);
221 }
222
223 /* Conventions:
224
225      A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
226      The parser passes CTLNUL as CTLESC CTLNUL. */
227
228 /* The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
229    This is necessary to make unquoted CTLESC and CTLNUL characters in the
230    data stream pass through properly.
231    Here we remove doubled CTLESC characters inside quoted strings before
232    quoting the entire string, so we do not double the number of CTLESC
233    characters. */
234 static char *
235 remove_quoted_escapes (string)
236      char *string;
237 {
238   register char *s;
239   int docopy;
240   char *t, *t1;
241
242   if (string == NULL)
243     return (string);
244
245   t1 = t = xmalloc (strlen (string) + 1);
246   for (docopy = 0, s = string; *s; s++, t1++)
247     {
248       if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL))
249         {
250           s++;
251           docopy = 1;
252         }
253       *t1 = *s;
254     }
255   *t1 = '\0';
256   if (docopy)
257     strcpy (string, t);
258   free (t);
259   return (string);
260 }
261
262 /* Quote escape characters in string s, but no other characters.  This is
263    used to protect CTLESC and CTLNUL in variable values from the rest of
264    the word expansion process after the variable is expanded. */
265 static char *
266 quote_escapes (string)
267      char *string;
268 {
269   register char *s, *t;
270   char *result;
271
272   result = xmalloc ((strlen (string) * 2) + 1);
273   for (s = string, t = result; *s; )
274     {
275       if (*s == CTLESC || *s == CTLNUL)
276         *t++ = CTLESC;
277       *t++ = *s++;
278     }
279   *t = '\0';
280   return (result);
281 }
282
283 #ifdef INCLUDE_UNUSED
284 static char *
285 dequote_escapes (string)
286      char *string;
287 {
288   register char *s, *t;
289   char *result;
290
291   result = xmalloc (strlen (string) + 1);
292   for (s = string, t = result; *s; )
293     {
294       if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL))
295         {
296           s++;
297           if (*s == '\0')
298             break;
299         }
300       *t++ = *s++;
301     }
302   *t = '\0';
303   return result;
304 }
305 #endif
306
307 /* Extract a substring from STRING, starting at SINDEX and ending with
308    one of the characters in CHARLIST.  Don't make the ending character
309    part of the string.  Leave SINDEX pointing at the ending character.
310    Understand about backslashes in the string.  If VARNAME is non-zero,
311    and array variables have been compiled into the shell, everything
312    between a `[' and a corresponding `]' is skipped over. */
313 static char *
314 string_extract (string, sindex, charlist, varname)
315      char *string, *charlist;
316      int *sindex, varname;
317 {
318   register int c, i;
319   char *temp;
320
321   for (i = *sindex; c = string[i]; i++)
322     {
323       if (c == '\\')
324         if (string[i + 1])
325           i++;
326         else
327           break;
328 #if defined (ARRAY_VARS)
329       else if (varname && c == '[')
330         {
331           int ni;
332           /* If this is an array subscript, skip over it and continue. */
333           ni = skipsubscript (string, i);
334           if (string[ni] == ']')
335             i = ni;
336         }
337 #endif
338       else if (MEMBER (c, charlist))
339           break;
340     }
341   c = i - *sindex;
342   temp = xmalloc (1 + c);
343   strncpy (temp, string + *sindex, c);
344   temp[c] = '\0';
345   *sindex = i;
346   return (temp);
347 }
348
349 /* Extract the contents of STRING as if it is enclosed in double quotes.
350    SINDEX, when passed in, is the offset of the character immediately
351    following the opening double quote; on exit, SINDEX is left pointing after
352    the closing double quote.  If STRIPDQ is non-zero, unquoted double
353    quotes are stripped and the string is terminated by a null byte.
354    Backslashes between the embedded double quotes are processed.  If STRIPDQ
355    is zero, an unquoted `"' terminates the string. */
356 static inline char *
357 string_extract_double_quoted (string, sindex, stripdq)
358      char *string;
359      int *sindex, stripdq;
360 {
361   int c, j, i, t;
362   char *temp, *ret;             /* The new string we return. */
363   int pass_next, backquote, si; /* State variables for the machine. */
364   int dquote;
365
366   pass_next = backquote = dquote = 0;
367   temp = xmalloc (1 + strlen (string) - *sindex);
368
369   for (j = 0, i = *sindex; c = string[i]; i++)
370     {
371       /* Process a character that was quoted by a backslash. */
372       if (pass_next)
373         {
374           /* Posix.2 sez:
375
376              ``The backslash shall retain its special meaning as an escape
377              character only when followed by one of the characters:
378                 $       `       "       \       <newline>''.
379
380              If STRIPDQ is zero, we handle the double quotes here and let
381              expand_word_internal handle the rest.  If STRIPDQ is non-zero,
382              we have already been through one round of backslash stripping,
383              and want to strip these backslashes only if DQUOTE is non-zero,
384              indicating that we are inside an embedded double-quoted string. */
385
386              /* If we are in an embedded quoted string, then don't strip
387                 backslashes before characters for which the backslash
388                 retains its special meaning, but remove backslashes in
389                 front of other characters.  If we are not in an
390                 embedded quoted string, don't strip backslashes at all.
391                 This mess is necessary because the string was already
392                 surrounded by double quotes (and sh has some really weird
393                 quoting rules).
394                 The returned string will be run through expansion as if
395                 it were double-quoted. */
396           if ((stripdq == 0 && c != '"') ||
397               (stripdq && ((dquote && strchr (slashify_in_quotes, c)) || dquote == 0)))
398             temp[j++] = '\\';
399           temp[j++] = c;
400           pass_next = 0;
401           continue;
402         }
403
404       /* A backslash protects the next character.  The code just above
405          handles preserving the backslash in front of any character but
406          a double quote. */
407       if (c == '\\')
408         {
409           pass_next++;
410           continue;
411         }
412
413       /* Inside backquotes, ``the portion of the quoted string from the
414          initial backquote and the characters up to the next backquote
415          that is not preceded by a backslash, having escape characters
416          removed, defines that command''. */
417       if (backquote)
418         {
419           if (c == '`')
420             backquote = 0;
421           temp[j++] = c;
422           continue;
423         }
424
425       if (c == '`')
426         {
427           temp[j++] = c;
428           backquote++;
429           continue;
430         }
431
432       /* Pass everything between `$(' and the matching `)' or a quoted
433          ${ ... } pair through according to the Posix.2 specification. */
434       if (c == '$' && ((string[i + 1] == '(') || (string[i + 1] == '{')))
435         {
436           si = i + 2;
437           if (string[i + 1] == '(')
438             ret = extract_delimited_string (string, &si, "$(", "(", ")");
439           else
440             ret = extract_dollar_brace_string (string, &si, 1);
441
442           temp[j++] = '$';
443           temp[j++] = string[i + 1];
444
445           for (t = 0; ret[t]; t++, j++)
446             temp[j] = ret[t];
447           temp[j++] = string[si];
448
449           i = si;
450           free (ret);
451           continue;
452         }
453
454       /* Add any character but a double quote to the quoted string we're
455          accumulating. */
456       if (c != '"')
457         {
458           temp[j++] = c;
459           continue;
460         }
461
462       /* c == '"' */
463       if (stripdq)
464         {
465           dquote ^= 1;
466           continue;
467         }
468
469       break;
470     }
471   temp[j] = '\0';
472
473   /* Point to after the closing quote. */
474   if (c)
475     i++;
476   *sindex = i;
477
478   return (temp);
479 }
480
481 /* This should really be another option to string_extract_double_quoted. */
482 static inline int
483 skip_double_quoted (string, sind)
484      char *string;
485      int sind;
486 {
487   int c, j, i;
488   char *ret;
489   int pass_next, backquote, si;
490
491   pass_next = backquote = 0;
492
493   for (j = 0, i = sind; c = string[i]; i++)
494     {
495       if (pass_next)
496         {
497           pass_next = 0;
498           continue;
499         }
500       else if (c == '\\')
501         {
502           pass_next++;
503           continue;
504         }
505       else if (backquote)
506         {
507           if (c == '`')
508             backquote = 0;
509           continue;
510         }
511       else if (c == '`')
512         {
513           backquote++;
514           continue;
515         }
516       else if (c == '$' && ((string[i + 1] == '(') || (string[i + 1] == '{')))
517         {
518           si = i + 2;
519           if (string[i + 1] == '(')
520             ret = extract_delimited_string (string, &si, "$(", "(", ")");
521           else
522             ret = extract_dollar_brace_string (string, &si, 0);
523
524           i = si;
525           free (ret);
526           continue;
527         }
528       else if (c != '"')
529         continue;
530       else
531         break;
532     }
533
534   if (c)
535     i++;
536
537   return (i);
538 }
539
540 /* Extract the contents of STRING as if it is enclosed in single quotes.
541    SINDEX, when passed in, is the offset of the character immediately
542    following the opening single quote; on exit, SINDEX is left pointing after
543    the closing single quote. */
544 static inline char *
545 string_extract_single_quoted (string, sindex)
546      char *string;
547      int *sindex;
548 {
549   register int i, j;
550   char *t;
551
552   for (i = *sindex; string[i] && string[i] != '\''; i++)
553     ;
554
555   j = i - *sindex;
556   t = xmalloc (1 + j);
557   strncpy (t, string + *sindex, j);
558   t[j] = '\0';
559
560   if (string[i])
561     i++;
562   *sindex = i;
563
564   return (t);
565 }
566
567 static inline int
568 skip_single_quoted (string, sind)
569      char *string;
570      int sind;
571 {
572   register int i;
573
574   for (i = sind; string[i] && string[i] != '\''; i++)
575     ;
576   if (string[i])
577     i++;
578   return i;
579 }
580
581 /* Just like string_extract, but doesn't hack backslashes or any of
582    that other stuff.  Obeys quoting.  Used to do splitting on $IFS. */
583 static char *
584 string_extract_verbatim (string, sindex, charlist)
585      char *string, *charlist;
586      int *sindex;
587 {
588   register int i = *sindex;
589   int c;
590   char *temp;
591
592   if (charlist[0] == '\'' && charlist[1] == '\0')
593     {
594       temp = string_extract_single_quoted (string, sindex);
595       --*sindex;        /* leave *sindex at separator character */
596       return temp;
597     }
598
599   for (i = *sindex; c = string[i]; i++)
600     {
601       if (c == CTLESC)
602         {
603           i++;
604           continue;
605         }
606
607       if (MEMBER (c, charlist))
608         break;
609     }
610
611   c = i - *sindex;
612   temp = xmalloc (1 + c);
613   strncpy (temp, string + *sindex, c);
614   temp[c] = '\0';
615   *sindex = i;
616
617   return (temp);
618 }
619
620 /* Extract the $( construct in STRING, and return a new string.
621    Start extracting at (SINDEX) as if we had just seen "$(".
622    Make (SINDEX) get the position of the matching ")". */
623 char *
624 extract_command_subst (string, sindex)
625      char *string;
626      int *sindex;
627 {
628   return (extract_delimited_string (string, sindex, "$(", "(", ")"));
629 }
630
631 /* Extract the $[ construct in STRING, and return a new string.
632    Start extracting at (SINDEX) as if we had just seen "$[".
633    Make (SINDEX) get the position of the matching "]". */
634 char *
635 extract_arithmetic_subst (string, sindex)
636      char *string;
637      int *sindex;
638 {
639   return (extract_delimited_string (string, sindex, "$[", "[", "]"));
640 }
641
642 #if defined (PROCESS_SUBSTITUTION)
643 /* Extract the <( or >( construct in STRING, and return a new string.
644    Start extracting at (SINDEX) as if we had just seen "<(".
645    Make (SINDEX) get the position of the matching ")". */
646 char *
647 extract_process_subst (string, starter, sindex)
648      char *string;
649      char *starter;
650      int *sindex;
651 {
652   return (extract_delimited_string (string, sindex, starter, "(", ")"));
653 }
654 #endif /* PROCESS_SUBSTITUTION */
655
656 #if defined (ARRAY_VARS)
657 char *
658 extract_array_assignment_list (string, sindex)
659      char *string;
660      int *sindex;
661 {
662   return (extract_delimited_string (string, sindex, "(", (char *)NULL, ")"));
663 }
664 #endif
665
666 /* Extract and create a new string from the contents of STRING, a
667    character string delimited with OPENER and CLOSER.  SINDEX is
668    the address of an int describing the current offset in STRING;
669    it should point to just after the first OPENER found.  On exit,
670    SINDEX gets the position of the last character of the matching CLOSER.
671    If OPENER is more than a single character, ALT_OPENER, if non-null,
672    contains a character string that can also match CLOSER and thus
673    needs to be skipped. */
674 static char *
675 extract_delimited_string (string, sindex, opener, alt_opener, closer)
676      char *string;
677      int *sindex;
678      char *opener, *alt_opener, *closer;
679 {
680   int i, c, si;
681   char *t, *result;
682   int pass_character, nesting_level;
683   int len_closer, len_opener, len_alt_opener;
684
685   len_opener = STRLEN (opener);
686   len_alt_opener = STRLEN (alt_opener);
687   len_closer = STRLEN (closer);
688
689   pass_character = 0;
690
691   nesting_level = 1;
692   i = *sindex;
693
694   while (nesting_level)
695     {
696       c = string[i];
697
698       if (c == 0)
699         break;
700
701       if (pass_character)       /* previous char was backslash */
702         {
703           pass_character = 0;
704           i++;
705           continue;
706         }
707
708       if (c == CTLESC)
709         {
710           pass_character++;
711           i++;
712           continue;
713         }
714
715 #if 0
716       if (c == '\\' && delimiter == '"' &&
717               (member (string[i], slashify_in_quotes)))
718 #else
719       if (c == '\\')
720 #endif
721         {
722           pass_character++;
723           i++;
724           continue;
725         }
726
727       /* Process a nested OPENER. */
728       if (STREQN (string + i, opener, len_opener))
729         {
730           si = i + len_opener;
731           t = extract_delimited_string (string, &si, opener, alt_opener, closer);
732           i = si + 1;
733           FREE (t);
734           continue;
735         }
736
737       /* Process a nested ALT_OPENER */
738       if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
739         {
740           si = i + len_alt_opener;
741           t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer);
742           i = si + 1;
743           FREE (t);
744           continue;
745         }
746
747       /* If the current substring terminates the delimited string, decrement
748          the nesting level. */
749       if (STREQN (string + i, closer, len_closer))
750         {
751           i += len_closer - 1;  /* move to last char of the closer */
752           nesting_level--;
753           if (nesting_level == 0)
754             break;
755         }
756
757       /* Pass old-style command substitution through verbatim. */
758       if (c == '`')
759         {
760           si = i + 1;
761           t = string_extract (string, &si, "`", 0);
762           i = si + 1;
763           FREE (t);
764           continue;
765         }
766
767       /* Pass single-quoted strings through verbatim. */
768       if (c == '\'')
769         {
770           si = i + 1;
771           i = skip_single_quoted (string, si);
772           continue;
773         }
774
775       /* Pass embedded double-quoted strings through verbatim as well. */
776       if (c == '"')
777         {
778           si = i + 1;
779           i = skip_double_quoted (string, si);
780           continue;
781         }
782
783       i++;      /* move past this character, which was not special. */
784     }
785
786   si = i - *sindex - len_closer + 1;
787   result = xmalloc (1 + si);
788   strncpy (result, string + *sindex, si);
789   result[si] = '\0';
790   *sindex = i;
791
792   if (c == 0 && nesting_level)
793     {
794       report_error ("bad substitution: no `%s' in %s", closer, string);
795       free (result);
796       jump_to_top_level (DISCARD);
797     }
798
799   return (result);
800 }
801
802 /* Extract a parameter expansion expression within ${ and } from STRING.
803    Obey the Posix.2 rules for finding the ending `}': count braces while
804    skipping over enclosed quoted strings and command substitutions.
805    SINDEX is the address of an int describing the current offset in STRING;
806    it should point to just after the first `{' found.  On exit, SINDEX
807    gets the position of the matching `}'.  QUOTED is non-zero if this
808    occurs inside double quotes. */
809 /* XXX -- this is very similar to extract_delimited_string -- XXX */
810 static char *
811 extract_dollar_brace_string (string, sindex, quoted)
812      char *string;
813      int *sindex, quoted;
814 {
815   register int i, c, l;
816   int pass_character, nesting_level, si;
817   char *result, *t;
818
819   pass_character = 0;
820
821   nesting_level = 1;
822
823   for (i = *sindex; (c = string[i]); i++)
824     {
825       if (pass_character)
826         {
827           pass_character = 0;
828           continue;
829         }
830
831       if (c == CTLESC)
832         {
833           pass_character++;
834           continue;
835         }
836
837       /* Backslashes quote the next character. */
838       if (c == '\\')
839         {
840           pass_character++;
841           continue;
842         }
843
844       if (string[i] == '$' && string[i+1] == '{')
845         {
846           nesting_level++;
847           i++;
848           continue;
849         }
850
851       if (c == '}')
852         {
853           nesting_level--;
854           if (nesting_level == 0)
855             break;
856           continue;
857         }
858
859       /* Pass the contents of old-style command substitutions through
860          verbatim. */
861       if (c == '`')
862         {
863           si = i + 1;
864           t = string_extract (string, &si, "`", 0);
865           i = si;
866           free (t);
867           continue;
868         }
869
870       /* Pass the contents of new-style command substitutions through
871          verbatim. */
872       if (string[i] == '$' && string[i+1] == '(')
873         {
874           si = i + 2;
875           t = extract_delimited_string (string, &si, "$(", "(", ")");
876           i = si;
877           free (t);
878           continue;
879         }
880
881       /* Pass the contents of single-quoted strings through verbatim. */
882       if (c == '\'')
883         {
884           si = i + 1;
885           i = skip_single_quoted (string, si);
886           /* skip_single_quoted leaves index one past close quote */
887           i--;
888           continue;
889         }
890
891       /* Pass embedded double-quoted strings through verbatim as well. */
892       if (c == '"')
893         {
894           si = i + 1;
895           /* skip_double_quoted leaves index one past close quote */
896           i = skip_double_quoted (string, si);
897           i--;
898           continue;
899         }
900     }
901
902   l = i - *sindex;
903   result = xmalloc (1 + l);
904   strncpy (result, string + *sindex, l);
905   result[l] = '\0';
906   *sindex = i;
907
908   if (c == 0 && nesting_level)
909     {
910       report_error ("bad substitution: no ending `}' in %s", string);
911       free (result);
912       jump_to_top_level (DISCARD);
913     }
914
915   return (result);
916 }
917
918 /* Remove backslashes which are quoting backquotes from STRING.  Modifies
919    STRING, and returns a pointer to it. */
920 char *
921 de_backslash (string)
922      char *string;
923 {
924   register int i, l;
925
926   for (i = 0, l = strlen (string); i < l; i++)
927     if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
928                               string[i + 1] == '$'))
929       strcpy (string + i, string + i + 1);      /* XXX - should be memmove */
930   return (string);
931 }
932
933 #if 0
934 /* Replace instances of \! in a string with !. */
935 void
936 unquote_bang (string)
937      char *string;
938 {
939   register int i, j;
940   register char *temp;
941
942   temp = xmalloc (1 + strlen (string));
943
944   for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
945     {
946       if (string[i] == '\\' && string[i + 1] == '!')
947         {
948           temp[j] = '!';
949           i++;
950         }
951     }
952   strcpy (string, temp);
953   free (temp);
954 }
955 #endif
956
957 #if defined (READLINE)
958 /* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
959    an unclosed quoted string), or if the character at EINDEX is quoted
960    by a backslash. */
961 int
962 char_is_quoted (string, eindex)
963      char *string;
964      int eindex;
965 {
966   int i, pass_next, quoted;
967
968   for (i = pass_next = quoted = 0; i <= eindex; i++)
969     {
970       if (pass_next)
971         {
972           pass_next = 0;
973           if (i >= eindex)      /* XXX was if (i >= eindex - 1) */
974             return 1;
975           continue;
976         }
977       else if (string[i] == '\'' || string[i] == '"')
978         {
979           i = (string[i] == '\'') ? skip_single_quoted (string, ++i)
980                                   : skip_double_quoted (string, ++i);
981           if (i > eindex)
982             return 1;
983           i--;  /* the skip functions increment past the closing quote. */
984         }
985       else if (string[i] == '\\')
986         {
987           pass_next = 1;
988           continue;
989         }
990     }
991   return (0);
992 }
993
994 int
995 unclosed_pair (string, eindex, openstr)
996      char *string;
997      int eindex;
998      char *openstr;
999 {
1000   int i, pass_next, openc, olen;
1001
1002   olen = strlen (openstr);
1003   for (i = pass_next = openc = 0; i <= eindex; i++)
1004     {
1005       if (pass_next)
1006         {
1007           pass_next = 0;
1008           if (i >= eindex)      /* XXX was if (i >= eindex - 1) */
1009             return 0;
1010           continue;
1011         }
1012       else if (STREQN (string + i, openstr, olen))
1013         {
1014           openc = 1 - openc;
1015           i += olen - 1;
1016         }
1017       else if (string[i] == '\'' || string[i] == '"')
1018         {
1019           i = (string[i] == '\'') ? skip_single_quoted (string, i)
1020                                   : skip_double_quoted (string, i);
1021           if (i > eindex)
1022             return 0;
1023         }
1024       else if (string[i] == '\\')
1025         {
1026           pass_next = 1;
1027           continue;
1028         }
1029     }
1030   return (openc);
1031 }
1032 #endif /* READLINE */
1033
1034 #if 0
1035 /* UNUSED */
1036 /* Extract the name of the variable to bind to from the assignment string. */
1037 char *
1038 assignment_name (string)
1039      char *string;
1040 {
1041   int offset;
1042   char *temp;
1043
1044   offset = assignment (string);
1045   if (offset == 0)
1046     return (char *)NULL;
1047   temp = xmalloc (offset + 1);
1048   strncpy (temp, string, offset);
1049   temp[offset] = '\0';
1050   return (temp);
1051 }
1052 #endif
1053
1054 /* Return a single string of all the words in LIST.  SEP is the separator
1055    to put between individual elements of LIST in the output string. */
1056 static char *
1057 string_list_internal (list, sep)
1058      WORD_LIST *list;
1059      char *sep;
1060 {
1061   register WORD_LIST *t;
1062   char *result, *r;
1063   int word_len, sep_len, result_size;
1064
1065   if (list == 0)
1066     return ((char *)NULL);
1067
1068   /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
1069   sep_len = STRLEN (sep);
1070   result_size = 0;
1071
1072   for (t = list; t; t = t->next)
1073     {
1074       if (t != list)
1075         result_size += sep_len;
1076       result_size += strlen (t->word->word);
1077     }
1078
1079   r = result = xmalloc (result_size + 1);
1080
1081   for (t = list; t; t = t->next)
1082     {
1083       if (t != list && sep_len)
1084         {
1085           if (sep_len > 1)
1086             {
1087               FASTCOPY (sep, r, sep_len);
1088               r += sep_len;
1089             }
1090           else
1091             *r++ = sep[0];
1092         }
1093
1094       word_len = strlen (t->word->word);
1095       FASTCOPY (t->word->word, r, word_len);
1096       r += word_len;
1097     }
1098
1099   *r = '\0';
1100   return (result);
1101 }
1102
1103 /* Return a single string of all the words present in LIST, separating
1104    each word with a space. */
1105 char *
1106 string_list (list)
1107      WORD_LIST *list;
1108 {
1109   return (string_list_internal (list, " "));
1110 }
1111
1112 /* Return a single string of all the words present in LIST, obeying the
1113    quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
1114    expansion [of $*] appears within a double quoted string, it expands
1115    to a single field with the value of each parameter separated by the
1116    first character of the IFS variable, or by a <space> if IFS is unset." */
1117 char *
1118 string_list_dollar_star (list)
1119      WORD_LIST *list;
1120 {
1121   char *ifs, sep[2];
1122
1123   ifs = get_string_value ("IFS");
1124   if (ifs == 0)
1125     sep[0] = ' ';
1126   else if (*ifs == '\0')
1127     sep[0] = '\0';
1128   else
1129     sep[0] = *ifs;
1130
1131   sep[1] = '\0';
1132
1133   return (string_list_internal (list, sep));
1134 }
1135
1136 /* Return the list of words present in STRING.  Separate the string into
1137    words at any of the characters found in SEPARATORS.  If QUOTED is
1138    non-zero then word in the list will have its quoted flag set, otherwise
1139    the quoted flag is left as make_word () deemed fit.
1140
1141    This obeys the P1003.2 word splitting semantics.  If `separators' is
1142    exactly <space><tab><newline>, then the splitting algorithm is that of
1143    the Bourne shell, which treats any sequence of characters from `separators'
1144    as a delimiter.  If IFS is unset, which results in `separators' being set
1145    to "", no splitting occurs.  If separators has some other value, the
1146    following rules are applied (`IFS white space' means zero or more
1147    occurrences of <space>, <tab>, or <newline>, as long as those characters
1148    are in `separators'):
1149
1150         1) IFS white space is ignored at the start and the end of the
1151            string.
1152         2) Each occurrence of a character in `separators' that is not
1153            IFS white space, along with any adjacent occurrences of
1154            IFS white space delimits a field.
1155         3) Any nonzero-length sequence of IFS white space delimits a field.
1156    */
1157
1158 /* BEWARE!  list_string strips null arguments.  Don't call it twice and
1159    expect to have "" preserved! */
1160
1161 /* Perform quoted null character removal on STRING.  We don't allow any
1162    quoted null characters in the middle or at the ends of strings because
1163    of how expand_word_internal works.  remove_quoted_nulls () turns
1164    STRING into an empty string iff it only consists of a quoted null,
1165    and removes all unquoted CTLNUL characters. */
1166 /*
1167 #define remove_quoted_nulls(string) \
1168   do { if (QUOTED_NULL (string)) string[0] ='\0'; } while (0)
1169 */
1170 static void
1171 remove_quoted_nulls (string)
1172      char *string;
1173 {
1174   char *nstr, *s, *p;
1175
1176   nstr = savestring (string);
1177   nstr[0] = '\0';
1178   for (p = nstr, s = string; *s; s++)
1179     {
1180       if (*s == CTLESC)
1181         {
1182           *p++ = *s++;  /* CTLESC */
1183           if (*s == 0)
1184             break;
1185           *p++ = *s;    /* quoted char */
1186           continue;
1187         }
1188       if (*s == CTLNUL)
1189         continue;
1190       *p++ = *s;
1191     }
1192   *p = '\0';
1193   strcpy (string, nstr);
1194   free (nstr);
1195 }
1196
1197 /* Perform quoted null character removal on each element of LIST.
1198    This modifies LIST. */
1199 void
1200 word_list_remove_quoted_nulls (list)
1201      WORD_LIST *list;
1202 {
1203   register WORD_LIST *t;
1204
1205   for (t = list; t; t = t->next)
1206     remove_quoted_nulls (t->word->word);
1207 }
1208
1209 /* This performs word splitting and quoted null character removal on
1210    STRING. */
1211 #define issep(c)        (member ((c), separators))
1212
1213 WORD_LIST *
1214 list_string (string, separators, quoted)
1215      register char *string, *separators;
1216      int quoted;
1217 {
1218   WORD_LIST *result;
1219   WORD_DESC *t;
1220   char *current_word, *s;
1221   int sindex, sh_style_split;
1222
1223   if (!string || !*string)
1224     return ((WORD_LIST *)NULL);
1225
1226   sh_style_split =
1227     separators && *separators && (STREQ (separators, " \t\n"));
1228
1229   /* Remove sequences of whitespace at the beginning of STRING, as
1230      long as those characters appear in IFS.  Do not do this if
1231      STRING is quoted or if there are no separator characters. */
1232   if (!quoted || !separators || !*separators)
1233     {
1234       for (s = string; *s && spctabnl (*s) && issep (*s); s++);
1235
1236       if (!*s)
1237         return ((WORD_LIST *)NULL);
1238
1239       string = s;
1240     }
1241
1242   /* OK, now STRING points to a word that does not begin with white space.
1243      The splitting algorithm is:
1244         extract a word, stopping at a separator
1245         skip sequences of spc, tab, or nl as long as they are separators
1246      This obeys the field splitting rules in Posix.2. */
1247   for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
1248     {
1249       current_word = string_extract_verbatim (string, &sindex, separators);
1250       if (current_word == 0)
1251         break;
1252
1253       /* If we have a quoted empty string, add a quoted null argument.  We
1254          want to preserve the quoted null character iff this is a quoted
1255          empty string; otherwise the quoted null characters are removed
1256          below. */
1257       if (QUOTED_NULL (current_word))
1258         {
1259           t = make_bare_word ("");
1260           t->flags |= W_QUOTED;
1261           free (t->word);
1262           t->word = make_quoted_char ('\0');
1263           result = make_word_list (t, result);
1264         }
1265       else if (current_word[0] != '\0')
1266         {
1267           /* If we have something, then add it regardless.  However,
1268              perform quoted null character removal on the current word. */
1269           remove_quoted_nulls (current_word);
1270           result = make_word_list (make_word (current_word), result);
1271           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
1272             result->word->flags |= W_QUOTED;
1273         }
1274
1275       /* If we're not doing sequences of separators in the traditional
1276          Bourne shell style, then add a quoted null argument. */
1277       else if (!sh_style_split && !spctabnl (string[sindex]))
1278         {
1279           t = make_bare_word ("");
1280           t->flags |= W_QUOTED;
1281           free (t->word);
1282           t->word = make_quoted_char ('\0');
1283           result = make_word_list (t, result);
1284         }
1285
1286       free (current_word);
1287
1288       /* Move past the current separator character. */
1289       if (string[sindex])
1290         sindex++;
1291
1292       /* Now skip sequences of space, tab, or newline characters if they are
1293          in the list of separators. */
1294       while (string[sindex] && spctabnl (string[sindex]) && issep (string[sindex]))
1295         sindex++;
1296     }
1297   return (REVERSE_LIST (result, WORD_LIST *));
1298 }
1299
1300 /* Parse a single word from STRING, using SEPARATORS to separate fields.
1301    ENDPTR is set to the first character after the word.  This is used by
1302    the `read' builtin.
1303    XXX - this function is very similar to list_string; they should be
1304          combined - XXX */
1305 char *
1306 get_word_from_string (stringp, separators, endptr)
1307      char **stringp, *separators, **endptr;
1308 {
1309   register char *s;
1310   char *current_word;
1311   int sindex, sh_style_split;
1312
1313   if (!stringp || !*stringp || !**stringp)
1314     return ((char *)NULL);
1315
1316   s = *stringp;
1317
1318   sh_style_split =
1319     separators && *separators && (STREQ (separators, " \t\n"));
1320
1321   /* Remove sequences of whitespace at the beginning of STRING, as
1322      long as those characters appear in IFS. */
1323   if (sh_style_split || !separators || !*separators)
1324     {
1325       for (; *s && spctabnl (*s) && issep (*s); s++);
1326
1327       /* If the string is nothing but whitespace, update it and return. */
1328       if (!*s)
1329         {
1330           *stringp = s;
1331           if (endptr)
1332             *endptr = s;
1333           return ((char *)NULL);
1334         }
1335     }
1336
1337   /* OK, S points to a word that does not begin with white space.
1338      Now extract a word, stopping at a separator, save a pointer to
1339      the first character after the word, then skip sequences of spc,
1340      tab, or nl as long as they are separators.
1341
1342      This obeys the field splitting rules in Posix.2. */
1343   sindex = 0;
1344   current_word = string_extract_verbatim (s, &sindex, separators);
1345
1346   /* Set ENDPTR to the first character after the end of the word. */
1347   if (endptr)
1348     *endptr = s + sindex;
1349
1350   /* Move past the current separator character. */
1351   if (s[sindex])
1352     sindex++;
1353
1354   /* Now skip sequences of space, tab, or newline characters if they are
1355      in the list of separators. */
1356   while (s[sindex] && spctabnl (s[sindex]) && issep (s[sindex]))
1357     sindex++;
1358
1359   /* Update STRING to point to the next field. */
1360   *stringp = s + sindex;
1361   return (current_word);
1362 }
1363
1364 /* Remove IFS white space at the end of STRING.  Start at the end
1365    of the string and walk backwards until the beginning of the string
1366    or we find a character that's not IFS white space and not CTLESC.
1367    Only let CTLESC escape a white space character if SAW_ESCAPE is
1368    non-zero.  */
1369 char *
1370 strip_trailing_ifs_whitespace (string, separators, saw_escape)
1371      char *string, *separators;
1372      int saw_escape;
1373 {
1374   char *s;
1375
1376   s = string + STRLEN (string) - 1;
1377   while (s > string && ((spctabnl (*s) && issep (*s)) ||
1378                         (saw_escape && *s == CTLESC && spctabnl (s[1]))))
1379     s--;
1380   *++s = '\0';
1381   return string;
1382 }
1383
1384 #if 0
1385 #if defined (ARRAY_VARS)
1386 WORD_LIST *
1387 list_string_with_quotes (string)
1388      char *string;
1389 {
1390   WORD_LIST *list;
1391   char *token, *s;
1392   int c, i, tokstart, len;
1393
1394   for (s = string; s && *s && spctabnl (*s); s++)
1395     ;
1396   if (s == 0 || *s == 0)
1397     return ((WORD_LIST *)NULL);
1398
1399   tokstart = i = 0;
1400   list = (WORD_LIST *)NULL;
1401   while (1)
1402     {
1403       c = s[i];
1404       if (c == '\\')
1405         {
1406           i++;
1407           if (s[i])
1408             i++;
1409         }
1410       else if (c == '\'')
1411         i = skip_single_quoted (s, ++i);
1412       else if (c == '"')
1413         i = skip_double_quoted (s, ++i);
1414       else if (c == 0 || spctabnl (c))
1415         {
1416           /* We have found the end of a token.  Make a word out of it and
1417              add it to the word list. */
1418           len = i - tokstart;
1419           token = xmalloc (len + 1);
1420           strncpy (token, s + tokstart, len);
1421           token[len] = '\0';
1422           list = make_word_list (make_word (token), list);
1423           free (token);
1424           while (spctabnl (s[i]))
1425             i++;
1426           if (s[i])
1427             tokstart = i;
1428           else
1429             break;
1430         }
1431       else
1432         i++;    /* normal character */
1433     }
1434   return (REVERSE_LIST (list, WORD_LIST *));
1435 }
1436 #endif /* ARRAY_VARS */
1437 #endif /* 0 */
1438
1439 #if defined (PROCESS_SUBSTITUTION)
1440 #define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC)
1441 #else
1442 #define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC)
1443 #endif
1444
1445 /* If there are any characters in STRING that require full expansion,
1446    then call FUNC to expand STRING; otherwise just perform quote
1447    removal if necessary.  This returns a new string. */
1448 static char *
1449 maybe_expand_string (string, quoted, func)
1450      char *string;
1451      int quoted;
1452      WORD_LIST *(*func)();
1453 {
1454   WORD_LIST *list;
1455   int i, saw_quote;
1456   char *ret;
1457
1458   for (i = saw_quote = 0; string[i]; i++)
1459     {
1460       if (EXP_CHAR (string[i]))
1461         break;
1462       else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
1463         saw_quote = 1;
1464     }
1465
1466   if (string[i])
1467     {
1468       list = (*func) (string, quoted);
1469       if (list)
1470         {
1471           ret = string_list (list);
1472           dispose_words (list);
1473         }
1474       else
1475         ret = (char *)NULL;
1476     }
1477   else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
1478     ret = string_quote_removal (string, quoted);
1479   else
1480     ret = savestring (string);
1481   return ret;
1482 }
1483
1484 static inline char *
1485 expand_string_to_string (string, quoted, func)
1486      char *string;
1487      int quoted;
1488      WORD_LIST *(*func)();
1489 {
1490   WORD_LIST *list;
1491   char *ret;
1492
1493   if (string == 0 || *string == '\0')
1494     return ((char *)NULL);
1495
1496   list = (*func) (string, quoted);
1497   if (list)
1498     {
1499       ret = string_list (list);
1500       dispose_words (list);
1501     }
1502   else
1503     ret = (char *)NULL;
1504
1505   return (ret);
1506 }
1507
1508 #if defined (ARRAY_VARS)
1509 SHELL_VAR *
1510 do_array_element_assignment (name, value)
1511      char *name, *value;
1512 {
1513   char *t;
1514   int ind, ni;
1515   SHELL_VAR *entry;
1516
1517   t = strchr (name, '[');
1518   if (t == 0)
1519     return ((SHELL_VAR *)NULL);
1520   ind = t - name;
1521   ni = skipsubscript (name, ind);
1522   if ((ALL_ELEMENT_SUB (t[1]) && t[2] == ']') || (ni <= ind + 1))
1523     {
1524       report_error ("%s: bad array subscript", name);
1525       return ((SHELL_VAR *)NULL);
1526     }
1527   *t++ = '\0';
1528   ind = array_expand_index (t, ni - ind);
1529   if (ind < 0)
1530     {
1531       t[-1] = '[';              /* restore original name */
1532       report_error ("%s: bad array subscript", name);
1533       return ((SHELL_VAR *)NULL);
1534     }
1535   entry = bind_array_variable (name, ind, value);
1536   t[-1] = '[';          /* restore original name */
1537   return (entry);
1538 }
1539 #endif /* ARRAY_VARS */
1540
1541 /* Given STRING, an assignment string, get the value of the right side
1542    of the `=', and bind it to the left side.  If EXPAND is true, then
1543    perform parameter expansion, command substitution, and arithmetic
1544    expansion on the right-hand side.  Perform tilde expansion in any
1545    case.  Do not perform word splitting on the result of expansion. */
1546 static int
1547 do_assignment_internal (string, expand)
1548      char *string;
1549      int expand;
1550 {
1551   int offset;
1552   char *name, *value;
1553   SHELL_VAR *entry;
1554 #if defined (ARRAY_VARS)
1555   char *t;
1556   int ni, assign_list = 0;
1557 #endif
1558
1559   offset = assignment (string);
1560   name = savestring (string);
1561   value = (char *)NULL;
1562
1563   if (name[offset] == '=')
1564     {
1565       char *temp;
1566
1567       name[offset] = 0;
1568       temp = name + offset + 1;
1569
1570 #if defined (ARRAY_VARS)
1571       if (expand && temp[0] == '(' && strchr (temp, ')'))
1572         {
1573           assign_list = ni = 1;
1574           value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")");
1575         }
1576       else
1577 #endif
1578
1579       /* Perform tilde expansion. */
1580       if (expand && temp[0])
1581         {
1582           temp = (strchr (temp, '~') && unquoted_member ('~', temp))
1583                         ? bash_tilde_expand (temp)
1584                         : savestring (temp);
1585
1586           value = maybe_expand_string (temp, 0, expand_string_unsplit);
1587           free (temp);
1588         }
1589       else
1590         value = savestring (temp);
1591     }
1592
1593   if (value == 0)
1594     {
1595       value = xmalloc (1);
1596       value[0] = '\0';
1597     }
1598
1599   if (echo_command_at_execute)
1600 #if defined (ARRAY_VARS)
1601     if (assign_list)
1602       fprintf (stderr, "%s%s=(%s)\n", indirection_level_string (), name, value);
1603     else
1604 #endif
1605     fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value);
1606
1607 #define ASSIGN_RETURN(r)        do { FREE (value); free (name); return (r); } while (0)
1608
1609 #if defined (ARRAY_VARS)
1610   if (t = strchr (name, '['))
1611     {
1612       if (assign_list)
1613         {
1614           report_error ("%s: cannot assign list to array member", name);
1615           ASSIGN_RETURN (0);
1616         }
1617       entry = do_array_element_assignment (name, value);
1618       if (entry == 0)
1619         ASSIGN_RETURN (0);
1620     }
1621   else if (assign_list)
1622     entry = assign_array_from_string (name, value);
1623   else
1624 #endif /* ARRAY_VARS */
1625   entry = bind_variable (name, value);
1626
1627   stupidly_hack_special_variables (name);
1628
1629   if (entry)
1630     entry->attributes &= ~att_invisible;
1631
1632   /* Return 1 if the assignment seems to have been performed correctly. */
1633   ASSIGN_RETURN (entry ? ((entry->attributes & att_readonly) == 0) : 0);
1634 }
1635
1636 /* Perform the assignment statement in STRING, and expand the
1637    right side by doing command and parameter expansion. */
1638 int
1639 do_assignment (string)
1640      char *string;
1641 {
1642   return do_assignment_internal (string, 1);
1643 }
1644
1645 /* Given STRING, an assignment string, get the value of the right side
1646    of the `=', and bind it to the left side.  Do not do command and
1647    parameter substitution on the right hand side. */
1648 int
1649 do_assignment_no_expand (string)
1650      char *string;
1651 {
1652   return do_assignment_internal (string, 0);
1653 }
1654
1655 /* Most of the substitutions must be done in parallel.  In order
1656    to avoid using tons of unclear goto's, I have some functions
1657    for manipulating malloc'ed strings.  They all take INDX, a
1658    pointer to an integer which is the offset into the string
1659    where manipulation is taking place.  They also take SIZE, a
1660    pointer to an integer which is the current length of the
1661    character array for this string. */
1662
1663 /* Append SOURCE to TARGET at INDEX.  SIZE is the current amount
1664    of space allocated to TARGET.  SOURCE can be NULL, in which
1665    case nothing happens.  Gets rid of SOURCE by freeing it.
1666    Returns TARGET in case the location has changed. */
1667 inline char *
1668 sub_append_string (source, target, indx, size)
1669      char *source, *target;
1670      int *indx, *size;
1671 {
1672   if (source)
1673     {
1674       int srclen, n;
1675
1676       srclen = STRLEN (source);
1677       if (srclen >= (int)(*size - *indx))
1678         {
1679           n = srclen + *indx;
1680           n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
1681           target = xrealloc (target, (*size = n));
1682         }
1683
1684       FASTCOPY (source, target + *indx, srclen);
1685       *indx += srclen;
1686       target[*indx] = '\0';
1687
1688       free (source);
1689     }
1690   return (target);
1691 }
1692
1693 #if 0
1694 /* UNUSED */
1695 /* Append the textual representation of NUMBER to TARGET.
1696    INDX and SIZE are as in SUB_APPEND_STRING. */
1697 char *
1698 sub_append_number (number, target, indx, size)
1699      int number, *indx, *size;
1700      char *target;
1701 {
1702   char *temp;
1703
1704   temp = itos (number);
1705   return (sub_append_string (temp, target, indx, size));
1706 }
1707 #endif
1708
1709 /* Return the word list that corresponds to `$*'. */
1710 WORD_LIST *
1711 list_rest_of_args ()
1712 {
1713   register WORD_LIST *list, *args;
1714   int i;
1715
1716   /* Break out of the loop as soon as one of the dollar variables is null. */
1717   for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
1718     list = make_word_list (make_bare_word (dollar_vars[i]), list);
1719
1720   for (args = rest_of_args; args; args = args->next)
1721     list = make_word_list (make_bare_word (args->word->word), list);
1722
1723   return (REVERSE_LIST (list, WORD_LIST *));
1724 }
1725
1726 int
1727 number_of_args ()
1728 {
1729   register WORD_LIST *list;
1730   int n;
1731
1732   for (n = 0; n < 9 && dollar_vars[n+1]; n++)
1733     ;
1734   for (list = rest_of_args; list; list = list->next)
1735     n++;
1736   return n;
1737 }
1738
1739 /* Make a single large string out of the dollar digit variables,
1740    and the rest_of_args.  If DOLLAR_STAR is 1, then obey the special
1741    case of "$*" with respect to IFS. */
1742 char *
1743 string_rest_of_args (dollar_star)
1744      int dollar_star;
1745 {
1746   register WORD_LIST *list;
1747   char *string;
1748
1749   list = list_rest_of_args ();
1750   string = dollar_star ? string_list_dollar_star (list) : string_list (list);
1751   dispose_words (list);
1752   return (string);
1753 }
1754
1755 /***************************************************
1756  *                                                 *
1757  *         Functions to Expand a String            *
1758  *                                                 *
1759  ***************************************************/
1760 /* Call expand_word_internal to expand W and handle error returns.
1761    A convenience function for functions that don't want to handle
1762    any errors or free any memory before aborting. */
1763 static WORD_LIST *
1764 call_expand_word_internal (w, q, c, e)
1765      WORD_DESC *w;
1766      int q, *c, *e;
1767 {
1768   WORD_LIST *result;
1769
1770   result = expand_word_internal (w, q, c, e);
1771   if (result == &expand_word_error)
1772     {
1773       /* By convention, each time this error is returned, w->word has
1774          already been freed. */
1775       w->word = (char *)NULL;
1776       jump_to_top_level (DISCARD);
1777       /* NOTREACHED */
1778     }
1779   else if (result == &expand_word_fatal)
1780     jump_to_top_level (FORCE_EOF);
1781     /* NOTREACHED */
1782   else
1783     return (result);
1784 }
1785
1786 /* Perform parameter expansion, command substitution, and arithmetic
1787    expansion on STRING, as if it were a word.  Leave the result quoted. */
1788 static WORD_LIST *
1789 expand_string_internal (string, quoted)
1790      char *string;
1791      int quoted;
1792 {
1793   WORD_DESC td;
1794   WORD_LIST *tresult;
1795
1796   if (string == 0 || *string == 0)
1797     return ((WORD_LIST *)NULL);
1798
1799   bzero ((char *)&td, sizeof (td));
1800   td.word = string;
1801   tresult = call_expand_word_internal (&td, quoted, (int *)NULL, (int *)NULL);
1802   return (tresult);
1803 }
1804
1805 /* Expand STRING by performing parameter expansion, command substitution,
1806    and arithmetic expansion.  Dequote the resulting WORD_LIST before
1807    returning it, but do not perform word splitting.  The call to
1808    remove_quoted_nulls () is in here because word splitting normally
1809    takes care of quote removal. */
1810 WORD_LIST *
1811 expand_string_unsplit (string, quoted)
1812      char *string;
1813      int quoted;
1814 {
1815   WORD_LIST *value;
1816
1817   if (!string || !*string)
1818     return ((WORD_LIST *)NULL);
1819
1820   value = expand_string_internal (string, quoted);
1821   if (value)
1822     {
1823       if (value->word)
1824         remove_quoted_nulls (value->word->word);
1825       dequote_list (value);
1826     }
1827   return (value);
1828 }
1829
1830 /* Expand STRING just as if you were expanding a word, but do not dequote
1831    the resultant WORD_LIST.  This is called only from within this file,
1832    and is used to correctly preserve quoted characters when expanding
1833    things like ${1+"$@"}.  This does parameter expansion, command
1834    subsitution, arithmetic expansion, and word splitting. */
1835 static WORD_LIST *
1836 expand_string_leave_quoted (string, quoted)
1837      char *string;
1838      int quoted;
1839 {
1840   WORD_LIST *tlist;
1841   WORD_LIST *tresult;
1842
1843   if (string == 0 || *string == '\0')
1844     return ((WORD_LIST *)NULL);
1845
1846   tlist = expand_string_internal (string, quoted);
1847
1848   if (tlist)
1849     {
1850       tresult = word_list_split (tlist);
1851       dispose_words (tlist);
1852       return (tresult);
1853     }
1854   return ((WORD_LIST *)NULL);
1855 }
1856
1857 /* This does not perform word splitting or dequote the WORD_LIST
1858    it returns. */
1859 static WORD_LIST *
1860 expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at)
1861      char *string;
1862      int quoted, *dollar_at_p, *has_dollar_at;
1863 {
1864   WORD_DESC td;
1865   WORD_LIST *tresult;
1866
1867   if (string == 0 || *string == '\0')
1868     return (WORD_LIST *)NULL;
1869
1870   bzero ((char *)&td, sizeof (td));
1871   td.word = string;
1872   tresult = call_expand_word_internal (&td, quoted, dollar_at_p, has_dollar_at);
1873   return (tresult);
1874 }
1875
1876 /* Expand STRING just as if you were expanding a word.  This also returns
1877    a list of words.  Note that filename globbing is *NOT* done for word
1878    or string expansion, just when the shell is expanding a command.  This
1879    does parameter expansion, command substitution, arithmetic expansion,
1880    and word splitting.  Dequote the resultant WORD_LIST before returning. */
1881 WORD_LIST *
1882 expand_string (string, quoted)
1883      char *string;
1884      int quoted;
1885 {
1886   WORD_LIST *result;
1887
1888   if (!string || !*string)
1889     return ((WORD_LIST *)NULL);
1890
1891   result = expand_string_leave_quoted (string, quoted);
1892   return (result ? dequote_list (result) : result);
1893 }
1894
1895 /***************************************************
1896  *                                                 *
1897  *      Functions to handle quoting chars          *
1898  *                                                 *
1899  ***************************************************/
1900
1901 static WORD_LIST *
1902 dequote_list (list)
1903      WORD_LIST *list;
1904 {
1905   register char *s;
1906   register WORD_LIST *tlist;
1907
1908   for (tlist = list; tlist; tlist = tlist->next)
1909     {
1910       s = dequote_string (tlist->word->word);
1911       free (tlist->word->word);
1912       tlist->word->word = s;
1913     }
1914   return list;
1915 }
1916
1917 static char *
1918 make_quoted_char (c)
1919      int c;
1920 {
1921   char *temp;
1922
1923   temp = xmalloc (3);
1924   if (c == 0)
1925     {
1926       temp[0] = CTLNUL;
1927       temp[1] = '\0';
1928     }
1929   else
1930     {
1931       temp[0] = CTLESC;
1932       temp[1] = c;
1933       temp[2] = '\0';
1934     }
1935   return (temp);
1936 }
1937
1938 /* Quote STRING.  Return a new string. */
1939 char *
1940 quote_string (string)
1941      char *string;
1942 {
1943   register char *t;
1944   char *result;
1945
1946   if (*string == 0)
1947     {
1948       result = xmalloc (2);
1949       result[0] = CTLNUL;
1950       result[1] = '\0';
1951     }
1952   else
1953     {
1954       result = xmalloc ((strlen (string) * 2) + 1);
1955
1956       for (t = result; *string; )
1957         {
1958           *t++ = CTLESC;
1959           *t++ = *string++;
1960         }
1961       *t = '\0';
1962     }
1963   return (result);
1964 }
1965
1966 /* De-quoted quoted characters in STRING. */
1967 char *
1968 dequote_string (string)
1969      char *string;
1970 {
1971   register char *t;
1972   char *result;
1973
1974   result = xmalloc (strlen (string) + 1);
1975
1976   if (QUOTED_NULL (string))
1977     {
1978       result[0] = '\0';
1979       return (result);
1980     }
1981
1982   /* If no character in the string can be quoted, don't bother examining
1983      each character.  Just return a copy of the string passed to us. */
1984   if (strchr (string, CTLESC) == NULL)          /* XXX */
1985     {                                           /* XXX */
1986       strcpy (result, string);                  /* XXX */
1987       return (result);                          /* XXX */
1988     }
1989
1990   for (t = result; *string; string++, t++)
1991     {
1992       if (*string == CTLESC)
1993         {
1994           string++;
1995
1996           if (!*string)
1997             break;
1998         }
1999
2000       *t = *string;
2001     }
2002
2003   *t = '\0';
2004   return (result);
2005 }
2006
2007 /* Quote the entire WORD_LIST list. */
2008 static WORD_LIST *
2009 quote_list (list)
2010      WORD_LIST *list;
2011 {
2012   register WORD_LIST *w;
2013   char *t;
2014
2015   for (w = list; w; w = w->next)
2016     {
2017       t = w->word->word;
2018       w->word->word = quote_string (t);
2019       free (t);
2020       w->word->flags |= W_QUOTED;
2021     }
2022   return list;
2023 }
2024
2025 /* **************************************************************** */
2026 /*                                                                  */
2027 /*                  Functions for Removing Patterns                 */
2028 /*                                                                  */
2029 /* **************************************************************** */
2030
2031 /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
2032    can have one of 4 values:
2033         RP_LONG_LEFT    remove longest matching portion at start of PARAM
2034         RP_SHORT_LEFT   remove shortest matching portion at start of PARAM
2035         RP_LONG_RIGHT   remove longest matching portion at end of PARAM
2036         RP_SHORT_RIGHT  remove shortest matching portion at end of PARAM
2037 */
2038
2039 #define RP_LONG_LEFT    1
2040 #define RP_SHORT_LEFT   2
2041 #define RP_LONG_RIGHT   3
2042 #define RP_SHORT_RIGHT  4
2043
2044 static char *
2045 remove_pattern (param, pattern, op)
2046      char *param, *pattern;
2047      int op;
2048 {
2049   register int len;
2050   register char *end;
2051   register char *p, *ret, c;
2052
2053   if (param == NULL || *param == '\0')
2054     return (param);
2055   if (pattern == NULL || *pattern == '\0')      /* minor optimization */
2056     return (savestring (param));
2057
2058   len = STRLEN (param);
2059   end = param + len;
2060
2061   switch (op)
2062     {
2063       case RP_LONG_LEFT:        /* remove longest match at start */
2064         for (p = end; p >= param; p--)
2065           {
2066             c = *p; *p = '\0';
2067             if (fnmatch (pattern, param, 0) != FNM_NOMATCH)
2068               {
2069                 *p = c;
2070                 return (savestring (p));
2071               }
2072             *p = c;
2073           }
2074         break;
2075
2076       case RP_SHORT_LEFT:       /* remove shortest match at start */
2077         for (p = param; p <= end; p++)
2078           {
2079             c = *p; *p = '\0';
2080             if (fnmatch (pattern, param, 0) != FNM_NOMATCH)
2081               {
2082                 *p = c;
2083                 return (savestring (p));
2084               }
2085             *p = c;
2086           }
2087         break;
2088
2089       case RP_LONG_RIGHT:       /* remove longest match at end */
2090         for (p = param; p <= end; p++)
2091           {
2092             if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
2093               {
2094                 c = *p; *p = '\0';
2095                 ret = savestring (param);
2096                 *p = c;
2097                 return (ret);
2098               }
2099           }
2100         break;
2101
2102       case RP_SHORT_RIGHT:      /* remove shortest match at end */
2103         for (p = end; p >= param; p--)
2104           {
2105             if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
2106               {
2107                 c = *p; *p = '\0';
2108                 ret = savestring (param);
2109                 *p = c;
2110                 return (ret);
2111               }
2112           }
2113         break;
2114     }
2115   return (savestring (param));  /* no match, return original string */
2116 }
2117
2118 /* Return 1 of the first character of STRING could match the first
2119    character of pattern PAT.  Used to avoid n2 calls to fnmatch(). */
2120 static int
2121 match_pattern_char (pat, string)
2122      char *pat, *string;
2123 {
2124 #if 0
2125   register char *np;
2126   int neg;
2127   char c1;
2128 #endif
2129   char c;
2130
2131   if (*string == 0)
2132     return (0);
2133
2134   switch (c = *pat++)
2135     {
2136     default:
2137       return (*string == c);
2138     case '\\':
2139       return (*string == *pat);
2140     case '?':
2141       return (*string != '\0');
2142     case '*':
2143       return (1);
2144     case '[':
2145 #if 0
2146       for (np = pat; *np != ']'; np++);
2147       if (*np == 0)
2148         return (*string == '[');
2149       if (neg = (*pat == '!' || *pat == '^'))
2150         pat++;
2151       for ( ; (c1 = *pat++) != ']'; )
2152         {
2153           if (c1 == '\\')
2154             c1 = *pat++;
2155           if (c1 == 0)
2156             return (0);
2157           if (*pat != '-' || pat[1] == '\0' || pat[1] == ']')
2158             return (neg ? *string != c1 : *string == c1);
2159           if (c1 <= *string && *string <= pat[1])
2160             return (1);
2161           pat += 2;
2162         }
2163 #else
2164       return (*string != '\0');
2165 #endif
2166     }
2167 }
2168
2169 /* Match PAT anywhere in STRING and return the match boundaries.
2170    This returns 1 in case of a successful match, 0 otherwise.  SP
2171    and EP are pointers into the string where the match begins and
2172    ends, respectively.  MTYPE controls what kind of match is attempted.
2173    MATCH_BEG and MATCH_END anchor the match at the beginning and end
2174    of the string, respectively.  The longest match is returned. */
2175 static int
2176 match_pattern (string, pat, mtype, sp, ep)
2177      char *string, *pat;
2178      int mtype;
2179      char **sp, **ep;
2180 {
2181   int c;
2182   register char *p, *p1;
2183   char *end;
2184
2185   if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
2186     return (0);
2187
2188   end = string + STRLEN (string);
2189
2190   switch (mtype)
2191     {
2192     case MATCH_ANY:
2193       for (p = string; p <= end; p++)
2194         {
2195           if (match_pattern_char (pat, p))
2196             {
2197               for (p1 = end; p1 >= p; p1--)
2198                 {
2199                   c = *p1; *p1 = '\0';
2200                   if (fnmatch (pat, p, 0) == 0)
2201                     {
2202                       *p1 = c;
2203                       *sp = p;
2204                       *ep = p1;
2205                       return 1;
2206                     }
2207                   *p1 = c;
2208                 }
2209             }
2210         }
2211       return (0);
2212
2213     case MATCH_BEG:
2214       if (match_pattern_char (pat, string) == 0)
2215         return (0);
2216       for (p = end; p >= string; p--)
2217         {
2218           c = *p; *p = '\0';
2219           if (fnmatch (pat, string, 0) == 0)
2220             {
2221               *p = c;
2222               *sp = string;
2223               *ep = p;
2224               return 1;
2225             }
2226           *p = c;
2227         }
2228       return (0);
2229
2230     case MATCH_END:
2231       for (p = string; p <= end; p++)
2232         if (fnmatch (pat, p, 0) == 0)
2233           {
2234             *sp = p;
2235             *ep = end;
2236             return 1;
2237           }
2238       return (0);
2239     }
2240
2241   return (0);
2242 }
2243
2244 /*******************************************
2245  *                                         *
2246  *      Functions to expand WORD_DESCs     *
2247  *                                         *
2248  *******************************************/
2249
2250 /* Expand WORD, performing word splitting on the result.  This does
2251    parameter expansion, command substitution, arithmetic expansion,
2252    word splitting, and quote removal. */
2253
2254 WORD_LIST *
2255 expand_word (word, quoted)
2256      WORD_DESC *word;
2257      int quoted;
2258 {
2259   WORD_LIST *result, *tresult;
2260
2261   tresult = call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
2262   result = word_list_split (tresult);
2263   dispose_words (tresult);
2264   return (result ? dequote_list (result) : result);
2265 }
2266
2267 /* Expand WORD, but do not perform word splitting on the result.  This
2268    does parameter expansion, command substitution, arithmetic expansion,
2269    and quote removal. */
2270 WORD_LIST *
2271 expand_word_no_split (word, quoted)
2272      WORD_DESC *word;
2273      int quoted;
2274 {
2275   WORD_LIST *result;
2276
2277   result = call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
2278   return (result ? dequote_list (result) : result);
2279 }
2280
2281 /* Perform shell expansions on WORD, but do not perform word splitting or
2282    quote removal on the result. */
2283 WORD_LIST *
2284 expand_word_leave_quoted (word, quoted)
2285      WORD_DESC *word;
2286      int quoted;
2287 {
2288   return (call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL));
2289 }
2290
2291 /* Return the value of a positional parameter.  This handles values > 10. */
2292 char *
2293 get_dollar_var_value (ind)
2294      int ind;
2295 {
2296   char *temp;
2297   WORD_LIST *p;
2298
2299   if (ind < 10)
2300     temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
2301   else  /* We want something like ${11} */
2302     {
2303       ind -= 10;
2304       for (p = rest_of_args; p && ind--; p = p->next)
2305         ;
2306       temp = p ? savestring (p->word->word) : (char *)NULL;
2307     }
2308   return (temp);
2309 }
2310
2311 #if defined (PROCESS_SUBSTITUTION)
2312
2313 /* **************************************************************** */
2314 /*                                                                */
2315 /*                  Hacking Process Substitution                    */
2316 /*                                                                */
2317 /* **************************************************************** */
2318
2319 #if !defined (HAVE_DEV_FD)
2320 /* Named pipes must be removed explicitly with `unlink'.  This keeps a list
2321    of FIFOs the shell has open.  unlink_fifo_list will walk the list and
2322    unlink all of them. add_fifo_list adds the name of an open FIFO to the
2323    list.  NFIFO is a count of the number of FIFOs in the list. */
2324 #define FIFO_INCR 20
2325 extern char *mktemp ();
2326
2327 static char **fifo_list = (char **)NULL;
2328 static int nfifo;
2329 static int fifo_list_size;
2330
2331 static void
2332 add_fifo_list (pathname)
2333      char *pathname;
2334 {
2335   if (nfifo >= fifo_list_size - 1)
2336     {
2337       fifo_list_size += FIFO_INCR;
2338       fifo_list = (char **)xrealloc (fifo_list,
2339                                      fifo_list_size * sizeof (char *));
2340     }
2341
2342   fifo_list[nfifo++] = savestring (pathname);
2343 }
2344
2345 void
2346 unlink_fifo_list ()
2347 {
2348   if (nfifo == 0)
2349     return;
2350
2351   while (nfifo--)
2352     {
2353       unlink (fifo_list[nfifo]);
2354       free (fifo_list[nfifo]);
2355       fifo_list[nfifo] = (char *)NULL;
2356     }
2357   nfifo = 0;
2358 }
2359
2360 static char *
2361 make_named_pipe ()
2362 {
2363   char *tname;
2364
2365   tname = mktemp (savestring ("/tmp/sh-np-XXXXXX"));
2366   if (mkfifo (tname, 0600) < 0)
2367     {
2368       free (tname);
2369       return ((char *)NULL);
2370     }
2371
2372   add_fifo_list (tname);
2373   return (tname);
2374 }
2375
2376 #else /* HAVE_DEV_FD */
2377
2378 /* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
2379    has open to children.  NFDS is a count of the number of bits currently
2380    set in DEV_FD_LIST.  TOTFDS is a count of the highest possible number
2381    of open files. */
2382 static char *dev_fd_list = (char *)NULL;
2383 static int nfds;
2384 static int totfds;      /* The highest possible number of open files. */
2385
2386 static void
2387 add_fifo_list (fd)
2388      int fd;
2389 {
2390   if (!dev_fd_list || fd >= totfds)
2391     {
2392       int ofds;
2393
2394       ofds = totfds;
2395       totfds = getdtablesize ();
2396       if (totfds < 0 || totfds > 256)
2397         totfds = 256;
2398       if (fd > totfds)
2399         totfds = fd + 2;
2400
2401       dev_fd_list = xrealloc (dev_fd_list, totfds);
2402       bzero (dev_fd_list + ofds, totfds - ofds);
2403     }
2404
2405   dev_fd_list[fd] = 1;
2406   nfds++;
2407 }
2408
2409 void
2410 unlink_fifo_list ()
2411 {
2412   register int i;
2413
2414   if (nfds == 0)
2415     return;
2416
2417   for (i = 0; nfds && i < totfds; i++)
2418     if (dev_fd_list[i])
2419       {
2420         close (i);
2421         dev_fd_list[i] = 0;
2422         nfds--;
2423       }
2424
2425   nfds = 0;
2426 }
2427
2428 #if defined (NOTDEF)
2429 print_dev_fd_list ()
2430 {
2431   register int i;
2432
2433   fprintf (stderr, "pid %d: dev_fd_list:", getpid ());
2434   fflush (stderr);
2435
2436   for (i = 0; i < totfds; i++)
2437     {
2438       if (dev_fd_list[i])
2439         fprintf (stderr, " %d", i);
2440     }
2441   fprintf (stderr, "\n");
2442 }
2443 #endif /* NOTDEF */
2444
2445 static char *
2446 make_dev_fd_filename (fd)
2447      int fd;
2448 {
2449   char *ret;
2450
2451   ret = xmalloc (sizeof (DEV_FD_PREFIX) + 4);
2452   sprintf (ret, "%s%d", DEV_FD_PREFIX, fd);
2453   add_fifo_list (fd);
2454   return (ret);
2455 }
2456
2457 #endif /* HAVE_DEV_FD */
2458
2459 /* Return a filename that will open a connection to the process defined by
2460    executing STRING.  HAVE_DEV_FD, if defined, means open a pipe and return
2461    a filename in /dev/fd corresponding to a descriptor that is one of the
2462    ends of the pipe.  If not defined, we use named pipes on systems that have
2463    them.  Systems without /dev/fd and named pipes are out of luck.
2464
2465    OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
2466    use the read end of the pipe and dup that file descriptor to fd 0 in
2467    the child.  If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
2468    writing or use the write end of the pipe in the child, and dup that
2469    file descriptor to fd 1 in the child.  The parent does the opposite. */
2470
2471 static char *
2472 process_substitute (string, open_for_read_in_child)
2473      char *string;
2474      int open_for_read_in_child;
2475 {
2476   char *pathname;
2477   int fd, result;
2478   pid_t old_pid, pid;
2479 #if defined (HAVE_DEV_FD)
2480   int parent_pipe_fd, child_pipe_fd;
2481   int fildes[2];
2482 #endif /* HAVE_DEV_FD */
2483 #if defined (JOB_CONTROL)
2484   pid_t old_pipeline_pgrp;
2485 #endif
2486
2487   if (!string || !*string)
2488     return ((char *)NULL);
2489
2490 #if !defined (HAVE_DEV_FD)
2491   pathname = make_named_pipe ();
2492 #else /* HAVE_DEV_FD */
2493   if (pipe (fildes) < 0)
2494     {
2495       sys_error ("cannot make pipe for process substitution");
2496       return ((char *)NULL);
2497     }
2498   /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
2499      the pipe in the parent, otherwise the read end. */
2500   parent_pipe_fd = fildes[open_for_read_in_child];
2501   child_pipe_fd = fildes[1 - open_for_read_in_child];
2502   /* Move the parent end of the pipe to some high file descriptor, to
2503      avoid clashes with FDs used by the script. */
2504   parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
2505
2506   pathname = make_dev_fd_filename (parent_pipe_fd);
2507 #endif /* HAVE_DEV_FD */
2508
2509   if (!pathname)
2510     {
2511       sys_error ("cannot make pipe for process substitution");
2512       return ((char *)NULL);
2513     }
2514
2515   old_pid = last_made_pid;
2516
2517 #if defined (JOB_CONTROL)
2518   old_pipeline_pgrp = pipeline_pgrp;
2519   pipeline_pgrp = shell_pgrp;
2520 #if 0
2521   cleanup_the_pipeline ();
2522 #else
2523   save_pipeline (1);
2524 #endif
2525 #endif /* JOB_CONTROL */
2526
2527   pid = make_child ((char *)NULL, 1);
2528   if (pid == 0)
2529     {
2530       reset_terminating_signals ();     /* XXX */
2531       /* Cancel traps, in trap.c. */
2532       restore_original_signals ();
2533       setup_async_signals ();
2534       subshell_environment = SUBSHELL_COMSUB;
2535     }
2536
2537 #if defined (JOB_CONTROL)
2538   set_sigchld_handler ();
2539   stop_making_children ();
2540   pipeline_pgrp = old_pipeline_pgrp;
2541 #endif /* JOB_CONTROL */
2542
2543   if (pid < 0)
2544     {
2545       sys_error ("cannot make child for process substitution");
2546       free (pathname);
2547 #if defined (HAVE_DEV_FD)
2548       close (parent_pipe_fd);
2549       close (child_pipe_fd);
2550 #endif /* HAVE_DEV_FD */
2551       return ((char *)NULL);
2552     }
2553
2554   if (pid > 0)
2555     {
2556 #if defined (JOB_CONTROL)
2557       restore_pipeline (1);
2558 #endif
2559
2560       last_made_pid = old_pid;
2561
2562 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
2563       close_pgrp_pipe ();
2564 #endif /* JOB_CONTROL && PGRP_PIPE */
2565
2566 #if defined (HAVE_DEV_FD)
2567       close (child_pipe_fd);
2568 #endif /* HAVE_DEV_FD */
2569
2570       return (pathname);
2571     }
2572
2573   set_sigint_handler ();
2574
2575 #if defined (JOB_CONTROL)
2576   set_job_control (0);
2577 #endif /* JOB_CONTROL */
2578
2579 #if !defined (HAVE_DEV_FD)
2580   /* Open the named pipe in the child. */
2581   fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY);
2582   if (fd < 0)
2583     {
2584       sys_error ("cannot open named pipe %s for %s", pathname,
2585         open_for_read_in_child ? "reading" : "writing");
2586       exit (127);
2587     }
2588 #else /* HAVE_DEV_FD */
2589   fd = child_pipe_fd;
2590 #endif /* HAVE_DEV_FD */
2591
2592   if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
2593     {
2594       sys_error ("cannot duplicate named pipe %s as fd %d", pathname,
2595         open_for_read_in_child ? 0 : 1);
2596       exit (127);
2597     }
2598
2599   close (fd);
2600
2601   /* Need to close any files that this process has open to pipes inherited
2602      from its parent. */
2603   if (current_fds_to_close)
2604     {
2605       close_fd_bitmap (current_fds_to_close);
2606       current_fds_to_close = (struct fd_bitmap *)NULL;
2607     }
2608
2609 #if defined (HAVE_DEV_FD)
2610   /* Make sure we close the parent's end of the pipe and clear the slot
2611      in the fd list so it is not closed later, if reallocated by, for
2612      instance, pipe(2). */
2613   close (parent_pipe_fd);
2614   dev_fd_list[parent_pipe_fd] = 0;
2615 #endif /* HAVE_DEV_FD */
2616
2617   result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
2618
2619 #if !defined (HAVE_DEV_FD)
2620   /* Make sure we close the named pipe in the child before we exit. */
2621   close (open_for_read_in_child ? 0 : 1);
2622 #endif /* !HAVE_DEV_FD */
2623
2624   exit (result);
2625   /*NOTREACHED*/
2626 }
2627 #endif /* PROCESS_SUBSTITUTION */
2628
2629 static char *
2630 read_comsub (fd, quoted)
2631      int fd, quoted;
2632 {
2633   char *istring, buf[128], *bufp;
2634   int bufn, istring_index, istring_size, c;
2635
2636   istring = (char *)NULL;
2637   istring_index = istring_size = bufn = 0;
2638
2639   /* Read the output of the command through the pipe. */
2640   while (1)
2641     {
2642       if (fd < 0)
2643         break;
2644       if (--bufn <= 0)
2645         {
2646           while ((bufn = read (fd, buf, sizeof(buf))) < 0 && errno == EINTR)
2647             ;
2648           if (bufn <= 0) 
2649             break;
2650           bufp = buf;
2651         }
2652       c = *bufp++;
2653
2654       /* Add the character to ISTRING, possibly after resizing it. */
2655       RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
2656
2657       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL)
2658         istring[istring_index++] = CTLESC;
2659
2660       istring[istring_index++] = c;
2661     }
2662
2663   if (istring)
2664     istring[istring_index] = '\0';
2665
2666   /* If we read no output, just return now and save ourselves some
2667      trouble. */
2668   if (istring_index == 0)
2669     {
2670       FREE (istring);
2671       return (char *)NULL;
2672     }
2673
2674   /* Strip trailing newlines from the output of the command. */
2675   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
2676     {
2677       while (istring_index > 0)
2678         {
2679           if (istring[istring_index - 1] == '\n')
2680             {
2681               --istring_index;
2682
2683               /* If the newline was quoted, remove the quoting char. */
2684               if (istring[istring_index - 1] == CTLESC)
2685                 --istring_index;
2686             }
2687           else
2688             break;
2689         }
2690       istring[istring_index] = '\0';
2691     }
2692   else
2693     strip_trailing (istring, istring_index - 1, 1);
2694
2695   return istring;
2696 }
2697
2698 /* Perform command substitution on STRING.  This returns a string,
2699    possibly quoted. */
2700 static char *
2701 command_substitute (string, quoted)
2702      char *string;
2703      int quoted;
2704 {
2705   pid_t pid, old_pid, old_pipeline_pgrp;
2706   char *istring;
2707   int result, fildes[2];
2708
2709   istring = (char *)NULL;
2710
2711   /* Don't fork () if there is no need to.  In the case of no command to
2712      run, just return NULL. */
2713   if (!string || !*string || (string[0] == '\n' && !string[1]))
2714     return ((char *)NULL);
2715
2716   /* Pipe the output of executing STRING into the current shell. */
2717   if (pipe (fildes) < 0)
2718     {
2719       sys_error ("cannot make pipes for command substitution");
2720       goto error_exit;
2721     }
2722
2723   old_pid = last_made_pid;
2724 #if defined (JOB_CONTROL)
2725   old_pipeline_pgrp = pipeline_pgrp;
2726   pipeline_pgrp = shell_pgrp;
2727   cleanup_the_pipeline ();
2728 #endif
2729
2730   pid = make_child ((char *)NULL, 0);
2731   if (pid == 0)
2732     /* Reset the signal handlers in the child, but don't free the
2733        trap strings. */
2734     reset_signal_handlers ();
2735
2736 #if defined (JOB_CONTROL)
2737   set_sigchld_handler ();
2738   stop_making_children ();
2739   pipeline_pgrp = old_pipeline_pgrp;
2740 #endif /* JOB_CONTROL */
2741
2742   if (pid < 0)
2743     {
2744       sys_error ("cannot make child for command substitution");
2745     error_exit:
2746
2747       FREE (istring);
2748       close (fildes[0]);
2749       close (fildes[1]);
2750       return ((char *)NULL);
2751     }
2752
2753   if (pid == 0)
2754     {
2755       set_sigint_handler ();    /* XXX */
2756 #if defined (JOB_CONTROL)
2757       set_job_control (0);
2758 #endif
2759       if (dup2 (fildes[1], 1) < 0)
2760         {
2761           sys_error ("command_substitute: cannot duplicate pipe as fd 1");
2762           exit (EXECUTION_FAILURE);
2763         }
2764
2765       /* If standard output is closed in the parent shell
2766          (such as after `exec >&-'), file descriptor 1 will be
2767          the lowest available file descriptor, and end up in
2768          fildes[0].  This can happen for stdin and stderr as well,
2769          but stdout is more important -- it will cause no output
2770          to be generated from this command. */
2771       if ((fildes[1] != fileno (stdin)) &&
2772           (fildes[1] != fileno (stdout)) &&
2773           (fildes[1] != fileno (stderr)))
2774         close (fildes[1]);
2775
2776       if ((fildes[0] != fileno (stdin)) &&
2777           (fildes[0] != fileno (stdout)) &&
2778           (fildes[0] != fileno (stderr)))
2779         close (fildes[0]);
2780
2781       /* The currently executing shell is not interactive. */
2782       interactive = 0;
2783
2784       /* This is a subshell environment. */
2785       subshell_environment = SUBSHELL_COMSUB;
2786
2787       /* Command substitution does not inherit the -e flag. */
2788       exit_immediately_on_error = 0;
2789
2790       remove_quoted_escapes (string);
2791
2792       startup_state = 2;        /* see if we can avoid a fork */
2793       /* Give command substitution a place to jump back to on failure,
2794          so we don't go back up to main (). */
2795       result = setjmp (top_level);
2796
2797       if (result == EXITPROG)
2798         exit (last_command_exit_value);
2799       else if (result)
2800         exit (EXECUTION_FAILURE);
2801       else
2802         exit (parse_and_execute (string, "command substitution", SEVAL_NOHIST));
2803     }
2804   else
2805     {
2806 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
2807       close_pgrp_pipe ();
2808 #endif /* JOB_CONTROL && PGRP_PIPE */
2809
2810       close (fildes[1]);
2811
2812       istring = read_comsub (fildes[0], quoted);
2813
2814       close (fildes[0]);
2815
2816       last_command_exit_value = wait_for (pid);
2817       last_command_subst_pid = pid;
2818       last_made_pid = old_pid;
2819
2820 #if defined (JOB_CONTROL)
2821       /* If last_command_exit_value > 128, then the substituted command
2822          was terminated by a signal.  If that signal was SIGINT, then send
2823          SIGINT to ourselves.  This will break out of loops, for instance. */
2824       if (last_command_exit_value == (128 + SIGINT))
2825         kill (getpid (), SIGINT);
2826
2827       /* wait_for gives the terminal back to shell_pgrp.  If some other
2828          process group should have it, give it away to that group here. */
2829       if (interactive && pipeline_pgrp != (pid_t)0)
2830         give_terminal_to (pipeline_pgrp);
2831 #endif /* JOB_CONTROL */
2832
2833       return (istring);
2834     }
2835 }
2836
2837 /********************************************************
2838  *                                                      *
2839  *      Utility functions for parameter expansion       *
2840  *                                                      *
2841  ********************************************************/
2842
2843 static int
2844 getpatspec (c, value)
2845      int c;
2846      char *value;
2847 {
2848   if (c == '#')
2849     return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
2850   else  /* c == '%' */
2851     return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
2852 }
2853
2854 /* Posix.2 says that the WORD should be run through tilde expansion,
2855    parameter expansion, command substitution and arithmetic expansion.
2856    This leaves the result quoted, so quote_string_for_globbing () has
2857    to be called to fix it up for fnmatch ().  If QUOTED is non-zero,
2858    it means that the entire expression was enclosed in double quotes.
2859    This means that quoting characters in the pattern do not make any
2860    special pattern characters quoted.  For example, the `*' in the
2861    following retains its special meaning: "${foo#'*'}". */
2862 static char *
2863 getpattern (value, quoted, expandpat)
2864      char *value;
2865      int quoted, expandpat;
2866 {
2867   char *pat, *tword;
2868   WORD_LIST *l;
2869   int i;
2870
2871   tword = strchr (value, '~') ? bash_tilde_expand (value) : savestring (value);
2872
2873   /* expand_string_internal () leaves WORD quoted and does not perform
2874      word splitting. */
2875   if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
2876     {
2877       i = 0;
2878       pat = string_extract_double_quoted (tword, &i, 1);
2879       free (tword);
2880       tword = pat;
2881     }
2882
2883   /* There is a problem here:  how to handle single or double quotes in the
2884      pattern string when the whole expression is between double quotes? */
2885 #if 0
2886   l = *tword ? expand_string_for_rhs (tword, quoted, (int *)NULL, (int *)NULL)
2887 #else
2888   l = *tword ? expand_string_for_rhs (tword,
2889                                       (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_NOQUOTE : quoted,
2890                                       (int *)NULL, (int *)NULL)
2891 #endif
2892              : (WORD_LIST *)0;
2893   free (tword);
2894   pat = string_list (l);
2895   dispose_words (l);
2896   if (pat)
2897     {
2898       tword = quote_string_for_globbing (pat, 1);
2899       free (pat);
2900       pat = tword;
2901     }
2902   return (pat);
2903 }
2904
2905 /* Handle removing a pattern from a string as a result of ${name%[%]value}
2906    or ${name#[#]value}. */
2907 static char *
2908 parameter_brace_remove_pattern (value, temp, c, quoted)
2909      char *value, *temp;
2910      int c, quoted;
2911 {
2912   int patspec;
2913   char *pattern, *tword;
2914
2915   patspec = getpatspec (c, value);
2916   if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
2917     value++;
2918
2919   pattern = getpattern (value, quoted, 1);
2920
2921   tword = remove_pattern (temp, pattern, patspec);
2922
2923   FREE (pattern);
2924   return (tword);
2925 }
2926
2927 static char *
2928 list_remove_pattern (list, pattern, patspec, type, quoted)
2929      WORD_LIST *list;
2930      char *pattern;
2931      int patspec, type, quoted;
2932 {
2933   WORD_LIST *new, *l;
2934   WORD_DESC *w;
2935   char *tword;
2936
2937   for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
2938     {
2939       tword = remove_pattern (l->word->word, pattern, patspec);
2940       w = make_bare_word (tword);
2941       free (tword);
2942       new = make_word_list (w, new);
2943     }
2944
2945   l = REVERSE_LIST (new, WORD_LIST *);
2946   if (type == '*')
2947     tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l);
2948   else
2949     tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l);
2950
2951   dispose_words (l);
2952   return (tword);
2953 }
2954
2955 static char *
2956 parameter_list_remove_pattern (value, type, c, quoted)
2957      char *value;
2958      int type, c, quoted;
2959 {
2960   int patspec;
2961   char *pattern, *ret;
2962   WORD_LIST *list;
2963
2964   patspec = getpatspec (c, value);
2965   if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
2966     value++;
2967
2968   pattern = getpattern (value, quoted, 1);
2969
2970   list = list_rest_of_args ();
2971   ret = list_remove_pattern (list, pattern, patspec, type, quoted);
2972   dispose_words (list);
2973   FREE (pattern);
2974   return (ret);
2975 }
2976
2977 #if defined (ARRAY_VARS)
2978 static char *
2979 array_remove_pattern (value, aspec, aval, c, quoted)
2980      char *value, *aspec, *aval;        /* AVAL == evaluated ASPEC */
2981      int c, quoted;
2982 {
2983   SHELL_VAR *var;
2984   int len, patspec;
2985 #if 0
2986   int ind;
2987 #endif
2988   char *ret, *t, *pattern;
2989   WORD_LIST *l;
2990
2991   var = array_variable_part (aspec, &t, &len);
2992   if (var == 0)
2993     return ((char *)NULL);
2994
2995   patspec = getpatspec (c, value);
2996   if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
2997     value++;
2998
2999   pattern = getpattern (value, quoted, 1);
3000
3001   if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
3002     {
3003       if (array_p (var) == 0)
3004         {
3005           report_error ("%s: bad array subscript", aspec);
3006           FREE (pattern);
3007           return ((char *)NULL);
3008         }
3009       l = array_to_word_list (array_cell (var));
3010       if (l == 0)
3011         return ((char *)NULL);
3012       ret = list_remove_pattern (l, pattern, patspec, t[0], quoted);
3013       dispose_words (l);
3014     }
3015   else
3016     {
3017 #if 0
3018       ind = array_expand_index (t, len);
3019       if (ind < 0)
3020         {
3021           report_error ("%s: bad array subscript", aspec);
3022           FREE (pattern);
3023           return ((char *)NULL);
3024         }
3025       if (array_p (var) == 0 && ind != 0)
3026         return ((char *)NULL);
3027
3028       t = array_p (var) ? array_reference (array_cell (var), ind) : value_cell (var);
3029       ret = remove_pattern (t, pattern, patspec);
3030 #else
3031       ret = remove_pattern (aval, pattern, patspec);
3032 #endif
3033       if (ret)
3034         {
3035           t = quote_escapes (ret);
3036           free (ret);
3037           ret = t;
3038         }
3039     }
3040
3041   FREE (pattern);
3042   return ret;
3043 }
3044
3045 int
3046 valid_array_reference (name)
3047      char *name;
3048 {
3049   char *t;
3050   int r, len;
3051
3052   t = strchr (name, '[');
3053   if (t)
3054     {
3055       *t = '\0';
3056       r = legal_identifier (name);
3057       *t = '[';
3058       if (r == 0)
3059         return 0;
3060       /* Check for a properly-terminated non-blank subscript. */
3061       len = skipsubscript (t, 0);
3062       if (t[len] != ']' || len == 1)
3063         return 0;
3064       for (r = 1; r < len; r++)
3065         if (whitespace (t[r]) == 0)
3066           return 1;
3067       return 0;
3068     }
3069   return 0;
3070 }
3071
3072 /* Expand the array index beginning at S and extending LEN characters. */
3073 int
3074 array_expand_index (s, len)
3075      char *s;
3076      int len;
3077 {
3078   char *exp, *t;
3079   int val, expok;
3080
3081   exp = xmalloc (len);
3082   strncpy (exp, s, len - 1);
3083   exp[len - 1] = '\0';
3084   t = maybe_expand_string (exp, 0, expand_string);
3085   this_command_name = (char *)NULL;
3086   val = evalexp (t, &expok);
3087   free (t);
3088   free (exp);
3089   if (expok == 0)
3090     jump_to_top_level (DISCARD);
3091   return val;
3092 }
3093
3094 /* Return the variable specified by S without any subscript.  If non-null,
3095    return the index of the start of the subscript in *SUBP.  If non-null,
3096    the length of the subscript is returned in *LENP. */
3097 SHELL_VAR *
3098 array_variable_part (s, subp, lenp)
3099      char *s, **subp;
3100      int *lenp;
3101 {
3102   char *t;
3103   int ind, ni;
3104   SHELL_VAR *var;
3105
3106   t = strchr (s, '[');
3107   ind = t - s;
3108   ni = skipsubscript (s, ind);
3109   if (ni <= ind + 1 || s[ni] != ']')
3110     {
3111       report_error ("%s: bad array subscript", s);
3112       return ((SHELL_VAR *)NULL);
3113     }
3114
3115   *t = '\0';
3116   var = find_variable (s);
3117   *t++ = '[';
3118
3119   if (subp)
3120     *subp = t;
3121   if (lenp)
3122     *lenp = ni - ind;
3123   return var;
3124 }
3125
3126 static char *
3127 array_value_internal (s, quoted, allow_all)
3128      char *s;
3129      int quoted, allow_all;
3130 {
3131   int len, ind;
3132   char *retval, *t;
3133   WORD_LIST *l;
3134   SHELL_VAR *var;
3135
3136   var = array_variable_part (s, &t, &len);
3137
3138   if (var == 0)
3139     return (char *)NULL;
3140
3141   if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
3142     {
3143       if (array_p (var) == 0 || allow_all == 0)
3144         {
3145           report_error ("%s: bad array subscript", s);
3146           return ((char *)NULL);
3147         }
3148       l = array_to_word_list (array_cell (var));
3149       if (l == (WORD_LIST *)NULL)
3150         return ((char *) NULL);
3151
3152       if (t[0] == '*')          /* ${name[*]} */
3153         retval = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l);
3154       else                      /* ${name[@]} */
3155         retval = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l);
3156
3157       dispose_words (l);
3158     }
3159   else
3160     {
3161       ind = array_expand_index (t, len);
3162       if (ind < 0)
3163         {
3164           report_error ("%s: bad array subscript", var->name);
3165           return ((char *)NULL);
3166         }
3167       if (array_p (var) == 0)
3168         return (ind == 0 ? savestring (value_cell (var)) : (char *)NULL);
3169       retval = array_reference (array_cell (var), ind);
3170       if (retval)
3171         retval = quote_escapes (retval);
3172     }
3173
3174   return retval;
3175 }
3176
3177 static char *
3178 array_value (s, quoted)
3179      char *s;
3180      int quoted;
3181 {
3182   return (array_value_internal (s, quoted, 1));
3183 }
3184
3185 /* Return the value of the array indexing expression S as a single string.
3186    If ALLOW_ALL is 0, do not allow `@' and `*' subscripts.  This is used
3187    by other parts of the shell such as the arithmetic expression evaluator
3188    in expr.c. */
3189 char *
3190 get_array_value (s, allow_all)
3191      char *s;
3192      int allow_all;
3193 {
3194   return (array_value_internal (s, 0, allow_all));
3195 }
3196
3197 static int
3198 array_length_reference (s)
3199      char *s;
3200 {
3201   int ind, len;
3202   char *t;
3203   ARRAY *array;
3204   SHELL_VAR *var;
3205
3206   var = array_variable_part (s, &t, &len);
3207
3208   /* If unbound variables should generate an error, report one and return
3209      failure. */
3210   if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error)
3211     {
3212       ind = *--t;
3213       *t = '\0';
3214       report_error ("%s: unbound variable", s);
3215       *t++ = (char)ind;
3216       return (-1);
3217     }
3218   else if (var == 0)
3219     return 0;
3220   else if (array_p (var) == 0)
3221     return 1;
3222
3223   array = array_cell (var);
3224
3225   if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
3226     return (array_num_elements (array));
3227
3228   ind = array_expand_index (t, len);
3229   if (ind < 0)
3230     {
3231       report_error ("%s: bad array subscript", t);
3232       return (-1);
3233     }
3234   t = array_reference (array, ind);
3235   len = STRLEN (t);
3236
3237   return (len);
3238 }
3239 #endif /* ARRAY_VARS */
3240
3241 static int
3242 valid_brace_expansion_word (name, var_is_special)
3243      char *name;
3244      int var_is_special;
3245 {
3246   if (digit (*name) && all_digits (name))
3247     return 1;
3248   else if (var_is_special)
3249     return 1;
3250 #if defined (ARRAY_VARS)
3251   else if (valid_array_reference (name))
3252     return 1;
3253 #endif /* ARRAY_VARS */
3254   else if (legal_identifier (name))
3255     return 1;
3256   else
3257     return 0;
3258 }
3259
3260 /* Parameter expand NAME, and return a new string which is the expansion,
3261    or NULL if there was no expansion.
3262    VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
3263    the shell, e.g., "@", "$", "*", etc.  QUOTED, if non-zero, means that
3264    NAME was found inside of a double-quoted expression. */
3265 static char *
3266 parameter_brace_expand_word (name, var_is_special, quoted)
3267      char *name;
3268      int var_is_special, quoted;
3269 {
3270   char *temp, *tt;
3271   int arg_index;
3272   SHELL_VAR *var;
3273   WORD_LIST *l;
3274
3275   /* Handle multiple digit arguments, as in ${11}. */
3276   if (digit (*name))
3277     {
3278       arg_index = atoi (name);
3279       temp = get_dollar_var_value (arg_index);
3280     }
3281   else if (var_is_special)      /* ${@} */
3282     {
3283       tt = xmalloc (2 + strlen (name));
3284       tt[0] = '$';
3285       strcpy (tt + 1, name);
3286       l = expand_string_leave_quoted (tt, quoted);
3287       free (tt);
3288       temp = string_list (l);
3289       dispose_words (l);
3290     }
3291 #if defined (ARRAY_VARS)
3292   else if (valid_array_reference (name))
3293     {
3294       temp = array_value (name, quoted);
3295     }
3296 #endif
3297   else if (var = find_variable (name))
3298     {
3299       if (var && invisible_p (var) == 0)
3300         {
3301 #if defined (ARRAY_VARS)
3302           temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var);
3303 #else
3304           temp = value_cell (var);
3305 #endif
3306
3307           if (temp)
3308             temp = quote_escapes (temp);
3309         }
3310       else
3311         temp = (char *)NULL;
3312     }
3313   else
3314     temp = (char *)NULL;
3315
3316   return (temp);
3317 }
3318
3319 /* Expand an indirect reference to a variable: ${!NAME} expands to the
3320    value of the variable whose name is the value of NAME. */
3321 static char *
3322 parameter_brace_expand_indir (name, var_is_special, quoted)
3323      char *name;
3324      int var_is_special, quoted;
3325 {
3326   char *temp, *t;
3327
3328   t = parameter_brace_expand_word (name, var_is_special, quoted);
3329   if (t == 0)
3330     return (t);
3331   temp = parameter_brace_expand_word (t, t[0] == '@' && t[1] == '\0', quoted);
3332   free (t);
3333   return temp;
3334 }
3335
3336 /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
3337    depending on the value of C, the separating character.  C can be one of
3338    "-", "+", or "=".  QUOTED is true if the entire brace expression occurs
3339    between double quotes. */
3340 static char *
3341 parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
3342      char *name, *value;
3343      int c, quoted, *qdollaratp, *hasdollarat;
3344 {
3345   WORD_LIST *l;
3346   char *t, *t1, *temp;
3347   int hasdol;
3348
3349   temp = (*value == '~' || (strchr (value, '~') && unquoted_substring ("=~", value)))
3350         ? bash_tilde_expand (value)
3351         : savestring (value);
3352
3353   /* If the entire expression is between double quotes, we want to treat
3354      the value as a double-quoted string, with the exception that we strip
3355      embedded unescaped double quotes. */
3356   if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *temp)
3357     {
3358       hasdol = 0;
3359       t = string_extract_double_quoted (temp, &hasdol, 1);
3360       free (temp);
3361       temp = t;
3362     }
3363
3364   hasdol = 0;
3365   /* XXX was 0 not quoted */
3366   l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL)
3367             : (WORD_LIST *)0;
3368   if (hasdollarat)
3369     *hasdollarat = hasdol || (l && l->next);
3370   free (temp);
3371   if (l)
3372     {
3373       /* The expansion of TEMP returned something.  We need to treat things
3374           slightly differently if HASDOL is non-zero. */
3375       temp = string_list (l);
3376       /* If l->next is not null, we know that TEMP contained "$@", since that
3377          is the only expansion that creates more than one word. */
3378       if ((hasdol && quoted) || l->next)
3379         *qdollaratp = 1;
3380       dispose_words (l);
3381     }
3382   else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol)
3383     {
3384       /* The brace expansion occurred between double quotes and there was
3385          a $@ in TEMP.  It does not matter if the $@ is quoted, as long as
3386          it does not expand to anything.  In this case, we want to return
3387          a quoted empty string. */
3388       temp = xmalloc (2);
3389       temp[0] = CTLNUL;
3390       temp[1] = '\0';
3391     }
3392   else
3393     temp = (char *)NULL;
3394
3395   if (c == '-' || c == '+')
3396     return (temp);
3397
3398   /* c == '=' */
3399   t = temp ? savestring (temp) : savestring ("");
3400   t1 = dequote_string (t);
3401   free (t);
3402   bind_variable (name, t1);
3403   free (t1);
3404   return (temp);
3405 }
3406
3407 /* Deal with the right hand side of a ${name:?value} expansion in the case
3408    that NAME is null or not set.  If VALUE is non-null it is expanded and
3409    used as the error message to print, otherwise a standard message is
3410    printed. */
3411 static void
3412 parameter_brace_expand_error (name, value)
3413      char *name, *value;
3414 {
3415   WORD_LIST *l;
3416   char *temp;
3417
3418   if (value && *value)
3419     {
3420       l = expand_string (value, 0);
3421       temp =  string_list (l);
3422       report_error ("%s: %s", name, temp ? temp : "");  /* XXX was value not "" */
3423       FREE (temp);
3424       dispose_words (l);
3425     }
3426   else
3427     report_error ("%s: parameter null or not set", name);
3428
3429   /* Free the data we have allocated during this expansion, since we
3430      are about to longjmp out. */
3431   free (name);
3432   FREE (value);
3433 }
3434
3435 /* Return 1 if NAME is something for which parameter_brace_expand_length is
3436    OK to do. */
3437 static int
3438 valid_length_expression (name)
3439      char *name;
3440 {
3441   return (!name[1] ||                                           /* ${#} */
3442           ((name[1] == '@' || name[1] == '*') && !name[2]) ||   /* ${#@}, ${#*} */
3443           (digit (name[1]) && all_digits (name + 1)) ||         /* ${#11} */
3444 #if defined (ARRAY_VARS)
3445           valid_array_reference (name + 1) ||                   /* ${#a[7]} */
3446 #endif
3447           legal_identifier (name + 1));                         /* ${#PS1} */
3448 }
3449
3450 /* Handle the parameter brace expansion that requires us to return the
3451    length of a parameter. */
3452 static int
3453 parameter_brace_expand_length (name)
3454      char *name;
3455 {
3456   char *t, *newname;
3457   int number;
3458   WORD_LIST *list;
3459 #if defined (ARRAY_VARS)
3460   SHELL_VAR *var;
3461 #endif
3462
3463   if (name[1] == '\0')                  /* ${#} */
3464     number = number_of_args ();
3465 #if defined (ARRAY_VARS)
3466   else if (valid_array_reference (name + 1))
3467     number = array_length_reference (name + 1);
3468 #endif /* ARRAY_VARS */
3469   else if (name[1] != '*' && name[1] != '@')
3470     {
3471       number = 0;
3472
3473       if (digit (name[1]))              /* ${#1} */
3474         {
3475           t = get_dollar_var_value (atoi (name + 1));
3476           number = STRLEN (t);
3477           FREE (t);
3478         }
3479 #if defined (ARRAY_VARS)
3480       else if ((var = find_variable (name + 1)) && array_p (var))
3481         {
3482           t = array_reference (array_cell (var), 0);
3483           number = STRLEN (t);
3484         }
3485 #endif
3486       else                              /* ${#PS1} */
3487         {
3488           newname = savestring (name);
3489           newname[0] = '$';
3490           list = expand_string (newname, Q_DOUBLE_QUOTES);
3491           t = list ? string_list (list) : (char *)NULL;
3492           free (newname);
3493           if (list)
3494             dispose_words (list);
3495
3496           number = STRLEN (t);
3497           FREE (t);
3498         }
3499     }
3500   else                                  /* ${#@} and ${#*} */
3501     number = number_of_args ();
3502
3503   return (number);
3504 }
3505
3506 /* Verify and limit the start and end of the desired substring.  If
3507    VTYPE == 0, a regular shell variable is being used; if it is 1,
3508    then the positional paramters are being used; if it is 2, then
3509    VALUE is really a pointer to an array variable that should be used. */
3510 static int
3511 verify_substring_values (value, substr, vtype, e1p, e2p)
3512      char *value, *substr;
3513      int vtype, *e1p, *e2p;
3514 {
3515   char *t, *temp1;
3516   int len, expok;
3517 #if defined (ARRAY_VARS)
3518  ARRAY *a;
3519 #endif
3520
3521   t = strchr (substr, ':');
3522   if (t)
3523     *t = '\0';
3524   temp1 = maybe_expand_string (substr, Q_DOUBLE_QUOTES, expand_string);
3525   *e1p = evalexp (temp1, &expok);
3526   free (temp1);
3527   if (expok == 0)
3528     return (0);
3529
3530   switch (vtype)
3531     {
3532     case VT_VARIABLE:
3533     case VT_ARRAYMEMBER:
3534       len = strlen (value);
3535       break;
3536     case VT_POSPARMS:
3537       len = number_of_args () + 1;
3538       break;
3539 #if defined (ARRAY_VARS)
3540     case VT_ARRAYVAR:
3541       a = (ARRAY *)value;
3542       len = array_num_elements (a) + 1;
3543       break;
3544 #endif
3545     }
3546
3547   if (*e1p < 0)         /* negative offsets count from end */
3548     *e1p += len;
3549
3550   if (*e1p >= len || *e1p < 0)
3551     return (0);
3552
3553   if (t)
3554     {
3555       t++;
3556       temp1 = maybe_expand_string (t, Q_DOUBLE_QUOTES, expand_string);
3557       t[-1] = ':';
3558       *e2p = evalexp (temp1, &expok);
3559       free (temp1);
3560       if (expok == 0)
3561         return (0);
3562       if (*e2p < 0)
3563         {
3564           internal_error ("%s: substring expression < 0", t);
3565           return (0);
3566         }
3567       *e2p += *e1p;             /* want E2 chars starting at E1 */
3568       if (*e2p > len)
3569         *e2p = len;
3570     }
3571   else
3572     *e2p = len;
3573
3574   return (1);
3575 }
3576
3577 /* Return a string containing the positional parameters from START to
3578    END, inclusive.  If STRING[0] == '*', we obey the rules for $*,
3579    which only makes a difference if QUOTED is non-zero. */
3580 static char *
3581 pos_params (string, start, end, quoted)
3582      char *string;
3583      int start, end, quoted;
3584 {
3585   WORD_LIST *save, *params, *h, *t;
3586   char *ret;
3587   int i;
3588
3589   save = params = list_rest_of_args ();
3590   if (save == 0)
3591     return ((char *)NULL);
3592
3593   for (i = 1; params && i < start; i++)
3594     params = params->next;
3595   if (params == 0)
3596     return ((char *)NULL);
3597   for (h = t = params; params && i < end; i++)
3598     {
3599       t = params;
3600       params = params->next;
3601     }
3602
3603   t->next = (WORD_LIST *)NULL;
3604   if (string[0] == '*')
3605     ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (h) : string_list (h);
3606   else
3607     ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h);
3608   t->next = params;
3609
3610   dispose_words (save);
3611   return (ret);
3612 }
3613
3614 /* Return the type of variable specified by VARNAME (simple variable,
3615    positional param, or array variable.  Also return the value specified
3616    by VARNAME (value of a variable or a reference to an array element). */
3617 static int
3618 get_var_and_type (varname, value, varp, valp)
3619      char *varname, *value;
3620      SHELL_VAR **varp;
3621      char **valp;
3622 {
3623   int vtype;
3624   char *temp;
3625 #if defined (ARRAY_VARS)
3626   SHELL_VAR *v;
3627 #endif
3628
3629   vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0';       /* VT_POSPARMS */
3630   *varp = (SHELL_VAR *)NULL;
3631
3632 #if defined (ARRAY_VARS)
3633   if (valid_array_reference (varname))
3634     {
3635       v = array_variable_part (varname, &temp, (int *)0);
3636       if (v && array_p (v))
3637         {
3638           if ((temp[0] == '@' || temp[0] == '*') && temp[1] == ']')
3639             {
3640               vtype = VT_ARRAYVAR;
3641               *valp = (char *)array_cell (v);
3642             }
3643           else
3644             {
3645               vtype = VT_ARRAYMEMBER;
3646               *valp = array_value (varname, 1);
3647             }
3648           *varp = v;
3649         }
3650       else
3651         return -1;
3652     }
3653   else if ((v = find_variable (varname)) && array_p (v))
3654     {
3655       vtype = VT_VARIABLE;
3656       *varp = v;
3657       *valp = array_reference (array_cell (v), 0);
3658     }
3659   else
3660 #endif
3661   *valp = value;
3662
3663   return vtype;
3664 }
3665
3666 /* Process a variable substring expansion: ${name:e1[:e2]}.  If VARNAME
3667    is `@', use the positional parameters; otherwise, use the value of
3668    VARNAME.  If VARNAME is an array variable, use the array elements. */
3669
3670 static char *
3671 parameter_brace_substring (varname, value, substr, quoted)
3672      char *varname, *value, *substr;
3673      int quoted;
3674 {
3675   int e1, e2, vtype;
3676   char *temp, *val;
3677   SHELL_VAR *v;
3678
3679   if (value == 0)
3680     return ((char *)NULL);
3681
3682   this_command_name = varname;
3683
3684   vtype = get_var_and_type (varname, value, &v, &val);
3685   if (vtype == -1)
3686     return ((char *)NULL);
3687
3688   if (verify_substring_values (val, substr, vtype, &e1, &e2) == 0)
3689     {
3690       if (val && vtype == VT_ARRAYMEMBER)
3691         free (val);
3692       return (&expand_param_error);
3693     }
3694
3695   switch (vtype)
3696     {
3697     case VT_VARIABLE:
3698     case VT_ARRAYMEMBER:
3699       temp = quoted ? quoted_substring (value, e1, e2) : substring (value, e1, e2);
3700       break;
3701     case VT_POSPARMS:
3702       temp = pos_params (varname, e1, e2, quoted);
3703       break;
3704 #if defined (ARRAY_VARS)
3705     case VT_ARRAYVAR:
3706       temp = array_subrange (array_cell (v), e1, e2, quoted);
3707       break;
3708 #endif
3709     }
3710
3711   return temp;
3712 }
3713
3714 char *
3715 pat_subst (string, pat, rep, mflags)
3716      char *string, *pat, *rep;
3717      int mflags;
3718 {
3719   char *ret, *s, *e, *str;
3720   int rsize, rptr, l, replen, mtype;
3721
3722   ret = xmalloc (rsize = 64);
3723   ret[0] = '\0';
3724
3725   mtype = mflags & MATCH_TYPEMASK;
3726
3727   for (replen = STRLEN (rep), rptr = 0, str = string;;)
3728     {
3729       if (match_pattern (str, pat, mtype, &s, &e) == 0)
3730         break;
3731       l = s - str;
3732       RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64);
3733
3734       /* OK, now copy the leading unmatched portion of the string (from
3735          str to s) to ret starting at rptr (the current offset).  Then copy
3736          the replacement string at ret + rptr + (s - str).  Increment
3737          rptr (if necessary) and str and go on. */
3738       if (l)
3739         {
3740           strncpy (ret + rptr, str, l);
3741           rptr += l;
3742         }
3743       if (replen)
3744         {
3745           strncpy (ret + rptr, rep, replen);
3746           rptr += replen;
3747         }
3748       str = e;          /* e == end of match */
3749       if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
3750         break;
3751     }
3752
3753   /* Now copy the unmatched portion of the input string */
3754   if (*str)
3755     {
3756       RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
3757       strcpy (ret + rptr, str);
3758     }
3759   else
3760     ret[rptr] = '\0';
3761
3762   return ret;
3763 }
3764
3765 /* Do pattern match and replacement on the positional parameters. */
3766 static char *
3767 pos_params_pat_subst (string, pat, rep, mflags)
3768      char *string, *pat, *rep;
3769      int mflags;
3770 {
3771   WORD_LIST *save, *params;
3772   WORD_DESC *w;
3773   char *ret;
3774
3775   save = params = list_rest_of_args ();
3776   if (save == 0)
3777     return ((char *)NULL);
3778
3779   for ( ; params; params = params->next)
3780     {
3781       ret = pat_subst (params->word->word, pat, rep, mflags);
3782       w = make_bare_word (ret);
3783       dispose_word (params->word);
3784       params->word = w;
3785       FREE (ret);
3786     }
3787
3788   ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save);
3789   dispose_words (save);
3790
3791   return (ret);
3792 }
3793
3794 static char *
3795 parameter_brace_patsub (varname, value, patsub, quoted)
3796      char *varname, *value, *patsub;
3797      int quoted;
3798 {
3799   int vtype, mflags;
3800   char *val, *temp, *pat, *rep, *p;
3801   SHELL_VAR *v;
3802
3803   if (value == 0)
3804     return ((char *)NULL);
3805
3806   this_command_name = varname;
3807
3808   vtype = get_var_and_type (varname, value, &v, &val);
3809   if (vtype == -1)
3810     return ((char *)NULL);
3811
3812   mflags = 0;
3813   if (*patsub == '/')
3814     {
3815       mflags |= MATCH_GLOBREP;
3816       patsub++;
3817     }
3818
3819   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
3820     mflags |= MATCH_QUOTED;
3821
3822   if (rep = quoted_strchr (patsub, '/', ST_BACKSL))
3823     *rep++ = '\0';
3824   else
3825     rep = (char *)NULL;
3826
3827   if (rep && *rep == '\0')
3828     rep = (char *)NULL;
3829
3830   /* Expand PAT and REP for command, variable and parameter, arithmetic,
3831      and process substitution.  Also perform quote removal.  Do not
3832      perform word splitting or filename generation. */
3833   pat = maybe_expand_string (patsub, quoted, expand_string_unsplit);
3834   if (rep)
3835     {
3836       if ((mflags & MATCH_QUOTED) == 0)
3837         rep = maybe_expand_string (rep, quoted, expand_string_unsplit);
3838       else
3839         rep = expand_string_to_string (rep, quoted, expand_string_unsplit);
3840     }
3841
3842   p = pat;
3843   if (pat && pat[0] == '#')
3844     {
3845       mflags |= MATCH_BEG;
3846       p++;
3847     }
3848   else if (pat && pat[0] == '%')
3849     {
3850       mflags |= MATCH_END;
3851       p++;
3852     }
3853   else
3854     mflags |= MATCH_ANY;
3855
3856   /* OK, we now want to substitute REP for PAT in VAL.  If GLOBAL is 1,
3857      the substitution is done everywhere, otherwise only the first
3858      occurrence of PAT is replaced. */
3859   switch (vtype)
3860     {
3861     case VT_VARIABLE:
3862     case VT_ARRAYMEMBER:
3863       temp = pat_subst (val, p, rep, mflags);
3864       break;
3865     case VT_POSPARMS:
3866       temp = pos_params_pat_subst (val, p, rep, mflags);
3867       break;
3868 #if defined (ARRAY_VARS)
3869     case VT_ARRAYVAR:
3870       temp = array_pat_subst (array_cell (v), p, rep, mflags);
3871       break;
3872 #endif
3873     }
3874
3875   if (val && v && array_p (v) && vtype == VT_ARRAYMEMBER)
3876     free (val);
3877
3878   FREE (pat);
3879   FREE (rep);
3880
3881   return temp;
3882 }
3883
3884 /* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */
3885 static char *
3886 parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at)
3887      char *string;
3888      int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at;
3889 {
3890   int check_nullness, var_is_set, var_is_null, var_is_special;
3891   int want_substring, want_indir, want_patsub;
3892   char *name, *value, *temp, *temp1;
3893   int t_index, sindex, c, number;
3894
3895   sindex = *indexp;
3896   t_index = ++sindex;
3897   name = string_extract (string, &t_index, "#%:-=?+/}", 1);
3898   value = (char *)NULL;
3899   var_is_set = var_is_null = var_is_special = check_nullness = 0;
3900   want_substring = want_indir = want_patsub = 0;
3901
3902   /* If the name really consists of a special variable, then
3903      make sure that we have the entire name.  Handle indirect
3904      references to special variables here, too. */
3905   if ((sindex == t_index ||
3906       ((sindex == t_index - 1) && string[sindex] == '!')) &&
3907         (string[t_index] == '-' ||
3908          string[t_index] == '?' ||
3909          string[t_index] == '#'))
3910     {
3911       t_index++;
3912       free (name);
3913       temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
3914       name = xmalloc (3 + (strlen (temp1)));
3915       *name = string[sindex];
3916       if (string[sindex] == '!')
3917         {
3918           /* indirect ref. of special variable */
3919           name[1] = string[sindex + 1];
3920           strcpy (name + 2, temp1);
3921         }
3922       else
3923         strcpy (name + 1, temp1);
3924       free (temp1);
3925     }
3926   sindex = t_index;
3927
3928   /* Find out what character ended the variable name.  Then
3929      do the appropriate thing. */
3930   if (c = string[sindex])
3931     sindex++;
3932
3933   /* If c is followed by one of the valid parameter expansion
3934      characters, move past it as normal.  If not, assume that
3935      a substring specification is being given, and do not move
3936      past it. */
3937   if (c == ':' && member (string[sindex], "-=?+"))
3938     {
3939       check_nullness++;
3940       if (c = string[sindex])
3941         sindex++;
3942     }
3943   else if (c == ':')
3944     want_substring = 1;
3945   else if (c == '/')
3946     want_patsub = 1;
3947
3948   want_indir = *name == '!';
3949
3950   /* Determine the value of this variable. */
3951
3952   /* Check for special variables, directly and indirectly
3953      referenced. */
3954   if ((digit (*name) && all_digits (name)) ||
3955       (name[1] == '\0' && member (*name, "#-?$!@*")) ||
3956       (want_indir && name[2] == '\0' && member (name[1], "#-?$!@*")))
3957     var_is_special++;
3958
3959   /* Check for special expansion things. */
3960   if (*name == '#')     /* length of a parameter */
3961     {
3962       /* Take the lengths of some of the shell's special
3963          parameters. */
3964       if (string[sindex] == '}' && name[1] == '\0' &&
3965           check_nullness == 0 && member (c, "-?$!#"))
3966         {
3967           free (name);
3968           switch (c)
3969             {
3970             case '-':
3971               temp1 = which_set_flags ();
3972               break;
3973             case '?':
3974               temp1 = itos (last_command_exit_value);
3975               break;
3976             case '$':
3977               temp1 = itos (dollar_dollar_pid);
3978               break;
3979             case '!':
3980               if (last_asynchronous_pid == NO_PID)
3981                 temp1 = (char *)NULL;
3982               else
3983                 temp1 = itos ((int)last_asynchronous_pid);
3984               break;
3985             case '#':
3986               temp1 = itos (number_of_args ());
3987               break;
3988             }
3989           number = STRLEN (temp1);
3990           FREE (temp1);
3991           *indexp = ++sindex;   /* { string[sindex] == '}' */
3992           return (itos (number));
3993         }
3994
3995       /* Don't allow things like ${#:-foo} to go by; they are
3996          errors.  If we are not pointing at the character just
3997          after the closing brace, then we haven't gotten all of
3998          the name.  Since it begins with a special character,
3999          this is a bad substitution.  Explicitly check for ${#:},
4000          which the rules do not catch.  Also check NAME for
4001          validity before trying to go on. */
4002       if (string[sindex - 1] != '}' ||
4003           member (c, "?-=+") ||
4004           (name[1] == '\0' && c == '}' && check_nullness) ||
4005           (valid_length_expression (name) == 0))
4006         {
4007           temp = (char *)NULL;
4008           goto bad_substitution;
4009         }
4010
4011       number = parameter_brace_expand_length (name);
4012       free (name);
4013
4014       *indexp = sindex;
4015       return ((number < 0) ? &expand_param_error : itos (number));
4016     }
4017
4018   /* ${@} is identical to $@. */
4019   if (name[0] == '@' && name[1] == '\0')
4020     {
4021       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4022         *quoted_dollar_atp = 1;
4023
4024       if (contains_dollar_at)
4025         *contains_dollar_at = 1;
4026     }
4027
4028   /* Make sure that NAME is valid before trying to go on. */
4029   if (valid_brace_expansion_word (want_indir ? name + 1 : name,
4030                                         var_is_special) == 0)
4031     {
4032       temp = (char *)NULL;
4033       goto bad_substitution;
4034     }
4035
4036   if (want_indir)
4037     temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted);
4038   else
4039     temp = parameter_brace_expand_word (name, var_is_special, quoted);
4040
4041 #if defined (ARRAY_VARS)
4042   if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && valid_array_reference (name))
4043     {
4044       temp1 = strchr (name, '[');
4045       if (temp1 && temp1[1] == '@' && temp1[2] == ']')
4046         {
4047           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4048             *quoted_dollar_atp = 1;
4049           if (contains_dollar_at)
4050             *contains_dollar_at = 1;
4051         }
4052     }
4053 #endif
4054
4055   var_is_set = temp != (char *)0;
4056   var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
4057
4058   /* Get the rest of the stuff inside the braces. */
4059   if (c && c != '}')
4060     {
4061       /* Extract the contents of the ${ ... } expansion
4062          according to the Posix.2 rules. */
4063       value = extract_dollar_brace_string (string, &sindex, quoted);
4064       /*{*/
4065       if (string[sindex] == '}')
4066         sindex++;
4067       else
4068         goto bad_substitution;
4069     }
4070   else
4071     value = (char *)NULL;
4072
4073   *indexp = sindex;
4074
4075   /* If this is a substring spec, process it and add the result. */
4076   if (want_substring)
4077     {
4078       temp1 = parameter_brace_substring (name, temp, value, quoted);
4079       FREE (name);
4080       FREE (value);
4081       FREE (temp);
4082       return (temp1);
4083     }
4084   else if (want_patsub)
4085     {
4086       temp1 = parameter_brace_patsub (name, temp, value, quoted);
4087       FREE (name);
4088       FREE (value);
4089       FREE (temp);
4090       return (temp1);
4091     }
4092
4093   /* Do the right thing based on which character ended the variable name. */
4094   switch (c)
4095     {
4096     default:
4097     case '\0':
4098     bad_substitution:
4099       report_error ("%s: bad substitution", string ? string : "??");
4100       FREE (value);
4101       FREE (temp);
4102       free (name);
4103       return &expand_param_error;
4104
4105     /*{*/
4106     case '}':
4107       if (var_is_set == 0 && unbound_vars_is_error)
4108         {
4109           report_error ("%s: unbound variable", name);
4110           FREE (value);
4111           FREE (temp);
4112           free (name);
4113           last_command_exit_value = EXECUTION_FAILURE;
4114           return (interactive_shell ? &expand_param_error : &expand_param_fatal);
4115         }
4116       break;
4117
4118     case '#':   /* ${param#[#]pattern} */
4119     case '%':   /* ${param%[%]pattern} */
4120       if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
4121         {
4122           FREE (value);
4123           break;
4124         }
4125       if ((name[0] == '@' || name[0] == '*') && name[1] == '\0')
4126         temp1 = parameter_list_remove_pattern (value, name[0], c, quoted);
4127 #if defined (ARRAY_VARS)
4128       else if (valid_array_reference (name))
4129         temp1 = array_remove_pattern (value, name, temp, c, quoted);
4130 #endif
4131       else
4132         temp1 = parameter_brace_remove_pattern (value, temp, c, quoted);
4133       free (temp);
4134       free (value);
4135       temp = temp1;
4136       break;
4137
4138     case '-':
4139     case '=':
4140     case '?':
4141     case '+':
4142       if (var_is_set && var_is_null == 0)
4143         {
4144           /* We don't want the value of the named variable for
4145              anything, just the value of the right hand side. */
4146           if (c == '+')
4147             {
4148               FREE (temp);
4149               if (value)
4150                 {
4151                   temp = parameter_brace_expand_rhs (name, value, c,
4152                                                      quoted,
4153                                                      quoted_dollar_atp,
4154                                                      contains_dollar_at);
4155                   free (value);
4156                 }
4157               else
4158                 temp = (char *)NULL;
4159             }
4160           else
4161             {
4162               FREE (value);
4163             }
4164           /* Otherwise do nothing; just use the value in TEMP. */
4165         }
4166       else      /* VAR not set or VAR is NULL. */
4167         {
4168           FREE (temp);
4169           temp = (char *)NULL;
4170           if (c == '=' && var_is_special)
4171             {
4172               report_error ("$%s: cannot assign in this way", name);
4173               free (name);
4174               free (value);
4175               return &expand_param_error;
4176             }
4177           else if (c == '?')
4178             {
4179               parameter_brace_expand_error (name, value);
4180               return (interactive ? &expand_param_error : &expand_param_fatal);
4181             }
4182           else if (c != '+')
4183             temp = parameter_brace_expand_rhs (name, value, c, quoted,
4184                                                quoted_dollar_atp,
4185                                                contains_dollar_at);
4186           free (value);
4187         }
4188       break;
4189     }
4190   free (name);
4191   return (temp);
4192 }
4193
4194 /* Make a word list which is the parameter and variable expansion,
4195    command substitution, arithmetic substitution, and quote removed
4196    expansion of WORD.  Return a pointer to a WORD_LIST which is the
4197    result of the expansion.  If WORD contains a null word, the word
4198    list returned is also null.
4199
4200    QUOTED contains flag values defined in shell.h.
4201
4202    CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
4203    they point to an integer value which receives information about expansion.
4204    CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
4205    EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
4206    else zero.
4207
4208    This only does word splitting in the case of $@ expansion.  In that
4209    case, we split on ' '. */
4210
4211 /* Values for the local variable quoted_state. */
4212 #define UNQUOTED         0
4213 #define PARTIALLY_QUOTED 1
4214 #define WHOLLY_QUOTED    2
4215
4216 static WORD_LIST *
4217 expand_word_internal (word, quoted, contains_dollar_at, expanded_something)
4218      WORD_DESC *word;
4219      int quoted;
4220      int *contains_dollar_at;
4221      int *expanded_something;
4222 {
4223   WORD_LIST *list;
4224   WORD_DESC *tword;
4225   SHELL_VAR *var;
4226
4227   /* The intermediate string that we build while expanding. */
4228   char *istring;
4229
4230   /* The current size of the above object. */
4231   int istring_size;
4232
4233   /* Index into ISTRING. */
4234   int istring_index;
4235
4236   /* Temporary string storage. */
4237   char *temp, *temp1;
4238
4239   /* The text of WORD. */
4240   register char *string;
4241
4242   /* The index into STRING. */
4243   int sindex;
4244
4245   /* This gets 1 if we see a $@ while quoted. */
4246   int quoted_dollar_at;
4247
4248   /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
4249      whether WORD contains no quoting characters, a partially quoted
4250      string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
4251   int quoted_state;
4252
4253   int had_quoted_null;
4254
4255   int expok;
4256
4257   register int c;               /* Current character. */
4258   int number;                   /* Temporary number value. */
4259   int t_index;                  /* For calls to string_extract_xxx. */
4260
4261   istring = xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
4262   istring[istring_index = 0] = '\0';
4263
4264   quoted_dollar_at = had_quoted_null = 0;
4265   quoted_state = UNQUOTED;
4266
4267   string = word->word;
4268   if (string == 0)
4269     goto finished_with_string;
4270
4271   if (contains_dollar_at)
4272     *contains_dollar_at = 0;
4273
4274   /* Begin the expansion. */
4275
4276   for (sindex = 0; ;)
4277     {
4278       c = string[sindex];
4279
4280       /* Case on toplevel character. */
4281       switch (c)
4282         {
4283         case '\0':
4284           goto finished_with_string;
4285
4286         case CTLESC:
4287           temp = xmalloc (3);
4288           temp[0] = CTLESC;
4289           temp[1] = c = string[++sindex];
4290           temp[2] = '\0';
4291
4292           if (string[sindex])
4293             sindex++;
4294
4295           goto add_string;
4296
4297 #if defined (PROCESS_SUBSTITUTION)
4298           /* Process substitution. */
4299         case '<':
4300         case '>':
4301           {
4302             if (string[++sindex] != '(' || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct)
4303               {
4304                 sindex--;
4305                 goto add_character;
4306               }
4307             else
4308               t_index = sindex + 1; /* skip past both '<' and '(' */
4309
4310             temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index);
4311             sindex = t_index;
4312
4313             /* If the process substitution specification is `<()', we want to
4314                open the pipe for writing in the child and produce output; if
4315                it is `>()', we want to open the pipe for reading in the child
4316                and consume input. */
4317             temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
4318
4319             FREE (temp1);
4320
4321             goto dollar_add_string;
4322           }
4323 #endif /* PROCESS_SUBSTITUTION */
4324
4325         /* See about breaking this into a separate function:
4326             char *
4327             param_expand (string, sindex, quoted, expanded_something,
4328                           contains_dollar_at, quoted_dollar_at)
4329             char *string;
4330             int *sindex, quoted, *expanded_something, *contains_dollar_at;
4331             int *quoted_dollar_at;
4332         */
4333         case '$':
4334
4335           if (expanded_something)
4336             *expanded_something = 1;
4337
4338           c = string[++sindex];
4339
4340           /* Do simple cases first. Switch on what follows '$'. */
4341           switch (c)
4342             {
4343               /* $0 .. $9? */
4344             case '0':
4345             case '1':
4346             case '2':
4347             case '3':
4348             case '4':
4349             case '5':
4350             case '6':
4351             case '7':
4352             case '8':
4353             case '9':
4354               temp1 = dollar_vars[digit_value (c)];
4355               if (unbound_vars_is_error && temp1 == (char *)NULL)
4356                 {
4357                   report_error ("$%c: unbound variable", c);
4358                   free (string);
4359                   free (istring);
4360                   last_command_exit_value = EXECUTION_FAILURE;
4361                   return (interactive_shell ? &expand_word_error : &expand_word_fatal);
4362                 }
4363               temp = temp1 ? savestring (temp1) : (char *)NULL;
4364               goto dollar_add_string;
4365
4366               /* $$ -- pid of the invoking shell. */
4367             case '$':
4368               number = dollar_dollar_pid;
4369
4370             add_number:
4371               temp = itos (number);
4372             dollar_add_string:
4373               if (string[sindex]) sindex++;
4374
4375               /* Add TEMP to ISTRING. */
4376             add_string:
4377               if (temp)
4378                 {
4379                   istring = sub_append_string
4380                     (temp, istring, &istring_index, &istring_size);
4381                   temp = (char *)0;
4382                 }
4383
4384               break;
4385
4386               /* $# -- number of positional parameters. */
4387             case '#':
4388               number = number_of_args ();
4389               goto add_number;
4390
4391               /* $? -- return value of the last synchronous command. */
4392             case '?':
4393               number = last_command_exit_value;
4394               goto add_number;
4395
4396               /* $- -- flags supplied to the shell on invocation or
4397                  by `set'. */
4398             case '-':
4399               temp = which_set_flags ();
4400               goto dollar_add_string;
4401
4402               /* $! -- Pid of the last asynchronous command. */
4403             case '!':
4404               number = (int)last_asynchronous_pid;
4405
4406               /* If no asynchronous pids have been created, expand
4407                  to nothing. */
4408               if (number == (int)NO_PID)
4409                 {
4410                   if (string[sindex])
4411                     sindex++;
4412                   if (expanded_something)
4413                     *expanded_something = 0;
4414                   break;
4415                 }
4416               goto add_number;
4417
4418               /* The only difference between this and $@ is when the
4419                  arg is quoted. */
4420             case '*':           /* `$*' */
4421               temp = string_rest_of_args (quoted);
4422
4423               /* If there are no command-line arguments, this should just
4424                  disappear if there are other characters in the expansion,
4425                  even if it's quoted. */
4426               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && temp && *temp == '\0')
4427                 {
4428                   free (temp);
4429                   temp = (char *)NULL;
4430                 }
4431               /* In the case of a quoted string, quote the entire arg-list.
4432                  "$1 $2 $3".  Otherwise quote the special escape characters. */
4433               if (temp)
4434                 {
4435                   temp1 = temp;
4436                   temp = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4437                                 ? quote_string (temp)
4438                                 : quote_escapes (temp);
4439                   free (temp1);
4440                 }
4441               goto dollar_add_string;
4442
4443               /* When we have "$@" what we want is "$1" "$2" "$3" ... This
4444                  means that we have to turn quoting off after we split into
4445                  the individually quoted arguments so that the final split
4446                  on the first character of $IFS is still done.  */
4447             case '@':           /* `$@' */
4448               list = list_rest_of_args ();
4449
4450               /* We want to flag the fact that we saw this.  We can't turn
4451                  off quoting entirely, because other characters in the
4452                  string might need it (consider "\"$@\""), but we need some
4453                  way to signal that the final split on the first character
4454                  of $IFS should be done, even though QUOTED is 1. */
4455               if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4456                 quoted_dollar_at = 1;
4457               if (contains_dollar_at)
4458                 *contains_dollar_at = 1;
4459               temp = string_list (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list) ? quote_list (list) : list);
4460               /* If the expansion is not quoted, protect any special escape
4461                  characters in the expansion by quoting them. */
4462               if (temp && quoted == 0)
4463                 {
4464                   temp1 = temp;
4465                   temp = quote_escapes (temp);
4466                   free (temp1);
4467                 }
4468               dispose_words (list);
4469               goto dollar_add_string;
4470
4471             case '{':   /*}*/
4472               temp = parameter_brace_expand (string, &sindex, quoted,
4473                                              &quoted_dollar_at,
4474                                              contains_dollar_at);
4475               if (temp == &expand_param_error || temp == &expand_param_fatal)
4476                 {
4477                   free (string);
4478                   free (istring);
4479                   return (temp == &expand_param_error) ? &expand_word_error
4480                                                        : &expand_word_fatal;
4481                 }
4482               /* XXX */
4483               /* quoted nulls should be removed if there is anything else
4484                  in the string. */
4485               /* Note that we saw the quoted null so we can add one back at
4486                  the end of this function if there are no other characters
4487                  in the string, discard TEMP, and go on. */
4488               if (temp && QUOTED_NULL (temp))
4489                 {
4490                   had_quoted_null = 1;
4491                   free (temp);
4492                   break;
4493                 }
4494
4495               goto add_string;
4496               /* break; */
4497
4498               /* Do command or arithmetic substitution. */
4499             case '(':   /*)*/
4500               /* We have to extract the contents of this paren substitution. */
4501               t_index = sindex + 1;
4502               temp = extract_command_subst (string, &t_index);
4503               sindex = t_index;
4504
4505               /* For Posix.2-style `$(( ))' arithmetic substitution,
4506                  extract the expression and pass it to the evaluator. */
4507               if (temp && *temp == '(')
4508                 {
4509                   temp1 = temp + 1;
4510                   t_index = strlen (temp1) - 1;
4511
4512                   if (temp1[t_index] != ')')
4513                     {
4514 #if 0
4515                       report_error ("%s: bad arithmetic substitution", temp);
4516                       free (temp);
4517                       free (string);
4518                       free (istring);
4519                       return (&expand_word_error);
4520 #else
4521                       goto comsub;
4522 #endif
4523                     }
4524
4525                   /* Cut off ending `)' */
4526                   temp1[t_index] = '\0';
4527
4528                   /* Expand variables found inside the expression. */
4529                   temp1 = maybe_expand_string (temp1, Q_DOUBLE_QUOTES, expand_string);
4530
4531                   /* No error messages. */
4532                   this_command_name = (char *)NULL;
4533                   number = evalexp (temp1, &expok);
4534                   free (temp);
4535                   free (temp1);
4536                   if (expok == 0)
4537                     {
4538                       free (string);
4539                       free (istring);
4540                       return (&expand_word_error);
4541                     }
4542                   goto add_number;
4543                 }
4544
4545         comsub:
4546               temp1 = command_substitute (temp, quoted);
4547               FREE (temp);
4548               temp = temp1;
4549               goto dollar_add_string;
4550
4551               /* Do straight arithmetic substitution. */
4552             case '[':
4553               /* We have to extract the contents of this
4554                  arithmetic substitution. */
4555               t_index = sindex + 1;
4556               temp = extract_arithmetic_subst (string, &t_index);
4557               sindex = t_index;
4558
4559                /* Do initial variable expansion. */
4560               temp1 = maybe_expand_string (temp, Q_DOUBLE_QUOTES, expand_string);
4561
4562               /* No error messages. */
4563               this_command_name = (char *)NULL;
4564               number = evalexp (temp1, &expok);
4565               free (temp1);
4566               free (temp);
4567               if (expok == 0)
4568                 {
4569                   free (string);
4570                   free (istring);
4571                   return (&expand_word_error);
4572                 }
4573               goto add_number;
4574
4575             default:
4576               /* Find the variable in VARIABLE_LIST. */
4577               temp = (char *)NULL;
4578
4579               for (t_index = sindex;
4580                    (c = string[sindex]) && legal_variable_char (c);
4581                    sindex++);
4582               temp1 = substring (string, t_index, sindex);
4583
4584               /* If this isn't a variable name, then just output the `$'. */
4585               if (temp1 == 0 || *temp1 == '\0')
4586                 {
4587                   FREE (temp1);
4588                   temp = xmalloc (2);
4589                   temp[0] = '$';
4590                   temp[1] = '\0';
4591                   if (expanded_something)
4592                     *expanded_something = 0;
4593                   goto add_string;
4594                 }
4595
4596               /* If the variable exists, return its value cell. */
4597               var = find_variable (temp1);
4598
4599               if (var && invisible_p (var) == 0 && value_cell (var))
4600                 {
4601 #if defined (ARRAY_VARS)
4602                   if (array_p (var))
4603                     {
4604                       temp = array_reference (array_cell (var), 0);
4605                       if (temp)
4606                         temp = quote_escapes (temp);
4607                     }
4608                   else
4609 #endif
4610                   temp = quote_escapes (value_cell (var));
4611                   free (temp1);
4612                   goto add_string;
4613                 }
4614
4615               temp = (char *)NULL;
4616
4617               if (unbound_vars_is_error)
4618                 report_error ("%s: unbound variable", temp1);
4619               else
4620                 {
4621                   free (temp1);
4622                   goto add_string;
4623                 }
4624
4625               free (temp1);
4626               free (string);
4627               last_command_exit_value = EXECUTION_FAILURE;
4628               free (istring);
4629               return ((unbound_vars_is_error && interactive_shell == 0)
4630                         ? &expand_word_fatal
4631                         : &expand_word_error);
4632             }
4633           break;                /* End case '$': */
4634
4635         case '`':               /* Backquoted command substitution. */
4636           {
4637             sindex++;
4638
4639             if (expanded_something)
4640               *expanded_something = 1;
4641
4642             temp = string_extract (string, &sindex, "`", 0);
4643             de_backslash (temp);
4644             temp1 = command_substitute (temp, quoted);
4645             FREE (temp);
4646             temp = temp1;
4647             goto dollar_add_string;
4648           }
4649
4650         case '\\':
4651           if (string[sindex + 1] == '\n')
4652             {
4653               sindex += 2;
4654               continue;
4655             }
4656
4657           c = string[++sindex];
4658
4659           if (quoted & Q_HERE_DOCUMENT)
4660             temp1 = slashify_in_here_document;
4661           else if (quoted & Q_DOUBLE_QUOTES)
4662             temp1 = slashify_in_quotes;
4663           else
4664             temp1 = "";
4665
4666           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && member (c, temp1) == 0)
4667             {
4668               temp = xmalloc (3);
4669               temp[0] = '\\'; temp[1] = c; temp[2] = '\0';
4670             }
4671           else
4672             /* This character is quoted, so add it in quoted mode. */
4673             temp = make_quoted_char (c);
4674
4675           if (c)
4676             sindex++;
4677           goto add_string;
4678
4679         case '"':
4680           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE))
4681             goto add_character;
4682
4683           t_index = ++sindex;
4684           temp = string_extract_double_quoted (string, &sindex, 0);
4685
4686           /* If the quotes surrounded the entire string, then the
4687              whole word was quoted. */
4688           quoted_state = (t_index == 1 && string[sindex] == '\0')
4689                             ? WHOLLY_QUOTED
4690                             : PARTIALLY_QUOTED;
4691
4692           if (temp && *temp)
4693             {
4694               int dollar_at_flag;
4695
4696               tword = make_word (temp);         /* XXX */
4697               free (temp);
4698               temp = (char *)NULL;
4699
4700               list = expand_word_internal (tword, Q_DOUBLE_QUOTES, &dollar_at_flag, (int *)NULL);
4701
4702               if (list == &expand_word_error || list == &expand_word_fatal)
4703                 {
4704                   free (istring);
4705                   free (string);
4706                   /* expand_word_internal has already freed temp_word->word
4707                      for us because of the way it prints error messages. */
4708                   tword->word = (char *)NULL;
4709                   dispose_word (tword);
4710                   return list;
4711                 }
4712
4713               dispose_word (tword);
4714
4715               /* "$@" (a double-quoted dollar-at) expands into nothing,
4716                  not even a NULL word, when there are no positional
4717                  parameters. */
4718               if (list == 0 && dollar_at_flag)
4719                 {
4720                   quoted_dollar_at++;
4721                   break;
4722                 }
4723
4724               /* If we get "$@", we know we have expanded something, so we
4725                  need to remember it for the final split on $IFS.  This is
4726                  a special case; it's the only case where a quoted string
4727                  can expand into more than one word.  It's going to come back
4728                  from the above call to expand_word_internal as a list with
4729                  a single word, in which all characters are quoted and
4730                  separated by blanks.  What we want to do is to turn it back
4731                  into a list for the next piece of code. */
4732               if (list)
4733                 dequote_list (list);
4734
4735               if (dollar_at_flag)
4736                 {
4737                   quoted_dollar_at++;
4738                   if (contains_dollar_at)
4739                     *contains_dollar_at = 1;
4740                   if (expanded_something)
4741                     *expanded_something = 1;
4742                 }
4743             }
4744           else
4745             {
4746               /* What we have is "".  This is a minor optimization. */
4747               free (temp);
4748               list = (WORD_LIST *)NULL;
4749             }
4750
4751           /* The code above *might* return a list (consider the case of "$@",
4752              where it returns "$1", "$2", etc.).  We can't throw away the
4753              rest of the list, and we have to make sure each word gets added
4754              as quoted.  We test on tresult->next:  if it is non-NULL, we
4755              quote the whole list, save it to a string with string_list, and
4756              add that string. We don't need to quote the results of this
4757              (and it would be wrong, since that would quote the separators
4758              as well), so we go directly to add_string. */
4759           if (list)
4760             {
4761               if (list->next)
4762                 {
4763                   temp = string_list (quote_list (list));
4764                   dispose_words (list);
4765                   goto add_string;
4766                 }
4767               else
4768                 {
4769                   temp = savestring (list->word->word);
4770                   dispose_words (list);
4771                 }
4772             }
4773           else
4774             temp = (char *)NULL;
4775
4776           /* We do not want to add quoted nulls to strings that are only
4777              partially quoted; we can throw them away. */
4778           if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
4779             {
4780               FREE (temp);
4781               continue;
4782             }
4783
4784         add_quoted_string:
4785
4786           if (temp)
4787             {
4788               temp1 = temp;
4789               temp = quote_string (temp);
4790               free (temp1);
4791             }
4792           else
4793             {
4794               /* Add NULL arg. */
4795               temp = xmalloc (2);
4796               temp[0] = CTLNUL;
4797               temp[1] = '\0';
4798             }
4799           goto add_string;
4800           /* break; */
4801
4802         case '\'':
4803           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE))
4804             goto add_character;
4805
4806           t_index = ++sindex;
4807           temp = string_extract_single_quoted (string, &sindex);
4808
4809           /* If the entire STRING was surrounded by single quotes,
4810              then the string is wholly quoted. */
4811           quoted_state = (t_index == 1 && string[sindex] == '\0')
4812                             ? WHOLLY_QUOTED
4813                             : PARTIALLY_QUOTED;
4814
4815           /* If all we had was '', it is a null expansion. */
4816           if (*temp == '\0')
4817             {
4818               free (temp);
4819               temp = (char *)NULL;
4820             }
4821           else
4822             remove_quoted_escapes (temp);
4823
4824           /* We do not want to add quoted nulls to strings that are only
4825              partially quoted; such nulls are discarded. */
4826           if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
4827             continue;
4828
4829           goto add_quoted_string;
4830           /* break; */
4831
4832         default:
4833           /* This is the fix for " $@ " */
4834           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4835             {
4836               temp = make_quoted_char (c);
4837               goto dollar_add_string;
4838             }
4839
4840         add_character:
4841           RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
4842                                   DEFAULT_ARRAY_SIZE);
4843           istring[istring_index++] = c;
4844           istring[istring_index] = '\0';
4845
4846           /* Next character. */
4847           sindex++;
4848         }
4849     }
4850
4851 finished_with_string:
4852   /* OK, we're ready to return.  If we have a quoted string, and
4853      quoted_dollar_at is not set, we do no splitting at all; otherwise
4854      we split on ' '.  The routines that call this will handle what to
4855      do if nothing has been expanded. */
4856
4857   /* Partially and wholly quoted strings which expand to the empty
4858      string are retained as an empty arguments.  Unquoted strings
4859      which expand to the empty string are discarded.  The single
4860      exception is the case of expanding "$@" when there are no
4861      positional parameters.  In that case, we discard the expansion. */
4862
4863   /* Because of how the code that handles "" and '' in partially
4864      quoted strings works, we need to make ISTRING into a QUOTED_NULL
4865      if we saw quoting characters, but the expansion was empty.
4866      "" and '' are tossed away before we get to this point when
4867      processing partially quoted strings.  This makes "" and $xxx""
4868      equivalent when xxx is unset.  We also look to see whether we
4869      saw a quoted null from a ${} expansion and add one back if we
4870      need to. */
4871
4872   /* If we expand to nothing and there were no single or double quotes
4873      in the word, we throw it away.  Otherwise, we return a NULL word.
4874      The single exception is for $@ surrounded by double quotes when
4875      there are no positional parameters.  In that case, we also throw
4876      the word away. */
4877
4878   if (*istring == '\0')
4879     {
4880       if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
4881         {
4882           istring[0] = CTLNUL;
4883           istring[1] = '\0';
4884           tword = make_bare_word (istring);
4885           list = make_word_list (tword, (WORD_LIST *)NULL);
4886           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4887             tword->flags |= W_QUOTED;
4888         }
4889       /* According to sh, ksh, and Posix.2, if a word expands into nothing
4890          and a double-quoted "$@" appears anywhere in it, then the entire
4891          word is removed. */
4892       else  if (quoted_state == UNQUOTED || quoted_dollar_at)
4893         list = (WORD_LIST *)NULL;
4894 #if 0
4895       else
4896         {
4897           tword = make_bare_word (istring);
4898           list = make_word_list (tword, (WORD_LIST *)NULL);
4899           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4900             tword->flags |= W_QUOTED;
4901         }
4902 #endif
4903     }
4904   else if (word->flags & W_NOSPLIT)
4905     {
4906       tword = make_bare_word (istring);
4907       list = make_word_list (tword, (WORD_LIST *)NULL);
4908       if (word->flags & W_ASSIGNMENT)
4909         tword->flags |= W_ASSIGNMENT;   /* XXX */
4910       if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4911         tword->flags |= W_QUOTED;
4912     }
4913   else
4914     {
4915       char *ifs_chars;
4916
4917       if (quoted_dollar_at)
4918         {
4919           var = find_variable ("IFS");
4920           ifs_chars = var ? value_cell (var) : " \t\n";
4921         }
4922       else
4923         ifs_chars = (char *)NULL;
4924
4925       /* According to Posix.2, "$@" expands to a single word if
4926          IFS="" and the positional parameters are not empty. */
4927       if (quoted_dollar_at && ifs_chars && *ifs_chars)
4928         {
4929           list = list_string (istring, " ", 1);
4930         }
4931       else
4932         {
4933           tword = make_bare_word (istring);
4934           list = make_word_list (tword, (WORD_LIST *)NULL);
4935           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
4936             tword->flags |= W_QUOTED;
4937           if (word->flags & W_ASSIGNMENT)
4938             tword->flags |= W_ASSIGNMENT;
4939         }
4940     }
4941
4942   free (istring);
4943   return (list);
4944 }
4945
4946 /* **************************************************************** */
4947 /*                                                                  */
4948 /*                 Functions for Quote Removal                      */
4949 /*                                                                  */
4950 /* **************************************************************** */
4951
4952 /* Perform quote removal on STRING.  If QUOTED > 0, assume we are obeying the
4953    backslash quoting rules for within double quotes. */
4954 char *
4955 string_quote_removal (string, quoted)
4956      char *string;
4957      int quoted;
4958 {
4959   char *r, *result_string, *temp;
4960   int sindex, tindex, c, dquote;
4961
4962   /* The result can be no longer than the original string. */
4963   r = result_string = xmalloc (strlen (string) + 1);
4964
4965   for (dquote = sindex = 0; c = string[sindex];)
4966     {
4967       switch (c)
4968         {
4969         case '\\':
4970           c = string[++sindex];
4971           if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && member (c, slashify_in_quotes) == 0)
4972             *r++ = '\\';
4973           /* FALLTHROUGH */
4974
4975         default:
4976           *r++ = c;
4977           sindex++;
4978           break;
4979
4980         case '\'':
4981           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
4982             {
4983               *r++ = c;
4984               sindex++;
4985               break;
4986             }
4987           tindex = sindex + 1;
4988           temp = string_extract_single_quoted (string, &tindex);
4989           if (temp)
4990             {
4991               strcpy (r, temp);
4992               r += strlen (r);
4993               free (temp);
4994             }
4995           sindex = tindex;
4996           break;
4997
4998         case '"':
4999           dquote = 1 - dquote;
5000           sindex++;
5001           break;
5002         }
5003     }
5004     *r = '\0';
5005     return (result_string);
5006 }
5007
5008 #if 0
5009 /* UNUSED */
5010 /* Perform quote removal on word WORD.  This allocates and returns a new
5011    WORD_DESC *. */
5012 WORD_DESC *
5013 word_quote_removal (word, quoted)
5014      WORD_DESC *word;
5015      int quoted;
5016 {
5017   WORD_DESC *w;
5018   char *t;
5019
5020   t = string_quote_removal (word->word, quoted);
5021   w = make_bare_word (t);
5022   free (t);
5023   return (w);
5024 }
5025
5026 /* Perform quote removal on all words in LIST.  If QUOTED is non-zero,
5027    the members of the list are treated as if they are surrounded by
5028    double quotes.  Return a new list, or NULL if LIST is NULL. */
5029 WORD_LIST *
5030 word_list_quote_removal (list, quoted)
5031      WORD_LIST *list;
5032      int quoted;
5033 {
5034   WORD_LIST *result, *t, *tresult;
5035
5036   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
5037     {
5038       tresult = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
5039       tresult->word = word_quote_removal (t->word, quoted);
5040       tresult->next = (WORD_LIST *)NULL;
5041       result = (WORD_LIST *) list_append (result, tresult);
5042     }
5043   return (result);
5044 }
5045 #endif
5046
5047 /* Return 1 if CHARACTER appears in an unquoted portion of
5048    STRING.  Return 0 otherwise. */
5049 static int
5050 unquoted_member (character, string)
5051      int character;
5052      char *string;
5053 {
5054   int sindex, c;
5055
5056   for (sindex = 0; c = string[sindex]; )
5057     {
5058       if (c == character)
5059         return (1);
5060
5061       switch (c)
5062         {
5063         default:
5064           sindex++;
5065           break;
5066
5067         case '\\':
5068           sindex++;
5069           if (string[sindex])
5070             sindex++;
5071           break;
5072
5073         case '\'':
5074           sindex = skip_single_quoted (string, ++sindex);
5075           break;
5076
5077         case '"':
5078           sindex = skip_double_quoted (string, ++sindex);
5079           break;
5080         }
5081     }
5082   return (0);
5083 }
5084
5085 /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
5086 static int
5087 unquoted_substring (substr, string)
5088      char *substr, *string;
5089 {
5090   int sindex, c, sublen;
5091
5092   if (substr == 0 || *substr == '\0')
5093     return (0);
5094
5095   sublen = strlen (substr);
5096   for (sindex = 0; c = string[sindex]; )
5097     {
5098       if (STREQN (string + sindex, substr, sublen))
5099         return (1);
5100
5101       switch (c)
5102         {
5103         case '\\':
5104           sindex++;
5105
5106           if (string[sindex])
5107             sindex++;
5108           break;
5109
5110         case '\'':
5111           sindex = skip_single_quoted (string, ++sindex);
5112           break;
5113
5114         case '"':
5115           sindex = skip_double_quoted (string, ++sindex);
5116           break;
5117
5118         default:
5119           sindex++;
5120           break;
5121         }
5122     }
5123   return (0);
5124 }
5125
5126 /*******************************************
5127  *                                         *
5128  *    Functions to perform word splitting  *
5129  *                                         *
5130  *******************************************/
5131
5132 /* This splits a single word into a WORD LIST on $IFS, but only if the word
5133    is not quoted.  list_string () performs quote removal for us, even if we
5134    don't do any splitting. */
5135 WORD_LIST *
5136 word_split (w)
5137      WORD_DESC *w;
5138 {
5139   WORD_LIST *result;
5140   SHELL_VAR *ifs;
5141   char *ifs_chars;
5142
5143   if (w)
5144     {
5145       ifs = find_variable ("IFS");
5146       /* If IFS is unset, it defaults to " \t\n". */
5147       ifs_chars = ifs ? value_cell (ifs) : " \t\n";
5148
5149       if ((w->flags & W_QUOTED) || !ifs_chars)
5150         ifs_chars = "";
5151
5152       result = list_string (w->word, ifs_chars, w->flags & W_QUOTED);
5153     }
5154   else
5155     result = (WORD_LIST *)NULL;
5156
5157   return (result);
5158 }
5159
5160 /* Perform word splitting on LIST and return the RESULT.  It is possible
5161    to return (WORD_LIST *)NULL. */
5162 static WORD_LIST *
5163 word_list_split (list)
5164      WORD_LIST *list;
5165 {
5166   WORD_LIST *result, *t, *tresult;
5167
5168   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
5169     {
5170       tresult = word_split (t->word);
5171       result = (WORD_LIST *) list_append (result, tresult);
5172     }
5173   return (result);
5174 }
5175
5176 /**************************************************
5177  *                                                *
5178  *      Functions to expand an entire WORD_LIST   *
5179  *                                                *
5180  **************************************************/
5181
5182 static WORD_LIST *varlist = (WORD_LIST *)NULL;
5183
5184 /* Separate out any initial variable assignments from TLIST.  If set -k has
5185    been executed, remove all assignment statements from TLIST.  Initial
5186    variable assignments and other environment assignments are placed
5187    on VARLIST. */
5188 static WORD_LIST *
5189 separate_out_assignments (tlist)
5190      WORD_LIST *tlist;
5191 {
5192   register WORD_LIST *vp, *lp;
5193
5194   if (!tlist)
5195     return ((WORD_LIST *)NULL);
5196
5197   varlist = (WORD_LIST *)NULL;
5198   vp = lp = tlist;
5199
5200   /* Separate out variable assignments at the start of the command.
5201      Loop invariant: vp->next == lp
5202      Loop postcondition:
5203         lp = list of words left after assignment statements skipped
5204         tlist = original list of words
5205   */
5206   while (lp && (lp->word->flags & W_ASSIGNMENT))
5207     {
5208       vp = lp;
5209       lp = lp->next;
5210     }
5211
5212   /* If lp != tlist, we have some initial assignment statements. */
5213   /* We make VARLIST point to the list of assignment words and
5214      TLIST point to the remaining words.  */
5215   if (lp != tlist)
5216     {
5217       varlist = tlist;
5218       /* ASSERT(vp->next == lp); */
5219       vp->next = (WORD_LIST *)NULL;     /* terminate variable list */
5220       tlist = lp;                       /* remainder of word list */
5221     }
5222
5223   /* vp == end of variable list */
5224   /* tlist == remainder of original word list without variable assignments */
5225   if (!tlist)
5226     /* All the words in tlist were assignment statements */
5227     return ((WORD_LIST *)NULL);
5228
5229   /* ASSERT(tlist != NULL); */
5230   /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
5231
5232   /* If the -k option is in effect, we need to go through the remaining
5233      words, separate out the assignment words, and place them on VARLIST. */
5234   if (place_keywords_in_env)
5235     {
5236       WORD_LIST *tp;    /* tp == running pointer into tlist */
5237
5238       tp = tlist;
5239       lp = tlist->next;
5240
5241       /* Loop Invariant: tp->next == lp */
5242       /* Loop postcondition: tlist == word list without assignment statements */
5243       while (lp)
5244         {
5245           if (lp->word->flags & W_ASSIGNMENT)
5246             {
5247               /* Found an assignment statement, add this word to end of
5248                  varlist (vp). */
5249               if (!varlist)
5250                 varlist = vp = lp;
5251               else
5252                 {
5253                   vp->next = lp;
5254                   vp = lp;
5255                 }
5256
5257               /* Remove the word pointed to by LP from TLIST. */
5258               tp->next = lp->next;
5259               /* ASSERT(vp == lp); */
5260               lp->next = (WORD_LIST *)NULL;
5261               lp = tp->next;
5262             }
5263           else
5264             {
5265               tp = lp;
5266               lp = lp->next;
5267             }
5268         }
5269     }
5270   return (tlist);
5271 }
5272
5273 /* Take the list of words in LIST and do the various substitutions.  Return
5274    a new list of words which is the expanded list, and without things like
5275    variable assignments. */
5276
5277 WORD_LIST *
5278 expand_words (list)
5279      WORD_LIST *list;
5280 {
5281   return (expand_word_list_internal (list, 1));
5282 }
5283
5284 /* Same as expand_words (), but doesn't hack variable or environment
5285    variables. */
5286 WORD_LIST *
5287 expand_words_no_vars (list)
5288      WORD_LIST *list;
5289 {
5290   return (expand_word_list_internal (list, 0));
5291 }
5292
5293 /* The workhorse for expand_words () and expand_words_no_vars ().
5294    First arg is LIST, a WORD_LIST of words.
5295    Second arg DO_VARS is non-zero if you want to do environment and
5296    variable assignments, else zero.
5297
5298    This does all of the substitutions: brace expansion, tilde expansion,
5299    parameter expansion, command substitution, arithmetic expansion,
5300    process substitution, word splitting, and pathname expansion.  Words
5301    with the W_QUOTED or W_NOSPLIT bits set, or for which no expansion
5302    is done, do not undergo word splitting.  Words with the W_ASSIGNMENT
5303    bit set do not undergo pathname expansion. */
5304 static WORD_LIST *
5305 expand_word_list_internal (list, do_vars)
5306      WORD_LIST *list;
5307      int do_vars;
5308 {
5309   WORD_LIST *tlist, *new_list, *next, *temp_list, *orig_list, *disposables;
5310   char *temp_string;
5311   int tint;
5312
5313   if (list == 0)
5314     return ((WORD_LIST *)NULL);
5315
5316   tlist = copy_word_list (list);
5317
5318   if (do_vars)
5319     {
5320       tlist = separate_out_assignments (tlist);
5321       if (tlist == 0)
5322         {
5323           if (varlist)
5324             {
5325               /* All the words were variable assignments, so they are placed
5326                  into the shell's environment. */
5327               for (new_list = varlist; new_list; new_list = new_list->next)
5328                 {
5329                   this_command_name = (char *)NULL;     /* no arithmetic errors */
5330                   tint = do_assignment (new_list->word->word);
5331                   /* Variable assignment errors in non-interactive shells
5332                      running in Posix.2 mode cause the shell to exit. */
5333                   if (tint == 0 && interactive_shell == 0 && posixly_correct)
5334                     {
5335                       last_command_exit_value = EXECUTION_FAILURE;
5336                       jump_to_top_level (FORCE_EOF);
5337                     }
5338                 }
5339               dispose_words (varlist);
5340               varlist = (WORD_LIST *)NULL;
5341             }
5342           return ((WORD_LIST *)NULL);
5343         }
5344     }
5345
5346   /* Begin expanding the words that remain.  The expansions take place on
5347      things that aren't really variable assignments. */
5348
5349 #if defined (BRACE_EXPANSION)
5350   /* Do brace expansion on this word if there are any brace characters
5351      in the string. */
5352   if (brace_expansion && tlist)
5353     {
5354       register char **expansions;
5355       WORD_LIST *braces;
5356       WORD_DESC *w;
5357       int eindex;
5358
5359       for (braces = disposables = (WORD_LIST *)NULL; tlist; tlist = next)
5360         {
5361           next = tlist->next;
5362
5363           /* Only do brace expansion if the word has a brace character.  If
5364              not, just add the word list element to BRACES and continue.  In
5365              the common case, at least when running shell scripts, this will
5366              degenerate to a bunch of calls to `strchr', and then what is
5367              basically a reversal of TLIST into BRACES, which is corrected
5368              by a call to reverse_list () on BRACES when the end of TLIST
5369              is reached. */
5370           if (strchr (tlist->word->word, '{'))
5371             {
5372               expansions = brace_expand (tlist->word->word);
5373
5374               for (eindex = 0; temp_string = expansions[eindex]; eindex++)
5375                 {
5376                   w = make_word (temp_string);
5377                   /* If brace expansion didn't change the word, preserve
5378                      the flags.  We may want to preserve the flags
5379                      unconditionally someday -- XXX */
5380                   if (STREQ (temp_string, tlist->word->word))
5381                     w->flags = tlist->word->flags;
5382                   braces = make_word_list (w, braces);
5383                   free (expansions[eindex]);
5384                 }
5385               free (expansions);
5386
5387               /* Add TLIST to the list of words to be freed after brace
5388                  expansion has been performed. */
5389               tlist->next = disposables;
5390               disposables = tlist;
5391             }
5392           else
5393             {
5394               tlist->next = braces;
5395               braces = tlist;
5396             }
5397         }
5398
5399       dispose_words (disposables);
5400       tlist = REVERSE_LIST (braces, WORD_LIST *);
5401     }
5402 #endif /* BRACE_EXPANSION */
5403
5404   /* We do tilde expansion all the time.  This is what 1003.2 says. */
5405   for (orig_list = tlist, new_list = (WORD_LIST *)NULL; tlist; tlist = next)
5406     {
5407       WORD_LIST *expanded;
5408       int expanded_something, has_dollar_at;
5409
5410       temp_string = tlist->word->word;
5411
5412       next = tlist->next;
5413
5414       /* Posix.2 section 3.6.1 says that tildes following `=' in words
5415          which are not assignment statements are not expanded.  We do
5416          this only if POSIXLY_CORRECT is enabled.  Essentially, we do
5417          tilde expansion on unquoted assignment statements (flags include
5418          W_ASSIGNMENT but not W_QUOTED). */
5419       if (temp_string[0] == '~' ||
5420             (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) &&
5421              posixly_correct == 0 &&
5422              strchr (temp_string, '~') &&
5423              (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string))))
5424         {
5425           tlist->word->word = bash_tilde_expand (temp_string);
5426           free (temp_string);
5427         }
5428
5429       expanded_something = 0;
5430       expanded = expand_word_internal
5431         (tlist->word, 0, &has_dollar_at, &expanded_something);
5432
5433       if (expanded == &expand_word_error || expanded == &expand_word_fatal)
5434         {
5435           /* By convention, each time this error is returned,
5436              tlist->word->word has already been freed. */
5437           tlist->word->word = (char *)NULL;
5438
5439           /* Dispose our copy of the original list. */
5440           dispose_words (orig_list);
5441           /* Dispose the new list we're building. */
5442           dispose_words (new_list);
5443
5444           if (expanded == &expand_word_error)
5445             jump_to_top_level (DISCARD);
5446           else
5447             jump_to_top_level (FORCE_EOF);
5448         }
5449
5450       /* Don't split words marked W_NOSPLIT. */
5451       if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
5452         {
5453           temp_list = word_list_split (expanded);
5454           dispose_words (expanded);
5455         }
5456       else
5457         {
5458           /* If no parameter expansion, command substitution, process
5459              substitution, or arithmetic substitution took place, then
5460              do not do word splitting.  We still have to remove quoted
5461              null characters from the result. */
5462           word_list_remove_quoted_nulls (expanded);
5463           temp_list = expanded;
5464         }
5465
5466       /* In the most common cases, t will be a list containing only one
5467          element, so the call to reverse_list would be wasted. */
5468       expanded = REVERSE_LIST (temp_list, WORD_LIST *);
5469       new_list = (WORD_LIST *)list_append (expanded, new_list);
5470     }
5471
5472   new_list = REVERSE_LIST (new_list, WORD_LIST *);
5473
5474   dispose_words (orig_list);
5475
5476   /* Okay, we're almost done.  Now let's just do some filename
5477      globbing. */
5478   if (new_list)
5479     {
5480       char **glob_array;
5481       register int glob_index;
5482       WORD_LIST *glob_list;
5483       WORD_DESC *tword;
5484
5485       orig_list = disposables = (WORD_LIST *)NULL;
5486       tlist = new_list;
5487
5488       /* orig_list == output list, despite the name. */
5489       if (disallow_filename_globbing == 0)
5490         {
5491           glob_array = (char **)NULL;
5492           while (tlist)
5493             {
5494               /* For each word, either globbing is attempted or the word is
5495                  added to orig_list.  If globbing succeeds, the results are
5496                  added to orig_list and the word (tlist) is added to the list
5497                  of disposable words.  If globbing fails and failed glob
5498                  expansions are left unchanged (the shell default), the
5499                  original word is added to orig_list.  If globbing fails and
5500                  failed glob expansions are removed, the original word is
5501                  added to the list of disposable words.  orig_list ends up
5502                  in reverse order and requires a call to reverse_list to
5503                  be set right.  After all words are examined, the disposable
5504                  words are freed. */
5505               next = tlist->next;
5506
5507               /* If the word isn't an assignment and contains an unquoted
5508                  pattern matching character, then glob it. */
5509 #if 0
5510               if ((tlist->word->flags & (W_QUOTED|W_ASSIGNMENT)) == 0 &&
5511 #else
5512               if ((tlist->word->flags & W_ASSIGNMENT) == 0 &&
5513 #endif
5514                   unquoted_glob_pattern_p (tlist->word->word))
5515                 {
5516                   glob_array = shell_glob_filename (tlist->word->word);
5517
5518                   /* Handle error cases.
5519                      I don't think we should report errors like "No such file
5520                      or directory".  However, I would like to report errors
5521                      like "Read failed". */
5522
5523                   if (GLOB_FAILED (glob_array))
5524                     {
5525                       glob_array = (char **) xmalloc (sizeof (char *));
5526                       glob_array[0] = (char *)NULL;
5527                     }
5528
5529                   /* Dequote the current word in case we have to use it. */
5530                   if (glob_array[0] == NULL)
5531                     {
5532                       temp_string = dequote_string (tlist->word->word);
5533                       free (tlist->word->word);
5534                       tlist->word->word = temp_string;
5535                     }
5536
5537                   /* Make the array into a word list. */
5538                   glob_list = (WORD_LIST *)NULL;
5539                   for (glob_index = 0; glob_array[glob_index]; glob_index++)
5540                     {
5541                       tword = make_bare_word (glob_array[glob_index]);
5542                       tword->flags |= W_GLOBEXP;        /* XXX */
5543                       glob_list = make_word_list (tword, glob_list);
5544                     }
5545
5546                   if (glob_list)
5547                     {
5548                       orig_list = (WORD_LIST *)list_append (glob_list, orig_list);
5549                       tlist->next = disposables;
5550                       disposables = tlist;
5551                     }
5552                   else if (allow_null_glob_expansion == 0)
5553                     {
5554                       /* Failed glob expressions are left unchanged. */
5555                       tlist->next = orig_list;
5556                       orig_list = tlist;
5557                     }
5558                   else
5559                     {
5560                       /* Failed glob expressions are removed. */
5561                       tlist->next = disposables;
5562                       disposables = tlist;
5563                     }
5564                 }
5565               else
5566                 {
5567                   /* Dequote the string. */
5568                   temp_string = dequote_string (tlist->word->word);
5569                   free (tlist->word->word);
5570                   tlist->word->word = temp_string;
5571                   tlist->next = orig_list;
5572                   orig_list = tlist;
5573                 }
5574
5575               free_array (glob_array);
5576               glob_array = (char **)NULL;
5577
5578               tlist = next;
5579             }
5580
5581           if (disposables)
5582             dispose_words (disposables);
5583
5584           new_list = REVERSE_LIST (orig_list, WORD_LIST *);
5585         }
5586       else
5587         {
5588           /* Dequote the words, because we're not performing globbing. */
5589           for (temp_list = new_list; temp_list; temp_list = temp_list->next)
5590             {
5591               temp_string = dequote_string (temp_list->word->word);
5592               free (temp_list->word->word);
5593               temp_list->word->word = temp_string;
5594             }
5595         }
5596     }
5597
5598   if (do_vars)
5599     {
5600       Function *assign_func;
5601
5602       /* If the remainder of the words expand to nothing, Posix.2 requires
5603          that the variable and environment assignments affect the shell's
5604          environment. */
5605       assign_func = new_list ? assign_in_env : do_assignment;
5606
5607       for (temp_list = varlist; temp_list; temp_list = temp_list->next)
5608         {
5609           this_command_name = (char *)NULL;
5610           tint = (*assign_func) (temp_list->word->word);
5611           /* Variable assignment errors in non-interactive shells running
5612              in Posix.2 mode cause the shell to exit. */
5613           if (tint == 0 && assign_func == do_assignment &&
5614                 interactive_shell == 0 && posixly_correct)
5615             {
5616               last_command_exit_value = EXECUTION_FAILURE;
5617               jump_to_top_level (FORCE_EOF);
5618             }
5619         }
5620
5621       dispose_words (varlist);
5622       varlist = (WORD_LIST *)NULL;
5623     }
5624
5625   tint = list_length (new_list) + 1;
5626   RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
5627   for (tint = 0, tlist = new_list; tlist; tlist = tlist->next)
5628     glob_argv_flags[tint++] = (tlist->word->flags & W_GLOBEXP) ? '1' : '0';
5629   glob_argv_flags[tint] = '\0';
5630
5631   return (new_list);
5632 }
5633
5634 /*************************************************
5635  *                                               *
5636  *      Functions to manage special variables    *
5637  *                                               *
5638  *************************************************/
5639
5640 /* An alist of name.function for each special variable.  Most of the
5641    functions don't do much, and in fact, this would be faster with a
5642    switch statement, but by the end of this file, I am sick of switch
5643    statements. */
5644
5645 #define SET_INT_VAR(name, intvar)  intvar = find_variable (name) != 0
5646
5647 struct name_and_function {
5648   char *name;
5649   VFunction *function;
5650 } special_vars[] = {
5651   { "PATH", sv_path },
5652   { "MAIL", sv_mail },
5653   { "MAILPATH", sv_mail },
5654   { "MAILCHECK", sv_mail },
5655
5656   { "POSIXLY_CORRECT", sv_strict_posix },
5657   { "GLOBIGNORE", sv_globignore },
5658
5659   /* Variables which only do something special when READLINE is defined. */
5660 #if defined (READLINE)
5661   { "TERM", sv_terminal },
5662   { "TERMCAP", sv_terminal },
5663   { "TERMINFO", sv_terminal },
5664   { "HOSTFILE", sv_hostfile },
5665 #endif /* READLINE */
5666
5667   /* Variables which only do something special when HISTORY is defined. */
5668 #if defined (HISTORY)
5669   { "HISTIGNORE", sv_histignore },
5670   { "HISTSIZE", sv_histsize },
5671   { "HISTFILESIZE", sv_histsize },
5672   { "HISTCONTROL", sv_history_control },
5673 #  if defined (BANG_HISTORY)
5674   { "histchars", sv_histchars },
5675 #  endif /* BANG_HISTORY */
5676 #endif /* HISTORY */
5677
5678   { "IGNOREEOF", sv_ignoreeof },
5679   { "ignoreeof", sv_ignoreeof },
5680
5681   { "OPTIND", sv_optind },
5682   { "OPTERR", sv_opterr },
5683
5684   { "TEXTDOMAIN", sv_locale },
5685   { "TEXTDOMAINDIR", sv_locale },
5686   { "LC_ALL", sv_locale },
5687   { "LC_COLLATE", sv_locale },
5688   { "LC_CTYPE", sv_locale },
5689   { "LC_MESSAGES", sv_locale },
5690   { "LANG", sv_locale },
5691
5692 #if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
5693   { "TZ", sv_tz },
5694 #endif
5695
5696   { (char *)0, (VFunction *)0 }
5697 };
5698
5699 /* The variable in NAME has just had its state changed.  Check to see if it
5700    is one of the special ones where something special happens. */
5701 void
5702 stupidly_hack_special_variables (name)
5703      char *name;
5704 {
5705   int i;
5706
5707   for (i = 0; special_vars[i].name; i++)
5708     {
5709       if (STREQ (special_vars[i].name, name))
5710         {
5711           (*(special_vars[i].function)) (name);
5712           return;
5713         }
5714     }
5715 }
5716
5717 /* What to do just after the PATH variable has changed. */
5718 void
5719 sv_path (name)
5720      char *name;
5721 {
5722   /* hash -r */
5723   flush_hashed_filenames ();
5724 }
5725
5726 /* What to do just after one of the MAILxxxx variables has changed.  NAME
5727    is the name of the variable.  This is called with NAME set to one of
5728    MAIL, MAILCHECK, or MAILPATH.  */
5729 void
5730 sv_mail (name)
5731      char *name;
5732 {
5733   /* If the time interval for checking the files has changed, then
5734      reset the mail timer.  Otherwise, one of the pathname vars
5735      to the users mailbox has changed, so rebuild the array of
5736      filenames. */
5737   if (name[4] == 'C')  /* if (strcmp (name, "MAILCHECK") == 0) */
5738     reset_mail_timer ();
5739   else
5740     {
5741       free_mail_files ();
5742       remember_mail_dates ();
5743     }
5744 }
5745
5746 /* What to do when GLOBIGNORE changes. */
5747 void
5748 sv_globignore (name)
5749      char *name;
5750 {
5751   setup_glob_ignore (name);
5752 }
5753
5754 #if defined (READLINE)
5755 /* What to do just after one of the TERMxxx variables has changed.
5756    If we are an interactive shell, then try to reset the terminal
5757    information in readline. */
5758 void
5759 sv_terminal (name)
5760      char *name;
5761 {
5762   if (interactive_shell && no_line_editing == 0)
5763     rl_reset_terminal (get_string_value ("TERM"));
5764 }
5765
5766 void
5767 sv_hostfile (name)
5768      char *name;
5769 {
5770   hostname_list_initialized = 0;
5771 }
5772 #endif /* READLINE */
5773
5774 #if defined (HISTORY)
5775 /* What to do after the HISTSIZE or HISTFILESIZE variables change.
5776    If there is a value for this HISTSIZE (and it is numeric), then stifle
5777    the history.  Otherwise, if there is NO value for this variable,
5778    unstifle the history.  If name is HISTFILESIZE, and its value is
5779    numeric, truncate the history file to hold no more than that many
5780    lines. */
5781 void
5782 sv_histsize (name)
5783      char *name;
5784 {
5785   char *temp;
5786   long num;
5787
5788   temp = get_string_value (name);
5789
5790   if (temp && *temp)
5791     {
5792       if (legal_number (temp, &num))
5793         {
5794           if (name[4] == 'S')
5795             {
5796               stifle_history (num);
5797               num = where_history ();
5798               if (history_lines_this_session > num)
5799                 history_lines_this_session = num;
5800             }
5801           else
5802             {
5803               history_truncate_file (get_string_value ("HISTFILE"), (int)num);
5804               if (num <= history_lines_in_file)
5805                 history_lines_in_file = num;
5806             }
5807         }
5808     }
5809   else if (name[4] == 'S')
5810     unstifle_history ();
5811 }
5812
5813 /* What to do after the HISTIGNORE variable changes. */
5814 void
5815 sv_histignore (name)
5816      char *name;
5817 {
5818   setup_history_ignore (name);
5819 }
5820
5821 /* What to do after the HISTCONTROL variable changes. */
5822 void
5823 sv_history_control (name)
5824      char *name;
5825 {
5826   char *temp;
5827
5828   history_control = 0;
5829   temp = get_string_value (name);
5830
5831   if (temp && *temp && STREQN (temp, "ignore", 6))
5832     {
5833       if (temp[6] == 's')       /* ignorespace */
5834         history_control = 1;
5835       else if (temp[6] == 'd')  /* ignoredups */
5836         history_control = 2;
5837       else if (temp[6] == 'b')  /* ignoreboth */
5838         history_control = 3;
5839     }
5840 }
5841
5842 #if defined (BANG_HISTORY)
5843 /* Setting/unsetting of the history expansion character. */
5844 void
5845 sv_histchars (name)
5846      char *name;
5847 {
5848   char *temp;
5849
5850   temp = get_string_value (name);
5851   if (temp)
5852     {
5853       history_expansion_char = *temp;
5854       if (temp[0] && temp[1])
5855         {
5856           history_subst_char = temp[1];
5857           if (temp[2])
5858               history_comment_char = temp[2];
5859         }
5860     }
5861   else
5862     {
5863       history_expansion_char = '!';
5864       history_subst_char = '^';
5865       history_comment_char = '#';
5866     }
5867 }
5868 #endif /* BANG_HISTORY */
5869 #endif /* HISTORY */
5870
5871 #if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
5872 void
5873 sv_tz (name)
5874      char *name;
5875 {
5876   tzset ();
5877 }
5878 #endif
5879
5880 /* If the variable exists, then the value of it can be the number
5881    of times we actually ignore the EOF.  The default is small,
5882    (smaller than csh, anyway). */
5883 void
5884 sv_ignoreeof (name)
5885      char *name;
5886 {
5887   SHELL_VAR *tmp_var;
5888   char *temp;
5889
5890   eof_encountered = 0;
5891
5892   tmp_var = find_variable (name);
5893   ignoreeof = tmp_var != 0;
5894   temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
5895   if (temp)
5896     eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
5897   set_shellopts ();     /* make sure `ignoreeof' is/is not in $SHELLOPTS */
5898 }
5899
5900 void
5901 sv_optind (name)
5902      char *name;
5903 {
5904   char *tt;
5905   int s;
5906
5907   tt = get_string_value ("OPTIND");
5908   if (tt && *tt)
5909     {
5910       s = atoi (tt);
5911
5912       /* According to POSIX, setting OPTIND=1 resets the internal state
5913          of getopt (). */
5914       if (s < 0 || s == 1)
5915         s = 0;
5916     }
5917   else
5918     s = 0;
5919   getopts_reset (s);
5920 }
5921
5922 void
5923 sv_opterr (name)
5924      char *name;
5925 {
5926   char *tt;
5927
5928   tt = get_string_value ("OPTERR");
5929   sh_opterr = (tt && *tt) ? atoi (tt) : 1;
5930 }
5931
5932 void
5933 sv_strict_posix (name)
5934      char *name;
5935 {
5936   SET_INT_VAR (name, posixly_correct);
5937   posix_initialize (posixly_correct);
5938 #if defined (READLINE)
5939   if (interactive_shell)
5940     posix_readline_initialize (posixly_correct);
5941 #endif /* READLINE */
5942   set_shellopts ();     /* make sure `posix' is/is not in $SHELLOPTS */
5943 }
5944
5945 void
5946 sv_locale (name)
5947      char *name;
5948 {
5949   char *v;
5950
5951   v = get_string_value (name);
5952   if (name[0] == 'L' && name[1] == 'A') /* LANG */
5953     set_lang (name, v);
5954   else
5955     set_locale_var (name, v);           /* LC_*, TEXTDOMAIN* */
5956 }