a2640f7f57dd890e5ffd4fb4a050b0d4b058eb85
[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    Return value is 1 if both values were OK, 0 if there was a problem
3511    with an invalid expression, or -1 if the values were out of range. */
3512 static int
3513 verify_substring_values (value, substr, vtype, e1p, e2p)
3514      char *value, *substr;
3515      int vtype, *e1p, *e2p;
3516 {
3517   char *t, *temp1;
3518   int len, expok;
3519 #if defined (ARRAY_VARS)
3520  ARRAY *a;
3521 #endif
3522
3523   t = strchr (substr, ':');
3524   if (t)
3525     *t = '\0';
3526   temp1 = maybe_expand_string (substr, Q_DOUBLE_QUOTES, expand_string);
3527   *e1p = evalexp (temp1, &expok);
3528   free (temp1);
3529   if (expok == 0)
3530     return (0);
3531
3532   switch (vtype)
3533     {
3534     case VT_VARIABLE:
3535     case VT_ARRAYMEMBER:
3536       len = strlen (value);
3537       break;
3538     case VT_POSPARMS:
3539       len = number_of_args () + 1;
3540       break;
3541 #if defined (ARRAY_VARS)
3542     case VT_ARRAYVAR:
3543       a = (ARRAY *)value;
3544       len = array_num_elements (a) + 1;
3545       break;
3546 #endif
3547     }
3548
3549   if (*e1p < 0)         /* negative offsets count from end */
3550     *e1p += len;
3551
3552   if (*e1p >= len || *e1p < 0)
3553     return (-1);
3554
3555   if (t)
3556     {
3557       t++;
3558       temp1 = maybe_expand_string (t, Q_DOUBLE_QUOTES, expand_string);
3559       t[-1] = ':';
3560       *e2p = evalexp (temp1, &expok);
3561       free (temp1);
3562       if (expok == 0)
3563         return (0);
3564       if (*e2p < 0)
3565         {
3566           internal_error ("%s: substring expression < 0", t);
3567           return (0);
3568         }
3569       *e2p += *e1p;             /* want E2 chars starting at E1 */
3570       if (*e2p > len)
3571         *e2p = len;
3572     }
3573   else
3574     *e2p = len;
3575
3576   return (1);
3577 }
3578
3579 /* Return a string containing the positional parameters from START to
3580    END, inclusive.  If STRING[0] == '*', we obey the rules for $*,
3581    which only makes a difference if QUOTED is non-zero. */
3582 static char *
3583 pos_params (string, start, end, quoted)
3584      char *string;
3585      int start, end, quoted;
3586 {
3587   WORD_LIST *save, *params, *h, *t;
3588   char *ret;
3589   int i;
3590
3591   save = params = list_rest_of_args ();
3592   if (save == 0)
3593     return ((char *)NULL);
3594
3595   for (i = 1; params && i < start; i++)
3596     params = params->next;
3597   if (params == 0)
3598     return ((char *)NULL);
3599   for (h = t = params; params && i < end; i++)
3600     {
3601       t = params;
3602       params = params->next;
3603     }
3604
3605   t->next = (WORD_LIST *)NULL;
3606   if (string[0] == '*')
3607     ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (h) : string_list (h);
3608   else
3609     ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h);
3610   t->next = params;
3611
3612   dispose_words (save);
3613   return (ret);
3614 }
3615
3616 /* Return the type of variable specified by VARNAME (simple variable,
3617    positional param, or array variable.  Also return the value specified
3618    by VARNAME (value of a variable or a reference to an array element). */
3619 static int
3620 get_var_and_type (varname, value, varp, valp)
3621      char *varname, *value;
3622      SHELL_VAR **varp;
3623      char **valp;
3624 {
3625   int vtype;
3626   char *temp;
3627 #if defined (ARRAY_VARS)
3628   SHELL_VAR *v;
3629 #endif
3630
3631   vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0';       /* VT_POSPARMS */
3632   *varp = (SHELL_VAR *)NULL;
3633
3634 #if defined (ARRAY_VARS)
3635   if (valid_array_reference (varname))
3636     {
3637       v = array_variable_part (varname, &temp, (int *)0);
3638       if (v && array_p (v))
3639         {
3640           if ((temp[0] == '@' || temp[0] == '*') && temp[1] == ']')
3641             {
3642               vtype = VT_ARRAYVAR;
3643               *valp = (char *)array_cell (v);
3644             }
3645           else
3646             {
3647               vtype = VT_ARRAYMEMBER;
3648               *valp = array_value (varname, 1);
3649             }
3650           *varp = v;
3651         }
3652       else
3653         return -1;
3654     }
3655   else if ((v = find_variable (varname)) && array_p (v))
3656     {
3657       vtype = VT_VARIABLE;
3658       *varp = v;
3659       *valp = array_reference (array_cell (v), 0);
3660     }
3661   else
3662 #endif
3663   *valp = value;
3664
3665   return vtype;
3666 }
3667
3668 /* Process a variable substring expansion: ${name:e1[:e2]}.  If VARNAME
3669    is `@', use the positional parameters; otherwise, use the value of
3670    VARNAME.  If VARNAME is an array variable, use the array elements. */
3671
3672 static char *
3673 parameter_brace_substring (varname, value, substr, quoted)
3674      char *varname, *value, *substr;
3675      int quoted;
3676 {
3677   int e1, e2, vtype, r;
3678   char *temp, *val;
3679   SHELL_VAR *v;
3680
3681   if (value == 0)
3682     return ((char *)NULL);
3683
3684   this_command_name = varname;
3685
3686   vtype = get_var_and_type (varname, value, &v, &val);
3687   if (vtype == -1)
3688     return ((char *)NULL);
3689
3690   r = verify_substring_values (val, substr, vtype, &e1, &e2);
3691   if (r <= 0)
3692     {
3693       if (val && vtype == VT_ARRAYMEMBER)
3694         free (val);
3695       return ((r == 0) ? &expand_param_error : (char *)NULL);
3696     }
3697
3698   switch (vtype)
3699     {
3700     case VT_VARIABLE:
3701     case VT_ARRAYMEMBER:
3702       temp = quoted ? quoted_substring (value, e1, e2) : substring (value, e1, e2);
3703       break;
3704     case VT_POSPARMS:
3705       temp = pos_params (varname, e1, e2, quoted);
3706       break;
3707 #if defined (ARRAY_VARS)
3708     case VT_ARRAYVAR:
3709       temp = array_subrange (array_cell (v), e1, e2, quoted);
3710       break;
3711 #endif
3712     }
3713
3714   return temp;
3715 }
3716
3717 char *
3718 pat_subst (string, pat, rep, mflags)
3719      char *string, *pat, *rep;
3720      int mflags;
3721 {
3722   char *ret, *s, *e, *str;
3723   int rsize, rptr, l, replen, mtype;
3724
3725   ret = xmalloc (rsize = 64);
3726   ret[0] = '\0';
3727
3728   mtype = mflags & MATCH_TYPEMASK;
3729
3730   for (replen = STRLEN (rep), rptr = 0, str = string;;)
3731     {
3732       if (match_pattern (str, pat, mtype, &s, &e) == 0)
3733         break;
3734       l = s - str;
3735       RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64);
3736
3737       /* OK, now copy the leading unmatched portion of the string (from
3738          str to s) to ret starting at rptr (the current offset).  Then copy
3739          the replacement string at ret + rptr + (s - str).  Increment
3740          rptr (if necessary) and str and go on. */
3741       if (l)
3742         {
3743           strncpy (ret + rptr, str, l);
3744           rptr += l;
3745         }
3746       if (replen)
3747         {
3748           strncpy (ret + rptr, rep, replen);
3749           rptr += replen;
3750         }
3751       str = e;          /* e == end of match */
3752       if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
3753         break;
3754     }
3755
3756   /* Now copy the unmatched portion of the input string */
3757   if (*str)
3758     {
3759       RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
3760       strcpy (ret + rptr, str);
3761     }
3762   else
3763     ret[rptr] = '\0';
3764
3765   return ret;
3766 }
3767
3768 /* Do pattern match and replacement on the positional parameters. */
3769 static char *
3770 pos_params_pat_subst (string, pat, rep, mflags)
3771      char *string, *pat, *rep;
3772      int mflags;
3773 {
3774   WORD_LIST *save, *params;
3775   WORD_DESC *w;
3776   char *ret;
3777
3778   save = params = list_rest_of_args ();
3779   if (save == 0)
3780     return ((char *)NULL);
3781
3782   for ( ; params; params = params->next)
3783     {
3784       ret = pat_subst (params->word->word, pat, rep, mflags);
3785       w = make_bare_word (ret);
3786       dispose_word (params->word);
3787       params->word = w;
3788       FREE (ret);
3789     }
3790
3791   ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save);
3792   dispose_words (save);
3793
3794   return (ret);
3795 }
3796
3797 static char *
3798 parameter_brace_patsub (varname, value, patsub, quoted)
3799      char *varname, *value, *patsub;
3800      int quoted;
3801 {
3802   int vtype, mflags;
3803   char *val, *temp, *pat, *rep, *p;
3804   SHELL_VAR *v;
3805
3806   if (value == 0)
3807     return ((char *)NULL);
3808
3809   this_command_name = varname;
3810
3811   vtype = get_var_and_type (varname, value, &v, &val);
3812   if (vtype == -1)
3813     return ((char *)NULL);
3814
3815   mflags = 0;
3816   if (*patsub == '/')
3817     {
3818       mflags |= MATCH_GLOBREP;
3819       patsub++;
3820     }
3821
3822   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
3823     mflags |= MATCH_QUOTED;
3824
3825   if (rep = quoted_strchr (patsub, '/', ST_BACKSL))
3826     *rep++ = '\0';
3827   else
3828     rep = (char *)NULL;
3829
3830   if (rep && *rep == '\0')
3831     rep = (char *)NULL;
3832
3833   /* Expand PAT and REP for command, variable and parameter, arithmetic,
3834      and process substitution.  Also perform quote removal.  Do not
3835      perform word splitting or filename generation. */
3836   pat = maybe_expand_string (patsub, quoted, expand_string_unsplit);
3837   if (rep)
3838     {
3839       if ((mflags & MATCH_QUOTED) == 0)
3840         rep = maybe_expand_string (rep, quoted, expand_string_unsplit);
3841       else
3842         rep = expand_string_to_string (rep, quoted, expand_string_unsplit);
3843     }
3844
3845   p = pat;
3846   if (pat && pat[0] == '#')
3847     {
3848       mflags |= MATCH_BEG;
3849       p++;
3850     }
3851   else if (pat && pat[0] == '%')
3852     {
3853       mflags |= MATCH_END;
3854       p++;
3855     }
3856   else
3857     mflags |= MATCH_ANY;
3858
3859   /* OK, we now want to substitute REP for PAT in VAL.  If GLOBAL is 1,
3860      the substitution is done everywhere, otherwise only the first
3861      occurrence of PAT is replaced. */
3862   switch (vtype)
3863     {
3864     case VT_VARIABLE:
3865     case VT_ARRAYMEMBER:
3866       temp = pat_subst (val, p, rep, mflags);
3867       break;
3868     case VT_POSPARMS:
3869       temp = pos_params_pat_subst (val, p, rep, mflags);
3870       break;
3871 #if defined (ARRAY_VARS)
3872     case VT_ARRAYVAR:
3873       temp = array_pat_subst (array_cell (v), p, rep, mflags);
3874       break;
3875 #endif
3876     }
3877
3878   if (val && v && array_p (v) && vtype == VT_ARRAYMEMBER)
3879     free (val);
3880
3881   FREE (pat);
3882   FREE (rep);
3883
3884   return temp;
3885 }
3886
3887 /* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */
3888 static char *
3889 parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at)
3890      char *string;
3891      int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at;
3892 {
3893   int check_nullness, var_is_set, var_is_null, var_is_special;
3894   int want_substring, want_indir, want_patsub;
3895   char *name, *value, *temp, *temp1;
3896   int t_index, sindex, c, number;
3897
3898   sindex = *indexp;
3899   t_index = ++sindex;
3900   name = string_extract (string, &t_index, "#%:-=?+/}", 1);
3901   value = (char *)NULL;
3902   var_is_set = var_is_null = var_is_special = check_nullness = 0;
3903   want_substring = want_indir = want_patsub = 0;
3904
3905   /* If the name really consists of a special variable, then
3906      make sure that we have the entire name.  Handle indirect
3907      references to special variables here, too. */
3908   if ((sindex == t_index ||
3909       ((sindex == t_index - 1) && string[sindex] == '!')) &&
3910         (string[t_index] == '-' ||
3911          string[t_index] == '?' ||
3912          string[t_index] == '#'))
3913     {
3914       t_index++;
3915       free (name);
3916       temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
3917       name = xmalloc (3 + (strlen (temp1)));
3918       *name = string[sindex];
3919       if (string[sindex] == '!')
3920         {
3921           /* indirect ref. of special variable */
3922           name[1] = string[sindex + 1];
3923           strcpy (name + 2, temp1);
3924         }
3925       else
3926         strcpy (name + 1, temp1);
3927       free (temp1);
3928     }
3929   sindex = t_index;
3930
3931   /* Find out what character ended the variable name.  Then
3932      do the appropriate thing. */
3933   if (c = string[sindex])
3934     sindex++;
3935
3936   /* If c is followed by one of the valid parameter expansion
3937      characters, move past it as normal.  If not, assume that
3938      a substring specification is being given, and do not move
3939      past it. */
3940   if (c == ':' && member (string[sindex], "-=?+"))
3941     {
3942       check_nullness++;
3943       if (c = string[sindex])
3944         sindex++;
3945     }
3946   else if (c == ':')
3947     want_substring = 1;
3948   else if (c == '/')
3949     want_patsub = 1;
3950
3951   want_indir = *name == '!';
3952
3953   /* Determine the value of this variable. */
3954
3955   /* Check for special variables, directly and indirectly
3956      referenced. */
3957   if ((digit (*name) && all_digits (name)) ||
3958       (name[1] == '\0' && member (*name, "#-?$!@*")) ||
3959       (want_indir && name[2] == '\0' && member (name[1], "#-?$!@*")))
3960     var_is_special++;
3961
3962   /* Check for special expansion things. */
3963   if (*name == '#')     /* length of a parameter */
3964     {
3965       /* Take the lengths of some of the shell's special
3966          parameters. */
3967       if (string[sindex] == '}' && name[1] == '\0' &&
3968           check_nullness == 0 && member (c, "-?$!#"))
3969         {
3970           free (name);
3971           switch (c)
3972             {
3973             case '-':
3974               temp1 = which_set_flags ();
3975               break;
3976             case '?':
3977               temp1 = itos (last_command_exit_value);
3978               break;
3979             case '$':
3980               temp1 = itos (dollar_dollar_pid);
3981               break;
3982             case '!':
3983               if (last_asynchronous_pid == NO_PID)
3984                 temp1 = (char *)NULL;
3985               else
3986                 temp1 = itos ((int)last_asynchronous_pid);
3987               break;
3988             case '#':
3989               temp1 = itos (number_of_args ());
3990               break;
3991             }
3992           number = STRLEN (temp1);
3993           FREE (temp1);
3994           *indexp = ++sindex;   /* { string[sindex] == '}' */
3995           return (itos (number));
3996         }
3997
3998       /* Don't allow things like ${#:-foo} to go by; they are
3999          errors.  If we are not pointing at the character just
4000          after the closing brace, then we haven't gotten all of
4001          the name.  Since it begins with a special character,
4002          this is a bad substitution.  Explicitly check for ${#:},
4003          which the rules do not catch.  Also check NAME for
4004          validity before trying to go on. */
4005       if (string[sindex - 1] != '}' ||
4006           member (c, "?-=+") ||
4007           (name[1] == '\0' && c == '}' && check_nullness) ||
4008           (valid_length_expression (name) == 0))
4009         {
4010           temp = (char *)NULL;
4011           goto bad_substitution;
4012         }
4013
4014       number = parameter_brace_expand_length (name);
4015       free (name);
4016
4017       *indexp = sindex;
4018       return ((number < 0) ? &expand_param_error : itos (number));
4019     }
4020
4021   /* ${@} is identical to $@. */
4022   if (name[0] == '@' && name[1] == '\0')
4023     {
4024       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4025         *quoted_dollar_atp = 1;
4026
4027       if (contains_dollar_at)
4028         *contains_dollar_at = 1;
4029     }
4030
4031   /* Make sure that NAME is valid before trying to go on. */
4032   if (valid_brace_expansion_word (want_indir ? name + 1 : name,
4033                                         var_is_special) == 0)
4034     {
4035       temp = (char *)NULL;
4036       goto bad_substitution;
4037     }
4038
4039   if (want_indir)
4040     temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted);
4041   else
4042     temp = parameter_brace_expand_word (name, var_is_special, quoted);
4043
4044 #if defined (ARRAY_VARS)
4045   if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && valid_array_reference (name))
4046     {
4047       temp1 = strchr (name, '[');
4048       if (temp1 && temp1[1] == '@' && temp1[2] == ']')
4049         {
4050           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4051             *quoted_dollar_atp = 1;
4052           if (contains_dollar_at)
4053             *contains_dollar_at = 1;
4054         }
4055     }
4056 #endif
4057
4058   var_is_set = temp != (char *)0;
4059   var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
4060
4061   /* Get the rest of the stuff inside the braces. */
4062   if (c && c != '}')
4063     {
4064       /* Extract the contents of the ${ ... } expansion
4065          according to the Posix.2 rules. */
4066       value = extract_dollar_brace_string (string, &sindex, quoted);
4067       /*{*/
4068       if (string[sindex] == '}')
4069         sindex++;
4070       else
4071         goto bad_substitution;
4072     }
4073   else
4074     value = (char *)NULL;
4075
4076   *indexp = sindex;
4077
4078   /* If this is a substring spec, process it and add the result. */
4079   if (want_substring)
4080     {
4081       temp1 = parameter_brace_substring (name, temp, value, quoted);
4082       FREE (name);
4083       FREE (value);
4084       FREE (temp);
4085       return (temp1);
4086     }
4087   else if (want_patsub)
4088     {
4089       temp1 = parameter_brace_patsub (name, temp, value, quoted);
4090       FREE (name);
4091       FREE (value);
4092       FREE (temp);
4093       return (temp1);
4094     }
4095
4096   /* Do the right thing based on which character ended the variable name. */
4097   switch (c)
4098     {
4099     default:
4100     case '\0':
4101     bad_substitution:
4102       report_error ("%s: bad substitution", string ? string : "??");
4103       FREE (value);
4104       FREE (temp);
4105       free (name);
4106       return &expand_param_error;
4107
4108     /*{*/
4109     case '}':
4110       if (var_is_set == 0 && unbound_vars_is_error)
4111         {
4112           report_error ("%s: unbound variable", name);
4113           FREE (value);
4114           FREE (temp);
4115           free (name);
4116           last_command_exit_value = EXECUTION_FAILURE;
4117           return (interactive_shell ? &expand_param_error : &expand_param_fatal);
4118         }
4119       break;
4120
4121     case '#':   /* ${param#[#]pattern} */
4122     case '%':   /* ${param%[%]pattern} */
4123       if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
4124         {
4125           FREE (value);
4126           break;
4127         }
4128       if ((name[0] == '@' || name[0] == '*') && name[1] == '\0')
4129         temp1 = parameter_list_remove_pattern (value, name[0], c, quoted);
4130 #if defined (ARRAY_VARS)
4131       else if (valid_array_reference (name))
4132         temp1 = array_remove_pattern (value, name, temp, c, quoted);
4133 #endif
4134       else
4135         temp1 = parameter_brace_remove_pattern (value, temp, c, quoted);
4136       free (temp);
4137       free (value);
4138       temp = temp1;
4139       break;
4140
4141     case '-':
4142     case '=':
4143     case '?':
4144     case '+':
4145       if (var_is_set && var_is_null == 0)
4146         {
4147           /* We don't want the value of the named variable for
4148              anything, just the value of the right hand side. */
4149           if (c == '+')
4150             {
4151               FREE (temp);
4152               if (value)
4153                 {
4154                   temp = parameter_brace_expand_rhs (name, value, c,
4155                                                      quoted,
4156                                                      quoted_dollar_atp,
4157                                                      contains_dollar_at);
4158                   free (value);
4159                 }
4160               else
4161                 temp = (char *)NULL;
4162             }
4163           else
4164             {
4165               FREE (value);
4166             }
4167           /* Otherwise do nothing; just use the value in TEMP. */
4168         }
4169       else      /* VAR not set or VAR is NULL. */
4170         {
4171           FREE (temp);
4172           temp = (char *)NULL;
4173           if (c == '=' && var_is_special)
4174             {
4175               report_error ("$%s: cannot assign in this way", name);
4176               free (name);
4177               free (value);
4178               return &expand_param_error;
4179             }
4180           else if (c == '?')
4181             {
4182               parameter_brace_expand_error (name, value);
4183               return (interactive ? &expand_param_error : &expand_param_fatal);
4184             }
4185           else if (c != '+')
4186             temp = parameter_brace_expand_rhs (name, value, c, quoted,
4187                                                quoted_dollar_atp,
4188                                                contains_dollar_at);
4189           free (value);
4190         }
4191       break;
4192     }
4193   free (name);
4194   return (temp);
4195 }
4196
4197 /* Make a word list which is the parameter and variable expansion,
4198    command substitution, arithmetic substitution, and quote removed
4199    expansion of WORD.  Return a pointer to a WORD_LIST which is the
4200    result of the expansion.  If WORD contains a null word, the word
4201    list returned is also null.
4202
4203    QUOTED contains flag values defined in shell.h.
4204
4205    CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
4206    they point to an integer value which receives information about expansion.
4207    CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
4208    EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
4209    else zero.
4210
4211    This only does word splitting in the case of $@ expansion.  In that
4212    case, we split on ' '. */
4213
4214 /* Values for the local variable quoted_state. */
4215 #define UNQUOTED         0
4216 #define PARTIALLY_QUOTED 1
4217 #define WHOLLY_QUOTED    2
4218
4219 static WORD_LIST *
4220 expand_word_internal (word, quoted, contains_dollar_at, expanded_something)
4221      WORD_DESC *word;
4222      int quoted;
4223      int *contains_dollar_at;
4224      int *expanded_something;
4225 {
4226   WORD_LIST *list;
4227   WORD_DESC *tword;
4228   SHELL_VAR *var;
4229
4230   /* The intermediate string that we build while expanding. */
4231   char *istring;
4232
4233   /* The current size of the above object. */
4234   int istring_size;
4235
4236   /* Index into ISTRING. */
4237   int istring_index;
4238
4239   /* Temporary string storage. */
4240   char *temp, *temp1;
4241
4242   /* The text of WORD. */
4243   register char *string;
4244
4245   /* The index into STRING. */
4246   int sindex;
4247
4248   /* This gets 1 if we see a $@ while quoted. */
4249   int quoted_dollar_at;
4250
4251   /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
4252      whether WORD contains no quoting characters, a partially quoted
4253      string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
4254   int quoted_state;
4255
4256   int had_quoted_null;
4257
4258   int expok;
4259
4260   register int c;               /* Current character. */
4261   int number;                   /* Temporary number value. */
4262   int t_index;                  /* For calls to string_extract_xxx. */
4263
4264   istring = xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
4265   istring[istring_index = 0] = '\0';
4266
4267   quoted_dollar_at = had_quoted_null = 0;
4268   quoted_state = UNQUOTED;
4269
4270   string = word->word;
4271   if (string == 0)
4272     goto finished_with_string;
4273
4274   if (contains_dollar_at)
4275     *contains_dollar_at = 0;
4276
4277   /* Begin the expansion. */
4278
4279   for (sindex = 0; ;)
4280     {
4281       c = string[sindex];
4282
4283       /* Case on toplevel character. */
4284       switch (c)
4285         {
4286         case '\0':
4287           goto finished_with_string;
4288
4289         case CTLESC:
4290           temp = xmalloc (3);
4291           temp[0] = CTLESC;
4292           temp[1] = c = string[++sindex];
4293           temp[2] = '\0';
4294
4295           if (string[sindex])
4296             sindex++;
4297
4298           goto add_string;
4299
4300 #if defined (PROCESS_SUBSTITUTION)
4301           /* Process substitution. */
4302         case '<':
4303         case '>':
4304           {
4305             if (string[++sindex] != '(' || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct)
4306               {
4307                 sindex--;
4308                 goto add_character;
4309               }
4310             else
4311               t_index = sindex + 1; /* skip past both '<' and '(' */
4312
4313             temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index);
4314             sindex = t_index;
4315
4316             /* If the process substitution specification is `<()', we want to
4317                open the pipe for writing in the child and produce output; if
4318                it is `>()', we want to open the pipe for reading in the child
4319                and consume input. */
4320             temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
4321
4322             FREE (temp1);
4323
4324             goto dollar_add_string;
4325           }
4326 #endif /* PROCESS_SUBSTITUTION */
4327
4328         /* See about breaking this into a separate function:
4329             char *
4330             param_expand (string, sindex, quoted, expanded_something,
4331                           contains_dollar_at, quoted_dollar_at)
4332             char *string;
4333             int *sindex, quoted, *expanded_something, *contains_dollar_at;
4334             int *quoted_dollar_at;
4335         */
4336         case '$':
4337
4338           if (expanded_something)
4339             *expanded_something = 1;
4340
4341           c = string[++sindex];
4342
4343           /* Do simple cases first. Switch on what follows '$'. */
4344           switch (c)
4345             {
4346               /* $0 .. $9? */
4347             case '0':
4348             case '1':
4349             case '2':
4350             case '3':
4351             case '4':
4352             case '5':
4353             case '6':
4354             case '7':
4355             case '8':
4356             case '9':
4357               temp1 = dollar_vars[digit_value (c)];
4358               if (unbound_vars_is_error && temp1 == (char *)NULL)
4359                 {
4360                   report_error ("$%c: unbound variable", c);
4361                   free (string);
4362                   free (istring);
4363                   last_command_exit_value = EXECUTION_FAILURE;
4364                   return (interactive_shell ? &expand_word_error : &expand_word_fatal);
4365                 }
4366               temp = temp1 ? savestring (temp1) : (char *)NULL;
4367               goto dollar_add_string;
4368
4369               /* $$ -- pid of the invoking shell. */
4370             case '$':
4371               number = dollar_dollar_pid;
4372
4373             add_number:
4374               temp = itos (number);
4375             dollar_add_string:
4376               if (string[sindex]) sindex++;
4377
4378               /* Add TEMP to ISTRING. */
4379             add_string:
4380               if (temp)
4381                 {
4382                   istring = sub_append_string
4383                     (temp, istring, &istring_index, &istring_size);
4384                   temp = (char *)0;
4385                 }
4386
4387               break;
4388
4389               /* $# -- number of positional parameters. */
4390             case '#':
4391               number = number_of_args ();
4392               goto add_number;
4393
4394               /* $? -- return value of the last synchronous command. */
4395             case '?':
4396               number = last_command_exit_value;
4397               goto add_number;
4398
4399               /* $- -- flags supplied to the shell on invocation or
4400                  by `set'. */
4401             case '-':
4402               temp = which_set_flags ();
4403               goto dollar_add_string;
4404
4405               /* $! -- Pid of the last asynchronous command. */
4406             case '!':
4407               number = (int)last_asynchronous_pid;
4408
4409               /* If no asynchronous pids have been created, expand
4410                  to nothing. */
4411               if (number == (int)NO_PID)
4412                 {
4413                   if (string[sindex])
4414                     sindex++;
4415                   if (expanded_something)
4416                     *expanded_something = 0;
4417                   break;
4418                 }
4419               goto add_number;
4420
4421               /* The only difference between this and $@ is when the
4422                  arg is quoted. */
4423             case '*':           /* `$*' */
4424               temp = string_rest_of_args (quoted);
4425
4426               /* If there are no command-line arguments, this should just
4427                  disappear if there are other characters in the expansion,
4428                  even if it's quoted. */
4429               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && temp && *temp == '\0')
4430                 {
4431                   free (temp);
4432                   temp = (char *)NULL;
4433                 }
4434               /* In the case of a quoted string, quote the entire arg-list.
4435                  "$1 $2 $3".  Otherwise quote the special escape characters. */
4436               if (temp)
4437                 {
4438                   temp1 = temp;
4439                   temp = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4440                                 ? quote_string (temp)
4441                                 : quote_escapes (temp);
4442                   free (temp1);
4443                 }
4444               goto dollar_add_string;
4445
4446               /* When we have "$@" what we want is "$1" "$2" "$3" ... This
4447                  means that we have to turn quoting off after we split into
4448                  the individually quoted arguments so that the final split
4449                  on the first character of $IFS is still done.  */
4450             case '@':           /* `$@' */
4451               list = list_rest_of_args ();
4452
4453               /* We want to flag the fact that we saw this.  We can't turn
4454                  off quoting entirely, because other characters in the
4455                  string might need it (consider "\"$@\""), but we need some
4456                  way to signal that the final split on the first character
4457                  of $IFS should be done, even though QUOTED is 1. */
4458               if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4459                 quoted_dollar_at = 1;
4460               if (contains_dollar_at)
4461                 *contains_dollar_at = 1;
4462               temp = string_list (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list) ? quote_list (list) : list);
4463               /* If the expansion is not quoted, protect any special escape
4464                  characters in the expansion by quoting them. */
4465               if (temp && quoted == 0)
4466                 {
4467                   temp1 = temp;
4468                   temp = quote_escapes (temp);
4469                   free (temp1);
4470                 }
4471               dispose_words (list);
4472               goto dollar_add_string;
4473
4474             case '{':   /*}*/
4475               temp = parameter_brace_expand (string, &sindex, quoted,
4476                                              &quoted_dollar_at,
4477                                              contains_dollar_at);
4478               if (temp == &expand_param_error || temp == &expand_param_fatal)
4479                 {
4480                   free (string);
4481                   free (istring);
4482                   return (temp == &expand_param_error) ? &expand_word_error
4483                                                        : &expand_word_fatal;
4484                 }
4485               /* XXX */
4486               /* quoted nulls should be removed if there is anything else
4487                  in the string. */
4488               /* Note that we saw the quoted null so we can add one back at
4489                  the end of this function if there are no other characters
4490                  in the string, discard TEMP, and go on. */
4491               if (temp && QUOTED_NULL (temp))
4492                 {
4493                   had_quoted_null = 1;
4494                   free (temp);
4495                   break;
4496                 }
4497
4498               goto add_string;
4499               /* break; */
4500
4501               /* Do command or arithmetic substitution. */
4502             case '(':   /*)*/
4503               /* We have to extract the contents of this paren substitution. */
4504               t_index = sindex + 1;
4505               temp = extract_command_subst (string, &t_index);
4506               sindex = t_index;
4507
4508               /* For Posix.2-style `$(( ))' arithmetic substitution,
4509                  extract the expression and pass it to the evaluator. */
4510               if (temp && *temp == '(')
4511                 {
4512                   char *temp2;
4513                   temp1 = temp + 1;
4514                   temp2 = savestring (temp1);
4515                   t_index = strlen (temp2) - 1;
4516
4517                   if (temp2[t_index] != ')')
4518                     {
4519                       free (temp2);
4520 #if 0
4521                       report_error ("%s: bad arithmetic substitution", temp);
4522                       free (temp);
4523                       free (string);
4524                       free (istring);
4525                       return (&expand_word_error);
4526 #else
4527                       goto comsub;
4528 #endif
4529                     }
4530
4531                   /* Cut off ending `)' */
4532                   temp2[t_index] = '\0';
4533
4534                   /* Expand variables found inside the expression. */
4535                   temp1 = maybe_expand_string (temp2, Q_DOUBLE_QUOTES, expand_string);
4536                   free (temp2);
4537
4538                   /* No error messages. */
4539                   this_command_name = (char *)NULL;
4540                   number = evalexp (temp1, &expok);
4541                   free (temp);
4542                   free (temp1);
4543                   if (expok == 0)
4544                     {
4545                       free (string);
4546                       free (istring);
4547                       return (&expand_word_error);
4548                     }
4549                   goto add_number;
4550                 }
4551
4552         comsub:
4553               temp1 = command_substitute (temp, quoted);
4554               FREE (temp);
4555               temp = temp1;
4556               goto dollar_add_string;
4557
4558               /* Do straight arithmetic substitution. */
4559             case '[':
4560               /* We have to extract the contents of this
4561                  arithmetic substitution. */
4562               t_index = sindex + 1;
4563               temp = extract_arithmetic_subst (string, &t_index);
4564               sindex = t_index;
4565
4566                /* Do initial variable expansion. */
4567               temp1 = maybe_expand_string (temp, Q_DOUBLE_QUOTES, expand_string);
4568
4569               /* No error messages. */
4570               this_command_name = (char *)NULL;
4571               number = evalexp (temp1, &expok);
4572               free (temp1);
4573               free (temp);
4574               if (expok == 0)
4575                 {
4576                   free (string);
4577                   free (istring);
4578                   return (&expand_word_error);
4579                 }
4580               goto add_number;
4581
4582             default:
4583               /* Find the variable in VARIABLE_LIST. */
4584               temp = (char *)NULL;
4585
4586               for (t_index = sindex;
4587                    (c = string[sindex]) && legal_variable_char (c);
4588                    sindex++);
4589               temp1 = substring (string, t_index, sindex);
4590
4591               /* If this isn't a variable name, then just output the `$'. */
4592               if (temp1 == 0 || *temp1 == '\0')
4593                 {
4594                   FREE (temp1);
4595                   temp = xmalloc (2);
4596                   temp[0] = '$';
4597                   temp[1] = '\0';
4598                   if (expanded_something)
4599                     *expanded_something = 0;
4600                   goto add_string;
4601                 }
4602
4603               /* If the variable exists, return its value cell. */
4604               var = find_variable (temp1);
4605
4606               if (var && invisible_p (var) == 0 && value_cell (var))
4607                 {
4608 #if defined (ARRAY_VARS)
4609                   if (array_p (var))
4610                     {
4611                       temp = array_reference (array_cell (var), 0);
4612                       if (temp)
4613                         temp = quote_escapes (temp);
4614                     }
4615                   else
4616 #endif
4617                   temp = quote_escapes (value_cell (var));
4618                   free (temp1);
4619                   goto add_string;
4620                 }
4621
4622               temp = (char *)NULL;
4623
4624               if (unbound_vars_is_error)
4625                 report_error ("%s: unbound variable", temp1);
4626               else
4627                 {
4628                   free (temp1);
4629                   goto add_string;
4630                 }
4631
4632               free (temp1);
4633               free (string);
4634               last_command_exit_value = EXECUTION_FAILURE;
4635               free (istring);
4636               return ((unbound_vars_is_error && interactive_shell == 0)
4637                         ? &expand_word_fatal
4638                         : &expand_word_error);
4639             }
4640           break;                /* End case '$': */
4641
4642         case '`':               /* Backquoted command substitution. */
4643           {
4644             sindex++;
4645
4646             if (expanded_something)
4647               *expanded_something = 1;
4648
4649             temp = string_extract (string, &sindex, "`", 0);
4650             de_backslash (temp);
4651             temp1 = command_substitute (temp, quoted);
4652             FREE (temp);
4653             temp = temp1;
4654             goto dollar_add_string;
4655           }
4656
4657         case '\\':
4658           if (string[sindex + 1] == '\n')
4659             {
4660               sindex += 2;
4661               continue;
4662             }
4663
4664           c = string[++sindex];
4665
4666           if (quoted & Q_HERE_DOCUMENT)
4667             temp1 = slashify_in_here_document;
4668           else if (quoted & Q_DOUBLE_QUOTES)
4669             temp1 = slashify_in_quotes;
4670           else
4671             temp1 = "";
4672
4673           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && member (c, temp1) == 0)
4674             {
4675               temp = xmalloc (3);
4676               temp[0] = '\\'; temp[1] = c; temp[2] = '\0';
4677             }
4678           else
4679             /* This character is quoted, so add it in quoted mode. */
4680             temp = make_quoted_char (c);
4681
4682           if (c)
4683             sindex++;
4684           goto add_string;
4685
4686         case '"':
4687           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE))
4688             goto add_character;
4689
4690           t_index = ++sindex;
4691           temp = string_extract_double_quoted (string, &sindex, 0);
4692
4693           /* If the quotes surrounded the entire string, then the
4694              whole word was quoted. */
4695           quoted_state = (t_index == 1 && string[sindex] == '\0')
4696                             ? WHOLLY_QUOTED
4697                             : PARTIALLY_QUOTED;
4698
4699           if (temp && *temp)
4700             {
4701               int dollar_at_flag;
4702
4703               tword = make_word (temp);         /* XXX */
4704               free (temp);
4705               temp = (char *)NULL;
4706
4707               list = expand_word_internal (tword, Q_DOUBLE_QUOTES, &dollar_at_flag, (int *)NULL);
4708
4709               if (list == &expand_word_error || list == &expand_word_fatal)
4710                 {
4711                   free (istring);
4712                   free (string);
4713                   /* expand_word_internal has already freed temp_word->word
4714                      for us because of the way it prints error messages. */
4715                   tword->word = (char *)NULL;
4716                   dispose_word (tword);
4717                   return list;
4718                 }
4719
4720               dispose_word (tword);
4721
4722               /* "$@" (a double-quoted dollar-at) expands into nothing,
4723                  not even a NULL word, when there are no positional
4724                  parameters. */
4725               if (list == 0 && dollar_at_flag)
4726                 {
4727                   quoted_dollar_at++;
4728                   break;
4729                 }
4730
4731               /* If we get "$@", we know we have expanded something, so we
4732                  need to remember it for the final split on $IFS.  This is
4733                  a special case; it's the only case where a quoted string
4734                  can expand into more than one word.  It's going to come back
4735                  from the above call to expand_word_internal as a list with
4736                  a single word, in which all characters are quoted and
4737                  separated by blanks.  What we want to do is to turn it back
4738                  into a list for the next piece of code. */
4739               if (list)
4740                 dequote_list (list);
4741
4742               if (dollar_at_flag)
4743                 {
4744                   quoted_dollar_at++;
4745                   if (contains_dollar_at)
4746                     *contains_dollar_at = 1;
4747                   if (expanded_something)
4748                     *expanded_something = 1;
4749                 }
4750             }
4751           else
4752             {
4753               /* What we have is "".  This is a minor optimization. */
4754               free (temp);
4755               list = (WORD_LIST *)NULL;
4756             }
4757
4758           /* The code above *might* return a list (consider the case of "$@",
4759              where it returns "$1", "$2", etc.).  We can't throw away the
4760              rest of the list, and we have to make sure each word gets added
4761              as quoted.  We test on tresult->next:  if it is non-NULL, we
4762              quote the whole list, save it to a string with string_list, and
4763              add that string. We don't need to quote the results of this
4764              (and it would be wrong, since that would quote the separators
4765              as well), so we go directly to add_string. */
4766           if (list)
4767             {
4768               if (list->next)
4769                 {
4770                   temp = string_list (quote_list (list));
4771                   dispose_words (list);
4772                   goto add_string;
4773                 }
4774               else
4775                 {
4776                   temp = savestring (list->word->word);
4777                   dispose_words (list);
4778                 }
4779             }
4780           else
4781             temp = (char *)NULL;
4782
4783           /* We do not want to add quoted nulls to strings that are only
4784              partially quoted; we can throw them away. */
4785           if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
4786             {
4787               FREE (temp);
4788               continue;
4789             }
4790
4791         add_quoted_string:
4792
4793           if (temp)
4794             {
4795               temp1 = temp;
4796               temp = quote_string (temp);
4797               free (temp1);
4798             }
4799           else
4800             {
4801               /* Add NULL arg. */
4802               temp = xmalloc (2);
4803               temp[0] = CTLNUL;
4804               temp[1] = '\0';
4805             }
4806           goto add_string;
4807           /* break; */
4808
4809         case '\'':
4810           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE))
4811             goto add_character;
4812
4813           t_index = ++sindex;
4814           temp = string_extract_single_quoted (string, &sindex);
4815
4816           /* If the entire STRING was surrounded by single quotes,
4817              then the string is wholly quoted. */
4818           quoted_state = (t_index == 1 && string[sindex] == '\0')
4819                             ? WHOLLY_QUOTED
4820                             : PARTIALLY_QUOTED;
4821
4822           /* If all we had was '', it is a null expansion. */
4823           if (*temp == '\0')
4824             {
4825               free (temp);
4826               temp = (char *)NULL;
4827             }
4828           else
4829             remove_quoted_escapes (temp);
4830
4831           /* We do not want to add quoted nulls to strings that are only
4832              partially quoted; such nulls are discarded. */
4833           if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
4834             continue;
4835
4836           goto add_quoted_string;
4837           /* break; */
4838
4839         default:
4840           /* This is the fix for " $@ " */
4841           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4842             {
4843               temp = make_quoted_char (c);
4844               goto dollar_add_string;
4845             }
4846
4847         add_character:
4848           RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
4849                                   DEFAULT_ARRAY_SIZE);
4850           istring[istring_index++] = c;
4851           istring[istring_index] = '\0';
4852
4853           /* Next character. */
4854           sindex++;
4855         }
4856     }
4857
4858 finished_with_string:
4859   /* OK, we're ready to return.  If we have a quoted string, and
4860      quoted_dollar_at is not set, we do no splitting at all; otherwise
4861      we split on ' '.  The routines that call this will handle what to
4862      do if nothing has been expanded. */
4863
4864   /* Partially and wholly quoted strings which expand to the empty
4865      string are retained as an empty arguments.  Unquoted strings
4866      which expand to the empty string are discarded.  The single
4867      exception is the case of expanding "$@" when there are no
4868      positional parameters.  In that case, we discard the expansion. */
4869
4870   /* Because of how the code that handles "" and '' in partially
4871      quoted strings works, we need to make ISTRING into a QUOTED_NULL
4872      if we saw quoting characters, but the expansion was empty.
4873      "" and '' are tossed away before we get to this point when
4874      processing partially quoted strings.  This makes "" and $xxx""
4875      equivalent when xxx is unset.  We also look to see whether we
4876      saw a quoted null from a ${} expansion and add one back if we
4877      need to. */
4878
4879   /* If we expand to nothing and there were no single or double quotes
4880      in the word, we throw it away.  Otherwise, we return a NULL word.
4881      The single exception is for $@ surrounded by double quotes when
4882      there are no positional parameters.  In that case, we also throw
4883      the word away. */
4884
4885   if (*istring == '\0')
4886     {
4887       if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
4888         {
4889           istring[0] = CTLNUL;
4890           istring[1] = '\0';
4891           tword = make_bare_word (istring);
4892           list = make_word_list (tword, (WORD_LIST *)NULL);
4893           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4894             tword->flags |= W_QUOTED;
4895         }
4896       /* According to sh, ksh, and Posix.2, if a word expands into nothing
4897          and a double-quoted "$@" appears anywhere in it, then the entire
4898          word is removed. */
4899       else  if (quoted_state == UNQUOTED || quoted_dollar_at)
4900         list = (WORD_LIST *)NULL;
4901 #if 0
4902       else
4903         {
4904           tword = make_bare_word (istring);
4905           list = make_word_list (tword, (WORD_LIST *)NULL);
4906           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4907             tword->flags |= W_QUOTED;
4908         }
4909 #endif
4910     }
4911   else if (word->flags & W_NOSPLIT)
4912     {
4913       tword = make_bare_word (istring);
4914       list = make_word_list (tword, (WORD_LIST *)NULL);
4915       if (word->flags & W_ASSIGNMENT)
4916         tword->flags |= W_ASSIGNMENT;   /* XXX */
4917       if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4918         tword->flags |= W_QUOTED;
4919     }
4920   else
4921     {
4922       char *ifs_chars;
4923
4924       if (quoted_dollar_at)
4925         {
4926           var = find_variable ("IFS");
4927           ifs_chars = var ? value_cell (var) : " \t\n";
4928         }
4929       else
4930         ifs_chars = (char *)NULL;
4931
4932       /* According to Posix.2, "$@" expands to a single word if
4933          IFS="" and the positional parameters are not empty. */
4934       if (quoted_dollar_at && ifs_chars && *ifs_chars)
4935         {
4936           list = list_string (istring, " ", 1);
4937         }
4938       else
4939         {
4940           tword = make_bare_word (istring);
4941           list = make_word_list (tword, (WORD_LIST *)NULL);
4942           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
4943             tword->flags |= W_QUOTED;
4944           if (word->flags & W_ASSIGNMENT)
4945             tword->flags |= W_ASSIGNMENT;
4946         }
4947     }
4948
4949   free (istring);
4950   return (list);
4951 }
4952
4953 /* **************************************************************** */
4954 /*                                                                  */
4955 /*                 Functions for Quote Removal                      */
4956 /*                                                                  */
4957 /* **************************************************************** */
4958
4959 /* Perform quote removal on STRING.  If QUOTED > 0, assume we are obeying the
4960    backslash quoting rules for within double quotes. */
4961 char *
4962 string_quote_removal (string, quoted)
4963      char *string;
4964      int quoted;
4965 {
4966   char *r, *result_string, *temp;
4967   int sindex, tindex, c, dquote;
4968
4969   /* The result can be no longer than the original string. */
4970   r = result_string = xmalloc (strlen (string) + 1);
4971
4972   for (dquote = sindex = 0; c = string[sindex];)
4973     {
4974       switch (c)
4975         {
4976         case '\\':
4977           c = string[++sindex];
4978           if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && member (c, slashify_in_quotes) == 0)
4979             *r++ = '\\';
4980           /* FALLTHROUGH */
4981
4982         default:
4983           *r++ = c;
4984           sindex++;
4985           break;
4986
4987         case '\'':
4988           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
4989             {
4990               *r++ = c;
4991               sindex++;
4992               break;
4993             }
4994           tindex = sindex + 1;
4995           temp = string_extract_single_quoted (string, &tindex);
4996           if (temp)
4997             {
4998               strcpy (r, temp);
4999               r += strlen (r);
5000               free (temp);
5001             }
5002           sindex = tindex;
5003           break;
5004
5005         case '"':
5006           dquote = 1 - dquote;
5007           sindex++;
5008           break;
5009         }
5010     }
5011     *r = '\0';
5012     return (result_string);
5013 }
5014
5015 #if 0
5016 /* UNUSED */
5017 /* Perform quote removal on word WORD.  This allocates and returns a new
5018    WORD_DESC *. */
5019 WORD_DESC *
5020 word_quote_removal (word, quoted)
5021      WORD_DESC *word;
5022      int quoted;
5023 {
5024   WORD_DESC *w;
5025   char *t;
5026
5027   t = string_quote_removal (word->word, quoted);
5028   w = make_bare_word (t);
5029   free (t);
5030   return (w);
5031 }
5032
5033 /* Perform quote removal on all words in LIST.  If QUOTED is non-zero,
5034    the members of the list are treated as if they are surrounded by
5035    double quotes.  Return a new list, or NULL if LIST is NULL. */
5036 WORD_LIST *
5037 word_list_quote_removal (list, quoted)
5038      WORD_LIST *list;
5039      int quoted;
5040 {
5041   WORD_LIST *result, *t, *tresult;
5042
5043   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
5044     {
5045       tresult = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
5046       tresult->word = word_quote_removal (t->word, quoted);
5047       tresult->next = (WORD_LIST *)NULL;
5048       result = (WORD_LIST *) list_append (result, tresult);
5049     }
5050   return (result);
5051 }
5052 #endif
5053
5054 /* Return 1 if CHARACTER appears in an unquoted portion of
5055    STRING.  Return 0 otherwise. */
5056 static int
5057 unquoted_member (character, string)
5058      int character;
5059      char *string;
5060 {
5061   int sindex, c;
5062
5063   for (sindex = 0; c = string[sindex]; )
5064     {
5065       if (c == character)
5066         return (1);
5067
5068       switch (c)
5069         {
5070         default:
5071           sindex++;
5072           break;
5073
5074         case '\\':
5075           sindex++;
5076           if (string[sindex])
5077             sindex++;
5078           break;
5079
5080         case '\'':
5081           sindex = skip_single_quoted (string, ++sindex);
5082           break;
5083
5084         case '"':
5085           sindex = skip_double_quoted (string, ++sindex);
5086           break;
5087         }
5088     }
5089   return (0);
5090 }
5091
5092 /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
5093 static int
5094 unquoted_substring (substr, string)
5095      char *substr, *string;
5096 {
5097   int sindex, c, sublen;
5098
5099   if (substr == 0 || *substr == '\0')
5100     return (0);
5101
5102   sublen = strlen (substr);
5103   for (sindex = 0; c = string[sindex]; )
5104     {
5105       if (STREQN (string + sindex, substr, sublen))
5106         return (1);
5107
5108       switch (c)
5109         {
5110         case '\\':
5111           sindex++;
5112
5113           if (string[sindex])
5114             sindex++;
5115           break;
5116
5117         case '\'':
5118           sindex = skip_single_quoted (string, ++sindex);
5119           break;
5120
5121         case '"':
5122           sindex = skip_double_quoted (string, ++sindex);
5123           break;
5124
5125         default:
5126           sindex++;
5127           break;
5128         }
5129     }
5130   return (0);
5131 }
5132
5133 /*******************************************
5134  *                                         *
5135  *    Functions to perform word splitting  *
5136  *                                         *
5137  *******************************************/
5138
5139 /* This splits a single word into a WORD LIST on $IFS, but only if the word
5140    is not quoted.  list_string () performs quote removal for us, even if we
5141    don't do any splitting. */
5142 WORD_LIST *
5143 word_split (w)
5144      WORD_DESC *w;
5145 {
5146   WORD_LIST *result;
5147   SHELL_VAR *ifs;
5148   char *ifs_chars;
5149
5150   if (w)
5151     {
5152       ifs = find_variable ("IFS");
5153       /* If IFS is unset, it defaults to " \t\n". */
5154       ifs_chars = ifs ? value_cell (ifs) : " \t\n";
5155
5156       if ((w->flags & W_QUOTED) || !ifs_chars)
5157         ifs_chars = "";
5158
5159       result = list_string (w->word, ifs_chars, w->flags & W_QUOTED);
5160     }
5161   else
5162     result = (WORD_LIST *)NULL;
5163
5164   return (result);
5165 }
5166
5167 /* Perform word splitting on LIST and return the RESULT.  It is possible
5168    to return (WORD_LIST *)NULL. */
5169 static WORD_LIST *
5170 word_list_split (list)
5171      WORD_LIST *list;
5172 {
5173   WORD_LIST *result, *t, *tresult;
5174
5175   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
5176     {
5177       tresult = word_split (t->word);
5178       result = (WORD_LIST *) list_append (result, tresult);
5179     }
5180   return (result);
5181 }
5182
5183 /**************************************************
5184  *                                                *
5185  *      Functions to expand an entire WORD_LIST   *
5186  *                                                *
5187  **************************************************/
5188
5189 static WORD_LIST *varlist = (WORD_LIST *)NULL;
5190
5191 /* Separate out any initial variable assignments from TLIST.  If set -k has
5192    been executed, remove all assignment statements from TLIST.  Initial
5193    variable assignments and other environment assignments are placed
5194    on VARLIST. */
5195 static WORD_LIST *
5196 separate_out_assignments (tlist)
5197      WORD_LIST *tlist;
5198 {
5199   register WORD_LIST *vp, *lp;
5200
5201   if (!tlist)
5202     return ((WORD_LIST *)NULL);
5203
5204   varlist = (WORD_LIST *)NULL;
5205   vp = lp = tlist;
5206
5207   /* Separate out variable assignments at the start of the command.
5208      Loop invariant: vp->next == lp
5209      Loop postcondition:
5210         lp = list of words left after assignment statements skipped
5211         tlist = original list of words
5212   */
5213   while (lp && (lp->word->flags & W_ASSIGNMENT))
5214     {
5215       vp = lp;
5216       lp = lp->next;
5217     }
5218
5219   /* If lp != tlist, we have some initial assignment statements. */
5220   /* We make VARLIST point to the list of assignment words and
5221      TLIST point to the remaining words.  */
5222   if (lp != tlist)
5223     {
5224       varlist = tlist;
5225       /* ASSERT(vp->next == lp); */
5226       vp->next = (WORD_LIST *)NULL;     /* terminate variable list */
5227       tlist = lp;                       /* remainder of word list */
5228     }
5229
5230   /* vp == end of variable list */
5231   /* tlist == remainder of original word list without variable assignments */
5232   if (!tlist)
5233     /* All the words in tlist were assignment statements */
5234     return ((WORD_LIST *)NULL);
5235
5236   /* ASSERT(tlist != NULL); */
5237   /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
5238
5239   /* If the -k option is in effect, we need to go through the remaining
5240      words, separate out the assignment words, and place them on VARLIST. */
5241   if (place_keywords_in_env)
5242     {
5243       WORD_LIST *tp;    /* tp == running pointer into tlist */
5244
5245       tp = tlist;
5246       lp = tlist->next;
5247
5248       /* Loop Invariant: tp->next == lp */
5249       /* Loop postcondition: tlist == word list without assignment statements */
5250       while (lp)
5251         {
5252           if (lp->word->flags & W_ASSIGNMENT)
5253             {
5254               /* Found an assignment statement, add this word to end of
5255                  varlist (vp). */
5256               if (!varlist)
5257                 varlist = vp = lp;
5258               else
5259                 {
5260                   vp->next = lp;
5261                   vp = lp;
5262                 }
5263
5264               /* Remove the word pointed to by LP from TLIST. */
5265               tp->next = lp->next;
5266               /* ASSERT(vp == lp); */
5267               lp->next = (WORD_LIST *)NULL;
5268               lp = tp->next;
5269             }
5270           else
5271             {
5272               tp = lp;
5273               lp = lp->next;
5274             }
5275         }
5276     }
5277   return (tlist);
5278 }
5279
5280 /* Take the list of words in LIST and do the various substitutions.  Return
5281    a new list of words which is the expanded list, and without things like
5282    variable assignments. */
5283
5284 WORD_LIST *
5285 expand_words (list)
5286      WORD_LIST *list;
5287 {
5288   return (expand_word_list_internal (list, 1));
5289 }
5290
5291 /* Same as expand_words (), but doesn't hack variable or environment
5292    variables. */
5293 WORD_LIST *
5294 expand_words_no_vars (list)
5295      WORD_LIST *list;
5296 {
5297   return (expand_word_list_internal (list, 0));
5298 }
5299
5300 /* The workhorse for expand_words () and expand_words_no_vars ().
5301    First arg is LIST, a WORD_LIST of words.
5302    Second arg DO_VARS is non-zero if you want to do environment and
5303    variable assignments, else zero.
5304
5305    This does all of the substitutions: brace expansion, tilde expansion,
5306    parameter expansion, command substitution, arithmetic expansion,
5307    process substitution, word splitting, and pathname expansion.  Words
5308    with the W_QUOTED or W_NOSPLIT bits set, or for which no expansion
5309    is done, do not undergo word splitting.  Words with the W_ASSIGNMENT
5310    bit set do not undergo pathname expansion. */
5311 static WORD_LIST *
5312 expand_word_list_internal (list, do_vars)
5313      WORD_LIST *list;
5314      int do_vars;
5315 {
5316   WORD_LIST *tlist, *new_list, *next, *temp_list, *orig_list, *disposables;
5317   char *temp_string;
5318   int tint;
5319
5320   if (list == 0)
5321     return ((WORD_LIST *)NULL);
5322
5323   tlist = copy_word_list (list);
5324
5325   if (do_vars)
5326     {
5327       tlist = separate_out_assignments (tlist);
5328       if (tlist == 0)
5329         {
5330           if (varlist)
5331             {
5332               /* All the words were variable assignments, so they are placed
5333                  into the shell's environment. */
5334               for (new_list = varlist; new_list; new_list = new_list->next)
5335                 {
5336                   this_command_name = (char *)NULL;     /* no arithmetic errors */
5337                   tint = do_assignment (new_list->word->word);
5338                   /* Variable assignment errors in non-interactive shells
5339                      running in Posix.2 mode cause the shell to exit. */
5340                   if (tint == 0 && interactive_shell == 0 && posixly_correct)
5341                     {
5342                       last_command_exit_value = EXECUTION_FAILURE;
5343                       jump_to_top_level (FORCE_EOF);
5344                     }
5345                 }
5346               dispose_words (varlist);
5347               varlist = (WORD_LIST *)NULL;
5348             }
5349           return ((WORD_LIST *)NULL);
5350         }
5351     }
5352
5353   /* Begin expanding the words that remain.  The expansions take place on
5354      things that aren't really variable assignments. */
5355
5356 #if defined (BRACE_EXPANSION)
5357   /* Do brace expansion on this word if there are any brace characters
5358      in the string. */
5359   if (brace_expansion && tlist)
5360     {
5361       register char **expansions;
5362       WORD_LIST *braces;
5363       WORD_DESC *w;
5364       int eindex;
5365
5366       for (braces = disposables = (WORD_LIST *)NULL; tlist; tlist = next)
5367         {
5368           next = tlist->next;
5369
5370           /* Only do brace expansion if the word has a brace character.  If
5371              not, just add the word list element to BRACES and continue.  In
5372              the common case, at least when running shell scripts, this will
5373              degenerate to a bunch of calls to `strchr', and then what is
5374              basically a reversal of TLIST into BRACES, which is corrected
5375              by a call to reverse_list () on BRACES when the end of TLIST
5376              is reached. */
5377           if (strchr (tlist->word->word, '{'))
5378             {
5379               expansions = brace_expand (tlist->word->word);
5380
5381               for (eindex = 0; temp_string = expansions[eindex]; eindex++)
5382                 {
5383                   w = make_word (temp_string);
5384                   /* If brace expansion didn't change the word, preserve
5385                      the flags.  We may want to preserve the flags
5386                      unconditionally someday -- XXX */
5387                   if (STREQ (temp_string, tlist->word->word))
5388                     w->flags = tlist->word->flags;
5389                   braces = make_word_list (w, braces);
5390                   free (expansions[eindex]);
5391                 }
5392               free (expansions);
5393
5394               /* Add TLIST to the list of words to be freed after brace
5395                  expansion has been performed. */
5396               tlist->next = disposables;
5397               disposables = tlist;
5398             }
5399           else
5400             {
5401               tlist->next = braces;
5402               braces = tlist;
5403             }
5404         }
5405
5406       dispose_words (disposables);
5407       tlist = REVERSE_LIST (braces, WORD_LIST *);
5408     }
5409 #endif /* BRACE_EXPANSION */
5410
5411   /* We do tilde expansion all the time.  This is what 1003.2 says. */
5412   for (orig_list = tlist, new_list = (WORD_LIST *)NULL; tlist; tlist = next)
5413     {
5414       WORD_LIST *expanded;
5415       int expanded_something, has_dollar_at;
5416
5417       temp_string = tlist->word->word;
5418
5419       next = tlist->next;
5420
5421       /* Posix.2 section 3.6.1 says that tildes following `=' in words
5422          which are not assignment statements are not expanded.  We do
5423          this only if POSIXLY_CORRECT is enabled.  Essentially, we do
5424          tilde expansion on unquoted assignment statements (flags include
5425          W_ASSIGNMENT but not W_QUOTED). */
5426       if (temp_string[0] == '~' ||
5427             (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) &&
5428              posixly_correct == 0 &&
5429              strchr (temp_string, '~') &&
5430              (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string))))
5431         {
5432           tlist->word->word = bash_tilde_expand (temp_string);
5433           free (temp_string);
5434         }
5435
5436       expanded_something = 0;
5437       expanded = expand_word_internal
5438         (tlist->word, 0, &has_dollar_at, &expanded_something);
5439
5440       if (expanded == &expand_word_error || expanded == &expand_word_fatal)
5441         {
5442           /* By convention, each time this error is returned,
5443              tlist->word->word has already been freed. */
5444           tlist->word->word = (char *)NULL;
5445
5446           /* Dispose our copy of the original list. */
5447           dispose_words (orig_list);
5448           /* Dispose the new list we're building. */
5449           dispose_words (new_list);
5450
5451           if (expanded == &expand_word_error)
5452             jump_to_top_level (DISCARD);
5453           else
5454             jump_to_top_level (FORCE_EOF);
5455         }
5456
5457       /* Don't split words marked W_NOSPLIT. */
5458       if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
5459         {
5460           temp_list = word_list_split (expanded);
5461           dispose_words (expanded);
5462         }
5463       else
5464         {
5465           /* If no parameter expansion, command substitution, process
5466              substitution, or arithmetic substitution took place, then
5467              do not do word splitting.  We still have to remove quoted
5468              null characters from the result. */
5469           word_list_remove_quoted_nulls (expanded);
5470           temp_list = expanded;
5471         }
5472
5473       /* In the most common cases, t will be a list containing only one
5474          element, so the call to reverse_list would be wasted. */
5475       expanded = REVERSE_LIST (temp_list, WORD_LIST *);
5476       new_list = (WORD_LIST *)list_append (expanded, new_list);
5477     }
5478
5479   new_list = REVERSE_LIST (new_list, WORD_LIST *);
5480
5481   dispose_words (orig_list);
5482
5483   /* Okay, we're almost done.  Now let's just do some filename
5484      globbing. */
5485   if (new_list)
5486     {
5487       char **glob_array;
5488       register int glob_index;
5489       WORD_LIST *glob_list;
5490       WORD_DESC *tword;
5491
5492       orig_list = disposables = (WORD_LIST *)NULL;
5493       tlist = new_list;
5494
5495       /* orig_list == output list, despite the name. */
5496       if (disallow_filename_globbing == 0)
5497         {
5498           glob_array = (char **)NULL;
5499           while (tlist)
5500             {
5501               /* For each word, either globbing is attempted or the word is
5502                  added to orig_list.  If globbing succeeds, the results are
5503                  added to orig_list and the word (tlist) is added to the list
5504                  of disposable words.  If globbing fails and failed glob
5505                  expansions are left unchanged (the shell default), the
5506                  original word is added to orig_list.  If globbing fails and
5507                  failed glob expansions are removed, the original word is
5508                  added to the list of disposable words.  orig_list ends up
5509                  in reverse order and requires a call to reverse_list to
5510                  be set right.  After all words are examined, the disposable
5511                  words are freed. */
5512               next = tlist->next;
5513
5514               /* If the word isn't an assignment and contains an unquoted
5515                  pattern matching character, then glob it. */
5516 #if 0
5517               if ((tlist->word->flags & (W_QUOTED|W_ASSIGNMENT)) == 0 &&
5518 #else
5519               if ((tlist->word->flags & W_ASSIGNMENT) == 0 &&
5520 #endif
5521                   unquoted_glob_pattern_p (tlist->word->word))
5522                 {
5523                   glob_array = shell_glob_filename (tlist->word->word);
5524
5525                   /* Handle error cases.
5526                      I don't think we should report errors like "No such file
5527                      or directory".  However, I would like to report errors
5528                      like "Read failed". */
5529
5530                   if (GLOB_FAILED (glob_array))
5531                     {
5532                       glob_array = (char **) xmalloc (sizeof (char *));
5533                       glob_array[0] = (char *)NULL;
5534                     }
5535
5536                   /* Dequote the current word in case we have to use it. */
5537                   if (glob_array[0] == NULL)
5538                     {
5539                       temp_string = dequote_string (tlist->word->word);
5540                       free (tlist->word->word);
5541                       tlist->word->word = temp_string;
5542                     }
5543
5544                   /* Make the array into a word list. */
5545                   glob_list = (WORD_LIST *)NULL;
5546                   for (glob_index = 0; glob_array[glob_index]; glob_index++)
5547                     {
5548                       tword = make_bare_word (glob_array[glob_index]);
5549                       tword->flags |= W_GLOBEXP;        /* XXX */
5550                       glob_list = make_word_list (tword, glob_list);
5551                     }
5552
5553                   if (glob_list)
5554                     {
5555                       orig_list = (WORD_LIST *)list_append (glob_list, orig_list);
5556                       tlist->next = disposables;
5557                       disposables = tlist;
5558                     }
5559                   else if (allow_null_glob_expansion == 0)
5560                     {
5561                       /* Failed glob expressions are left unchanged. */
5562                       tlist->next = orig_list;
5563                       orig_list = tlist;
5564                     }
5565                   else
5566                     {
5567                       /* Failed glob expressions are removed. */
5568                       tlist->next = disposables;
5569                       disposables = tlist;
5570                     }
5571                 }
5572               else
5573                 {
5574                   /* Dequote the string. */
5575                   temp_string = dequote_string (tlist->word->word);
5576                   free (tlist->word->word);
5577                   tlist->word->word = temp_string;
5578                   tlist->next = orig_list;
5579                   orig_list = tlist;
5580                 }
5581
5582               free_array (glob_array);
5583               glob_array = (char **)NULL;
5584
5585               tlist = next;
5586             }
5587
5588           if (disposables)
5589             dispose_words (disposables);
5590
5591           new_list = REVERSE_LIST (orig_list, WORD_LIST *);
5592         }
5593       else
5594         {
5595           /* Dequote the words, because we're not performing globbing. */
5596           for (temp_list = new_list; temp_list; temp_list = temp_list->next)
5597             {
5598               temp_string = dequote_string (temp_list->word->word);
5599               free (temp_list->word->word);
5600               temp_list->word->word = temp_string;
5601             }
5602         }
5603     }
5604
5605   if (do_vars)
5606     {
5607       Function *assign_func;
5608
5609       /* If the remainder of the words expand to nothing, Posix.2 requires
5610          that the variable and environment assignments affect the shell's
5611          environment. */
5612       assign_func = new_list ? assign_in_env : do_assignment;
5613
5614       for (temp_list = varlist; temp_list; temp_list = temp_list->next)
5615         {
5616           this_command_name = (char *)NULL;
5617           tint = (*assign_func) (temp_list->word->word);
5618           /* Variable assignment errors in non-interactive shells running
5619              in Posix.2 mode cause the shell to exit. */
5620           if (tint == 0 && assign_func == do_assignment &&
5621                 interactive_shell == 0 && posixly_correct)
5622             {
5623               last_command_exit_value = EXECUTION_FAILURE;
5624               jump_to_top_level (FORCE_EOF);
5625             }
5626         }
5627
5628       dispose_words (varlist);
5629       varlist = (WORD_LIST *)NULL;
5630     }
5631
5632   tint = list_length (new_list) + 1;
5633   RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
5634   for (tint = 0, tlist = new_list; tlist; tlist = tlist->next)
5635     glob_argv_flags[tint++] = (tlist->word->flags & W_GLOBEXP) ? '1' : '0';
5636   glob_argv_flags[tint] = '\0';
5637
5638   return (new_list);
5639 }
5640
5641 /*************************************************
5642  *                                               *
5643  *      Functions to manage special variables    *
5644  *                                               *
5645  *************************************************/
5646
5647 /* An alist of name.function for each special variable.  Most of the
5648    functions don't do much, and in fact, this would be faster with a
5649    switch statement, but by the end of this file, I am sick of switch
5650    statements. */
5651
5652 #define SET_INT_VAR(name, intvar)  intvar = find_variable (name) != 0
5653
5654 struct name_and_function {
5655   char *name;
5656   VFunction *function;
5657 } special_vars[] = {
5658   { "PATH", sv_path },
5659   { "MAIL", sv_mail },
5660   { "MAILPATH", sv_mail },
5661   { "MAILCHECK", sv_mail },
5662
5663   { "POSIXLY_CORRECT", sv_strict_posix },
5664   { "GLOBIGNORE", sv_globignore },
5665
5666   /* Variables which only do something special when READLINE is defined. */
5667 #if defined (READLINE)
5668   { "TERM", sv_terminal },
5669   { "TERMCAP", sv_terminal },
5670   { "TERMINFO", sv_terminal },
5671   { "HOSTFILE", sv_hostfile },
5672 #endif /* READLINE */
5673
5674   /* Variables which only do something special when HISTORY is defined. */
5675 #if defined (HISTORY)
5676   { "HISTIGNORE", sv_histignore },
5677   { "HISTSIZE", sv_histsize },
5678   { "HISTFILESIZE", sv_histsize },
5679   { "HISTCONTROL", sv_history_control },
5680 #  if defined (BANG_HISTORY)
5681   { "histchars", sv_histchars },
5682 #  endif /* BANG_HISTORY */
5683 #endif /* HISTORY */
5684
5685   { "IGNOREEOF", sv_ignoreeof },
5686   { "ignoreeof", sv_ignoreeof },
5687
5688   { "OPTIND", sv_optind },
5689   { "OPTERR", sv_opterr },
5690
5691   { "TEXTDOMAIN", sv_locale },
5692   { "TEXTDOMAINDIR", sv_locale },
5693   { "LC_ALL", sv_locale },
5694   { "LC_COLLATE", sv_locale },
5695   { "LC_CTYPE", sv_locale },
5696   { "LC_MESSAGES", sv_locale },
5697   { "LANG", sv_locale },
5698
5699 #if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
5700   { "TZ", sv_tz },
5701 #endif
5702
5703   { (char *)0, (VFunction *)0 }
5704 };
5705
5706 /* The variable in NAME has just had its state changed.  Check to see if it
5707    is one of the special ones where something special happens. */
5708 void
5709 stupidly_hack_special_variables (name)
5710      char *name;
5711 {
5712   int i;
5713
5714   for (i = 0; special_vars[i].name; i++)
5715     {
5716       if (STREQ (special_vars[i].name, name))
5717         {
5718           (*(special_vars[i].function)) (name);
5719           return;
5720         }
5721     }
5722 }
5723
5724 /* What to do just after the PATH variable has changed. */
5725 void
5726 sv_path (name)
5727      char *name;
5728 {
5729   /* hash -r */
5730   flush_hashed_filenames ();
5731 }
5732
5733 /* What to do just after one of the MAILxxxx variables has changed.  NAME
5734    is the name of the variable.  This is called with NAME set to one of
5735    MAIL, MAILCHECK, or MAILPATH.  */
5736 void
5737 sv_mail (name)
5738      char *name;
5739 {
5740   /* If the time interval for checking the files has changed, then
5741      reset the mail timer.  Otherwise, one of the pathname vars
5742      to the users mailbox has changed, so rebuild the array of
5743      filenames. */
5744   if (name[4] == 'C')  /* if (strcmp (name, "MAILCHECK") == 0) */
5745     reset_mail_timer ();
5746   else
5747     {
5748       free_mail_files ();
5749       remember_mail_dates ();
5750     }
5751 }
5752
5753 /* What to do when GLOBIGNORE changes. */
5754 void
5755 sv_globignore (name)
5756      char *name;
5757 {
5758   setup_glob_ignore (name);
5759 }
5760
5761 #if defined (READLINE)
5762 /* What to do just after one of the TERMxxx variables has changed.
5763    If we are an interactive shell, then try to reset the terminal
5764    information in readline. */
5765 void
5766 sv_terminal (name)
5767      char *name;
5768 {
5769   if (interactive_shell && no_line_editing == 0)
5770     rl_reset_terminal (get_string_value ("TERM"));
5771 }
5772
5773 void
5774 sv_hostfile (name)
5775      char *name;
5776 {
5777   hostname_list_initialized = 0;
5778 }
5779 #endif /* READLINE */
5780
5781 #if defined (HISTORY)
5782 /* What to do after the HISTSIZE or HISTFILESIZE variables change.
5783    If there is a value for this HISTSIZE (and it is numeric), then stifle
5784    the history.  Otherwise, if there is NO value for this variable,
5785    unstifle the history.  If name is HISTFILESIZE, and its value is
5786    numeric, truncate the history file to hold no more than that many
5787    lines. */
5788 void
5789 sv_histsize (name)
5790      char *name;
5791 {
5792   char *temp;
5793   long num;
5794
5795   temp = get_string_value (name);
5796
5797   if (temp && *temp)
5798     {
5799       if (legal_number (temp, &num))
5800         {
5801           if (name[4] == 'S')
5802             {
5803               stifle_history (num);
5804               num = where_history ();
5805               if (history_lines_this_session > num)
5806                 history_lines_this_session = num;
5807             }
5808           else
5809             {
5810               history_truncate_file (get_string_value ("HISTFILE"), (int)num);
5811               if (num <= history_lines_in_file)
5812                 history_lines_in_file = num;
5813             }
5814         }
5815     }
5816   else if (name[4] == 'S')
5817     unstifle_history ();
5818 }
5819
5820 /* What to do after the HISTIGNORE variable changes. */
5821 void
5822 sv_histignore (name)
5823      char *name;
5824 {
5825   setup_history_ignore (name);
5826 }
5827
5828 /* What to do after the HISTCONTROL variable changes. */
5829 void
5830 sv_history_control (name)
5831      char *name;
5832 {
5833   char *temp;
5834
5835   history_control = 0;
5836   temp = get_string_value (name);
5837
5838   if (temp && *temp && STREQN (temp, "ignore", 6))
5839     {
5840       if (temp[6] == 's')       /* ignorespace */
5841         history_control = 1;
5842       else if (temp[6] == 'd')  /* ignoredups */
5843         history_control = 2;
5844       else if (temp[6] == 'b')  /* ignoreboth */
5845         history_control = 3;
5846     }
5847 }
5848
5849 #if defined (BANG_HISTORY)
5850 /* Setting/unsetting of the history expansion character. */
5851 void
5852 sv_histchars (name)
5853      char *name;
5854 {
5855   char *temp;
5856
5857   temp = get_string_value (name);
5858   if (temp)
5859     {
5860       history_expansion_char = *temp;
5861       if (temp[0] && temp[1])
5862         {
5863           history_subst_char = temp[1];
5864           if (temp[2])
5865               history_comment_char = temp[2];
5866         }
5867     }
5868   else
5869     {
5870       history_expansion_char = '!';
5871       history_subst_char = '^';
5872       history_comment_char = '#';
5873     }
5874 }
5875 #endif /* BANG_HISTORY */
5876 #endif /* HISTORY */
5877
5878 #if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
5879 void
5880 sv_tz (name)
5881      char *name;
5882 {
5883   tzset ();
5884 }
5885 #endif
5886
5887 /* If the variable exists, then the value of it can be the number
5888    of times we actually ignore the EOF.  The default is small,
5889    (smaller than csh, anyway). */
5890 void
5891 sv_ignoreeof (name)
5892      char *name;
5893 {
5894   SHELL_VAR *tmp_var;
5895   char *temp;
5896
5897   eof_encountered = 0;
5898
5899   tmp_var = find_variable (name);
5900   ignoreeof = tmp_var != 0;
5901   temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
5902   if (temp)
5903     eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
5904   set_shellopts ();     /* make sure `ignoreeof' is/is not in $SHELLOPTS */
5905 }
5906
5907 void
5908 sv_optind (name)
5909      char *name;
5910 {
5911   char *tt;
5912   int s;
5913
5914   tt = get_string_value ("OPTIND");
5915   if (tt && *tt)
5916     {
5917       s = atoi (tt);
5918
5919       /* According to POSIX, setting OPTIND=1 resets the internal state
5920          of getopt (). */
5921       if (s < 0 || s == 1)
5922         s = 0;
5923     }
5924   else
5925     s = 0;
5926   getopts_reset (s);
5927 }
5928
5929 void
5930 sv_opterr (name)
5931      char *name;
5932 {
5933   char *tt;
5934
5935   tt = get_string_value ("OPTERR");
5936   sh_opterr = (tt && *tt) ? atoi (tt) : 1;
5937 }
5938
5939 void
5940 sv_strict_posix (name)
5941      char *name;
5942 {
5943   SET_INT_VAR (name, posixly_correct);
5944   posix_initialize (posixly_correct);
5945 #if defined (READLINE)
5946   if (interactive_shell)
5947     posix_readline_initialize (posixly_correct);
5948 #endif /* READLINE */
5949   set_shellopts ();     /* make sure `posix' is/is not in $SHELLOPTS */
5950 }
5951
5952 void
5953 sv_locale (name)
5954      char *name;
5955 {
5956   char *v;
5957
5958   v = get_string_value (name);
5959   if (name[0] == 'L' && name[1] == 'A') /* LANG */
5960     set_lang (name, v);
5961   else
5962     set_locale_var (name, v);           /* LC_*, TEXTDOMAIN* */
5963 }