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