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