48c89c1fab4b2b050b54bd2fdff91ea9a17d2bb7
[platform/upstream/bash.git] / subst.c
1 /* subst.c -- The part of the shell that does parameter, command, arithmetic,
2    and globbing substitutions. */
3
4 /* ``Have a little faith, there's magic in the night.  You ain't a
5      beauty, but, hey, you're alright.'' */
6
7 /* Copyright (C) 1987-2010 Free Software Foundation, Inc.
8
9    This file is part of GNU Bash, the Bourne Again SHell.
10
11    Bash is free software: you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation, either version 3 of the License, or
14    (at your option) any later version.
15
16    Bash is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "config.h"
26
27 #include "bashtypes.h"
28 #include <stdio.h>
29 #include "chartypes.h"
30 #if defined (HAVE_PWD_H)
31 #  include <pwd.h>
32 #endif
33 #include <signal.h>
34 #include <errno.h>
35
36 #if defined (HAVE_UNISTD_H)
37 #  include <unistd.h>
38 #endif
39
40 #include "bashansi.h"
41 #include "posixstat.h"
42 #include "bashintl.h"
43
44 #include "shell.h"
45 #include "parser.h"
46 #include "flags.h"
47 #include "jobs.h"
48 #include "execute_cmd.h"
49 #include "filecntl.h"
50 #include "trap.h"
51 #include "pathexp.h"
52 #include "mailcheck.h"
53
54 #include "shmbutil.h"
55 #include "typemax.h"
56
57 #include "builtins/getopt.h"
58 #include "builtins/common.h"
59
60 #include "builtins/builtext.h"
61
62 #include <tilde/tilde.h>
63 #include <glob/strmatch.h>
64
65 #if !defined (errno)
66 extern int errno;
67 #endif /* !errno */
68
69 /* The size that strings change by. */
70 #define DEFAULT_INITIAL_ARRAY_SIZE 112
71 #define DEFAULT_ARRAY_SIZE 128
72
73 /* Variable types. */
74 #define VT_VARIABLE     0
75 #define VT_POSPARMS     1
76 #define VT_ARRAYVAR     2
77 #define VT_ARRAYMEMBER  3
78 #define VT_ASSOCVAR     4
79
80 #define VT_STARSUB      128     /* $* or ${array[*]} -- used to split */
81
82 /* Flags for quoted_strchr */
83 #define ST_BACKSL       0x01
84 #define ST_CTLESC       0x02
85 #define ST_SQUOTE       0x04    /* unused yet */
86 #define ST_DQUOTE       0x08    /* unused yet */
87
88 /* Flags for the `pflags' argument to param_expand() */
89 #define PF_NOCOMSUB     0x01    /* Do not perform command substitution */
90 #define PF_IGNUNBOUND   0x02    /* ignore unbound vars even if -u set */
91 #define PF_NOSPLIT2     0x04    /* same as W_NOSPLIT2 */
92
93 /* These defs make it easier to use the editor. */
94 #define LBRACE          '{'
95 #define RBRACE          '}'
96 #define LPAREN          '('
97 #define RPAREN          ')'
98
99 #if defined (HANDLE_MULTIBYTE)
100 #define WLPAREN         L'('
101 #define WRPAREN         L')'
102 #endif
103
104 /* Evaluates to 1 if C is one of the shell's special parameters whose length
105    can be taken, but is also one of the special expansion characters. */
106 #define VALID_SPECIAL_LENGTH_PARAM(c) \
107   ((c) == '-' || (c) == '?' || (c) == '#')
108
109 /* Evaluates to 1 if C is one of the shell's special parameters for which an
110    indirect variable reference may be made. */
111 #define VALID_INDIR_PARAM(c) \
112   ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
113
114 /* Evaluates to 1 if C is one of the OP characters that follows the parameter
115    in ${parameter[:]OPword}. */
116 #define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)
117
118 /* Evaluates to 1 if this is one of the shell's special variables. */
119 #define SPECIAL_VAR(name, wi) \
120  ((DIGIT (*name) && all_digits (name)) || \
121       (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \
122       (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1])))
123
124 /* An expansion function that takes a string and a quoted flag and returns
125    a WORD_LIST *.  Used as the type of the third argument to
126    expand_string_if_necessary(). */
127 typedef WORD_LIST *EXPFUNC __P((char *, int));
128
129 /* Process ID of the last command executed within command substitution. */
130 pid_t last_command_subst_pid = NO_PID;
131 pid_t current_command_subst_pid = NO_PID;
132
133 /* Variables used to keep track of the characters in IFS. */
134 SHELL_VAR *ifs_var;
135 char *ifs_value;
136 unsigned char ifs_cmap[UCHAR_MAX + 1];
137
138 #if defined (HANDLE_MULTIBYTE)
139 unsigned char ifs_firstc[MB_LEN_MAX];
140 size_t ifs_firstc_len;
141 #else
142 unsigned char ifs_firstc;
143 #endif
144
145 /* Sentinel to tell when we are performing variable assignments preceding a
146    command name and putting them into the environment.  Used to make sure
147    we use the temporary environment when looking up variable values. */
148 int assigning_in_environment;
149
150 /* Used to hold a list of variable assignments preceding a command.  Global
151    so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
152    SIGCHLD trap and so it can be saved and restored by the trap handlers. */
153 WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
154
155 /* Extern functions and variables from different files. */
156 extern int last_command_exit_value, last_command_exit_signal;
157 extern int subshell_environment, line_number;
158 extern int subshell_level, parse_and_execute_level, sourcelevel;
159 extern int eof_encountered;
160 extern int return_catch_flag, return_catch_value;
161 extern pid_t dollar_dollar_pid;
162 extern int posixly_correct;
163 extern char *this_command_name;
164 extern struct fd_bitmap *current_fds_to_close;
165 extern int wordexp_only;
166 extern int expanding_redir;
167 extern int tempenv_assign_error;
168
169 #if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)
170 extern wchar_t *wcsdup __P((const wchar_t *));
171 #endif
172
173 /* Non-zero means to allow unmatched globbed filenames to expand to
174    a null file. */
175 int allow_null_glob_expansion;
176
177 /* Non-zero means to throw an error when globbing fails to match anything. */
178 int fail_glob_expansion;
179
180 #if 0
181 /* Variables to keep track of which words in an expanded word list (the
182    output of expand_word_list_internal) are the result of globbing
183    expansions.  GLOB_ARGV_FLAGS is used by execute_cmd.c.
184    (CURRENTLY UNUSED). */
185 char *glob_argv_flags;
186 static int glob_argv_flags_size;
187 #endif
188
189 static WORD_LIST expand_word_error, expand_word_fatal;
190 static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
191 static char expand_param_error, expand_param_fatal;
192 static char extract_string_error, extract_string_fatal;
193
194 /* Tell the expansion functions to not longjmp back to top_level on fatal
195    errors.  Enabled when doing completion and prompt string expansion. */
196 static int no_longjmp_on_fatal_error = 0;
197
198 /* Set by expand_word_unsplit; used to inhibit splitting and re-joining
199    $* on $IFS, primarily when doing assignment statements. */
200 static int expand_no_split_dollar_star = 0;
201
202 /* A WORD_LIST of words to be expanded by expand_word_list_internal,
203    without any leading variable assignments. */
204 static WORD_LIST *garglist = (WORD_LIST *)NULL;
205
206 static char *quoted_substring __P((char *, int, int));
207 static int quoted_strlen __P((char *));
208 static char *quoted_strchr __P((char *, int, int));
209
210 static char *expand_string_if_necessary __P((char *, int, EXPFUNC *));
211 static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *));
212 static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *));
213 static WORD_LIST *expand_string_internal __P((char *, int));
214 static WORD_LIST *expand_string_leave_quoted __P((char *, int));
215 static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *));
216
217 static WORD_LIST *list_quote_escapes __P((WORD_LIST *));
218 static char *make_quoted_char __P((int));
219 static WORD_LIST *quote_list __P((WORD_LIST *));
220
221 static int unquoted_substring __P((char *, char *));
222 static int unquoted_member __P((int, char *));
223
224 #if defined (ARRAY_VARS)
225 static SHELL_VAR *do_compound_assignment __P((char *, char *, int));
226 #endif
227 static int do_assignment_internal __P((const WORD_DESC *, int));
228
229 static char *string_extract_verbatim __P((char *, size_t, int *, char *, int));
230 static char *string_extract __P((char *, int *, char *, int));
231 static char *string_extract_double_quoted __P((char *, int *, int));
232 static inline char *string_extract_single_quoted __P((char *, int *));
233 static inline int skip_single_quoted __P((const char *, size_t, int));
234 static int skip_double_quoted __P((char *, size_t, int));
235 static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int));
236 static char *extract_dollar_brace_string __P((char *, int *, int, int));
237 static int skip_matched_pair __P((const char *, int, int, int, int));
238
239 static char *pos_params __P((char *, int, int, int));
240
241 static unsigned char *mb_getcharlens __P((char *, int));
242
243 static char *remove_upattern __P((char *, char *, int));
244 #if defined (HANDLE_MULTIBYTE) 
245 static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int));
246 #endif
247 static char *remove_pattern __P((char *, char *, int));
248
249 static int match_upattern __P((char *, char *, int, char **, char **));
250 #if defined (HANDLE_MULTIBYTE)
251 static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
252 #endif
253 static int match_pattern __P((char *, char *, int, char **, char **));
254 static int getpatspec __P((int, char *));
255 static char *getpattern __P((char *, int, int));
256 static char *variable_remove_pattern __P((char *, char *, int, int));
257 static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int));
258 static char *parameter_list_remove_pattern __P((int, char *, int, int));
259 #ifdef ARRAY_VARS
260 static char *array_remove_pattern __P((SHELL_VAR *, char *, int, char *, int));
261 #endif
262 static char *parameter_brace_remove_pattern __P((char *, char *, int, char *, int, int, int));
263
264 static char *process_substitute __P((char *, int));
265
266 static char *read_comsub __P((int, int, int *));
267
268 #ifdef ARRAY_VARS
269 static arrayind_t array_length_reference __P((char *));
270 #endif
271
272 static int valid_brace_expansion_word __P((char *, int));
273 static int chk_atstar __P((char *, int, int *, int *));
274 static int chk_arithsub __P((const char *, int));
275
276 static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int, arrayind_t *));
277 static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *));
278 static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *));
279 static void parameter_brace_expand_error __P((char *, char *));
280
281 static int valid_length_expression __P((char *));
282 static intmax_t parameter_brace_expand_length __P((char *));
283
284 static char *skiparith __P((char *, int));
285 static int verify_substring_values __P((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
286 static int get_var_and_type __P((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **));
287 static char *mb_substring __P((char *, int, int));
288 static char *parameter_brace_substring __P((char *, char *, int, char *, int, int));
289
290 static int shouldexp_replacement __P((char *));
291
292 static char *pos_params_pat_subst __P((char *, char *, char *, int));
293
294 static char *parameter_brace_patsub __P((char *, char *, int, char *, int, int));
295
296 static char *pos_params_casemod __P((char *, char *, int, int));
297 static char *parameter_brace_casemod __P((char *, char *, int, int, char *, int, int));
298
299 static WORD_DESC *parameter_brace_expand __P((char *, int *, int, int, int *, int *));
300 static WORD_DESC *param_expand __P((char *, int *, int, int *, int *, int *, int *, int));
301
302 static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *));
303
304 static WORD_LIST *word_list_split __P((WORD_LIST *));
305
306 static void exp_jump_to_top_level __P((int));
307
308 static WORD_LIST *separate_out_assignments __P((WORD_LIST *));
309 static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int));
310 #ifdef BRACE_EXPANSION
311 static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int));
312 #endif
313 #if defined (ARRAY_VARS)
314 static int make_internal_declare __P((char *, char *));
315 #endif
316 static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int));
317 static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int));
318
319 /* **************************************************************** */
320 /*                                                                  */
321 /*                      Utility Functions                           */
322 /*                                                                  */
323 /* **************************************************************** */
324
325 #if defined (DEBUG)
326 void
327 dump_word_flags (flags)
328      int flags;
329 {
330   int f;
331
332   f = flags;
333   fprintf (stderr, "%d -> ", f);
334   if (f & W_ASSIGNASSOC)
335     {
336       f &= ~W_ASSIGNASSOC;
337       fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
338     }
339   if (f & W_HASCTLESC)
340     {
341       f &= ~W_HASCTLESC;
342       fprintf (stderr, "W_HASCTLESC%s", f ? "|" : "");
343     }
344   if (f & W_NOPROCSUB)
345     {
346       f &= ~W_NOPROCSUB;
347       fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
348     }
349   if (f & W_DQUOTE)
350     {
351       f &= ~W_DQUOTE;
352       fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
353     }
354   if (f & W_HASQUOTEDNULL)
355     {
356       f &= ~W_HASQUOTEDNULL;
357       fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
358     }
359   if (f & W_ASSIGNARG)
360     {
361       f &= ~W_ASSIGNARG;
362       fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
363     }
364   if (f & W_ASSNBLTIN)
365     {
366       f &= ~W_ASSNBLTIN;
367       fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
368     }
369   if (f & W_ASSNGLOBAL)
370     {
371       f &= ~W_ASSNGLOBAL;
372       fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : "");
373     }
374   if (f & W_COMPASSIGN)
375     {
376       f &= ~W_COMPASSIGN;
377       fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
378     }
379   if (f & W_NOEXPAND)
380     {
381       f &= ~W_NOEXPAND;
382       fprintf (stderr, "W_NOEXPAND%s", f ? "|" : "");
383     }
384   if (f & W_ITILDE)
385     {
386       f &= ~W_ITILDE;
387       fprintf (stderr, "W_ITILDE%s", f ? "|" : "");
388     }
389   if (f & W_NOTILDE)
390     {
391       f &= ~W_NOTILDE;
392       fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
393     }
394   if (f & W_ASSIGNRHS)
395     {
396       f &= ~W_ASSIGNRHS;
397       fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
398     }
399   if (f & W_NOCOMSUB)
400     {
401       f &= ~W_NOCOMSUB;
402       fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
403     }
404   if (f & W_DOLLARSTAR)
405     {
406       f &= ~W_DOLLARSTAR;
407       fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : "");
408     }
409   if (f & W_DOLLARAT)
410     {
411       f &= ~W_DOLLARAT;
412       fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
413     }
414   if (f & W_TILDEEXP)
415     {
416       f &= ~W_TILDEEXP;
417       fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
418     }
419   if (f & W_NOSPLIT2)
420     {
421       f &= ~W_NOSPLIT2;
422       fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
423     }
424   if (f & W_NOGLOB)
425     {
426       f &= ~W_NOGLOB;
427       fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
428     }
429   if (f & W_NOSPLIT)
430     {
431       f &= ~W_NOSPLIT;
432       fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
433     }
434   if (f & W_GLOBEXP)
435     {
436       f &= ~W_GLOBEXP;
437       fprintf (stderr, "W_GLOBEXP%s", f ? "|" : "");
438     }
439   if (f & W_ASSIGNMENT)
440     {
441       f &= ~W_ASSIGNMENT;
442       fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
443     }
444   if (f & W_QUOTED)
445     {
446       f &= ~W_QUOTED;
447       fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
448     }
449   if (f & W_HASDOLLAR)
450     {
451       f &= ~W_HASDOLLAR;
452       fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
453     }
454   fprintf (stderr, "\n");
455   fflush (stderr);
456 }
457 #endif
458
459 #ifdef INCLUDE_UNUSED
460 static char *
461 quoted_substring (string, start, end)
462      char *string;
463      int start, end;
464 {
465   register int len, l;
466   register char *result, *s, *r;
467
468   len = end - start;
469
470   /* Move to string[start], skipping quoted characters. */
471   for (s = string, l = 0; *s && l < start; )
472     {
473       if (*s == CTLESC)
474         {
475           s++;
476           continue;
477         }
478       l++;
479       if (*s == 0)
480         break;
481     }
482
483   r = result = (char *)xmalloc (2*len + 1);      /* save room for quotes */
484
485   /* Copy LEN characters, including quote characters. */
486   s = string + l;
487   for (l = 0; l < len; s++)
488     {
489       if (*s == CTLESC)
490         *r++ = *s++;
491       *r++ = *s;
492       l++;
493       if (*s == 0)
494         break;
495     }
496   *r = '\0';
497   return result;
498 }
499 #endif
500
501 #ifdef INCLUDE_UNUSED
502 /* Return the length of S, skipping over quoted characters */
503 static int
504 quoted_strlen (s)
505      char *s;
506 {
507   register char *p;
508   int i;
509
510   i = 0;
511   for (p = s; *p; p++)
512     {
513       if (*p == CTLESC)
514         {
515           p++;
516           if (*p == 0)
517             return (i + 1);
518         }
519       i++;
520     }
521
522   return i;
523 }
524 #endif
525
526 /* Find the first occurrence of character C in string S, obeying shell
527    quoting rules.  If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
528    characters are skipped.  If (FLAGS & ST_CTLESC) is non-zero, characters
529    escaped with CTLESC are skipped. */
530 static char *
531 quoted_strchr (s, c, flags)
532      char *s;
533      int c, flags;
534 {
535   register char *p;
536
537   for (p = s; *p; p++)
538     {
539       if (((flags & ST_BACKSL) && *p == '\\')
540             || ((flags & ST_CTLESC) && *p == CTLESC))
541         {
542           p++;
543           if (*p == '\0')
544             return ((char *)NULL);
545           continue;
546         }
547       else if (*p == c)
548         return p;
549     }
550   return ((char *)NULL);
551 }
552
553 /* Return 1 if CHARACTER appears in an unquoted portion of
554    STRING.  Return 0 otherwise.  CHARACTER must be a single-byte character. */
555 static int
556 unquoted_member (character, string)
557      int character;
558      char *string;
559 {
560   size_t slen;
561   int sindex, c;
562   DECLARE_MBSTATE;
563
564   slen = strlen (string);
565   sindex = 0;
566   while (c = string[sindex])
567     {
568       if (c == character)
569         return (1);
570
571       switch (c)
572         {
573         default:
574           ADVANCE_CHAR (string, slen, sindex);
575           break;
576
577         case '\\':
578           sindex++;
579           if (string[sindex])
580             ADVANCE_CHAR (string, slen, sindex);
581           break;
582
583         case '\'':
584           sindex = skip_single_quoted (string, slen, ++sindex);
585           break;
586
587         case '"':
588           sindex = skip_double_quoted (string, slen, ++sindex);
589           break;
590         }
591     }
592   return (0);
593 }
594
595 /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
596 static int
597 unquoted_substring (substr, string)
598      char *substr, *string;
599 {
600   size_t slen;
601   int sindex, c, sublen;
602   DECLARE_MBSTATE;
603
604   if (substr == 0 || *substr == '\0')
605     return (0);
606
607   slen = strlen (string);
608   sublen = strlen (substr);
609   for (sindex = 0; c = string[sindex]; )
610     {
611       if (STREQN (string + sindex, substr, sublen))
612         return (1);
613
614       switch (c)
615         {
616         case '\\':
617           sindex++;
618           if (string[sindex])
619             ADVANCE_CHAR (string, slen, sindex);
620           break;
621
622         case '\'':
623           sindex = skip_single_quoted (string, slen, ++sindex);
624           break;
625
626         case '"':
627           sindex = skip_double_quoted (string, slen, ++sindex);
628           break;
629
630         default:
631           ADVANCE_CHAR (string, slen, sindex);
632           break;
633         }
634     }
635   return (0);
636 }
637
638 /* Most of the substitutions must be done in parallel.  In order
639    to avoid using tons of unclear goto's, I have some functions
640    for manipulating malloc'ed strings.  They all take INDX, a
641    pointer to an integer which is the offset into the string
642    where manipulation is taking place.  They also take SIZE, a
643    pointer to an integer which is the current length of the
644    character array for this string. */
645
646 /* Append SOURCE to TARGET at INDEX.  SIZE is the current amount
647    of space allocated to TARGET.  SOURCE can be NULL, in which
648    case nothing happens.  Gets rid of SOURCE by freeing it.
649    Returns TARGET in case the location has changed. */
650 INLINE char *
651 sub_append_string (source, target, indx, size)
652      char *source, *target;
653      int *indx, *size;
654 {
655   if (source)
656     {
657       int srclen, n;
658
659       srclen = STRLEN (source);
660       if (srclen >= (int)(*size - *indx))
661         {
662           n = srclen + *indx;
663           n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
664           target = (char *)xrealloc (target, (*size = n));
665         }
666
667       FASTCOPY (source, target + *indx, srclen);
668       *indx += srclen;
669       target[*indx] = '\0';
670
671       free (source);
672     }
673   return (target);
674 }
675
676 #if 0
677 /* UNUSED */
678 /* Append the textual representation of NUMBER to TARGET.
679    INDX and SIZE are as in SUB_APPEND_STRING. */
680 char *
681 sub_append_number (number, target, indx, size)
682      intmax_t number;
683      int *indx, *size;
684      char *target;
685 {
686   char *temp;
687
688   temp = itos (number);
689   return (sub_append_string (temp, target, indx, size));
690 }
691 #endif
692
693 /* Extract a substring from STRING, starting at SINDEX and ending with
694    one of the characters in CHARLIST.  Don't make the ending character
695    part of the string.  Leave SINDEX pointing at the ending character.
696    Understand about backslashes in the string.  If (flags & SX_VARNAME)
697    is non-zero, and array variables have been compiled into the shell,
698    everything between a `[' and a corresponding `]' is skipped over.
699    If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
700    update SINDEX.  If (flags & SX_REQMATCH) is non-zero, the string must
701    contain a closing character from CHARLIST. */
702 static char *
703 string_extract (string, sindex, charlist, flags)
704      char *string;
705      int *sindex;
706      char *charlist;
707      int flags;
708 {
709   register int c, i;
710   int found;
711   size_t slen;
712   char *temp;
713   DECLARE_MBSTATE;
714
715   slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
716   i = *sindex;
717   found = 0;
718   while (c = string[i])
719     {
720       if (c == '\\')
721         {
722           if (string[i + 1])
723             i++;
724           else
725             break;
726         }
727 #if defined (ARRAY_VARS)
728       else if ((flags & SX_VARNAME) && c == '[')
729         {
730           int ni;
731           /* If this is an array subscript, skip over it and continue. */
732           ni = skipsubscript (string, i, 0);
733           if (string[ni] == ']')
734             i = ni;
735         }
736 #endif
737       else if (MEMBER (c, charlist))
738         {
739           found = 1;
740           break;
741         }
742
743       ADVANCE_CHAR (string, slen, i);
744     }
745
746   /* If we had to have a matching delimiter and didn't find one, return an
747      error and let the caller deal with it. */
748   if ((flags & SX_REQMATCH) && found == 0)
749     {
750       *sindex = i;
751       return (&extract_string_error);
752     }
753   
754   temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
755   *sindex = i;
756   
757   return (temp);
758 }
759
760 /* Extract the contents of STRING as if it is enclosed in double quotes.
761    SINDEX, when passed in, is the offset of the character immediately
762    following the opening double quote; on exit, SINDEX is left pointing after
763    the closing double quote.  If STRIPDQ is non-zero, unquoted double
764    quotes are stripped and the string is terminated by a null byte.
765    Backslashes between the embedded double quotes are processed.  If STRIPDQ
766    is zero, an unquoted `"' terminates the string. */
767 static char *
768 string_extract_double_quoted (string, sindex, stripdq)
769      char *string;
770      int *sindex, stripdq;
771 {
772   size_t slen;
773   char *send;
774   int j, i, t;
775   unsigned char c;
776   char *temp, *ret;             /* The new string we return. */
777   int pass_next, backquote, si; /* State variables for the machine. */
778   int dquote;
779   DECLARE_MBSTATE;
780
781   slen = strlen (string + *sindex) + *sindex;
782   send = string + slen;
783
784   pass_next = backquote = dquote = 0;
785   temp = (char *)xmalloc (1 + slen - *sindex);
786
787   j = 0;
788   i = *sindex;
789   while (c = string[i])
790     {
791       /* Process a character that was quoted by a backslash. */
792       if (pass_next)
793         {
794           /* XXX - take another look at this in light of Interp 221 */
795           /* Posix.2 sez:
796
797              ``The backslash shall retain its special meaning as an escape
798              character only when followed by one of the characters:
799                 $       `       "       \       <newline>''.
800
801              If STRIPDQ is zero, we handle the double quotes here and let
802              expand_word_internal handle the rest.  If STRIPDQ is non-zero,
803              we have already been through one round of backslash stripping,
804              and want to strip these backslashes only if DQUOTE is non-zero,
805              indicating that we are inside an embedded double-quoted string. */
806
807              /* If we are in an embedded quoted string, then don't strip
808                 backslashes before characters for which the backslash
809                 retains its special meaning, but remove backslashes in
810                 front of other characters.  If we are not in an
811                 embedded quoted string, don't strip backslashes at all.
812                 This mess is necessary because the string was already
813                 surrounded by double quotes (and sh has some really weird
814                 quoting rules).
815                 The returned string will be run through expansion as if
816                 it were double-quoted. */
817           if ((stripdq == 0 && c != '"') ||
818               (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0)))
819             temp[j++] = '\\';
820           pass_next = 0;
821
822 add_one_character:
823           COPY_CHAR_I (temp, j, string, send, i);
824           continue;
825         }
826
827       /* A backslash protects the next character.  The code just above
828          handles preserving the backslash in front of any character but
829          a double quote. */
830       if (c == '\\')
831         {
832           pass_next++;
833           i++;
834           continue;
835         }
836
837       /* Inside backquotes, ``the portion of the quoted string from the
838          initial backquote and the characters up to the next backquote
839          that is not preceded by a backslash, having escape characters
840          removed, defines that command''. */
841       if (backquote)
842         {
843           if (c == '`')
844             backquote = 0;
845           temp[j++] = c;
846           i++;
847           continue;
848         }
849
850       if (c == '`')
851         {
852           temp[j++] = c;
853           backquote++;
854           i++;
855           continue;
856         }
857
858       /* Pass everything between `$(' and the matching `)' or a quoted
859          ${ ... } pair through according to the Posix.2 specification. */
860       if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
861         {
862           int free_ret = 1;
863
864           si = i + 2;
865           if (string[i + 1] == LPAREN)
866             ret = extract_command_subst (string, &si, 0);
867           else
868             ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0);
869
870           temp[j++] = '$';
871           temp[j++] = string[i + 1];
872
873           /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error
874              is set. */
875           if (ret == 0 && no_longjmp_on_fatal_error)
876             {
877               free_ret = 0;
878               ret = string + i + 2;
879             }
880
881           for (t = 0; ret[t]; t++, j++)
882             temp[j] = ret[t];
883           temp[j] = string[si];
884
885           if (string[si])
886             {
887               j++;
888               i = si + 1;
889             }
890           else
891             i = si;
892
893           if (free_ret)
894             free (ret);
895           continue;
896         }
897
898       /* Add any character but a double quote to the quoted string we're
899          accumulating. */
900       if (c != '"')
901         goto add_one_character;
902
903       /* c == '"' */
904       if (stripdq)
905         {
906           dquote ^= 1;
907           i++;
908           continue;
909         }
910
911       break;
912     }
913   temp[j] = '\0';
914
915   /* Point to after the closing quote. */
916   if (c)
917     i++;
918   *sindex = i;
919
920   return (temp);
921 }
922
923 /* This should really be another option to string_extract_double_quoted. */
924 static int
925 skip_double_quoted (string, slen, sind)
926      char *string;
927      size_t slen;
928      int sind;
929 {
930   int c, i;
931   char *ret;
932   int pass_next, backquote, si;
933   DECLARE_MBSTATE;
934
935   pass_next = backquote = 0;
936   i = sind;
937   while (c = string[i])
938     {
939       if (pass_next)
940         {
941           pass_next = 0;
942           ADVANCE_CHAR (string, slen, i);
943           continue;
944         }
945       else if (c == '\\')
946         {
947           pass_next++;
948           i++;
949           continue;
950         }
951       else if (backquote)
952         {
953           if (c == '`')
954             backquote = 0;
955           ADVANCE_CHAR (string, slen, i);
956           continue;
957         }
958       else if (c == '`')
959         {
960           backquote++;
961           i++;
962           continue;
963         }
964       else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
965         {
966           si = i + 2;
967           if (string[i + 1] == LPAREN)
968             ret = extract_command_subst (string, &si, SX_NOALLOC);
969           else
970             ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC);
971
972           i = si + 1;
973           continue;
974         }
975       else if (c != '"')
976         {
977           ADVANCE_CHAR (string, slen, i);
978           continue;
979         }
980       else
981         break;
982     }
983
984   if (c)
985     i++;
986
987   return (i);
988 }
989
990 /* Extract the contents of STRING as if it is enclosed in single quotes.
991    SINDEX, when passed in, is the offset of the character immediately
992    following the opening single quote; on exit, SINDEX is left pointing after
993    the closing single quote. */
994 static inline char *
995 string_extract_single_quoted (string, sindex)
996      char *string;
997      int *sindex;
998 {
999   register int i;
1000   size_t slen;
1001   char *t;
1002   DECLARE_MBSTATE;
1003
1004   /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */
1005   slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
1006   i = *sindex;
1007   while (string[i] && string[i] != '\'')
1008     ADVANCE_CHAR (string, slen, i);
1009
1010   t = substring (string, *sindex, i);
1011
1012   if (string[i])
1013     i++;
1014   *sindex = i;
1015
1016   return (t);
1017 }
1018
1019 static inline int
1020 skip_single_quoted (string, slen, sind)
1021      const char *string;
1022      size_t slen;
1023      int sind;
1024 {
1025   register int c;
1026   DECLARE_MBSTATE;
1027
1028   c = sind;
1029   while (string[c] && string[c] != '\'')
1030     ADVANCE_CHAR (string, slen, c);
1031
1032   if (string[c])
1033     c++;
1034   return c;
1035 }
1036
1037 /* Just like string_extract, but doesn't hack backslashes or any of
1038    that other stuff.  Obeys CTLESC quoting.  Used to do splitting on $IFS. */
1039 static char *
1040 string_extract_verbatim (string, slen, sindex, charlist, flags)
1041      char *string;
1042      size_t slen;
1043      int *sindex;
1044      char *charlist;
1045      int flags;
1046 {
1047   register int i;
1048 #if defined (HANDLE_MULTIBYTE)
1049   size_t clen;
1050   wchar_t *wcharlist;
1051 #endif
1052   int c;
1053   char *temp;
1054   DECLARE_MBSTATE;
1055
1056   if (charlist[0] == '\'' && charlist[1] == '\0')
1057     {
1058       temp = string_extract_single_quoted (string, sindex);
1059       --*sindex;        /* leave *sindex at separator character */
1060       return temp;
1061     }
1062
1063   i = *sindex;
1064 #if 0
1065   /* See how the MBLEN and ADVANCE_CHAR macros work to understand why we need
1066      this only if MB_CUR_MAX > 1. */
1067   slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 1;
1068 #endif
1069 #if defined (HANDLE_MULTIBYTE)
1070   clen = strlen (charlist);
1071   wcharlist = 0;
1072 #endif
1073   while (c = string[i])
1074     {
1075 #if defined (HANDLE_MULTIBYTE)
1076       size_t mblength;
1077 #endif
1078       if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
1079         {
1080           i += 2;
1081           continue;
1082         }
1083       /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
1084          through, to protect the CTLNULs from later calls to
1085          remove_quoted_nulls. */
1086       else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
1087         {
1088           i += 2;
1089           continue;
1090         }
1091
1092 #if defined (HANDLE_MULTIBYTE)
1093       mblength = MBLEN (string + i, slen - i);
1094       if (mblength > 1)
1095         {
1096           wchar_t wc;
1097           mblength = mbtowc (&wc, string + i, slen - i);
1098           if (MB_INVALIDCH (mblength))
1099             {
1100               if (MEMBER (c, charlist))
1101                 break;
1102             }
1103           else
1104             {
1105               if (wcharlist == 0)
1106                 {
1107                   size_t len;
1108                   len = mbstowcs (wcharlist, charlist, 0);
1109                   if (len == -1)
1110                     len = 0;
1111                   wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
1112                   mbstowcs (wcharlist, charlist, len + 1);
1113                 }
1114
1115               if (wcschr (wcharlist, wc))
1116                 break;
1117             }
1118         }
1119       else              
1120 #endif
1121       if (MEMBER (c, charlist))
1122         break;
1123
1124       ADVANCE_CHAR (string, slen, i);
1125     }
1126
1127 #if defined (HANDLE_MULTIBYTE)
1128   FREE (wcharlist);
1129 #endif
1130
1131   temp = substring (string, *sindex, i);
1132   *sindex = i;
1133
1134   return (temp);
1135 }
1136
1137 /* Extract the $( construct in STRING, and return a new string.
1138    Start extracting at (SINDEX) as if we had just seen "$(".
1139    Make (SINDEX) get the position of the matching ")". )
1140    XFLAGS is additional flags to pass to other extraction functions. */
1141 char *
1142 extract_command_subst (string, sindex, xflags)
1143      char *string;
1144      int *sindex;
1145      int xflags;
1146 {
1147   if (string[*sindex] == LPAREN)
1148     return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
1149   else
1150     {
1151       xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1152       return (xparse_dolparen (string, string+*sindex, sindex, xflags));
1153     }
1154 }
1155
1156 /* Extract the $[ construct in STRING, and return a new string. (])
1157    Start extracting at (SINDEX) as if we had just seen "$[".
1158    Make (SINDEX) get the position of the matching "]". */
1159 char *
1160 extract_arithmetic_subst (string, sindex)
1161      char *string;
1162      int *sindex;
1163 {
1164   return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/
1165 }
1166
1167 #if defined (PROCESS_SUBSTITUTION)
1168 /* Extract the <( or >( construct in STRING, and return a new string.
1169    Start extracting at (SINDEX) as if we had just seen "<(".
1170    Make (SINDEX) get the position of the matching ")". */ /*))*/
1171 char *
1172 extract_process_subst (string, starter, sindex)
1173      char *string;
1174      char *starter;
1175      int *sindex;
1176 {
1177   return (extract_delimited_string (string, sindex, starter, "(", ")", 0));
1178 }
1179 #endif /* PROCESS_SUBSTITUTION */
1180
1181 #if defined (ARRAY_VARS)
1182 /* This can be fooled by unquoted right parens in the passed string. If
1183    each caller verifies that the last character in STRING is a right paren,
1184    we don't even need to call extract_delimited_string. */
1185 char *
1186 extract_array_assignment_list (string, sindex)
1187      char *string;
1188      int *sindex;
1189 {
1190   int slen;
1191   char *ret;
1192
1193   slen = strlen (string);       /* ( */
1194   if (string[slen - 1] == ')')
1195    {
1196       ret = substring (string, *sindex, slen - 1);
1197       *sindex = slen - 1;
1198       return ret;
1199     }
1200   return 0;  
1201 }
1202 #endif
1203
1204 /* Extract and create a new string from the contents of STRING, a
1205    character string delimited with OPENER and CLOSER.  SINDEX is
1206    the address of an int describing the current offset in STRING;
1207    it should point to just after the first OPENER found.  On exit,
1208    SINDEX gets the position of the last character of the matching CLOSER.
1209    If OPENER is more than a single character, ALT_OPENER, if non-null,
1210    contains a character string that can also match CLOSER and thus
1211    needs to be skipped. */
1212 static char *
1213 extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
1214      char *string;
1215      int *sindex;
1216      char *opener, *alt_opener, *closer;
1217      int flags;
1218 {
1219   int i, c, si;
1220   size_t slen;
1221   char *t, *result;
1222   int pass_character, nesting_level, in_comment;
1223   int len_closer, len_opener, len_alt_opener;
1224   DECLARE_MBSTATE;
1225
1226   slen = strlen (string + *sindex) + *sindex;
1227   len_opener = STRLEN (opener);
1228   len_alt_opener = STRLEN (alt_opener);
1229   len_closer = STRLEN (closer);
1230
1231   pass_character = in_comment = 0;
1232
1233   nesting_level = 1;
1234   i = *sindex;
1235
1236   while (nesting_level)
1237     {
1238       c = string[i];
1239
1240       if (c == 0)
1241         break;
1242
1243       if (in_comment)
1244         {
1245           if (c == '\n')
1246             in_comment = 0;
1247           ADVANCE_CHAR (string, slen, i);
1248           continue;
1249         }
1250
1251       if (pass_character)       /* previous char was backslash */
1252         {
1253           pass_character = 0;
1254           ADVANCE_CHAR (string, slen, i);
1255           continue;
1256         }
1257
1258       /* Not exactly right yet; should handle shell metacharacters and
1259          multibyte characters, too.  See COMMENT_BEGIN define in parse.y */
1260       if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
1261         {
1262           in_comment = 1;
1263           ADVANCE_CHAR (string, slen, i);
1264           continue;
1265         }
1266         
1267       if (c == CTLESC || c == '\\')
1268         {
1269           pass_character++;
1270           i++;
1271           continue;
1272         }
1273
1274       /* Process a nested command substitution, but only if we're parsing an
1275          arithmetic substitution. */
1276       if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
1277         {
1278           si = i + 2;
1279           t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1280           i = si + 1;
1281           continue;
1282         }
1283
1284       /* Process a nested OPENER. */
1285       if (STREQN (string + i, opener, len_opener))
1286         {
1287           si = i + len_opener;
1288           t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
1289           i = si + 1;
1290           continue;
1291         }
1292
1293       /* Process a nested ALT_OPENER */
1294       if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
1295         {
1296           si = i + len_alt_opener;
1297           t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
1298           i = si + 1;
1299           continue;
1300         }
1301
1302       /* If the current substring terminates the delimited string, decrement
1303          the nesting level. */
1304       if (STREQN (string + i, closer, len_closer))
1305         {
1306           i += len_closer - 1;  /* move to last byte of the closer */
1307           nesting_level--;
1308           if (nesting_level == 0)
1309             break;
1310         }
1311
1312       /* Pass old-style command substitution through verbatim. */
1313       if (c == '`')
1314         {
1315           si = i + 1;
1316           t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1317           i = si + 1;
1318           continue;
1319         }
1320
1321       /* Pass single-quoted and double-quoted strings through verbatim. */
1322       if (c == '\'' || c == '"')
1323         {
1324           si = i + 1;
1325           i = (c == '\'') ? skip_single_quoted (string, slen, si)
1326                           : skip_double_quoted (string, slen, si);
1327           continue;
1328         }
1329
1330       /* move past this character, which was not special. */
1331       ADVANCE_CHAR (string, slen, i);
1332     }
1333
1334   if (c == 0 && nesting_level)
1335     {
1336       if (no_longjmp_on_fatal_error == 0)
1337         {
1338           report_error (_("bad substitution: no closing `%s' in %s"), closer, string);
1339           last_command_exit_value = EXECUTION_FAILURE;
1340           exp_jump_to_top_level (DISCARD);
1341         }
1342       else
1343         {
1344           *sindex = i;
1345           return (char *)NULL;
1346         }
1347     }
1348
1349   si = i - *sindex - len_closer + 1;
1350   if (flags & SX_NOALLOC)
1351     result = (char *)NULL;
1352   else    
1353     {
1354       result = (char *)xmalloc (1 + si);
1355       strncpy (result, string + *sindex, si);
1356       result[si] = '\0';
1357     }
1358   *sindex = i;
1359
1360   return (result);
1361 }
1362
1363 /* Extract a parameter expansion expression within ${ and } from STRING.
1364    Obey the Posix.2 rules for finding the ending `}': count braces while
1365    skipping over enclosed quoted strings and command substitutions.
1366    SINDEX is the address of an int describing the current offset in STRING;
1367    it should point to just after the first `{' found.  On exit, SINDEX
1368    gets the position of the matching `}'.  QUOTED is non-zero if this
1369    occurs inside double quotes. */
1370 /* XXX -- this is very similar to extract_delimited_string -- XXX */
1371 static char *
1372 extract_dollar_brace_string (string, sindex, quoted, flags)
1373      char *string;
1374      int *sindex, quoted, flags;
1375 {
1376   register int i, c;
1377   size_t slen;
1378   int pass_character, nesting_level, si, dolbrace_state;
1379   char *result, *t;
1380   DECLARE_MBSTATE;
1381
1382   pass_character = 0;
1383   nesting_level = 1;
1384   slen = strlen (string + *sindex) + *sindex;
1385
1386   /* The handling of dolbrace_state needs to agree with the code in parse.y:
1387      parse_matched_pair().  The different initial value is to handle the
1388      case where this function is called to parse the word in
1389      ${param op word} (SX_WORD). */
1390   dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM;
1391   if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP))
1392     dolbrace_state = DOLBRACE_QUOTE;
1393
1394   i = *sindex;
1395   while (c = string[i])
1396     {
1397       if (pass_character)
1398         {
1399           pass_character = 0;
1400           ADVANCE_CHAR (string, slen, i);
1401           continue;
1402         }
1403
1404       /* CTLESCs and backslashes quote the next character. */
1405       if (c == CTLESC || c == '\\')
1406         {
1407           pass_character++;
1408           i++;
1409           continue;
1410         }
1411
1412       if (string[i] == '$' && string[i+1] == LBRACE)
1413         {
1414           nesting_level++;
1415           i += 2;
1416           continue;
1417         }
1418
1419       if (c == RBRACE)
1420         {
1421           nesting_level--;
1422           if (nesting_level == 0)
1423             break;
1424           i++;
1425           continue;
1426         }
1427
1428       /* Pass the contents of old-style command substitutions through
1429          verbatim. */
1430       if (c == '`')
1431         {
1432           si = i + 1;
1433           t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1434           i = si + 1;
1435           continue;
1436         }
1437
1438       /* Pass the contents of new-style command substitutions and
1439          arithmetic substitutions through verbatim. */
1440       if (string[i] == '$' && string[i+1] == LPAREN)
1441         {
1442           si = i + 2;
1443           t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1444           i = si + 1;
1445           continue;
1446         }
1447
1448 #if 0
1449       /* Pass the contents of single-quoted and double-quoted strings
1450          through verbatim. */
1451       if (c == '\'' || c == '"')
1452         {
1453           si = i + 1;
1454           i = (c == '\'') ? skip_single_quoted (string, slen, si)
1455                           : skip_double_quoted (string, slen, si);
1456           /* skip_XXX_quoted leaves index one past close quote */
1457           continue;
1458         }
1459 #else   /* XXX - bash-4.2 */
1460       /* Pass the contents of double-quoted strings through verbatim. */
1461       if (c == '"')
1462         {
1463           si = i + 1;
1464           i = skip_double_quoted (string, slen, si);
1465           /* skip_XXX_quoted leaves index one past close quote */
1466           continue;
1467         }
1468
1469       if (c == '\'')
1470         {
1471 /*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
1472           if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1473             ADVANCE_CHAR (string, slen, i);
1474           else
1475             {
1476               si = i + 1;
1477               i = skip_single_quoted (string, slen, si);
1478             }
1479
1480           continue;
1481         }
1482 #endif
1483
1484       /* move past this character, which was not special. */
1485       ADVANCE_CHAR (string, slen, i);
1486
1487       /* This logic must agree with parse.y:parse_matched_pair, since they
1488          share the same defines. */
1489       if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
1490         dolbrace_state = DOLBRACE_QUOTE;
1491       else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
1492         dolbrace_state = DOLBRACE_QUOTE;
1493       else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
1494         dolbrace_state = DOLBRACE_QUOTE;
1495       else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
1496         dolbrace_state = DOLBRACE_QUOTE;
1497       else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
1498         dolbrace_state = DOLBRACE_QUOTE;
1499       else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
1500         dolbrace_state = DOLBRACE_OP;
1501       else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
1502         dolbrace_state = DOLBRACE_WORD;
1503     }
1504
1505   if (c == 0 && nesting_level)
1506     {
1507       if (no_longjmp_on_fatal_error == 0)
1508         {                       /* { */
1509           report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
1510           last_command_exit_value = EXECUTION_FAILURE;
1511           exp_jump_to_top_level (DISCARD);
1512         }
1513       else
1514         {
1515           *sindex = i;
1516           return ((char *)NULL);
1517         }
1518     }
1519
1520   result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
1521   *sindex = i;
1522
1523   return (result);
1524 }
1525
1526 /* Remove backslashes which are quoting backquotes from STRING.  Modifies
1527    STRING, and returns a pointer to it. */
1528 char *
1529 de_backslash (string)
1530      char *string;
1531 {
1532   register size_t slen;
1533   register int i, j, prev_i;
1534   DECLARE_MBSTATE;
1535
1536   slen = strlen (string);
1537   i = j = 0;
1538
1539   /* Loop copying string[i] to string[j], i >= j. */
1540   while (i < slen)
1541     {
1542       if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
1543                               string[i + 1] == '$'))
1544         i++;
1545       prev_i = i;
1546       ADVANCE_CHAR (string, slen, i);
1547       if (j < prev_i)
1548         do string[j++] = string[prev_i++]; while (prev_i < i);
1549       else
1550         j = i;
1551     }
1552   string[j] = '\0';
1553
1554   return (string);
1555 }
1556
1557 #if 0
1558 /*UNUSED*/
1559 /* Replace instances of \! in a string with !. */
1560 void
1561 unquote_bang (string)
1562      char *string;
1563 {
1564   register int i, j;
1565   register char *temp;
1566
1567   temp = (char *)xmalloc (1 + strlen (string));
1568
1569   for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
1570     {
1571       if (string[i] == '\\' && string[i + 1] == '!')
1572         {
1573           temp[j] = '!';
1574           i++;
1575         }
1576     }
1577   strcpy (string, temp);
1578   free (temp);
1579 }
1580 #endif
1581
1582 #define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
1583
1584 /* This function assumes s[i] == open; returns with s[ret] == close; used to
1585    parse array subscripts.  FLAGS & 1 means to not attempt to skip over
1586    matched pairs of quotes or backquotes, or skip word expansions; it is
1587    intended to be used after expansion has been performed and during final
1588    assignment parsing (see arrayfunc.c:assign_compound_array_list()). */
1589 static int
1590 skip_matched_pair (string, start, open, close, flags)
1591      const char *string;
1592      int start, open, close, flags;
1593 {
1594   int i, pass_next, backq, si, c, count;
1595   size_t slen;
1596   char *temp, *ss;
1597   DECLARE_MBSTATE;
1598
1599   slen = strlen (string + start) + start;
1600   no_longjmp_on_fatal_error = 1;
1601
1602   i = start + 1;                /* skip over leading bracket */
1603   count = 1;
1604   pass_next = backq = 0;
1605   ss = (char *)string;
1606   while (c = string[i])
1607     {
1608       if (pass_next)
1609         {
1610           pass_next = 0;
1611           if (c == 0)
1612             CQ_RETURN(i);
1613           ADVANCE_CHAR (string, slen, i);
1614           continue;
1615         }
1616       else if (c == '\\')
1617         {
1618           pass_next = 1;
1619           i++;
1620           continue;
1621         }
1622       else if (backq)
1623         {
1624           if (c == '`')
1625             backq = 0;
1626           ADVANCE_CHAR (string, slen, i);
1627           continue;
1628         }
1629       else if ((flags & 1) == 0 && c == '`')
1630         {
1631           backq = 1;
1632           i++;
1633           continue;
1634         }
1635       else if ((flags & 1) == 0 && c == open)
1636         {
1637           count++;
1638           i++;
1639           continue;
1640         }
1641       else if (c == close)
1642         {
1643           count--;
1644           if (count == 0)
1645             break;
1646           i++;
1647           continue;
1648         }
1649       else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
1650         {
1651           i = (c == '\'') ? skip_single_quoted (ss, slen, ++i)
1652                           : skip_double_quoted (ss, slen, ++i);
1653           /* no increment, the skip functions increment past the closing quote. */
1654         }
1655       else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
1656         {
1657           si = i + 2;
1658           if (string[si] == '\0')
1659             CQ_RETURN(si);
1660
1661           if (string[i+1] == LPAREN)
1662             temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
1663           else
1664             temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
1665           i = si;
1666           if (string[i] == '\0')        /* don't increment i past EOS in loop */
1667             break;
1668           i++;
1669           continue;
1670         }
1671       else
1672         ADVANCE_CHAR (string, slen, i);
1673     }
1674
1675   CQ_RETURN(i);
1676 }
1677
1678 #if defined (ARRAY_VARS)
1679 int
1680 skipsubscript (string, start, flags)
1681      const char *string;
1682      int start, flags;
1683 {
1684   return (skip_matched_pair (string, start, '[', ']', flags));
1685 }
1686 #endif
1687
1688 /* Skip characters in STRING until we find a character in DELIMS, and return
1689    the index of that character.  START is the index into string at which we
1690    begin.  This is similar in spirit to strpbrk, but it returns an index into
1691    STRING and takes a starting index.  This little piece of code knows quite
1692    a lot of shell syntax.  It's very similar to skip_double_quoted and other
1693    functions of that ilk. */
1694 int
1695 skip_to_delim (string, start, delims, flags)
1696      char *string;
1697      int start;
1698      char *delims;
1699      int flags;
1700 {
1701   int i, pass_next, backq, si, c, invert, skipquote, skipcmd;
1702   size_t slen;
1703   char *temp, open[3];
1704   DECLARE_MBSTATE;
1705
1706   slen = strlen (string + start) + start;
1707   if (flags & SD_NOJMP)
1708     no_longjmp_on_fatal_error = 1;
1709   invert = (flags & SD_INVERT);
1710   skipcmd = (flags & SD_NOSKIPCMD) == 0;
1711
1712   i = start;
1713   pass_next = backq = 0;
1714   while (c = string[i])
1715     {
1716       /* If this is non-zero, we should not let quote characters be delimiters
1717          and the current character is a single or double quote.  We should not
1718          test whether or not it's a delimiter until after we skip single- or
1719          double-quoted strings. */
1720       skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
1721       if (pass_next)
1722         {
1723           pass_next = 0;
1724           if (c == 0)
1725             CQ_RETURN(i);
1726           ADVANCE_CHAR (string, slen, i);
1727           continue;
1728         }
1729       else if (c == '\\')
1730         {
1731           pass_next = 1;
1732           i++;
1733           continue;
1734         }
1735       else if (backq)
1736         {
1737           if (c == '`')
1738             backq = 0;
1739           ADVANCE_CHAR (string, slen, i);
1740           continue;
1741         }
1742       else if (c == '`')
1743         {
1744           backq = 1;
1745           i++;
1746           continue;
1747         }
1748       else if (skipquote == 0 && invert == 0 && member (c, delims))
1749         break;
1750       else if (c == '\'' || c == '"')
1751         {
1752           i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
1753                           : skip_double_quoted (string, slen, ++i);
1754           /* no increment, the skip functions increment past the closing quote. */
1755         }
1756       else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
1757         {
1758           si = i + 2;
1759           if (string[si] == '\0')
1760             CQ_RETURN(si);
1761
1762           if (string[i+1] == LPAREN)
1763             temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
1764           else
1765             temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
1766           i = si;
1767           if (string[i] == '\0')        /* don't increment i past EOS in loop */
1768             break;
1769           i++;
1770           continue;
1771         }
1772 #if defined (PROCESS_SUBSTITUTION)
1773       else if (skipcmd && (c == '<' || c == '>') && string[i+1] == LPAREN)
1774         {
1775           si = i + 2;
1776           if (string[si] == '\0')
1777             CQ_RETURN(si);
1778           temp = extract_process_subst (string, (c == '<') ? "<(" : ">(", &si);
1779           i = si;
1780           if (string[i] == '\0')
1781             break;
1782           i++;
1783           continue;
1784         }
1785 #endif /* PROCESS_SUBSTITUTION */
1786 #if defined (EXTENDED_GLOB)
1787       else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@"))
1788         {
1789           si = i + 2;
1790           if (string[si] == '\0')
1791             CQ_RETURN(si);
1792
1793           open[0] = c;
1794           open[1] = LPAREN;
1795           open[2] = '\0';
1796           temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */
1797
1798           i = si;
1799           if (string[i] == '\0')        /* don't increment i past EOS in loop */
1800             break;
1801           i++;
1802           continue;
1803         }
1804 #endif
1805       else if ((skipquote || invert) && (member (c, delims) == 0))
1806         break;
1807       else
1808         ADVANCE_CHAR (string, slen, i);
1809     }
1810
1811   CQ_RETURN(i);
1812 }
1813
1814 #if defined (READLINE)
1815 /* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
1816    an unclosed quoted string), or if the character at EINDEX is quoted
1817    by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various
1818    single and double-quoted string parsing functions should not return an
1819    error if there are unclosed quotes or braces.  The characters that this
1820    recognizes need to be the same as the contents of
1821    rl_completer_quote_characters. */
1822
1823 int
1824 char_is_quoted (string, eindex)
1825      char *string;
1826      int eindex;
1827 {
1828   int i, pass_next, c;
1829   size_t slen;
1830   DECLARE_MBSTATE;
1831
1832   slen = strlen (string);
1833   no_longjmp_on_fatal_error = 1;
1834   i = pass_next = 0;
1835   while (i <= eindex)
1836     {
1837       c = string[i];
1838
1839       if (pass_next)
1840         {
1841           pass_next = 0;
1842           if (i >= eindex)      /* XXX was if (i >= eindex - 1) */
1843             CQ_RETURN(1);
1844           ADVANCE_CHAR (string, slen, i);
1845           continue;
1846         }
1847       else if (c == '\\')
1848         {
1849           pass_next = 1;
1850           i++;
1851           continue;
1852         }
1853       else if (c == '\'' || c == '"')
1854         {
1855           i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
1856                           : skip_double_quoted (string, slen, ++i);
1857           if (i > eindex)
1858             CQ_RETURN(1);
1859           /* no increment, the skip_xxx functions go one past end */
1860         }
1861       else
1862         ADVANCE_CHAR (string, slen, i);
1863     }
1864
1865   CQ_RETURN(0);
1866 }
1867
1868 int
1869 unclosed_pair (string, eindex, openstr)
1870      char *string;
1871      int eindex;
1872      char *openstr;
1873 {
1874   int i, pass_next, openc, olen;
1875   size_t slen;
1876   DECLARE_MBSTATE;
1877
1878   slen = strlen (string);
1879   olen = strlen (openstr);
1880   i = pass_next = openc = 0;
1881   while (i <= eindex)
1882     {
1883       if (pass_next)
1884         {
1885           pass_next = 0;
1886           if (i >= eindex)      /* XXX was if (i >= eindex - 1) */
1887             return 0;
1888           ADVANCE_CHAR (string, slen, i);
1889           continue;
1890         }
1891       else if (string[i] == '\\')
1892         {
1893           pass_next = 1;
1894           i++;
1895           continue;
1896         }
1897       else if (STREQN (string + i, openstr, olen))
1898         {
1899           openc = 1 - openc;
1900           i += olen;
1901         }
1902       else if (string[i] == '\'' || string[i] == '"')
1903         {
1904           i = (string[i] == '\'') ? skip_single_quoted (string, slen, i)
1905                                   : skip_double_quoted (string, slen, i);
1906           if (i > eindex)
1907             return 0;
1908         }
1909       else
1910         ADVANCE_CHAR (string, slen, i);
1911     }
1912   return (openc);
1913 }
1914
1915 /* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
1916    individual words.  If DELIMS is NULL, the current value of $IFS is used
1917    to split the string, and the function follows the shell field splitting
1918    rules.  SENTINEL is an index to look for.  NWP, if non-NULL,
1919    gets the number of words in the returned list.  CWP, if non-NULL, gets
1920    the index of the word containing SENTINEL.  Non-whitespace chars in
1921    DELIMS delimit separate fields. */
1922 WORD_LIST *
1923 split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
1924      char *string;
1925      int slen;
1926      char *delims;
1927      int sentinel, flags;
1928      int *nwp, *cwp;
1929 {
1930   int ts, te, i, nw, cw, ifs_split, dflags;
1931   char *token, *d, *d2;
1932   WORD_LIST *ret, *tl;
1933
1934   if (string == 0 || *string == '\0')
1935     {
1936       if (nwp)
1937         *nwp = 0;
1938       if (cwp)
1939         *cwp = 0;       
1940       return ((WORD_LIST *)NULL);
1941     }
1942
1943   d = (delims == 0) ? ifs_value : delims;
1944   ifs_split = delims == 0;
1945
1946   /* Make d2 the non-whitespace characters in delims */
1947   d2 = 0;
1948   if (delims)
1949     {
1950       size_t slength;
1951 #if defined (HANDLE_MULTIBYTE)
1952       size_t mblength = 1;
1953 #endif
1954       DECLARE_MBSTATE;
1955
1956       slength = strlen (delims);
1957       d2 = (char *)xmalloc (slength + 1);
1958       i = ts = 0;
1959       while (delims[i])
1960         {
1961 #if defined (HANDLE_MULTIBYTE)
1962           mbstate_t state_bak;
1963           state_bak = state;
1964           mblength = MBRLEN (delims + i, slength, &state);
1965           if (MB_INVALIDCH (mblength))
1966             state = state_bak;
1967           else if (mblength > 1)
1968             {
1969               memcpy (d2 + ts, delims + i, mblength);
1970               ts += mblength;
1971               i += mblength;
1972               slength -= mblength;
1973               continue;
1974             }
1975 #endif
1976           if (whitespace (delims[i]) == 0)
1977             d2[ts++] = delims[i];
1978
1979           i++;
1980           slength--;
1981         }
1982       d2[ts] = '\0';
1983     }
1984
1985   ret = (WORD_LIST *)NULL;
1986
1987   /* Remove sequences of whitespace characters at the start of the string, as
1988      long as those characters are delimiters. */
1989   for (i = 0; member (string[i], d) && spctabnl (string[i]); i++)
1990     ;
1991   if (string[i] == '\0')
1992     return (ret);
1993
1994   ts = i;
1995   nw = 0;
1996   cw = -1;
1997   dflags = flags|SD_NOJMP;
1998   while (1)
1999     {
2000       te = skip_to_delim (string, ts, d, dflags);
2001
2002       /* If we have a non-whitespace delimiter character, use it to make a
2003          separate field.  This is just about what $IFS splitting does and
2004          is closer to the behavior of the shell parser. */
2005       if (ts == te && d2 && member (string[ts], d2))
2006         {
2007           te = ts + 1;
2008           /* If we're using IFS splitting, the non-whitespace delimiter char
2009              and any additional IFS whitespace delimits a field. */
2010           if (ifs_split)
2011             while (member (string[te], d) && spctabnl (string[te]))
2012               te++;
2013           else
2014             while (member (string[te], d2))
2015               te++;
2016         }
2017
2018       token = substring (string, ts, te);
2019
2020       ret = add_string_to_list (token, ret);
2021       free (token);
2022       nw++;
2023
2024       if (sentinel >= ts && sentinel <= te)
2025         cw = nw;
2026
2027       /* If the cursor is at whitespace just before word start, set the
2028          sentinel word to the current word. */
2029       if (cwp && cw == -1 && sentinel == ts-1)
2030         cw = nw;
2031
2032       /* If the cursor is at whitespace between two words, make a new, empty
2033          word, add it before (well, after, since the list is in reverse order)
2034          the word we just added, and set the current word to that one. */
2035       if (cwp && cw == -1 && sentinel < ts)
2036         {
2037           tl = make_word_list (make_word (""), ret->next);
2038           ret->next = tl;
2039           cw = nw;
2040           nw++;
2041         }
2042
2043       if (string[te] == 0)
2044         break;
2045
2046       i = te;
2047       while (member (string[i], d) && (ifs_split || spctabnl(string[i])))
2048         i++;
2049
2050       if (string[i])
2051         ts = i;
2052       else
2053         break;
2054     }
2055
2056   /* Special case for SENTINEL at the end of STRING.  If we haven't found
2057      the word containing SENTINEL yet, and the index we're looking for is at
2058      the end of STRING (or past the end of the previously-found token,
2059      possible if the end of the line is composed solely of IFS whitespace)
2060      add an additional null argument and set the current word pointer to that. */
2061   if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
2062     {
2063       if (whitespace (string[sentinel - 1]))
2064         {
2065           token = "";
2066           ret = add_string_to_list (token, ret);
2067           nw++;
2068         }
2069       cw = nw;
2070     }
2071
2072   if (nwp)
2073     *nwp = nw;
2074   if (cwp)
2075     *cwp = cw;
2076
2077   return (REVERSE_LIST (ret, WORD_LIST *));
2078 }
2079 #endif /* READLINE */
2080
2081 #if 0
2082 /* UNUSED */
2083 /* Extract the name of the variable to bind to from the assignment string. */
2084 char *
2085 assignment_name (string)
2086      char *string;
2087 {
2088   int offset;
2089   char *temp;
2090
2091   offset = assignment (string, 0);
2092   if (offset == 0)
2093     return (char *)NULL;
2094   temp = substring (string, 0, offset);
2095   return (temp);
2096 }
2097 #endif
2098
2099 /* **************************************************************** */
2100 /*                                                                  */
2101 /*     Functions to convert strings to WORD_LISTs and vice versa    */
2102 /*                                                                  */
2103 /* **************************************************************** */
2104
2105 /* Return a single string of all the words in LIST.  SEP is the separator
2106    to put between individual elements of LIST in the output string. */
2107 char *
2108 string_list_internal (list, sep)
2109      WORD_LIST *list;
2110      char *sep;
2111 {
2112   register WORD_LIST *t;
2113   char *result, *r;
2114   int word_len, sep_len, result_size;
2115
2116   if (list == 0)
2117     return ((char *)NULL);
2118
2119   /* Short-circuit quickly if we don't need to separate anything. */
2120   if (list->next == 0)
2121     return (savestring (list->word->word));
2122
2123   /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
2124   sep_len = STRLEN (sep);
2125   result_size = 0;
2126
2127   for (t = list; t; t = t->next)
2128     {
2129       if (t != list)
2130         result_size += sep_len;
2131       result_size += strlen (t->word->word);
2132     }
2133
2134   r = result = (char *)xmalloc (result_size + 1);
2135
2136   for (t = list; t; t = t->next)
2137     {
2138       if (t != list && sep_len)
2139         {
2140           if (sep_len > 1)
2141             {
2142               FASTCOPY (sep, r, sep_len);
2143               r += sep_len;
2144             }
2145           else
2146             *r++ = sep[0];
2147         }
2148
2149       word_len = strlen (t->word->word);
2150       FASTCOPY (t->word->word, r, word_len);
2151       r += word_len;
2152     }
2153
2154   *r = '\0';
2155   return (result);
2156 }
2157
2158 /* Return a single string of all the words present in LIST, separating
2159    each word with a space. */
2160 char *
2161 string_list (list)
2162      WORD_LIST *list;
2163 {
2164   return (string_list_internal (list, " "));
2165 }
2166
2167 /* An external interface that can be used by the rest of the shell to
2168    obtain a string containing the first character in $IFS.  Handles all
2169    the multibyte complications.  If LENP is non-null, it is set to the
2170    length of the returned string. */
2171 char *
2172 ifs_firstchar (lenp)
2173      int *lenp;
2174 {
2175   char *ret;
2176   int len;
2177
2178   ret = xmalloc (MB_LEN_MAX + 1);
2179 #if defined (HANDLE_MULTIBYTE)
2180   if (ifs_firstc_len == 1)
2181     {
2182       ret[0] = ifs_firstc[0];
2183       ret[1] = '\0';
2184       len = ret[0] ? 1 : 0;
2185     }
2186   else
2187     {
2188       memcpy (ret, ifs_firstc, ifs_firstc_len);
2189       ret[len = ifs_firstc_len] = '\0';
2190     }
2191 #else
2192   ret[0] = ifs_firstc;
2193   ret[1] = '\0';
2194   len = ret[0] ? 0 : 1;
2195 #endif
2196
2197   if (lenp)
2198     *lenp = len;
2199
2200   return ret;
2201 }
2202
2203 /* Return a single string of all the words present in LIST, obeying the
2204    quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
2205    expansion [of $*] appears within a double quoted string, it expands
2206    to a single field with the value of each parameter separated by the
2207    first character of the IFS variable, or by a <space> if IFS is unset." */
2208 char *
2209 string_list_dollar_star (list)
2210      WORD_LIST *list;
2211 {
2212   char *ret;
2213 #if defined (HANDLE_MULTIBYTE)
2214 #  if defined (__GNUC__)
2215   char sep[MB_CUR_MAX + 1];
2216 #  else
2217   char *sep = 0;
2218 #  endif
2219 #else
2220   char sep[2];
2221 #endif
2222
2223 #if defined (HANDLE_MULTIBYTE)
2224 #  if !defined (__GNUC__)
2225   sep = (char *)xmalloc (MB_CUR_MAX + 1);
2226 #  endif /* !__GNUC__ */
2227   if (ifs_firstc_len == 1)
2228     {
2229       sep[0] = ifs_firstc[0];
2230       sep[1] = '\0';
2231     }
2232   else
2233     {
2234       memcpy (sep, ifs_firstc, ifs_firstc_len);
2235       sep[ifs_firstc_len] = '\0';
2236     }
2237 #else
2238   sep[0] = ifs_firstc;
2239   sep[1] = '\0';
2240 #endif
2241
2242   ret = string_list_internal (list, sep);
2243 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2244   free (sep);
2245 #endif
2246   return ret;
2247 }
2248
2249 /* Turn $@ into a string.  If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
2250    is non-zero, the $@ appears within double quotes, and we should quote
2251    the list before converting it into a string.  If IFS is unset, and the
2252    word is not quoted, we just need to quote CTLESC and CTLNUL characters
2253    in the words in the list, because the default value of $IFS is
2254    <space><tab><newline>, IFS characters in the words in the list should
2255    also be split.  If IFS is null, and the word is not quoted, we need
2256    to quote the words in the list to preserve the positional parameters
2257    exactly. */
2258 char *
2259 string_list_dollar_at (list, quoted)
2260      WORD_LIST *list;
2261      int quoted;
2262 {
2263   char *ifs, *ret;
2264 #if defined (HANDLE_MULTIBYTE)
2265 #  if defined (__GNUC__)
2266   char sep[MB_CUR_MAX + 1];
2267 #  else
2268   char *sep = 0;
2269 #  endif /* !__GNUC__ */
2270 #else
2271   char sep[2];
2272 #endif
2273   WORD_LIST *tlist;
2274
2275   /* XXX this could just be ifs = ifs_value; */
2276   ifs = ifs_var ? value_cell (ifs_var) : (char *)0;
2277
2278 #if defined (HANDLE_MULTIBYTE)
2279 #  if !defined (__GNUC__)
2280   sep = (char *)xmalloc (MB_CUR_MAX + 1);
2281 #  endif /* !__GNUC__ */
2282   if (ifs && *ifs)
2283     {
2284       if (ifs_firstc_len == 1)
2285         {
2286           sep[0] = ifs_firstc[0];
2287           sep[1] = '\0';
2288         }
2289       else
2290         {
2291           memcpy (sep, ifs_firstc, ifs_firstc_len);
2292           sep[ifs_firstc_len] = '\0';
2293         }
2294     }
2295   else
2296     {
2297       sep[0] = ' ';
2298       sep[1] = '\0';
2299     }
2300 #else
2301   sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs;
2302   sep[1] = '\0';
2303 #endif
2304
2305   /* XXX -- why call quote_list if ifs == 0?  we can get away without doing
2306      it now that quote_escapes quotes spaces */
2307   tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
2308                 ? quote_list (list)
2309                 : list_quote_escapes (list);
2310
2311   ret = string_list_internal (tlist, sep);
2312 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2313   free (sep);
2314 #endif
2315   return ret;
2316 }
2317
2318 /* Turn the positional paramters into a string, understanding quoting and
2319    the various subtleties of using the first character of $IFS as the
2320    separator.  Calls string_list_dollar_at, string_list_dollar_star, and
2321    string_list as appropriate. */
2322 char *
2323 string_list_pos_params (pchar, list, quoted)
2324      int pchar;
2325      WORD_LIST *list;
2326      int quoted;
2327 {
2328   char *ret;
2329   WORD_LIST *tlist;
2330
2331   if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
2332     {
2333       tlist = quote_list (list);
2334       word_list_remove_quoted_nulls (tlist);
2335       ret = string_list_dollar_star (tlist);
2336     }
2337   else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
2338     {
2339       tlist = quote_list (list);
2340       word_list_remove_quoted_nulls (tlist);
2341       ret = string_list (tlist);
2342     }
2343   else if (pchar == '*')
2344     {
2345       /* Even when unquoted, string_list_dollar_star does the right thing
2346          making sure that the first character of $IFS is used as the
2347          separator. */
2348       ret = string_list_dollar_star (list);
2349     }
2350   else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
2351     /* We use string_list_dollar_at, but only if the string is quoted, since
2352        that quotes the escapes if it's not, which we don't want.  We could
2353        use string_list (the old code did), but that doesn't do the right
2354        thing if the first character of $IFS is not a space.  We use
2355        string_list_dollar_star if the string is unquoted so we make sure that
2356        the elements of $@ are separated by the first character of $IFS for
2357        later splitting. */
2358     ret = string_list_dollar_at (list, quoted);
2359   else if (pchar == '@')
2360     ret = string_list_dollar_star (list);
2361   else
2362     ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
2363
2364   return ret;
2365 }
2366
2367 /* Return the list of words present in STRING.  Separate the string into
2368    words at any of the characters found in SEPARATORS.  If QUOTED is
2369    non-zero then word in the list will have its quoted flag set, otherwise
2370    the quoted flag is left as make_word () deemed fit.
2371
2372    This obeys the P1003.2 word splitting semantics.  If `separators' is
2373    exactly <space><tab><newline>, then the splitting algorithm is that of
2374    the Bourne shell, which treats any sequence of characters from `separators'
2375    as a delimiter.  If IFS is unset, which results in `separators' being set
2376    to "", no splitting occurs.  If separators has some other value, the
2377    following rules are applied (`IFS white space' means zero or more
2378    occurrences of <space>, <tab>, or <newline>, as long as those characters
2379    are in `separators'):
2380
2381         1) IFS white space is ignored at the start and the end of the
2382            string.
2383         2) Each occurrence of a character in `separators' that is not
2384            IFS white space, along with any adjacent occurrences of
2385            IFS white space delimits a field.
2386         3) Any nonzero-length sequence of IFS white space delimits a field.
2387    */
2388
2389 /* BEWARE!  list_string strips null arguments.  Don't call it twice and
2390    expect to have "" preserved! */
2391
2392 /* This performs word splitting and quoted null character removal on
2393    STRING. */
2394 #define issep(c) \
2395         (((separators)[0]) ? ((separators)[1] ? isifs(c) \
2396                                               : (c) == (separators)[0]) \
2397                            : 0)
2398
2399 WORD_LIST *
2400 list_string (string, separators, quoted)
2401      register char *string, *separators;
2402      int quoted;
2403 {
2404   WORD_LIST *result;
2405   WORD_DESC *t;
2406   char *current_word, *s;
2407   int sindex, sh_style_split, whitesep, xflags;
2408   size_t slen;
2409
2410   if (!string || !*string)
2411     return ((WORD_LIST *)NULL);
2412
2413   sh_style_split = separators && separators[0] == ' ' &&
2414                                  separators[1] == '\t' &&
2415                                  separators[2] == '\n' &&
2416                                  separators[3] == '\0';
2417   for (xflags = 0, s = ifs_value; s && *s; s++)
2418     {
2419       if (*s == CTLESC) xflags |= SX_NOCTLESC;
2420       else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
2421     }
2422
2423   slen = 0;
2424   /* Remove sequences of whitespace at the beginning of STRING, as
2425      long as those characters appear in IFS.  Do not do this if
2426      STRING is quoted or if there are no separator characters. */
2427   if (!quoted || !separators || !*separators)
2428     {
2429       for (s = string; *s && spctabnl (*s) && issep (*s); s++);
2430
2431       if (!*s)
2432         return ((WORD_LIST *)NULL);
2433
2434       string = s;
2435     }
2436
2437   /* OK, now STRING points to a word that does not begin with white space.
2438      The splitting algorithm is:
2439         extract a word, stopping at a separator
2440         skip sequences of spc, tab, or nl as long as they are separators
2441      This obeys the field splitting rules in Posix.2. */
2442   slen = (MB_CUR_MAX > 1) ? strlen (string) : 1;
2443   for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
2444     {
2445       /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
2446          unless multibyte chars are possible. */
2447       current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
2448       if (current_word == 0)
2449         break;
2450
2451       /* If we have a quoted empty string, add a quoted null argument.  We
2452          want to preserve the quoted null character iff this is a quoted
2453          empty string; otherwise the quoted null characters are removed
2454          below. */
2455       if (QUOTED_NULL (current_word))
2456         {
2457           t = alloc_word_desc ();
2458           t->word = make_quoted_char ('\0');
2459           t->flags |= W_QUOTED|W_HASQUOTEDNULL;
2460           result = make_word_list (t, result);
2461         }
2462       else if (current_word[0] != '\0')
2463         {
2464           /* If we have something, then add it regardless.  However,
2465              perform quoted null character removal on the current word. */
2466           remove_quoted_nulls (current_word);
2467           result = add_string_to_list (current_word, result);
2468           result->word->flags &= ~W_HASQUOTEDNULL;      /* just to be sure */
2469           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
2470             result->word->flags |= W_QUOTED;
2471         }
2472
2473       /* If we're not doing sequences of separators in the traditional
2474          Bourne shell style, then add a quoted null argument. */
2475       else if (!sh_style_split && !spctabnl (string[sindex]))
2476         {
2477           t = alloc_word_desc ();
2478           t->word = make_quoted_char ('\0');
2479           t->flags |= W_QUOTED|W_HASQUOTEDNULL;
2480           result = make_word_list (t, result);
2481         }
2482
2483       free (current_word);
2484
2485       /* Note whether or not the separator is IFS whitespace, used later. */
2486       whitesep = string[sindex] && spctabnl (string[sindex]);
2487
2488       /* Move past the current separator character. */
2489       if (string[sindex])
2490         {
2491           DECLARE_MBSTATE;
2492           ADVANCE_CHAR (string, slen, sindex);
2493         }
2494
2495       /* Now skip sequences of space, tab, or newline characters if they are
2496          in the list of separators. */
2497       while (string[sindex] && spctabnl (string[sindex]) && issep (string[sindex]))
2498         sindex++;
2499
2500       /* If the first separator was IFS whitespace and the current character
2501          is a non-whitespace IFS character, it should be part of the current
2502          field delimiter, not a separate delimiter that would result in an
2503          empty field.  Look at POSIX.2, 3.6.5, (3)(b). */
2504       if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (string[sindex]))
2505         {
2506           sindex++;
2507           /* An IFS character that is not IFS white space, along with any
2508              adjacent IFS white space, shall delimit a field. (SUSv3) */
2509           while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex]))
2510             sindex++;
2511         }
2512     }
2513   return (REVERSE_LIST (result, WORD_LIST *));
2514 }
2515
2516 /* Parse a single word from STRING, using SEPARATORS to separate fields.
2517    ENDPTR is set to the first character after the word.  This is used by
2518    the `read' builtin.  This is never called with SEPARATORS != $IFS;
2519    it should be simplified.
2520
2521    XXX - this function is very similar to list_string; they should be
2522          combined - XXX */
2523 char *
2524 get_word_from_string (stringp, separators, endptr)
2525      char **stringp, *separators, **endptr;
2526 {
2527   register char *s;
2528   char *current_word;
2529   int sindex, sh_style_split, whitesep, xflags;
2530   size_t slen;
2531
2532   if (!stringp || !*stringp || !**stringp)
2533     return ((char *)NULL);
2534
2535   sh_style_split = separators && separators[0] == ' ' &&
2536                                  separators[1] == '\t' &&
2537                                  separators[2] == '\n' &&
2538                                  separators[3] == '\0';
2539   for (xflags = 0, s = ifs_value; s && *s; s++)
2540     {
2541       if (*s == CTLESC) xflags |= SX_NOCTLESC;
2542       if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
2543     }
2544
2545   s = *stringp;
2546   slen = 0;
2547
2548   /* Remove sequences of whitespace at the beginning of STRING, as
2549      long as those characters appear in IFS. */
2550   if (sh_style_split || !separators || !*separators)
2551     {
2552       for (; *s && spctabnl (*s) && isifs (*s); s++);
2553
2554       /* If the string is nothing but whitespace, update it and return. */
2555       if (!*s)
2556         {
2557           *stringp = s;
2558           if (endptr)
2559             *endptr = s;
2560           return ((char *)NULL);
2561         }
2562     }
2563
2564   /* OK, S points to a word that does not begin with white space.
2565      Now extract a word, stopping at a separator, save a pointer to
2566      the first character after the word, then skip sequences of spc,
2567      tab, or nl as long as they are separators.
2568
2569      This obeys the field splitting rules in Posix.2. */
2570   sindex = 0;
2571   /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
2572      unless multibyte chars are possible. */
2573   slen = (MB_CUR_MAX > 1) ? strlen (s) : 1;
2574   current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
2575
2576   /* Set ENDPTR to the first character after the end of the word. */
2577   if (endptr)
2578     *endptr = s + sindex;
2579
2580   /* Note whether or not the separator is IFS whitespace, used later. */
2581   whitesep = s[sindex] && spctabnl (s[sindex]);
2582
2583   /* Move past the current separator character. */
2584   if (s[sindex])
2585     {
2586       DECLARE_MBSTATE;
2587       ADVANCE_CHAR (s, slen, sindex);
2588     }
2589
2590   /* Now skip sequences of space, tab, or newline characters if they are
2591      in the list of separators. */
2592   while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
2593     sindex++;
2594
2595   /* If the first separator was IFS whitespace and the current character is
2596      a non-whitespace IFS character, it should be part of the current field
2597      delimiter, not a separate delimiter that would result in an empty field.
2598      Look at POSIX.2, 3.6.5, (3)(b). */
2599   if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (s[sindex]))
2600     {
2601       sindex++;
2602       /* An IFS character that is not IFS white space, along with any adjacent
2603          IFS white space, shall delimit a field. */
2604       while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
2605         sindex++;
2606     }
2607
2608   /* Update STRING to point to the next field. */
2609   *stringp = s + sindex;
2610   return (current_word);
2611 }
2612
2613 /* Remove IFS white space at the end of STRING.  Start at the end
2614    of the string and walk backwards until the beginning of the string
2615    or we find a character that's not IFS white space and not CTLESC.
2616    Only let CTLESC escape a white space character if SAW_ESCAPE is
2617    non-zero.  */
2618 char *
2619 strip_trailing_ifs_whitespace (string, separators, saw_escape)
2620      char *string, *separators;
2621      int saw_escape;
2622 {
2623   char *s;
2624
2625   s = string + STRLEN (string) - 1;
2626   while (s > string && ((spctabnl (*s) && isifs (*s)) ||
2627                         (saw_escape && *s == CTLESC && spctabnl (s[1]))))
2628     s--;
2629   *++s = '\0';
2630   return string;
2631 }
2632
2633 #if 0
2634 /* UNUSED */
2635 /* Split STRING into words at whitespace.  Obeys shell-style quoting with
2636    backslashes, single and double quotes. */
2637 WORD_LIST *
2638 list_string_with_quotes (string)
2639      char *string;
2640 {
2641   WORD_LIST *list;
2642   char *token, *s;
2643   size_t s_len;
2644   int c, i, tokstart, len;
2645
2646   for (s = string; s && *s && spctabnl (*s); s++)
2647     ;
2648   if (s == 0 || *s == 0)
2649     return ((WORD_LIST *)NULL);
2650
2651   s_len = strlen (s);
2652   tokstart = i = 0;
2653   list = (WORD_LIST *)NULL;
2654   while (1)
2655     {
2656       c = s[i];
2657       if (c == '\\')
2658         {
2659           i++;
2660           if (s[i])
2661             i++;
2662         }
2663       else if (c == '\'')
2664         i = skip_single_quoted (s, s_len, ++i);
2665       else if (c == '"')
2666         i = skip_double_quoted (s, s_len, ++i);
2667       else if (c == 0 || spctabnl (c))
2668         {
2669           /* We have found the end of a token.  Make a word out of it and
2670              add it to the word list. */
2671           token = substring (s, tokstart, i);
2672           list = add_string_to_list (token, list);
2673           free (token);
2674           while (spctabnl (s[i]))
2675             i++;
2676           if (s[i])
2677             tokstart = i;
2678           else
2679             break;
2680         }
2681       else
2682         i++;    /* normal character */
2683     }
2684   return (REVERSE_LIST (list, WORD_LIST *));
2685 }
2686 #endif
2687
2688 /********************************************************/
2689 /*                                                      */
2690 /*      Functions to perform assignment statements      */
2691 /*                                                      */
2692 /********************************************************/
2693
2694 #if defined (ARRAY_VARS)
2695 static SHELL_VAR *
2696 do_compound_assignment (name, value, flags)
2697      char *name, *value;
2698      int flags;
2699 {
2700   SHELL_VAR *v;
2701   int mklocal, mkassoc;
2702   WORD_LIST *list;
2703
2704   mklocal = flags & ASS_MKLOCAL;
2705   mkassoc = flags & ASS_MKASSOC;
2706
2707   if (mklocal && variable_context)
2708     {
2709       v = find_variable (name);
2710       list = expand_compound_array_assignment (v, value, flags);
2711       if (mkassoc)
2712         v = make_local_assoc_variable (name);
2713       else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context)
2714         v = make_local_array_variable (name);
2715       assign_compound_array_list (v, list, flags);
2716     }
2717   else
2718     v = assign_array_from_string (name, value, flags);
2719
2720   return (v);
2721 }
2722 #endif
2723
2724 /* Given STRING, an assignment string, get the value of the right side
2725    of the `=', and bind it to the left side.  If EXPAND is true, then
2726    perform parameter expansion, command substitution, and arithmetic
2727    expansion on the right-hand side.  Perform tilde expansion in any
2728    case.  Do not perform word splitting on the result of expansion. */
2729 static int
2730 do_assignment_internal (word, expand)
2731      const WORD_DESC *word;
2732      int expand;
2733 {
2734   int offset, appendop, assign_list, aflags, retval;
2735   char *name, *value, *temp;
2736   SHELL_VAR *entry;
2737 #if defined (ARRAY_VARS)
2738   char *t;
2739   int ni;
2740 #endif
2741   const char *string;
2742
2743   if (word == 0 || word->word == 0)
2744     return 0;
2745
2746   appendop = assign_list = aflags = 0;
2747   string = word->word;
2748   offset = assignment (string, 0);
2749   name = savestring (string);
2750   value = (char *)NULL;
2751
2752   if (name[offset] == '=')
2753     {
2754       if (name[offset - 1] == '+')
2755         {
2756           appendop = 1;
2757           name[offset - 1] = '\0';
2758         }
2759
2760       name[offset] = 0;         /* might need this set later */
2761       temp = name + offset + 1;
2762
2763 #if defined (ARRAY_VARS)
2764       if (expand && (word->flags & W_COMPASSIGN))
2765         {
2766           assign_list = ni = 1;
2767           value = extract_array_assignment_list (temp, &ni);
2768         }
2769       else
2770 #endif
2771       if (expand && temp[0])
2772         value = expand_string_if_necessary (temp, 0, expand_string_assignment);
2773       else
2774         value = savestring (temp);
2775     }
2776
2777   if (value == 0)
2778     {
2779       value = (char *)xmalloc (1);
2780       value[0] = '\0';
2781     }
2782
2783   if (echo_command_at_execute)
2784     {
2785       if (appendop)
2786         name[offset - 1] = '+';
2787       xtrace_print_assignment (name, value, assign_list, 1);
2788       if (appendop)
2789         name[offset - 1] = '\0';
2790     }
2791
2792 #define ASSIGN_RETURN(r)        do { FREE (value); free (name); return (r); } while (0)
2793
2794   if (appendop)
2795     aflags |= ASS_APPEND;
2796
2797 #if defined (ARRAY_VARS)
2798   if (t = mbschr (name, '['))   /*]*/
2799     {
2800       if (assign_list)
2801         {
2802           report_error (_("%s: cannot assign list to array member"), name);
2803           ASSIGN_RETURN (0);
2804         }
2805       entry = assign_array_element (name, value, aflags);
2806       if (entry == 0)
2807         ASSIGN_RETURN (0);
2808     }
2809   else if (assign_list)
2810     {
2811       if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0)
2812         aflags |= ASS_MKLOCAL;
2813       if (word->flags & W_ASSIGNASSOC)
2814         aflags |= ASS_MKASSOC;
2815       entry = do_compound_assignment (name, value, aflags);
2816     }
2817   else
2818 #endif /* ARRAY_VARS */
2819   entry = bind_variable (name, value, aflags);
2820
2821   stupidly_hack_special_variables (name);
2822
2823 #if 1
2824   /* Return 1 if the assignment seems to have been performed correctly. */
2825   if (entry == 0 || readonly_p (entry))
2826     retval = 0;         /* assignment failure */
2827   else if (noassign_p (entry))
2828     {
2829       last_command_exit_value = EXECUTION_FAILURE;
2830       retval = 1;       /* error status, but not assignment failure */
2831     }
2832   else
2833     retval = 1;
2834
2835   if (entry && retval != 0 && noassign_p (entry) == 0)
2836     VUNSETATTR (entry, att_invisible);
2837
2838   ASSIGN_RETURN (retval);
2839 #else
2840   if (entry)
2841     VUNSETATTR (entry, att_invisible);
2842
2843   ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0);
2844 #endif
2845 }
2846
2847 /* Perform the assignment statement in STRING, and expand the
2848    right side by doing tilde, command and parameter expansion. */
2849 int
2850 do_assignment (string)
2851      char *string;
2852 {
2853   WORD_DESC td;
2854
2855   td.flags = W_ASSIGNMENT;
2856   td.word = string;
2857
2858   return do_assignment_internal (&td, 1);
2859 }
2860
2861 int
2862 do_word_assignment (word, flags)
2863      WORD_DESC *word;
2864      int flags;
2865 {
2866   return do_assignment_internal (word, 1);
2867 }
2868
2869 /* Given STRING, an assignment string, get the value of the right side
2870    of the `=', and bind it to the left side.  Do not perform any word
2871    expansions on the right hand side. */
2872 int
2873 do_assignment_no_expand (string)
2874      char *string;
2875 {
2876   WORD_DESC td;
2877
2878   td.flags = W_ASSIGNMENT;
2879   td.word = string;
2880
2881   return (do_assignment_internal (&td, 0));
2882 }
2883
2884 /***************************************************
2885  *                                                 *
2886  *  Functions to manage the positional parameters  *
2887  *                                                 *
2888  ***************************************************/
2889
2890 /* Return the word list that corresponds to `$*'. */
2891 WORD_LIST *
2892 list_rest_of_args ()
2893 {
2894   register WORD_LIST *list, *args;
2895   int i;
2896
2897   /* Break out of the loop as soon as one of the dollar variables is null. */
2898   for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
2899     list = make_word_list (make_bare_word (dollar_vars[i]), list);
2900
2901   for (args = rest_of_args; args; args = args->next)
2902     list = make_word_list (make_bare_word (args->word->word), list);
2903
2904   return (REVERSE_LIST (list, WORD_LIST *));
2905 }
2906
2907 int
2908 number_of_args ()
2909 {
2910   register WORD_LIST *list;
2911   int n;
2912
2913   for (n = 0; n < 9 && dollar_vars[n+1]; n++)
2914     ;
2915   for (list = rest_of_args; list; list = list->next)
2916     n++;
2917   return n;
2918 }
2919
2920 /* Return the value of a positional parameter.  This handles values > 10. */
2921 char *
2922 get_dollar_var_value (ind)
2923      intmax_t ind;
2924 {
2925   char *temp;
2926   WORD_LIST *p;
2927
2928   if (ind < 10)
2929     temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
2930   else  /* We want something like ${11} */
2931     {
2932       ind -= 10;
2933       for (p = rest_of_args; p && ind--; p = p->next)
2934         ;
2935       temp = p ? savestring (p->word->word) : (char *)NULL;
2936     }
2937   return (temp);
2938 }
2939
2940 /* Make a single large string out of the dollar digit variables,
2941    and the rest_of_args.  If DOLLAR_STAR is 1, then obey the special
2942    case of "$*" with respect to IFS. */
2943 char *
2944 string_rest_of_args (dollar_star)
2945      int dollar_star;
2946 {
2947   register WORD_LIST *list;
2948   char *string;
2949
2950   list = list_rest_of_args ();
2951   string = dollar_star ? string_list_dollar_star (list) : string_list (list);
2952   dispose_words (list);
2953   return (string);
2954 }
2955
2956 /* Return a string containing the positional parameters from START to
2957    END, inclusive.  If STRING[0] == '*', we obey the rules for $*,
2958    which only makes a difference if QUOTED is non-zero.  If QUOTED includes
2959    Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise
2960    no quoting chars are added. */
2961 static char *
2962 pos_params (string, start, end, quoted)
2963      char *string;
2964      int start, end, quoted;
2965 {
2966   WORD_LIST *save, *params, *h, *t;
2967   char *ret;
2968   int i;
2969
2970   /* see if we can short-circuit.  if start == end, we want 0 parameters. */
2971   if (start == end)
2972     return ((char *)NULL);
2973
2974   save = params = list_rest_of_args ();
2975   if (save == 0)
2976     return ((char *)NULL);
2977
2978   if (start == 0)               /* handle ${@:0[:x]} specially */
2979     {
2980       t = make_word_list (make_word (dollar_vars[0]), params);
2981       save = params = t;
2982     }
2983
2984   for (i = start ? 1 : 0; params && i < start; i++)
2985     params = params->next;
2986   if (params == 0)
2987     return ((char *)NULL);
2988   for (h = t = params; params && i < end; i++)
2989     {
2990       t = params;
2991       params = params->next;
2992     }
2993
2994   t->next = (WORD_LIST *)NULL;
2995
2996   ret = string_list_pos_params (string[0], h, quoted);
2997
2998   if (t != params)
2999     t->next = params;
3000
3001   dispose_words (save);
3002   return (ret);
3003 }
3004
3005 /******************************************************************/
3006 /*                                                                */
3007 /*      Functions to expand strings to strings or WORD_LISTs      */
3008 /*                                                                */
3009 /******************************************************************/
3010
3011 #if defined (PROCESS_SUBSTITUTION)
3012 #define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~')
3013 #else
3014 #define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
3015 #endif
3016
3017 /* If there are any characters in STRING that require full expansion,
3018    then call FUNC to expand STRING; otherwise just perform quote
3019    removal if necessary.  This returns a new string. */
3020 static char *
3021 expand_string_if_necessary (string, quoted, func)
3022      char *string;
3023      int quoted;
3024      EXPFUNC *func;
3025 {
3026   WORD_LIST *list;
3027   size_t slen;
3028   int i, saw_quote;
3029   char *ret;
3030   DECLARE_MBSTATE;
3031
3032   /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3033   slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
3034   i = saw_quote = 0;
3035   while (string[i])
3036     {
3037       if (EXP_CHAR (string[i]))
3038         break;
3039       else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3040         saw_quote = 1;
3041       ADVANCE_CHAR (string, slen, i);
3042     }
3043
3044   if (string[i])
3045     {
3046       list = (*func) (string, quoted);
3047       if (list)
3048         {
3049           ret = string_list (list);
3050           dispose_words (list);
3051         }
3052       else
3053         ret = (char *)NULL;
3054     }
3055   else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3056     ret = string_quote_removal (string, quoted);
3057   else
3058     ret = savestring (string);
3059
3060   return ret;
3061 }
3062
3063 static inline char *
3064 expand_string_to_string_internal (string, quoted, func)
3065      char *string;
3066      int quoted;
3067      EXPFUNC *func;
3068 {
3069   WORD_LIST *list;
3070   char *ret;
3071
3072   if (string == 0 || *string == '\0')
3073     return ((char *)NULL);
3074
3075   list = (*func) (string, quoted);
3076   if (list)
3077     {
3078       ret = string_list (list);
3079       dispose_words (list);
3080     }
3081   else
3082     ret = (char *)NULL;
3083
3084   return (ret);
3085 }
3086
3087 char *
3088 expand_string_to_string (string, quoted)
3089      char *string;
3090      int quoted;
3091 {
3092   return (expand_string_to_string_internal (string, quoted, expand_string));
3093 }
3094
3095 char *
3096 expand_string_unsplit_to_string (string, quoted)
3097      char *string;
3098      int quoted;
3099 {
3100   return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
3101 }
3102
3103 char *
3104 expand_assignment_string_to_string (string, quoted)
3105      char *string;
3106      int quoted;
3107 {
3108   return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
3109 }
3110
3111 char *
3112 expand_arith_string (string, quoted)
3113      char *string;
3114      int quoted;
3115 {
3116   return (expand_string_if_necessary (string, quoted, expand_string));
3117 }
3118
3119 #if defined (COND_COMMAND)
3120 /* Just remove backslashes in STRING.  Returns a new string. */
3121 char *
3122 remove_backslashes (string)
3123      char *string;
3124 {
3125   char *r, *ret, *s;
3126
3127   r = ret = (char *)xmalloc (strlen (string) + 1);
3128   for (s = string; s && *s; )
3129     {
3130       if (*s == '\\')
3131         s++;
3132       if (*s == 0)
3133         break;
3134       *r++ = *s++;
3135     }
3136   *r = '\0';
3137   return ret;
3138 }
3139
3140 /* This needs better error handling. */
3141 /* Expand W for use as an argument to a unary or binary operator in a
3142    [[...]] expression.  If SPECIAL is 1, this is the rhs argument
3143    to the != or == operator, and should be treated as a pattern.  In
3144    this case, we quote the string specially for the globbing code.  If
3145    SPECIAL is 2, this is an rhs argument for the =~ operator, and should
3146    be quoted appropriately for regcomp/regexec.  The caller is responsible
3147    for removing the backslashes if the unquoted word is needed later. */   
3148 char *
3149 cond_expand_word (w, special)
3150      WORD_DESC *w;
3151      int special;
3152 {
3153   char *r, *p;
3154   WORD_LIST *l;
3155   int qflags;
3156
3157   if (w->word == 0 || w->word[0] == '\0')
3158     return ((char *)NULL);
3159
3160   w->flags |= W_NOSPLIT2;
3161   l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
3162   if (l)
3163     {
3164       if (special == 0)
3165         {
3166           dequote_list (l);
3167           r = string_list (l);
3168         }
3169       else
3170         {
3171           qflags = QGLOB_CVTNULL;
3172           if (special == 2)
3173             qflags |= QGLOB_REGEXP;
3174           p = string_list (l);
3175           r = quote_string_for_globbing (p, qflags);
3176           free (p);
3177         }
3178       dispose_words (l);
3179     }
3180   else
3181     r = (char *)NULL;
3182
3183   return r;
3184 }
3185 #endif
3186
3187 /* Call expand_word_internal to expand W and handle error returns.
3188    A convenience function for functions that don't want to handle
3189    any errors or free any memory before aborting. */
3190 static WORD_LIST *
3191 call_expand_word_internal (w, q, i, c, e)
3192      WORD_DESC *w;
3193      int q, i, *c, *e;
3194 {
3195   WORD_LIST *result;
3196
3197   result = expand_word_internal (w, q, i, c, e);
3198   if (result == &expand_word_error || result == &expand_word_fatal)
3199     {
3200       /* By convention, each time this error is returned, w->word has
3201          already been freed (it sometimes may not be in the fatal case,
3202          but that doesn't result in a memory leak because we're going
3203          to exit in most cases). */
3204       w->word = (char *)NULL;
3205       last_command_exit_value = EXECUTION_FAILURE;
3206       exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
3207       /* NOTREACHED */
3208     }
3209   else
3210     return (result);
3211 }
3212
3213 /* Perform parameter expansion, command substitution, and arithmetic
3214    expansion on STRING, as if it were a word.  Leave the result quoted. */
3215 static WORD_LIST *
3216 expand_string_internal (string, quoted)
3217      char *string;
3218      int quoted;
3219 {
3220   WORD_DESC td;
3221   WORD_LIST *tresult;
3222
3223   if (string == 0 || *string == 0)
3224     return ((WORD_LIST *)NULL);
3225
3226   td.flags = 0;
3227   td.word = savestring (string);
3228
3229   tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3230
3231   FREE (td.word);
3232   return (tresult);
3233 }
3234
3235 /* Expand STRING by performing parameter expansion, command substitution,
3236    and arithmetic expansion.  Dequote the resulting WORD_LIST before
3237    returning it, but do not perform word splitting.  The call to
3238    remove_quoted_nulls () is in here because word splitting normally
3239    takes care of quote removal. */
3240 WORD_LIST *
3241 expand_string_unsplit (string, quoted)
3242      char *string;
3243      int quoted;
3244 {
3245   WORD_LIST *value;
3246
3247   if (string == 0 || *string == '\0')
3248     return ((WORD_LIST *)NULL);
3249
3250   expand_no_split_dollar_star = 1;
3251   value = expand_string_internal (string, quoted);
3252   expand_no_split_dollar_star = 0;
3253
3254   if (value)
3255     {
3256       if (value->word)
3257         {
3258           remove_quoted_nulls (value->word->word);
3259           value->word->flags &= ~W_HASQUOTEDNULL;
3260         }
3261       dequote_list (value);
3262     }
3263   return (value);
3264 }
3265
3266 /* Expand the rhs of an assignment statement */
3267 WORD_LIST *
3268 expand_string_assignment (string, quoted)
3269      char *string;
3270      int quoted;
3271 {
3272   WORD_DESC td;
3273   WORD_LIST *value;
3274
3275   if (string == 0 || *string == '\0')
3276     return ((WORD_LIST *)NULL);
3277
3278   expand_no_split_dollar_star = 1;
3279
3280   td.flags = W_ASSIGNRHS;
3281   td.word = savestring (string);
3282   value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3283   FREE (td.word);
3284
3285   expand_no_split_dollar_star = 0;
3286
3287   if (value)
3288     {
3289       if (value->word)
3290         {
3291           remove_quoted_nulls (value->word->word);
3292           value->word->flags &= ~W_HASQUOTEDNULL;
3293         }
3294       dequote_list (value);
3295     }
3296   return (value);
3297 }
3298
3299
3300 /* Expand one of the PS? prompt strings. This is a sort of combination of
3301    expand_string_unsplit and expand_string_internal, but returns the
3302    passed string when an error occurs.  Might want to trap other calls
3303    to jump_to_top_level here so we don't endlessly loop. */
3304 WORD_LIST *
3305 expand_prompt_string (string, quoted, wflags)
3306      char *string;
3307      int quoted;
3308      int wflags;
3309 {
3310   WORD_LIST *value;
3311   WORD_DESC td;
3312
3313   if (string == 0 || *string == 0)
3314     return ((WORD_LIST *)NULL);
3315
3316   td.flags = wflags;
3317   td.word = savestring (string);
3318
3319   no_longjmp_on_fatal_error = 1;
3320   value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3321   no_longjmp_on_fatal_error = 0;
3322
3323   if (value == &expand_word_error || value == &expand_word_fatal)
3324     {
3325       value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
3326       return value;
3327     }
3328   FREE (td.word);
3329   if (value)
3330     {
3331       if (value->word)
3332         {
3333           remove_quoted_nulls (value->word->word);
3334           value->word->flags &= ~W_HASQUOTEDNULL;
3335         }
3336       dequote_list (value);
3337     }
3338   return (value);
3339 }
3340
3341 /* Expand STRING just as if you were expanding a word, but do not dequote
3342    the resultant WORD_LIST.  This is called only from within this file,
3343    and is used to correctly preserve quoted characters when expanding
3344    things like ${1+"$@"}.  This does parameter expansion, command
3345    substitution, arithmetic expansion, and word splitting. */
3346 static WORD_LIST *
3347 expand_string_leave_quoted (string, quoted)
3348      char *string;
3349      int quoted;
3350 {
3351   WORD_LIST *tlist;
3352   WORD_LIST *tresult;
3353
3354   if (string == 0 || *string == '\0')
3355     return ((WORD_LIST *)NULL);
3356
3357   tlist = expand_string_internal (string, quoted);
3358
3359   if (tlist)
3360     {
3361       tresult = word_list_split (tlist);
3362       dispose_words (tlist);
3363       return (tresult);
3364     }
3365   return ((WORD_LIST *)NULL);
3366 }
3367
3368 /* This does not perform word splitting or dequote the WORD_LIST
3369    it returns. */
3370 static WORD_LIST *
3371 expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at)
3372      char *string;
3373      int quoted, *dollar_at_p, *has_dollar_at;
3374 {
3375   WORD_DESC td;
3376   WORD_LIST *tresult;
3377
3378   if (string == 0 || *string == '\0')
3379     return (WORD_LIST *)NULL;
3380
3381   td.flags = W_NOSPLIT2;                /* no splitting, remove "" and '' */
3382   td.word = string;
3383   tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at);
3384   return (tresult);
3385 }
3386
3387 /* Expand STRING just as if you were expanding a word.  This also returns
3388    a list of words.  Note that filename globbing is *NOT* done for word
3389    or string expansion, just when the shell is expanding a command.  This
3390    does parameter expansion, command substitution, arithmetic expansion,
3391    and word splitting.  Dequote the resultant WORD_LIST before returning. */
3392 WORD_LIST *
3393 expand_string (string, quoted)
3394      char *string;
3395      int quoted;
3396 {
3397   WORD_LIST *result;
3398
3399   if (string == 0 || *string == '\0')
3400     return ((WORD_LIST *)NULL);
3401
3402   result = expand_string_leave_quoted (string, quoted);
3403   return (result ? dequote_list (result) : result);
3404 }
3405
3406 /***************************************************
3407  *                                                 *
3408  *      Functions to handle quoting chars          *
3409  *                                                 *
3410  ***************************************************/
3411
3412 /* Conventions:
3413
3414      A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
3415      The parser passes CTLNUL as CTLESC CTLNUL. */
3416
3417 /* Quote escape characters in string s, but no other characters.  This is
3418    used to protect CTLESC and CTLNUL in variable values from the rest of
3419    the word expansion process after the variable is expanded (word splitting
3420    and filename generation).  If IFS is null, we quote spaces as well, just
3421    in case we split on spaces later (in the case of unquoted $@, we will
3422    eventually attempt to split the entire word on spaces).  Corresponding
3423    code exists in dequote_escapes.  Even if we don't end up splitting on
3424    spaces, quoting spaces is not a problem.  This should never be called on
3425    a string that is quoted with single or double quotes or part of a here
3426    document (effectively double-quoted). */
3427 char *
3428 quote_escapes (string)
3429      char *string;
3430 {
3431   register char *s, *t;
3432   size_t slen;
3433   char *result, *send;
3434   int quote_spaces, skip_ctlesc, skip_ctlnul;
3435   DECLARE_MBSTATE; 
3436
3437   slen = strlen (string);
3438   send = string + slen;
3439
3440   quote_spaces = (ifs_value && *ifs_value == 0);
3441
3442   for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
3443     skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
3444
3445   t = result = (char *)xmalloc ((slen * 2) + 1);
3446   s = string;
3447
3448   while (*s)
3449     {
3450       if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
3451         *t++ = CTLESC;
3452       COPY_CHAR_P (t, s, send);
3453     }
3454   *t = '\0';
3455   return (result);
3456 }
3457
3458 static WORD_LIST *
3459 list_quote_escapes (list)
3460      WORD_LIST *list;
3461 {
3462   register WORD_LIST *w;
3463   char *t;
3464
3465   for (w = list; w; w = w->next)
3466     {
3467       t = w->word->word;
3468       w->word->word = quote_escapes (t);
3469       free (t);
3470     }
3471   return list;
3472 }
3473
3474 /* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
3475
3476    The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
3477    This is necessary to make unquoted CTLESC and CTLNUL characters in the
3478    data stream pass through properly.
3479
3480    We need to remove doubled CTLESC characters inside quoted strings before
3481    quoting the entire string, so we do not double the number of CTLESC
3482    characters.
3483
3484    Also used by parts of the pattern substitution code. */
3485 char *
3486 dequote_escapes (string)
3487      char *string;
3488 {
3489   register char *s, *t, *s1;
3490   size_t slen;
3491   char *result, *send;
3492   int quote_spaces;
3493   DECLARE_MBSTATE;
3494
3495   if (string == 0)
3496     return string;
3497
3498   slen = strlen (string);
3499   send = string + slen;
3500
3501   t = result = (char *)xmalloc (slen + 1);
3502
3503   if (strchr (string, CTLESC) == 0)
3504     return (strcpy (result, string));
3505
3506   quote_spaces = (ifs_value && *ifs_value == 0);
3507
3508   s = string;
3509   while (*s)
3510     {
3511       if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
3512         {
3513           s++;
3514           if (*s == '\0')
3515             break;
3516         }
3517       COPY_CHAR_P (t, s, send);
3518     }
3519   *t = '\0';
3520   return result;
3521 }
3522
3523 /* Return a new string with the quoted representation of character C.
3524    This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
3525    set in any resultant WORD_DESC where this value is the word. */
3526 static char *
3527 make_quoted_char (c)
3528      int c;
3529 {
3530   char *temp;
3531
3532   temp = (char *)xmalloc (3);
3533   if (c == 0)
3534     {
3535       temp[0] = CTLNUL;
3536       temp[1] = '\0';
3537     }
3538   else
3539     {
3540       temp[0] = CTLESC;
3541       temp[1] = c;
3542       temp[2] = '\0';
3543     }
3544   return (temp);
3545 }
3546
3547 /* Quote STRING, returning a new string.  This turns "" into QUOTED_NULL, so
3548    the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
3549    this value is the word. */
3550 char *
3551 quote_string (string)
3552      char *string;
3553 {
3554   register char *t;
3555   size_t slen;
3556   char *result, *send;
3557
3558   if (*string == 0)
3559     {
3560       result = (char *)xmalloc (2);
3561       result[0] = CTLNUL;
3562       result[1] = '\0';
3563     }
3564   else
3565     {
3566       DECLARE_MBSTATE;
3567
3568       slen = strlen (string);
3569       send = string + slen;
3570
3571       result = (char *)xmalloc ((slen * 2) + 1);
3572
3573       for (t = result; string < send; )
3574         {
3575           *t++ = CTLESC;
3576           COPY_CHAR_P (t, string, send);
3577         }
3578       *t = '\0';
3579     }
3580   return (result);
3581 }
3582
3583 /* De-quote quoted characters in STRING. */
3584 char *
3585 dequote_string (string)
3586      char *string;
3587 {
3588   register char *s, *t;
3589   size_t slen;
3590   char *result, *send;
3591   DECLARE_MBSTATE;
3592
3593   slen = strlen (string);
3594
3595   t = result = (char *)xmalloc (slen + 1);
3596
3597   if (QUOTED_NULL (string))
3598     {
3599       result[0] = '\0';
3600       return (result);
3601     }
3602
3603   /* If no character in the string can be quoted, don't bother examining
3604      each character.  Just return a copy of the string passed to us. */
3605   if (strchr (string, CTLESC) == NULL)
3606     return (strcpy (result, string));
3607
3608   send = string + slen;
3609   s = string;
3610   while (*s)
3611     {
3612       if (*s == CTLESC)
3613         {
3614           s++;
3615           if (*s == '\0')
3616             break;
3617         }
3618       COPY_CHAR_P (t, s, send);
3619     }
3620
3621   *t = '\0';
3622   return (result);
3623 }
3624
3625 /* Quote the entire WORD_LIST list. */
3626 static WORD_LIST *
3627 quote_list (list)
3628      WORD_LIST *list;
3629 {
3630   register WORD_LIST *w;
3631   char *t;
3632
3633   for (w = list; w; w = w->next)
3634     {
3635       t = w->word->word;
3636       w->word->word = quote_string (t);
3637       if (*t == 0)
3638         w->word->flags |= W_HASQUOTEDNULL;      /* XXX - turn on W_HASQUOTEDNULL here? */
3639       w->word->flags |= W_QUOTED;
3640       free (t);
3641     }
3642   return list;
3643 }
3644
3645 /* De-quote quoted characters in each word in LIST. */
3646 WORD_LIST *
3647 dequote_list (list)
3648      WORD_LIST *list;
3649 {
3650   register char *s;
3651   register WORD_LIST *tlist;
3652
3653   for (tlist = list; tlist; tlist = tlist->next)
3654     {
3655       s = dequote_string (tlist->word->word);
3656       if (QUOTED_NULL (tlist->word->word))
3657         tlist->word->flags &= ~W_HASQUOTEDNULL;
3658       free (tlist->word->word);
3659       tlist->word->word = s;
3660     }
3661   return list;
3662 }
3663
3664 /* Remove CTLESC protecting a CTLESC or CTLNUL in place.  Return the passed
3665    string. */
3666 char *
3667 remove_quoted_escapes (string)
3668      char *string;
3669 {
3670   char *t;
3671
3672   if (string)
3673     {
3674       t = dequote_escapes (string);
3675       strcpy (string, t);
3676       free (t);
3677     }
3678
3679   return (string);
3680 }
3681
3682 /* Perform quoted null character removal on STRING.  We don't allow any
3683    quoted null characters in the middle or at the ends of strings because
3684    of how expand_word_internal works.  remove_quoted_nulls () turns
3685    STRING into an empty string iff it only consists of a quoted null,
3686    and removes all unquoted CTLNUL characters. */
3687 char *
3688 remove_quoted_nulls (string)
3689      char *string;
3690 {
3691   register size_t slen;
3692   register int i, j, prev_i;
3693   DECLARE_MBSTATE;
3694
3695   if (strchr (string, CTLNUL) == 0)             /* XXX */
3696     return string;                              /* XXX */
3697
3698   slen = strlen (string);
3699   i = j = 0;
3700
3701   while (i < slen)
3702     {
3703       if (string[i] == CTLESC)
3704         {
3705           /* Old code had j++, but we cannot assume that i == j at this
3706              point -- what if a CTLNUL has already been removed from the
3707              string?  We don't want to drop the CTLESC or recopy characters
3708              that we've already copied down. */
3709           i++; string[j++] = CTLESC;
3710           if (i == slen)
3711             break;
3712         }
3713       else if (string[i] == CTLNUL)
3714         {
3715           i++;
3716           continue;
3717         }
3718
3719       prev_i = i;
3720       ADVANCE_CHAR (string, slen, i);
3721       if (j < prev_i)
3722         {
3723           do string[j++] = string[prev_i++]; while (prev_i < i);
3724         }
3725       else
3726         j = i;
3727     }
3728   string[j] = '\0';
3729
3730   return (string);
3731 }
3732
3733 /* Perform quoted null character removal on each element of LIST.
3734    This modifies LIST. */
3735 void
3736 word_list_remove_quoted_nulls (list)
3737      WORD_LIST *list;
3738 {
3739   register WORD_LIST *t;
3740
3741   for (t = list; t; t = t->next)
3742     {
3743       remove_quoted_nulls (t->word->word);
3744       t->word->flags &= ~W_HASQUOTEDNULL;
3745     }
3746 }
3747
3748 /* **************************************************************** */
3749 /*                                                                  */
3750 /*         Functions for Matching and Removing Patterns             */
3751 /*                                                                  */
3752 /* **************************************************************** */
3753
3754 #if defined (HANDLE_MULTIBYTE)
3755 #if 0 /* Currently unused */
3756 static unsigned char *
3757 mb_getcharlens (string, len)
3758      char *string;
3759      int len;
3760 {
3761   int i, offset, last;
3762   unsigned char *ret;
3763   char *p;
3764   DECLARE_MBSTATE;
3765
3766   i = offset = 0;
3767   last = 0;
3768   ret = (unsigned char *)xmalloc (len);
3769   memset (ret, 0, len);
3770   while (string[last])
3771     {
3772       ADVANCE_CHAR (string, len, offset);
3773       ret[last] = offset - last;
3774       last = offset;
3775     }
3776   return ret;
3777 }
3778 #endif
3779 #endif
3780
3781 /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
3782    can have one of 4 values:
3783         RP_LONG_LEFT    remove longest matching portion at start of PARAM
3784         RP_SHORT_LEFT   remove shortest matching portion at start of PARAM
3785         RP_LONG_RIGHT   remove longest matching portion at end of PARAM
3786         RP_SHORT_RIGHT  remove shortest matching portion at end of PARAM
3787 */
3788
3789 #define RP_LONG_LEFT    1
3790 #define RP_SHORT_LEFT   2
3791 #define RP_LONG_RIGHT   3
3792 #define RP_SHORT_RIGHT  4
3793
3794 /* Returns its first argument if nothing matched; new memory otherwise */
3795 static char *
3796 remove_upattern (param, pattern, op)
3797      char *param, *pattern;
3798      int op;
3799 {
3800   register int len;
3801   register char *end;
3802   register char *p, *ret, c;
3803
3804   len = STRLEN (param);
3805   end = param + len;
3806
3807   switch (op)
3808     {
3809       case RP_LONG_LEFT:        /* remove longest match at start */
3810         for (p = end; p >= param; p--)
3811           {
3812             c = *p; *p = '\0';
3813             if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3814               {
3815                 *p = c;
3816                 return (savestring (p));
3817               }
3818             *p = c;
3819
3820           }
3821         break;
3822
3823       case RP_SHORT_LEFT:       /* remove shortest match at start */
3824         for (p = param; p <= end; p++)
3825           {
3826             c = *p; *p = '\0';
3827             if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3828               {
3829                 *p = c;
3830                 return (savestring (p));
3831               }
3832             *p = c;
3833           }
3834         break;
3835
3836       case RP_LONG_RIGHT:       /* remove longest match at end */
3837         for (p = param; p <= end; p++)
3838           {
3839             if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3840               {
3841                 c = *p; *p = '\0';
3842                 ret = savestring (param);
3843                 *p = c;
3844                 return (ret);
3845               }
3846           }
3847         break;
3848
3849       case RP_SHORT_RIGHT:      /* remove shortest match at end */
3850         for (p = end; p >= param; p--)
3851           {
3852             if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3853               {
3854                 c = *p; *p = '\0';
3855                 ret = savestring (param);
3856                 *p = c;
3857                 return (ret);
3858               }
3859           }
3860         break;
3861     }
3862
3863   return (param);       /* no match, return original string */
3864 }
3865
3866 #if defined (HANDLE_MULTIBYTE)
3867 /* Returns its first argument if nothing matched; new memory otherwise */
3868 static wchar_t *
3869 remove_wpattern (wparam, wstrlen, wpattern, op)
3870      wchar_t *wparam;
3871      size_t wstrlen;
3872      wchar_t *wpattern;
3873      int op;
3874 {
3875   wchar_t wc, *ret;
3876   int n;
3877
3878   switch (op)
3879     {
3880       case RP_LONG_LEFT:        /* remove longest match at start */
3881         for (n = wstrlen; n >= 0; n--)
3882           {
3883             wc = wparam[n]; wparam[n] = L'\0';
3884             if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3885               {
3886                 wparam[n] = wc;
3887                 return (wcsdup (wparam + n));
3888               }
3889             wparam[n] = wc;
3890           }
3891         break;
3892
3893       case RP_SHORT_LEFT:       /* remove shortest match at start */
3894         for (n = 0; n <= wstrlen; n++)
3895           {
3896             wc = wparam[n]; wparam[n] = L'\0';
3897             if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3898               {
3899                 wparam[n] = wc;
3900                 return (wcsdup (wparam + n));
3901               }
3902             wparam[n] = wc;
3903           }
3904         break;
3905
3906       case RP_LONG_RIGHT:       /* remove longest match at end */
3907         for (n = 0; n <= wstrlen; n++)
3908           {
3909             if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3910               {
3911                 wc = wparam[n]; wparam[n] = L'\0';
3912                 ret = wcsdup (wparam);
3913                 wparam[n] = wc;
3914                 return (ret);
3915               }
3916           }
3917         break;
3918
3919       case RP_SHORT_RIGHT:      /* remove shortest match at end */
3920         for (n = wstrlen; n >= 0; n--)
3921           {
3922             if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3923               {
3924                 wc = wparam[n]; wparam[n] = L'\0';
3925                 ret = wcsdup (wparam);
3926                 wparam[n] = wc;
3927                 return (ret);
3928               }
3929           }
3930         break;
3931     }
3932
3933   return (wparam);      /* no match, return original string */
3934 }
3935 #endif /* HANDLE_MULTIBYTE */
3936
3937 static char *
3938 remove_pattern (param, pattern, op)
3939      char *param, *pattern;
3940      int op;
3941 {
3942   char *xret;
3943
3944   if (param == NULL)
3945     return (param);
3946   if (*param == '\0' || pattern == NULL || *pattern == '\0')    /* minor optimization */
3947     return (savestring (param));
3948
3949 #if defined (HANDLE_MULTIBYTE)
3950   if (MB_CUR_MAX > 1)
3951     {
3952       wchar_t *ret, *oret;
3953       size_t n;
3954       wchar_t *wparam, *wpattern;
3955       mbstate_t ps;
3956
3957       n = xdupmbstowcs (&wpattern, NULL, pattern);
3958       if (n == (size_t)-1)
3959         {
3960           xret = remove_upattern (param, pattern, op);
3961           return ((xret == param) ? savestring (param) : xret);
3962         }
3963       n = xdupmbstowcs (&wparam, NULL, param);
3964       if (n == (size_t)-1)
3965         {
3966           free (wpattern);
3967           xret = remove_upattern (param, pattern, op);
3968           return ((xret == param) ? savestring (param) : xret);
3969         }
3970       oret = ret = remove_wpattern (wparam, n, wpattern, op);
3971       /* Don't bother to convert wparam back to multibyte string if nothing
3972          matched; just return copy of original string */
3973       if (ret == wparam)
3974         {
3975           free (wparam);
3976           free (wpattern);
3977           return (savestring (param));
3978         }
3979
3980       free (wparam);
3981       free (wpattern);
3982
3983       n = strlen (param);
3984       xret = (char *)xmalloc (n + 1);
3985       memset (&ps, '\0', sizeof (mbstate_t));
3986       n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
3987       xret[n] = '\0';           /* just to make sure */
3988       free (oret);
3989       return xret;      
3990     }
3991   else
3992 #endif
3993     {
3994       xret = remove_upattern (param, pattern, op);
3995       return ((xret == param) ? savestring (param) : xret);
3996     }
3997 }
3998
3999 /* Match PAT anywhere in STRING and return the match boundaries.
4000    This returns 1 in case of a successful match, 0 otherwise.  SP
4001    and EP are pointers into the string where the match begins and
4002    ends, respectively.  MTYPE controls what kind of match is attempted.
4003    MATCH_BEG and MATCH_END anchor the match at the beginning and end
4004    of the string, respectively.  The longest match is returned. */
4005 static int
4006 match_upattern (string, pat, mtype, sp, ep)
4007      char *string, *pat;
4008      int mtype;
4009      char **sp, **ep;
4010 {
4011   int c, len, mlen;
4012   register char *p, *p1, *npat;
4013   char *end;
4014   int n1;
4015
4016   /* If the pattern doesn't match anywhere in the string, go ahead and
4017      short-circuit right away.  A minor optimization, saves a bunch of
4018      unnecessary calls to strmatch (up to N calls for a string of N
4019      characters) if the match is unsuccessful.  To preserve the semantics
4020      of the substring matches below, we make sure that the pattern has
4021      `*' as first and last character, making a new pattern if necessary. */
4022   /* XXX - check this later if I ever implement `**' with special meaning,
4023      since this will potentially result in `**' at the beginning or end */
4024   len = STRLEN (pat);
4025   if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
4026     {
4027       p = npat = (char *)xmalloc (len + 3);
4028       p1 = pat;
4029       if (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))
4030         *p++ = '*';
4031       while (*p1)
4032         *p++ = *p1++;
4033       if (p1[-1] != '*' || p[-2] == '\\')
4034         *p++ = '*';
4035       *p = '\0';
4036     }
4037   else
4038     npat = pat;
4039   c = strmatch (npat, string, FNMATCH_EXTFLAG);
4040   if (npat != pat)
4041     free (npat);
4042   if (c == FNM_NOMATCH)
4043     return (0);
4044
4045   len = STRLEN (string);
4046   end = string + len;
4047
4048   mlen = umatchlen (pat, len);
4049
4050   switch (mtype)
4051     {
4052     case MATCH_ANY:
4053       for (p = string; p <= end; p++)
4054         {
4055           if (match_pattern_char (pat, p))
4056             {
4057 #if 0
4058               for (p1 = end; p1 >= p; p1--)
4059 #else
4060               p1 = (mlen == -1) ? end : p + mlen;
4061               /* p1 - p = length of portion of string to be considered
4062                  p = current position in string
4063                  mlen = number of characters consumed by match (-1 for entire string)
4064                  end = end of string
4065                  we want to break immediately if the potential match len
4066                  is greater than the number of characters remaining in the
4067                  string
4068               */
4069               if (p1 > end)
4070                 break;
4071               for ( ; p1 >= p; p1--)
4072 #endif
4073                 {
4074                   c = *p1; *p1 = '\0';
4075                   if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
4076                     {
4077                       *p1 = c;
4078                       *sp = p;
4079                       *ep = p1;
4080                       return 1;
4081                     }
4082                   *p1 = c;
4083 #if 1
4084                   /* If MLEN != -1, we have a fixed length pattern. */
4085                   if (mlen != -1)
4086                     break;
4087 #endif
4088                 }
4089             }
4090         }
4091
4092       return (0);
4093
4094     case MATCH_BEG:
4095       if (match_pattern_char (pat, string) == 0)
4096         return (0);
4097
4098 #if 0
4099       for (p = end; p >= string; p--)
4100 #else
4101       for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
4102 #endif
4103         {
4104           c = *p; *p = '\0';
4105           if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0)
4106             {
4107               *p = c;
4108               *sp = string;
4109               *ep = p;
4110               return 1;
4111             }
4112           *p = c;
4113 #if 1
4114           /* If MLEN != -1, we have a fixed length pattern. */
4115           if (mlen != -1)
4116             break;
4117 #endif
4118         }
4119
4120       return (0);
4121
4122     case MATCH_END:
4123 #if 0
4124       for (p = string; p <= end; p++)
4125 #else
4126       for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
4127 #endif
4128         {
4129           if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
4130             {
4131               *sp = p;
4132               *ep = end;
4133               return 1;
4134             }
4135 #if 1
4136           /* If MLEN != -1, we have a fixed length pattern. */
4137           if (mlen != -1)
4138             break;
4139 #endif
4140         }
4141
4142       return (0);
4143     }
4144
4145   return (0);
4146 }
4147
4148 #if defined (HANDLE_MULTIBYTE)
4149 /* Match WPAT anywhere in WSTRING and return the match boundaries.
4150    This returns 1 in case of a successful match, 0 otherwise.  Wide
4151    character version. */
4152 static int
4153 match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
4154      wchar_t *wstring;
4155      char **indices;
4156      size_t wstrlen;
4157      wchar_t *wpat;
4158      int mtype;
4159      char **sp, **ep;
4160 {
4161   wchar_t wc, *wp, *nwpat, *wp1;
4162   size_t len;
4163   int mlen;
4164   int n, n1, n2, simple;
4165
4166   simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
4167 #if defined (EXTENDED_GLOB)
4168   if (extended_glob)
4169     simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
4170 #endif
4171
4172   /* If the pattern doesn't match anywhere in the string, go ahead and
4173      short-circuit right away.  A minor optimization, saves a bunch of
4174      unnecessary calls to strmatch (up to N calls for a string of N
4175      characters) if the match is unsuccessful.  To preserve the semantics
4176      of the substring matches below, we make sure that the pattern has
4177      `*' as first and last character, making a new pattern if necessary. */
4178   len = wcslen (wpat);
4179   if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
4180     {
4181       wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
4182       wp1 = wpat;
4183       if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
4184         *wp++ = L'*';
4185       while (*wp1 != L'\0')
4186         *wp++ = *wp1++;
4187       if (wp1[-1] != L'*' || wp1[-2] == L'\\')
4188         *wp++ = L'*';
4189       *wp = '\0';
4190     }
4191   else
4192     nwpat = wpat;
4193   len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG);
4194   if (nwpat != wpat)
4195     free (nwpat);
4196   if (len == FNM_NOMATCH)
4197     return (0);
4198
4199   mlen = wmatchlen (wpat, wstrlen);
4200
4201 /* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
4202   switch (mtype)
4203     {
4204     case MATCH_ANY:
4205       for (n = 0; n <= wstrlen; n++)
4206         {
4207 #if 1
4208           n2 = simple ? (*wpat == wstring[n]) : match_pattern_wchar (wpat, wstring + n);
4209 #else
4210           n2 = match_pattern_wchar (wpat, wstring + n);
4211 #endif
4212           if (n2)
4213             {
4214 #if 0
4215               for (n1 = wstrlen; n1 >= n; n1--)
4216 #else
4217               n1 = (mlen == -1) ? wstrlen : n + mlen;
4218               if (n1 > wstrlen)
4219                 break;
4220
4221               for ( ; n1 >= n; n1--)
4222 #endif
4223                 {
4224                   wc = wstring[n1]; wstring[n1] = L'\0';
4225                   if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
4226                     {
4227                       wstring[n1] = wc;
4228                       *sp = indices[n];
4229                       *ep = indices[n1];
4230                       return 1;
4231                     }
4232                   wstring[n1] = wc;
4233 #if 1
4234                   /* If MLEN != -1, we have a fixed length pattern. */
4235                   if (mlen != -1)
4236                     break;
4237 #endif
4238                 }
4239             }
4240         }
4241
4242       return (0);
4243
4244     case MATCH_BEG:
4245       if (match_pattern_wchar (wpat, wstring) == 0)
4246         return (0);
4247
4248 #if 0
4249       for (n = wstrlen; n >= 0; n--)
4250 #else
4251       for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
4252 #endif
4253         {
4254           wc = wstring[n]; wstring[n] = L'\0';
4255           if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0)
4256             {
4257               wstring[n] = wc;
4258               *sp = indices[0];
4259               *ep = indices[n];
4260               return 1;
4261             }
4262           wstring[n] = wc;
4263 #if 1
4264           /* If MLEN != -1, we have a fixed length pattern. */
4265           if (mlen != -1)
4266             break;
4267 #endif
4268         }
4269
4270       return (0);
4271
4272     case MATCH_END:
4273 #if 0
4274       for (n = 0; n <= wstrlen; n++)
4275 #else
4276       for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
4277 #endif
4278         {
4279           if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
4280             {
4281               *sp = indices[n];
4282               *ep = indices[wstrlen];
4283               return 1;
4284             }
4285 #if 1
4286           /* If MLEN != -1, we have a fixed length pattern. */
4287           if (mlen != -1)
4288             break;
4289 #endif
4290         }
4291
4292       return (0);
4293     }
4294
4295   return (0);
4296 }
4297 #endif /* HANDLE_MULTIBYTE */
4298
4299 static int
4300 match_pattern (string, pat, mtype, sp, ep)
4301      char *string, *pat;
4302      int mtype;
4303      char **sp, **ep;
4304 {
4305 #if defined (HANDLE_MULTIBYTE)
4306   int ret;
4307   size_t n;
4308   wchar_t *wstring, *wpat;
4309   char **indices;
4310   size_t slen, plen, mslen, mplen;
4311 #endif
4312
4313   if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
4314     return (0);
4315
4316 #if defined (HANDLE_MULTIBYTE)
4317   if (MB_CUR_MAX > 1)
4318     {
4319 #if 0
4320       slen = STRLEN (string);
4321       mslen = MBSLEN (string);
4322       plen = STRLEN (pat);
4323       mplen = MBSLEN (pat);
4324       if (slen == mslen && plen == mplen)
4325 #else
4326       if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
4327 #endif
4328         return (match_upattern (string, pat, mtype, sp, ep));
4329
4330       n = xdupmbstowcs (&wpat, NULL, pat);
4331       if (n == (size_t)-1)
4332         return (match_upattern (string, pat, mtype, sp, ep));
4333       n = xdupmbstowcs (&wstring, &indices, string);
4334       if (n == (size_t)-1)
4335         {
4336           free (wpat);
4337           return (match_upattern (string, pat, mtype, sp, ep));
4338         }
4339       ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
4340
4341       free (wpat);
4342       free (wstring);
4343       free (indices);
4344
4345       return (ret);
4346     }
4347   else
4348 #endif
4349     return (match_upattern (string, pat, mtype, sp, ep));
4350 }
4351
4352 static int
4353 getpatspec (c, value)
4354      int c;
4355      char *value;
4356 {
4357   if (c == '#')
4358     return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
4359   else  /* c == '%' */
4360     return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
4361 }
4362
4363 /* Posix.2 says that the WORD should be run through tilde expansion,
4364    parameter expansion, command substitution and arithmetic expansion.
4365    This leaves the result quoted, so quote_string_for_globbing () has
4366    to be called to fix it up for strmatch ().  If QUOTED is non-zero,
4367    it means that the entire expression was enclosed in double quotes.
4368    This means that quoting characters in the pattern do not make any
4369    special pattern characters quoted.  For example, the `*' in the
4370    following retains its special meaning: "${foo#'*'}". */
4371 static char *
4372 getpattern (value, quoted, expandpat)
4373      char *value;
4374      int quoted, expandpat;
4375 {
4376   char *pat, *tword;
4377   WORD_LIST *l;
4378 #if 0
4379   int i;
4380 #endif
4381   /* There is a problem here:  how to handle single or double quotes in the
4382      pattern string when the whole expression is between double quotes?
4383      POSIX.2 says that enclosing double quotes do not cause the pattern to
4384      be quoted, but does that leave us a problem with @ and array[@] and their
4385      expansions inside a pattern? */
4386 #if 0
4387   if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
4388     {
4389       i = 0;
4390       pat = string_extract_double_quoted (tword, &i, 1);
4391       free (tword);
4392       tword = pat;
4393     }
4394 #endif
4395
4396   /* expand_string_for_rhs () leaves WORD quoted and does not perform
4397      word splitting. */
4398   l = *value ? expand_string_for_rhs (value,
4399                                       (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
4400                                       (int *)NULL, (int *)NULL)
4401              : (WORD_LIST *)0;
4402   pat = string_list (l);
4403   dispose_words (l);
4404   if (pat)
4405     {
4406       tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
4407       free (pat);
4408       pat = tword;
4409     }
4410   return (pat);
4411 }
4412
4413 #if 0
4414 /* Handle removing a pattern from a string as a result of ${name%[%]value}
4415    or ${name#[#]value}. */
4416 static char *
4417 variable_remove_pattern (value, pattern, patspec, quoted)
4418      char *value, *pattern;
4419      int patspec, quoted;
4420 {
4421   char *tword;
4422
4423   tword = remove_pattern (value, pattern, patspec);
4424
4425   return (tword);
4426 }
4427 #endif
4428
4429 static char *
4430 list_remove_pattern (list, pattern, patspec, itype, quoted)
4431      WORD_LIST *list;
4432      char *pattern;
4433      int patspec, itype, quoted;
4434 {
4435   WORD_LIST *new, *l;
4436   WORD_DESC *w;
4437   char *tword;
4438
4439   for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
4440     {
4441       tword = remove_pattern (l->word->word, pattern, patspec);
4442       w = alloc_word_desc ();
4443       w->word = tword ? tword : savestring ("");
4444       new = make_word_list (w, new);
4445     }
4446
4447   l = REVERSE_LIST (new, WORD_LIST *);
4448   tword = string_list_pos_params (itype, l, quoted);
4449   dispose_words (l);
4450
4451   return (tword);
4452 }
4453
4454 static char *
4455 parameter_list_remove_pattern (itype, pattern, patspec, quoted)
4456      int itype;
4457      char *pattern;
4458      int patspec, quoted;
4459 {
4460   char *ret;
4461   WORD_LIST *list;
4462
4463   list = list_rest_of_args ();
4464   if (list == 0)
4465     return ((char *)NULL);
4466   ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
4467   dispose_words (list);
4468   return (ret);
4469 }
4470
4471 #if defined (ARRAY_VARS)
4472 static char *
4473 array_remove_pattern (var, pattern, patspec, varname, quoted)
4474      SHELL_VAR *var;
4475      char *pattern;
4476      int patspec;
4477      char *varname;     /* so we can figure out how it's indexed */
4478      int quoted;
4479 {
4480   ARRAY *a;
4481   HASH_TABLE *h;
4482   int itype;
4483   char *ret;
4484   WORD_LIST *list;
4485   SHELL_VAR *v;
4486
4487   /* compute itype from varname here */
4488   v = array_variable_part (varname, &ret, 0);
4489   itype = ret[0];
4490
4491   a = (v && array_p (v)) ? array_cell (v) : 0;
4492   h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
4493   
4494   list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
4495   if (list == 0)
4496    return ((char *)NULL);
4497   ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
4498   dispose_words (list);
4499
4500   return ret;
4501 }
4502 #endif /* ARRAY_VARS */
4503
4504 static char *
4505 parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags)
4506      char *varname, *value;
4507      int ind;
4508      char *patstr;
4509      int rtype, quoted, flags;
4510 {
4511   int vtype, patspec, starsub;
4512   char *temp1, *val, *pattern;
4513   SHELL_VAR *v;
4514
4515   if (value == 0)
4516     return ((char *)NULL);
4517
4518   this_command_name = varname;
4519
4520   vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
4521   if (vtype == -1)
4522     return ((char *)NULL);
4523
4524   starsub = vtype & VT_STARSUB;
4525   vtype &= ~VT_STARSUB;
4526
4527   patspec = getpatspec (rtype, patstr);
4528   if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
4529     patstr++;
4530
4531   /* Need to pass getpattern newly-allocated memory in case of expansion --
4532      the expansion code will free the passed string on an error. */
4533   temp1 = savestring (patstr);
4534   pattern = getpattern (temp1, quoted, 1);
4535   free (temp1);
4536
4537   temp1 = (char *)NULL;         /* shut up gcc */
4538   switch (vtype)
4539     {
4540     case VT_VARIABLE:
4541     case VT_ARRAYMEMBER:
4542       temp1 = remove_pattern (val, pattern, patspec);
4543       if (vtype == VT_VARIABLE)
4544         FREE (val);
4545       if (temp1)
4546         {
4547           val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4548                         ? quote_string (temp1)
4549                         : quote_escapes (temp1);
4550           free (temp1);
4551           temp1 = val;
4552         }
4553       break;
4554 #if defined (ARRAY_VARS)
4555     case VT_ARRAYVAR:
4556       temp1 = array_remove_pattern (v, pattern, patspec, varname, quoted);
4557       if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4558         {
4559           val = quote_escapes (temp1);
4560           free (temp1);
4561           temp1 = val;
4562         }
4563       break;
4564 #endif
4565     case VT_POSPARMS:
4566       temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
4567       if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4568         {
4569           val = quote_escapes (temp1);
4570           free (temp1);
4571           temp1 = val;
4572         }
4573       break;
4574     }
4575
4576   FREE (pattern);
4577   return temp1;
4578 }    
4579
4580 /*******************************************
4581  *                                         *
4582  *      Functions to expand WORD_DESCs     *
4583  *                                         *
4584  *******************************************/
4585
4586 /* Expand WORD, performing word splitting on the result.  This does
4587    parameter expansion, command substitution, arithmetic expansion,
4588    word splitting, and quote removal. */
4589
4590 WORD_LIST *
4591 expand_word (word, quoted)
4592      WORD_DESC *word;
4593      int quoted;
4594 {
4595   WORD_LIST *result, *tresult;
4596
4597   tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4598   result = word_list_split (tresult);
4599   dispose_words (tresult);
4600   return (result ? dequote_list (result) : result);
4601 }
4602
4603 /* Expand WORD, but do not perform word splitting on the result.  This
4604    does parameter expansion, command substitution, arithmetic expansion,
4605    and quote removal. */
4606 WORD_LIST *
4607 expand_word_unsplit (word, quoted)
4608      WORD_DESC *word;
4609      int quoted;
4610 {
4611   WORD_LIST *result;
4612
4613   expand_no_split_dollar_star = 1;
4614 #if defined (HANDLE_MULTIBYTE)
4615   if (ifs_firstc[0] == 0)
4616 #else
4617   if (ifs_firstc == 0)
4618 #endif
4619     word->flags |= W_NOSPLIT;
4620   word->flags |= W_NOSPLIT2;
4621   result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4622   expand_no_split_dollar_star = 0;
4623
4624   return (result ? dequote_list (result) : result);
4625 }
4626
4627 /* Perform shell expansions on WORD, but do not perform word splitting or
4628    quote removal on the result.  Virtually identical to expand_word_unsplit;
4629    could be combined if implementations don't diverge. */
4630 WORD_LIST *
4631 expand_word_leave_quoted (word, quoted)
4632      WORD_DESC *word;
4633      int quoted;
4634 {
4635   WORD_LIST *result;
4636
4637   expand_no_split_dollar_star = 1;
4638 #if defined (HANDLE_MULTIBYTE)
4639   if (ifs_firstc[0] == 0)
4640 #else
4641   if (ifs_firstc == 0)
4642 #endif
4643     word->flags |= W_NOSPLIT;
4644   word->flags |= W_NOSPLIT2;
4645   result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4646   expand_no_split_dollar_star = 0;
4647
4648   return result;
4649 }
4650
4651 #if defined (PROCESS_SUBSTITUTION)
4652
4653 /*****************************************************************/
4654 /*                                                               */
4655 /*                  Hacking Process Substitution                 */
4656 /*                                                               */
4657 /*****************************************************************/
4658
4659 #if !defined (HAVE_DEV_FD)
4660 /* Named pipes must be removed explicitly with `unlink'.  This keeps a list
4661    of FIFOs the shell has open.  unlink_fifo_list will walk the list and
4662    unlink all of them. add_fifo_list adds the name of an open FIFO to the
4663    list.  NFIFO is a count of the number of FIFOs in the list. */
4664 #define FIFO_INCR 20
4665
4666 struct temp_fifo {
4667   char *file;
4668   pid_t proc;
4669 };
4670
4671 static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
4672 static int nfifo;
4673 static int fifo_list_size;
4674
4675 char *
4676 copy_fifo_list (sizep)
4677      int *sizep;
4678 {
4679   if (sizep)
4680     *sizep = 0;
4681   return (char *)NULL;
4682 }
4683
4684 static void
4685 add_fifo_list (pathname)
4686      char *pathname;
4687 {
4688   if (nfifo >= fifo_list_size - 1)
4689     {
4690       fifo_list_size += FIFO_INCR;
4691       fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
4692                                 fifo_list_size * sizeof (struct temp_fifo));
4693     }
4694
4695   fifo_list[nfifo].file = savestring (pathname);
4696   nfifo++;
4697 }
4698
4699 void
4700 unlink_fifo (i)
4701      int i;
4702 {
4703   if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1))
4704     {
4705       unlink (fifo_list[i].file);
4706       free (fifo_list[i].file);
4707       fifo_list[i].file = (char *)NULL;
4708       fifo_list[i].proc = -1;
4709     }
4710 }
4711
4712 void
4713 unlink_fifo_list ()
4714 {
4715   int saved, i, j;
4716
4717   if (nfifo == 0)
4718     return;
4719
4720   for (i = saved = 0; i < nfifo; i++)
4721     {
4722       if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1))
4723         {
4724           unlink (fifo_list[i].file);
4725           free (fifo_list[i].file);
4726           fifo_list[i].file = (char *)NULL;
4727           fifo_list[i].proc = -1;
4728         }
4729       else
4730         saved++;
4731     }
4732
4733   /* If we didn't remove some of the FIFOs, compact the list. */
4734   if (saved)
4735     {
4736       for (i = j = 0; i < nfifo; i++)
4737         if (fifo_list[i].file)
4738           {
4739             fifo_list[j].file = fifo_list[i].file;
4740             fifo_list[j].proc = fifo_list[i].proc;
4741             j++;
4742           }
4743       nfifo = j;
4744     }
4745   else
4746     nfifo = 0;
4747 }
4748
4749 /* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
4750    from some point in the past, and close all open FIFOs in fifo_list
4751    that are not marked as active in LIST.  If LIST is NULL, close
4752    everything in fifo_list. LSIZE is the number of elements in LIST, in
4753    case it's larger than fifo_list_size (size of fifo_list). */
4754 void
4755 close_new_fifos (list, lsize)
4756      char *list;
4757      int lsize;
4758 {
4759   int i;
4760
4761   if (list == 0)
4762     {
4763       unlink_fifo_list ();
4764       return;
4765     }
4766
4767   for (i = 0; i < lsize; i++)
4768     if (list[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
4769       unlink_fifo (i);
4770
4771   for (i = lsize; i < fifo_list_size; i++)
4772     unlink_fifo (i);  
4773 }
4774
4775 int
4776 fifos_pending ()
4777 {
4778   return nfifo;
4779 }
4780
4781 int
4782 num_fifos ()
4783 {
4784   return nfifo;
4785 }
4786
4787 static char *
4788 make_named_pipe ()
4789 {
4790   char *tname;
4791
4792   tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
4793   if (mkfifo (tname, 0600) < 0)
4794     {
4795       free (tname);
4796       return ((char *)NULL);
4797     }
4798
4799   add_fifo_list (tname);
4800   return (tname);
4801 }
4802
4803 #else /* HAVE_DEV_FD */
4804
4805 /* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
4806    has open to children.  NFDS is a count of the number of bits currently
4807    set in DEV_FD_LIST.  TOTFDS is a count of the highest possible number
4808    of open files. */
4809 static char *dev_fd_list = (char *)NULL;
4810 static int nfds;
4811 static int totfds;      /* The highest possible number of open files. */
4812
4813 char *
4814 copy_fifo_list (sizep)
4815      int *sizep;
4816 {
4817   char *ret;
4818
4819   if (nfds == 0 || totfds == 0)
4820     {
4821       if (sizep)
4822         *sizep = 0;
4823       return (char *)NULL;
4824     }
4825
4826   if (sizep)
4827     *sizep = totfds;
4828   ret = (char *)xmalloc (totfds);
4829   return (memcpy (ret, dev_fd_list, totfds));
4830 }
4831
4832 static void
4833 add_fifo_list (fd)
4834      int fd;
4835 {
4836   if (dev_fd_list == 0 || fd >= totfds)
4837     {
4838       int ofds;
4839
4840       ofds = totfds;
4841       totfds = getdtablesize ();
4842       if (totfds < 0 || totfds > 256)
4843         totfds = 256;
4844       if (fd >= totfds)
4845         totfds = fd + 2;
4846
4847       dev_fd_list = (char *)xrealloc (dev_fd_list, totfds);
4848       memset (dev_fd_list + ofds, '\0', totfds - ofds);
4849     }
4850
4851   dev_fd_list[fd] = 1;
4852   nfds++;
4853 }
4854
4855 int
4856 fifos_pending ()
4857 {
4858   return 0;     /* used for cleanup; not needed with /dev/fd */
4859 }
4860
4861 int
4862 num_fifos ()
4863 {
4864   return nfds;
4865 }
4866
4867 void
4868 unlink_fifo (fd)
4869      int fd;
4870 {
4871   if (dev_fd_list[fd])
4872     {
4873       close (fd);
4874       dev_fd_list[fd] = 0;
4875       nfds--;
4876     }
4877 }
4878
4879 void
4880 unlink_fifo_list ()
4881 {
4882   register int i;
4883
4884   if (nfds == 0)
4885     return;
4886
4887   for (i = 0; nfds && i < totfds; i++)
4888     unlink_fifo (i);
4889
4890   nfds = 0;
4891 }
4892
4893 /* Take LIST, which is a snapshot copy of dev_fd_list from some point in
4894    the past, and close all open fds in dev_fd_list that are not marked
4895    as open in LIST.  If LIST is NULL, close everything in dev_fd_list.
4896    LSIZE is the number of elements in LIST, in case it's larger than
4897    totfds (size of dev_fd_list). */
4898 void
4899 close_new_fifos (list, lsize)
4900      char *list;
4901      int lsize;
4902 {
4903   int i;
4904
4905   if (list == 0)
4906     {
4907       unlink_fifo_list ();
4908       return;
4909     }
4910
4911   for (i = 0; i < lsize; i++)
4912     if (list[i] == 0 && i < totfds && dev_fd_list[i])
4913       unlink_fifo (i);
4914
4915   for (i = lsize; i < totfds; i++)
4916     unlink_fifo (i);  
4917 }
4918
4919 #if defined (NOTDEF)
4920 print_dev_fd_list ()
4921 {
4922   register int i;
4923
4924   fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
4925   fflush (stderr);
4926
4927   for (i = 0; i < totfds; i++)
4928     {
4929       if (dev_fd_list[i])
4930         fprintf (stderr, " %d", i);
4931     }
4932   fprintf (stderr, "\n");
4933 }
4934 #endif /* NOTDEF */
4935
4936 static char *
4937 make_dev_fd_filename (fd)
4938      int fd;
4939 {
4940   char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
4941
4942   ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
4943
4944   strcpy (ret, DEV_FD_PREFIX);
4945   p = inttostr (fd, intbuf, sizeof (intbuf));
4946   strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
4947
4948   add_fifo_list (fd);
4949   return (ret);
4950 }
4951
4952 #endif /* HAVE_DEV_FD */
4953
4954 /* Return a filename that will open a connection to the process defined by
4955    executing STRING.  HAVE_DEV_FD, if defined, means open a pipe and return
4956    a filename in /dev/fd corresponding to a descriptor that is one of the
4957    ends of the pipe.  If not defined, we use named pipes on systems that have
4958    them.  Systems without /dev/fd and named pipes are out of luck.
4959
4960    OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
4961    use the read end of the pipe and dup that file descriptor to fd 0 in
4962    the child.  If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
4963    writing or use the write end of the pipe in the child, and dup that
4964    file descriptor to fd 1 in the child.  The parent does the opposite. */
4965
4966 static char *
4967 process_substitute (string, open_for_read_in_child)
4968      char *string;
4969      int open_for_read_in_child;
4970 {
4971   char *pathname;
4972   int fd, result;
4973   pid_t old_pid, pid;
4974 #if defined (HAVE_DEV_FD)
4975   int parent_pipe_fd, child_pipe_fd;
4976   int fildes[2];
4977 #endif /* HAVE_DEV_FD */
4978 #if defined (JOB_CONTROL)
4979   pid_t old_pipeline_pgrp;
4980 #endif
4981
4982   if (!string || !*string || wordexp_only)
4983     return ((char *)NULL);
4984
4985 #if !defined (HAVE_DEV_FD)
4986   pathname = make_named_pipe ();
4987 #else /* HAVE_DEV_FD */
4988   if (pipe (fildes) < 0)
4989     {
4990       sys_error (_("cannot make pipe for process substitution"));
4991       return ((char *)NULL);
4992     }
4993   /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
4994      the pipe in the parent, otherwise the read end. */
4995   parent_pipe_fd = fildes[open_for_read_in_child];
4996   child_pipe_fd = fildes[1 - open_for_read_in_child];
4997   /* Move the parent end of the pipe to some high file descriptor, to
4998      avoid clashes with FDs used by the script. */
4999   parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
5000
5001   pathname = make_dev_fd_filename (parent_pipe_fd);
5002 #endif /* HAVE_DEV_FD */
5003
5004   if (pathname == 0)
5005     {
5006       sys_error (_("cannot make pipe for process substitution"));
5007       return ((char *)NULL);
5008     }
5009
5010   old_pid = last_made_pid;
5011
5012 #if defined (JOB_CONTROL)
5013   old_pipeline_pgrp = pipeline_pgrp;
5014   pipeline_pgrp = shell_pgrp;
5015   save_pipeline (1);
5016 #endif /* JOB_CONTROL */
5017
5018   pid = make_child ((char *)NULL, 1);
5019   if (pid == 0)
5020     {
5021       reset_terminating_signals ();     /* XXX */
5022       free_pushed_string_input ();
5023       /* Cancel traps, in trap.c. */
5024       restore_original_signals ();      /* XXX - what about special builtins? bash-4.2 */
5025       setup_async_signals ();
5026       subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB;
5027     }
5028
5029 #if defined (JOB_CONTROL)
5030   set_sigchld_handler ();
5031   stop_making_children ();
5032   /* XXX - should we only do this in the parent? (as in command subst) */
5033   pipeline_pgrp = old_pipeline_pgrp;
5034 #endif /* JOB_CONTROL */
5035
5036   if (pid < 0)
5037     {
5038       sys_error (_("cannot make child for process substitution"));
5039       free (pathname);
5040 #if defined (HAVE_DEV_FD)
5041       close (parent_pipe_fd);
5042       close (child_pipe_fd);
5043 #endif /* HAVE_DEV_FD */
5044       return ((char *)NULL);
5045     }
5046
5047   if (pid > 0)
5048     {
5049 #if defined (JOB_CONTROL)
5050       restore_pipeline (1);
5051 #endif
5052
5053 #if !defined (HAVE_DEV_FD)
5054       fifo_list[nfifo-1].proc = pid;
5055 #endif
5056
5057       last_made_pid = old_pid;
5058
5059 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
5060       close_pgrp_pipe ();
5061 #endif /* JOB_CONTROL && PGRP_PIPE */
5062
5063 #if defined (HAVE_DEV_FD)
5064       close (child_pipe_fd);
5065 #endif /* HAVE_DEV_FD */
5066
5067       return (pathname);
5068     }
5069
5070   set_sigint_handler ();
5071
5072 #if defined (JOB_CONTROL)
5073   set_job_control (0);
5074 #endif /* JOB_CONTROL */
5075
5076 #if !defined (HAVE_DEV_FD)
5077   /* Open the named pipe in the child. */
5078   fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY);
5079   if (fd < 0)
5080     {
5081       /* Two separate strings for ease of translation. */
5082       if (open_for_read_in_child)
5083         sys_error (_("cannot open named pipe %s for reading"), pathname);
5084       else
5085         sys_error (_("cannot open named pipe %s for writing"), pathname);
5086
5087       exit (127);
5088     }
5089   if (open_for_read_in_child)
5090     {
5091       if (sh_unset_nodelay_mode (fd) < 0)
5092         {
5093           sys_error (_("cannot reset nodelay mode for fd %d"), fd);
5094           exit (127);
5095         }
5096     }
5097 #else /* HAVE_DEV_FD */
5098   fd = child_pipe_fd;
5099 #endif /* HAVE_DEV_FD */
5100
5101   if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
5102     {
5103       sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
5104         open_for_read_in_child ? 0 : 1);
5105       exit (127);
5106     }
5107
5108   if (fd != (open_for_read_in_child ? 0 : 1))
5109     close (fd);
5110
5111   /* Need to close any files that this process has open to pipes inherited
5112      from its parent. */
5113   if (current_fds_to_close)
5114     {
5115       close_fd_bitmap (current_fds_to_close);
5116       current_fds_to_close = (struct fd_bitmap *)NULL;
5117     }
5118
5119 #if defined (HAVE_DEV_FD)
5120   /* Make sure we close the parent's end of the pipe and clear the slot
5121      in the fd list so it is not closed later, if reallocated by, for
5122      instance, pipe(2). */
5123   close (parent_pipe_fd);
5124   dev_fd_list[parent_pipe_fd] = 0;
5125 #endif /* HAVE_DEV_FD */
5126
5127   /* subshells shouldn't have this flag, which controls using the temporary
5128      environment for variable lookups. */
5129   expanding_redir = 0;
5130
5131   result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
5132
5133 #if !defined (HAVE_DEV_FD)
5134   /* Make sure we close the named pipe in the child before we exit. */
5135   close (open_for_read_in_child ? 0 : 1);
5136 #endif /* !HAVE_DEV_FD */
5137
5138   exit (result);
5139   /*NOTREACHED*/
5140 }
5141 #endif /* PROCESS_SUBSTITUTION */
5142
5143 /***********************************/
5144 /*                                 */
5145 /*      Command Substitution       */
5146 /*                                 */
5147 /***********************************/
5148
5149 static char *
5150 read_comsub (fd, quoted, rflag)
5151      int fd, quoted;
5152      int *rflag;
5153 {
5154   char *istring, buf[128], *bufp, *s;
5155   int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul;
5156   ssize_t bufn;
5157
5158   istring = (char *)NULL;
5159   istring_index = istring_size = bufn = tflag = 0;
5160
5161   for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
5162     skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
5163
5164   /* Read the output of the command through the pipe.  This may need to be
5165      changed to understand multibyte characters in the future. */
5166   while (1)
5167     {
5168       if (fd < 0)
5169         break;
5170       if (--bufn <= 0)
5171         {
5172           bufn = zread (fd, buf, sizeof (buf));
5173           if (bufn <= 0) 
5174             break;
5175           bufp = buf;
5176         }
5177       c = *bufp++;
5178
5179       if (c == 0)
5180         {
5181 #if 0
5182           internal_warning ("read_comsub: ignored null byte in input");
5183 #endif
5184           continue;
5185         }
5186
5187       /* Add the character to ISTRING, possibly after resizing it. */
5188       RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
5189
5190       /* This is essentially quote_string inline */
5191       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
5192         istring[istring_index++] = CTLESC;
5193       /* Escape CTLESC and CTLNUL in the output to protect those characters
5194          from the rest of the word expansions (word splitting and globbing.)
5195          This is essentially quote_escapes inline. */
5196       else if (skip_ctlesc == 0 && c == CTLESC)
5197         {
5198           tflag |= W_HASCTLESC;
5199           istring[istring_index++] = CTLESC;
5200         }
5201       else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
5202         istring[istring_index++] = CTLESC;
5203
5204       istring[istring_index++] = c;
5205
5206 #if 0
5207 #if defined (__CYGWIN__)
5208       if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r')
5209         {
5210           istring_index--;
5211           istring[istring_index - 1] = '\n';
5212         }
5213 #endif
5214 #endif
5215     }
5216
5217   if (istring)
5218     istring[istring_index] = '\0';
5219
5220   /* If we read no output, just return now and save ourselves some
5221      trouble. */
5222   if (istring_index == 0)
5223     {
5224       FREE (istring);
5225       if (rflag)
5226         *rflag = tflag;
5227       return (char *)NULL;
5228     }
5229
5230   /* Strip trailing newlines from the output of the command. */
5231   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5232     {
5233       while (istring_index > 0)
5234         {
5235           if (istring[istring_index - 1] == '\n')
5236             {
5237               --istring_index;
5238
5239               /* If the newline was quoted, remove the quoting char. */
5240               if (istring[istring_index - 1] == CTLESC)
5241                 --istring_index;
5242             }
5243           else
5244             break;
5245         }
5246       istring[istring_index] = '\0';
5247     }
5248   else
5249     strip_trailing (istring, istring_index - 1, 1);
5250
5251   if (rflag)
5252     *rflag = tflag;
5253   return istring;
5254 }
5255
5256 /* Perform command substitution on STRING.  This returns a WORD_DESC * with the
5257    contained string possibly quoted. */
5258 WORD_DESC *
5259 command_substitute (string, quoted)
5260      char *string;
5261      int quoted;
5262 {
5263   pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
5264   char *istring;
5265   int result, fildes[2], function_value, pflags, rc, tflag;
5266   WORD_DESC *ret;
5267
5268   istring = (char *)NULL;
5269
5270   /* Don't fork () if there is no need to.  In the case of no command to
5271      run, just return NULL. */
5272   if (!string || !*string || (string[0] == '\n' && !string[1]))
5273     return ((WORD_DESC *)NULL);
5274
5275   if (wordexp_only && read_but_dont_execute)
5276     {
5277       last_command_exit_value = EX_WEXPCOMSUB;
5278       jump_to_top_level (EXITPROG);
5279     }
5280
5281   /* We're making the assumption here that the command substitution will
5282      eventually run a command from the file system.  Since we'll run
5283      maybe_make_export_env in this subshell before executing that command,
5284      the parent shell and any other shells it starts will have to remake
5285      the environment.  If we make it before we fork, other shells won't
5286      have to.  Don't bother if we have any temporary variable assignments,
5287      though, because the export environment will be remade after this
5288      command completes anyway, but do it if all the words to be expanded
5289      are variable assignments. */
5290   if (subst_assign_varlist == 0 || garglist == 0)
5291     maybe_make_export_env ();   /* XXX */
5292
5293   /* Flags to pass to parse_and_execute() */
5294   pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
5295
5296   /* Pipe the output of executing STRING into the current shell. */
5297   if (pipe (fildes) < 0)
5298     {
5299       sys_error (_("cannot make pipe for command substitution"));
5300       goto error_exit;
5301     }
5302
5303   old_pid = last_made_pid;
5304 #if defined (JOB_CONTROL)
5305   old_pipeline_pgrp = pipeline_pgrp;
5306   /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */
5307   if ((subshell_environment & SUBSHELL_PIPE) == 0)
5308     pipeline_pgrp = shell_pgrp;
5309   cleanup_the_pipeline ();
5310 #endif /* JOB_CONTROL */
5311
5312   old_async_pid = last_asynchronous_pid;
5313   pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC);
5314   last_asynchronous_pid = old_async_pid;
5315
5316   if (pid == 0)
5317     {
5318       /* Reset the signal handlers in the child, but don't free the
5319          trap strings.  Set a flag noting that we have to free the
5320          trap strings if we run trap to change a signal disposition. */
5321       reset_signal_handlers ();
5322       subshell_environment |= SUBSHELL_RESETTRAP;
5323     }
5324
5325 #if defined (JOB_CONTROL)
5326   /* XXX DO THIS ONLY IN PARENT ? XXX */
5327   set_sigchld_handler ();
5328   stop_making_children ();
5329   if (pid != 0)
5330     pipeline_pgrp = old_pipeline_pgrp;
5331 #else
5332   stop_making_children ();
5333 #endif /* JOB_CONTROL */
5334
5335   if (pid < 0)
5336     {
5337       sys_error (_("cannot make child for command substitution"));
5338     error_exit:
5339
5340       FREE (istring);
5341       close (fildes[0]);
5342       close (fildes[1]);
5343       return ((WORD_DESC *)NULL);
5344     }
5345
5346   if (pid == 0)
5347     {
5348       set_sigint_handler ();    /* XXX */
5349
5350       free_pushed_string_input ();
5351
5352       if (dup2 (fildes[1], 1) < 0)
5353         {
5354           sys_error (_("command_substitute: cannot duplicate pipe as fd 1"));
5355           exit (EXECUTION_FAILURE);
5356         }
5357
5358       /* If standard output is closed in the parent shell
5359          (such as after `exec >&-'), file descriptor 1 will be
5360          the lowest available file descriptor, and end up in
5361          fildes[0].  This can happen for stdin and stderr as well,
5362          but stdout is more important -- it will cause no output
5363          to be generated from this command. */
5364       if ((fildes[1] != fileno (stdin)) &&
5365           (fildes[1] != fileno (stdout)) &&
5366           (fildes[1] != fileno (stderr)))
5367         close (fildes[1]);
5368
5369       if ((fildes[0] != fileno (stdin)) &&
5370           (fildes[0] != fileno (stdout)) &&
5371           (fildes[0] != fileno (stderr)))
5372         close (fildes[0]);
5373
5374 #ifdef __CYGWIN__
5375       /* Let stdio know the fd may have changed from text to binary mode, and
5376          make sure to preserve stdout line buffering. */
5377       freopen (NULL, "w", stdout);
5378       sh_setlinebuf (stdout);
5379 #endif /* __CYGWIN__ */
5380
5381       /* The currently executing shell is not interactive. */
5382       interactive = 0;
5383
5384       /* This is a subshell environment. */
5385       subshell_environment |= SUBSHELL_COMSUB;
5386
5387       /* When not in POSIX mode, command substitution does not inherit
5388          the -e flag. */
5389       if (posixly_correct == 0)
5390         exit_immediately_on_error = 0;
5391
5392       remove_quoted_escapes (string);
5393
5394       startup_state = 2;        /* see if we can avoid a fork */
5395       /* Give command substitution a place to jump back to on failure,
5396          so we don't go back up to main (). */
5397       result = setjmp (top_level);
5398
5399       /* If we're running a command substitution inside a shell function,
5400          trap `return' so we don't return from the function in the subshell
5401          and go off to never-never land. */
5402       if (result == 0 && return_catch_flag)
5403         function_value = setjmp (return_catch);
5404       else
5405         function_value = 0;
5406
5407       if (result == ERREXIT)
5408         rc = last_command_exit_value;
5409       else if (result == EXITPROG)
5410         rc = last_command_exit_value;
5411       else if (result)
5412         rc = EXECUTION_FAILURE;
5413       else if (function_value)
5414         rc = return_catch_value;
5415       else
5416         {
5417           subshell_level++;
5418           rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
5419           subshell_level--;
5420         }
5421
5422       last_command_exit_value = rc;
5423       rc = run_exit_trap ();
5424 #if defined (PROCESS_SUBSTITUTION)
5425       unlink_fifo_list ();
5426 #endif
5427       exit (rc);
5428     }
5429   else
5430     {
5431 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
5432       close_pgrp_pipe ();
5433 #endif /* JOB_CONTROL && PGRP_PIPE */
5434
5435       close (fildes[1]);
5436
5437       tflag = 0;
5438       istring = read_comsub (fildes[0], quoted, &tflag);
5439
5440       close (fildes[0]);
5441
5442       current_command_subst_pid = pid;
5443       last_command_exit_value = wait_for (pid);
5444       last_command_subst_pid = pid;
5445       last_made_pid = old_pid;
5446
5447 #if defined (JOB_CONTROL)
5448       /* If last_command_exit_value > 128, then the substituted command
5449          was terminated by a signal.  If that signal was SIGINT, then send
5450          SIGINT to ourselves.  This will break out of loops, for instance. */
5451       if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
5452         kill (getpid (), SIGINT);
5453
5454       /* wait_for gives the terminal back to shell_pgrp.  If some other
5455          process group should have it, give it away to that group here.
5456          pipeline_pgrp is non-zero only while we are constructing a
5457          pipline, so what we are concerned about is whether or not that
5458          pipeline was started in the background.  A pipeline started in
5459          the background should never get the tty back here. */
5460       if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0)
5461         give_terminal_to (pipeline_pgrp, 0);
5462 #endif /* JOB_CONTROL */
5463
5464       ret = alloc_word_desc ();
5465       ret->word = istring;
5466       ret->flags = tflag;
5467
5468       return ret;
5469     }
5470 }
5471
5472 /********************************************************
5473  *                                                      *
5474  *      Utility functions for parameter expansion       *
5475  *                                                      *
5476  ********************************************************/
5477
5478 #if defined (ARRAY_VARS)
5479
5480 static arrayind_t
5481 array_length_reference (s)
5482      char *s;
5483 {
5484   int len;
5485   arrayind_t ind;
5486   char *akey;
5487   char *t, c;
5488   ARRAY *array;
5489   HASH_TABLE *h;
5490   SHELL_VAR *var;
5491
5492   var = array_variable_part (s, &t, &len);
5493
5494   /* If unbound variables should generate an error, report one and return
5495      failure. */
5496   if ((var == 0 || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
5497     {
5498       c = *--t;
5499       *t = '\0';
5500       last_command_exit_value = EXECUTION_FAILURE;
5501       err_unboundvar (s);
5502       *t = c;
5503       return (-1);
5504     }
5505   else if (var == 0)
5506     return 0;
5507
5508   /* We support a couple of expansions for variables that are not arrays.
5509      We'll return the length of the value for v[0], and 1 for v[@] or
5510      v[*].  Return 0 for everything else. */
5511
5512   array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
5513   h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
5514
5515   if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
5516     {
5517       if (assoc_p (var))
5518         return (h ? assoc_num_elements (h) : 0);
5519       else if (array_p (var))
5520         return (array ? array_num_elements (array) : 0);
5521       else
5522         return (var_isset (var) ? 1 : 0);
5523     }
5524
5525   if (assoc_p (var))
5526     {
5527       t[len - 1] = '\0';
5528       akey = expand_assignment_string_to_string (t, 0); /* [ */
5529       t[len - 1] = ']';
5530       if (akey == 0 || *akey == 0)
5531         {
5532           err_badarraysub (t);
5533           return (-1);
5534         }
5535       t = assoc_reference (assoc_cell (var), akey);
5536     }
5537   else
5538     {
5539       ind = array_expand_index (t, len);
5540       if (ind < 0)
5541         {
5542           err_badarraysub (t);
5543           return (-1);
5544         }
5545       if (array_p (var))
5546         t = array_reference (array, ind);
5547       else
5548         t = (ind == 0) ? value_cell (var) : (char *)NULL;
5549     }
5550
5551   len = MB_STRLEN (t);
5552   return (len);
5553 }
5554 #endif /* ARRAY_VARS */
5555
5556 static int
5557 valid_brace_expansion_word (name, var_is_special)
5558      char *name;
5559      int var_is_special;
5560 {
5561   if (DIGIT (*name) && all_digits (name))
5562     return 1;
5563   else if (var_is_special)
5564     return 1;
5565 #if defined (ARRAY_VARS)
5566   else if (valid_array_reference (name))
5567     return 1;
5568 #endif /* ARRAY_VARS */
5569   else if (legal_identifier (name))
5570     return 1;
5571   else
5572     return 0;
5573 }
5574
5575 static int
5576 chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at)
5577      char *name;
5578      int quoted;
5579      int *quoted_dollar_atp, *contains_dollar_at;
5580 {
5581   char *temp1;
5582
5583   if (name == 0)
5584     {
5585       if (quoted_dollar_atp)
5586         *quoted_dollar_atp = 0;
5587       if (contains_dollar_at)
5588         *contains_dollar_at = 0;
5589       return 0;
5590     }
5591
5592   /* check for $@ and $* */
5593   if (name[0] == '@' && name[1] == 0)
5594     {
5595       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5596         *quoted_dollar_atp = 1;
5597       if (contains_dollar_at)
5598         *contains_dollar_at = 1;
5599       return 1;
5600     }
5601   else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
5602     {
5603       if (contains_dollar_at)
5604         *contains_dollar_at = 1;
5605       return 1;
5606     }
5607
5608   /* Now check for ${array[@]} and ${array[*]} */
5609 #if defined (ARRAY_VARS)
5610   else if (valid_array_reference (name))
5611     {
5612       temp1 = mbschr (name, '[');
5613       if (temp1 && temp1[1] == '@' && temp1[2] == ']')
5614         {
5615           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5616             *quoted_dollar_atp = 1;
5617           if (contains_dollar_at)
5618             *contains_dollar_at = 1;
5619           return 1;
5620         }       /* [ */
5621       /* ${array[*]}, when unquoted, should be treated like ${array[@]},
5622          which should result in separate words even when IFS is unset. */
5623       if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0)
5624         {
5625           if (contains_dollar_at)
5626             *contains_dollar_at = 1;
5627           return 1;
5628         }
5629     }
5630 #endif
5631   return 0;
5632 }
5633
5634 /* Parameter expand NAME, and return a new string which is the expansion,
5635    or NULL if there was no expansion.
5636    VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
5637    the shell, e.g., "@", "$", "*", etc.  QUOTED, if non-zero, means that
5638    NAME was found inside of a double-quoted expression. */
5639 static WORD_DESC *
5640 parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp)
5641      char *name;
5642      int var_is_special, quoted, pflags;
5643      arrayind_t *indp;
5644 {
5645   WORD_DESC *ret;
5646   char *temp, *tt;
5647   intmax_t arg_index;
5648   SHELL_VAR *var;
5649   int atype, rflags;
5650   arrayind_t ind;
5651
5652   ret = 0;
5653   temp = 0;
5654   rflags = 0;
5655
5656   if (indp)
5657     *indp = INTMAX_MIN;
5658
5659   /* Handle multiple digit arguments, as in ${11}. */  
5660   if (legal_number (name, &arg_index))
5661     {
5662       tt = get_dollar_var_value (arg_index);
5663       if (tt)
5664         temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5665                   ? quote_string (tt)
5666                   : quote_escapes (tt);
5667       else
5668         temp = (char *)NULL;
5669       FREE (tt);
5670     }
5671   else if (var_is_special)      /* ${@} */
5672     {
5673       int sindex;
5674       tt = (char *)xmalloc (2 + strlen (name));
5675       tt[sindex = 0] = '$';
5676       strcpy (tt + 1, name);
5677
5678       ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
5679                           (int *)NULL, (int *)NULL, pflags);
5680       free (tt);
5681     }
5682 #if defined (ARRAY_VARS)
5683   else if (valid_array_reference (name))
5684     {
5685       temp = array_value (name, quoted, 0, &atype, &ind);
5686       if (atype == 0 && temp)
5687         {
5688           temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5689                     ? quote_string (temp)
5690                     : quote_escapes (temp);
5691           rflags |= W_ARRAYIND;
5692           if (indp)
5693             *indp = ind;
5694         }                 
5695       else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5696         rflags |= W_HASQUOTEDNULL;
5697     }
5698 #endif
5699   else if (var = find_variable (name))
5700     {
5701       if (var_isset (var) && invisible_p (var) == 0)
5702         {
5703 #if defined (ARRAY_VARS)
5704           if (assoc_p (var))
5705             temp = assoc_reference (assoc_cell (var), "0");
5706           else if (array_p (var))
5707             temp = array_reference (array_cell (var), 0);
5708           else
5709             temp = value_cell (var);
5710 #else
5711           temp = value_cell (var);
5712 #endif
5713
5714           if (temp)
5715             temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5716                       ? quote_string (temp)
5717                       : quote_escapes (temp);
5718         }
5719       else
5720         temp = (char *)NULL;
5721     }
5722   else
5723     temp = (char *)NULL;
5724
5725   if (ret == 0)
5726     {
5727       ret = alloc_word_desc ();
5728       ret->word = temp;
5729       ret->flags |= rflags;
5730     }
5731   return ret;
5732 }
5733
5734 /* Expand an indirect reference to a variable: ${!NAME} expands to the
5735    value of the variable whose name is the value of NAME. */
5736 static WORD_DESC *
5737 parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at)
5738      char *name;
5739      int var_is_special, quoted;
5740      int *quoted_dollar_atp, *contains_dollar_at;
5741 {
5742   char *temp, *t;
5743   WORD_DESC *w;
5744
5745   w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND, 0);
5746   t = w->word;
5747   /* Have to dequote here if necessary */
5748   if (t)
5749     {
5750       temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
5751                 ? dequote_string (t)
5752                 : dequote_escapes (t);
5753       free (t);
5754       t = temp;
5755     }
5756   dispose_word_desc (w);
5757
5758   chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at);
5759   if (t == 0)
5760     return (WORD_DESC *)NULL;
5761
5762   w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0, 0);
5763   free (t);
5764
5765   return w;
5766 }
5767
5768 /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
5769    depending on the value of C, the separating character.  C can be one of
5770    "-", "+", or "=".  QUOTED is true if the entire brace expression occurs
5771    between double quotes. */
5772 static WORD_DESC *
5773 parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
5774      char *name, *value;
5775      int c, quoted, *qdollaratp, *hasdollarat;
5776 {
5777   WORD_DESC *w;
5778   WORD_LIST *l;
5779   char *t, *t1, *temp;
5780   int hasdol;
5781
5782   /* If the entire expression is between double quotes, we want to treat
5783      the value as a double-quoted string, with the exception that we strip
5784      embedded unescaped double quotes (for sh backwards compatibility). */
5785   if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
5786     {
5787       hasdol = 0;
5788       temp = string_extract_double_quoted (value, &hasdol, 1);
5789     }
5790   else
5791     temp = value;
5792
5793   w = alloc_word_desc ();
5794   hasdol = 0;
5795   /* XXX was 0 not quoted */
5796   l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL)
5797             : (WORD_LIST *)0;
5798   if (hasdollarat)
5799     *hasdollarat = hasdol || (l && l->next);
5800   if (temp != value)
5801     free (temp);
5802   if (l)
5803     {
5804       /* The expansion of TEMP returned something.  We need to treat things
5805           slightly differently if HASDOL is non-zero.  If we have "$@", the
5806           individual words have already been quoted.  We need to turn them
5807           into a string with the words separated by the first character of
5808           $IFS without any additional quoting, so string_list_dollar_at won't
5809           do the right thing.  We use string_list_dollar_star instead. */
5810       temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l);
5811
5812       /* If l->next is not null, we know that TEMP contained "$@", since that
5813          is the only expansion that creates more than one word. */
5814       if (qdollaratp && ((hasdol && quoted) || l->next))
5815         *qdollaratp = 1;
5816       /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
5817          a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
5818          flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
5819          expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5820          (which is more paranoia than anything else), we need to return the
5821          quoted null string and set the flags to indicate it. */
5822       if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL(temp) && QUOTED_NULL(l->word->word) && (l->word->flags & W_HASQUOTEDNULL))
5823         {
5824           w->flags |= W_HASQUOTEDNULL;
5825         }
5826       dispose_words (l);
5827     }
5828   else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol)
5829     {
5830       /* The brace expansion occurred between double quotes and there was
5831          a $@ in TEMP.  It does not matter if the $@ is quoted, as long as
5832          it does not expand to anything.  In this case, we want to return
5833          a quoted empty string. */
5834       temp = make_quoted_char ('\0');
5835       w->flags |= W_HASQUOTEDNULL;
5836     }
5837   else
5838     temp = (char *)NULL;
5839
5840   if (c == '-' || c == '+')
5841     {
5842       w->word = temp;
5843       return w;
5844     }
5845
5846   /* c == '=' */
5847   t = temp ? savestring (temp) : savestring ("");
5848   t1 = dequote_string (t);
5849   free (t);
5850 #if defined (ARRAY_VARS)
5851   if (valid_array_reference (name))
5852     assign_array_element (name, t1, 0);
5853   else
5854 #endif /* ARRAY_VARS */
5855   bind_variable (name, t1, 0);
5856
5857   /* From Posix group discussion Feb-March 2010.  Issue 7 0000221 */
5858   free (temp);
5859
5860   w->word = t1;
5861   return w;
5862 }
5863
5864 /* Deal with the right hand side of a ${name:?value} expansion in the case
5865    that NAME is null or not set.  If VALUE is non-null it is expanded and
5866    used as the error message to print, otherwise a standard message is
5867    printed. */
5868 static void
5869 parameter_brace_expand_error (name, value)
5870      char *name, *value;
5871 {
5872   WORD_LIST *l;
5873   char *temp;
5874
5875   if (value && *value)
5876     {
5877       l = expand_string (value, 0);
5878       temp =  string_list (l);
5879       report_error ("%s: %s", name, temp ? temp : "");  /* XXX was value not "" */
5880       FREE (temp);
5881       dispose_words (l);
5882     }
5883   else
5884     report_error (_("%s: parameter null or not set"), name);
5885
5886   /* Free the data we have allocated during this expansion, since we
5887      are about to longjmp out. */
5888   free (name);
5889   FREE (value);
5890 }
5891
5892 /* Return 1 if NAME is something for which parameter_brace_expand_length is
5893    OK to do. */
5894 static int
5895 valid_length_expression (name)
5896      char *name;
5897 {
5898   return (name[1] == '\0' ||                                    /* ${#} */
5899           ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') ||  /* special param */
5900           (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
5901 #if defined (ARRAY_VARS)
5902           valid_array_reference (name + 1) ||                   /* ${#a[7]} */
5903 #endif
5904           legal_identifier (name + 1));                         /* ${#PS1} */
5905 }
5906
5907 /* Handle the parameter brace expansion that requires us to return the
5908    length of a parameter. */
5909 static intmax_t
5910 parameter_brace_expand_length (name)
5911      char *name;
5912 {
5913   char *t, *newname;
5914   intmax_t number, arg_index;
5915   WORD_LIST *list;
5916 #if defined (ARRAY_VARS)
5917   SHELL_VAR *var;
5918 #endif
5919
5920   if (name[1] == '\0')                  /* ${#} */
5921     number = number_of_args ();
5922   else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0')       /* ${#@}, ${#*} */
5923     number = number_of_args ();
5924   else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
5925     {
5926       /* Take the lengths of some of the shell's special parameters. */
5927       switch (name[1])
5928         {
5929         case '-':
5930           t = which_set_flags ();
5931           break;
5932         case '?':
5933           t = itos (last_command_exit_value);
5934           break;
5935         case '$':
5936           t = itos (dollar_dollar_pid);
5937           break;
5938         case '!':
5939           if (last_asynchronous_pid == NO_PID)
5940             t = (char *)NULL;   /* XXX - error if set -u set? */
5941           else
5942             t = itos (last_asynchronous_pid);
5943           break;
5944         case '#':
5945           t = itos (number_of_args ());
5946           break;
5947         }
5948       number = STRLEN (t);
5949       FREE (t);
5950     }
5951 #if defined (ARRAY_VARS)
5952   else if (valid_array_reference (name + 1))
5953     number = array_length_reference (name + 1);
5954 #endif /* ARRAY_VARS */
5955   else
5956     {
5957       number = 0;
5958
5959       if (legal_number (name + 1, &arg_index))          /* ${#1} */
5960         {
5961           t = get_dollar_var_value (arg_index);
5962           if (t == 0 && unbound_vars_is_error)
5963             return INTMAX_MIN;
5964           number = MB_STRLEN (t);
5965           FREE (t);
5966         }
5967 #if defined (ARRAY_VARS)
5968       else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
5969         {
5970           if (assoc_p (var))
5971             t = assoc_reference (assoc_cell (var), "0");
5972           else
5973             t = array_reference (array_cell (var), 0);
5974           if (t == 0 && unbound_vars_is_error)
5975             return INTMAX_MIN;
5976           number = MB_STRLEN (t);
5977         }
5978 #endif
5979       else                              /* ${#PS1} */
5980         {
5981           newname = savestring (name);
5982           newname[0] = '$';
5983           list = expand_string (newname, Q_DOUBLE_QUOTES);
5984           t = list ? string_list (list) : (char *)NULL;
5985           free (newname);
5986           if (list)
5987             dispose_words (list);
5988
5989           number = t ? MB_STRLEN (t) : 0;
5990           FREE (t);
5991         }
5992     }
5993
5994   return (number);
5995 }
5996
5997 /* Skip characters in SUBSTR until DELIM.  SUBSTR is an arithmetic expression,
5998    so we do some ad-hoc parsing of an arithmetic expression to find
5999    the first DELIM, instead of using strchr(3).  Two rules:
6000         1.  If the substring contains a `(', read until closing `)'.
6001         2.  If the substring contains a `?', read past one `:' for each `?'.
6002 */
6003
6004 static char *
6005 skiparith (substr, delim)
6006      char *substr;
6007      int delim;
6008 {
6009   size_t sublen;
6010   int skipcol, pcount, i;
6011   DECLARE_MBSTATE;
6012
6013   sublen = strlen (substr);
6014   i = skipcol = pcount = 0;
6015   while (substr[i])
6016     {
6017       /* Balance parens */
6018       if (substr[i] == LPAREN)
6019         {
6020           pcount++;
6021           i++;
6022           continue;
6023         }
6024       if (substr[i] == RPAREN && pcount)
6025         {
6026           pcount--;
6027           i++;
6028           continue;
6029         }
6030       if (pcount)
6031         {
6032           ADVANCE_CHAR (substr, sublen, i);
6033           continue;
6034         }
6035
6036       /* Skip one `:' for each `?' */
6037       if (substr[i] == ':' && skipcol)
6038         {
6039           skipcol--;
6040           i++;
6041           continue;
6042         }
6043       if (substr[i] == delim)
6044         break;
6045       if (substr[i] == '?')
6046         {
6047           skipcol++;
6048           i++;
6049           continue;
6050         }
6051       ADVANCE_CHAR (substr, sublen, i);
6052     }
6053
6054   return (substr + i);
6055 }
6056
6057 /* Verify and limit the start and end of the desired substring.  If
6058    VTYPE == 0, a regular shell variable is being used; if it is 1,
6059    then the positional parameters are being used; if it is 2, then
6060    VALUE is really a pointer to an array variable that should be used.
6061    Return value is 1 if both values were OK, 0 if there was a problem
6062    with an invalid expression, or -1 if the values were out of range. */
6063 static int
6064 verify_substring_values (v, value, substr, vtype, e1p, e2p)
6065      SHELL_VAR *v;
6066      char *value, *substr;
6067      int vtype;
6068      intmax_t *e1p, *e2p;
6069 {
6070   char *t, *temp1, *temp2;
6071   arrayind_t len;
6072   int expok;
6073 #if defined (ARRAY_VARS)
6074  ARRAY *a;
6075  HASH_TABLE *h;
6076 #endif
6077
6078   /* duplicate behavior of strchr(3) */
6079   t = skiparith (substr, ':');
6080   if (*t && *t == ':')
6081     *t = '\0';
6082   else
6083     t = (char *)0;
6084
6085   temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES);
6086   *e1p = evalexp (temp1, &expok);
6087   free (temp1);
6088   if (expok == 0)
6089     return (0);
6090
6091   len = -1;     /* paranoia */
6092   switch (vtype)
6093     {
6094     case VT_VARIABLE:
6095     case VT_ARRAYMEMBER:
6096       len = MB_STRLEN (value);
6097       break;
6098     case VT_POSPARMS:
6099       len = number_of_args () + 1;
6100       if (*e1p == 0)
6101         len++;          /* add one arg if counting from $0 */
6102       break;
6103 #if defined (ARRAY_VARS)
6104     case VT_ARRAYVAR:
6105       /* For arrays, the first value deals with array indices.  Negative
6106          offsets count from one past the array's maximum index.  Associative
6107          arrays treat the number of elements as the maximum index. */
6108       if (assoc_p (v))
6109         {
6110           h = assoc_cell (v);
6111           len = assoc_num_elements (h) + (*e1p < 0);
6112         }
6113       else
6114         {
6115           a = (ARRAY *)value;
6116           len = array_max_index (a) + (*e1p < 0);       /* arrays index from 0 to n - 1 */
6117         }
6118       break;
6119 #endif
6120     }
6121
6122   if (len == -1)        /* paranoia */
6123     return -1;
6124
6125   if (*e1p < 0)         /* negative offsets count from end */
6126     *e1p += len;
6127
6128   if (*e1p > len || *e1p < 0)
6129     return (-1);
6130
6131 #if defined (ARRAY_VARS)
6132   /* For arrays, the second offset deals with the number of elements. */
6133   if (vtype == VT_ARRAYVAR)
6134     len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
6135 #endif
6136
6137   if (t)
6138     {
6139       t++;
6140       temp2 = savestring (t);
6141       temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
6142       free (temp2);
6143       t[-1] = ':';
6144       *e2p = evalexp (temp1, &expok);
6145       free (temp1);
6146       if (expok == 0)
6147         return (0);
6148       if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
6149         {
6150           internal_error (_("%s: substring expression < 0"), t);
6151           return (0);
6152         }
6153 #if defined (ARRAY_VARS)
6154       /* In order to deal with sparse arrays, push the intelligence about how
6155          to deal with the number of elements desired down to the array-
6156          specific functions.  */
6157       if (vtype != VT_ARRAYVAR)
6158 #endif
6159         {
6160           if (*e2p < 0)
6161             {
6162               *e2p += len;
6163               if (*e2p < 0 || *e2p < *e1p)
6164                 {
6165                   internal_error (_("%s: substring expression < 0"), t);
6166                   return (0);
6167                 }
6168             }
6169           else
6170             *e2p += *e1p;               /* want E2 chars starting at E1 */
6171           if (*e2p > len)
6172             *e2p = len;
6173         }
6174     }
6175   else
6176     *e2p = len;
6177
6178   return (1);
6179 }
6180
6181 /* Return the type of variable specified by VARNAME (simple variable,
6182    positional param, or array variable).  Also return the value specified
6183    by VARNAME (value of a variable or a reference to an array element).
6184    QUOTED is the standard description of quoting state, using Q_* defines.
6185    FLAGS is currently a set of flags to pass to array_value.  If IND is
6186    non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
6187    passed to array_value so the array index is not computed again.
6188    If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
6189    characters in the value are quoted with CTLESC and takes appropriate
6190    steps.  For convenience, *VALP is set to the dequoted VALUE. */
6191 static int
6192 get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
6193      char *varname, *value;
6194      arrayind_t ind;
6195      int quoted, flags;
6196      SHELL_VAR **varp;
6197      char **valp;
6198 {
6199   int vtype;
6200   char *temp;
6201 #if defined (ARRAY_VARS)
6202   SHELL_VAR *v;
6203 #endif
6204   arrayind_t lind;
6205
6206   /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
6207   vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0';
6208   if (vtype == VT_POSPARMS && varname[0] == '*')
6209     vtype |= VT_STARSUB;
6210   *varp = (SHELL_VAR *)NULL;
6211
6212 #if defined (ARRAY_VARS)
6213   if (valid_array_reference (varname))
6214     {
6215       v = array_variable_part (varname, &temp, (int *)0);
6216       /* If we want to signal array_value to use an already-computed index,
6217          set LIND to that index */
6218       lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0;
6219       if (v && (array_p (v) || assoc_p (v)))
6220         { /* [ */
6221           if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
6222             {
6223               /* Callers have to differentiate betwen indexed and associative */
6224               vtype = VT_ARRAYVAR;
6225               if (temp[0] == '*')
6226                 vtype |= VT_STARSUB;
6227               *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
6228             }
6229           else
6230             {
6231               vtype = VT_ARRAYMEMBER;
6232               *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
6233             }
6234           *varp = v;
6235         }
6236       else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']'))
6237         {
6238           vtype = VT_VARIABLE;
6239           *varp = v;
6240           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6241             *valp = dequote_string (value);
6242           else
6243             *valp = dequote_escapes (value);
6244         }
6245       else
6246         {
6247           vtype = VT_ARRAYMEMBER;
6248           *varp = v;
6249           *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
6250         }
6251     }
6252   else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
6253     {
6254       vtype = VT_ARRAYMEMBER;
6255       *varp = v;
6256       *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
6257     }
6258   else
6259 #endif
6260     {
6261       if (value && vtype == VT_VARIABLE)
6262         {
6263           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6264             *valp = dequote_string (value);
6265           else
6266             *valp = dequote_escapes (value);
6267         }
6268       else
6269         *valp = value;
6270     }
6271
6272   return vtype;
6273 }
6274
6275 /******************************************************/
6276 /*                                                    */
6277 /* Functions to extract substrings of variable values */
6278 /*                                                    */
6279 /******************************************************/
6280
6281 #if defined (HANDLE_MULTIBYTE)
6282 /* Character-oriented rather than strictly byte-oriented substrings.  S and
6283    E, rather being strict indices into STRING, indicate character (possibly
6284    multibyte character) positions that require calculation.
6285    Used by the ${param:offset[:length]} expansion. */
6286 static char *
6287 mb_substring (string, s, e)
6288      char *string;
6289      int s, e;
6290 {
6291   char *tt;
6292   int start, stop, i, slen;
6293   DECLARE_MBSTATE;
6294
6295   start = 0;
6296   /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
6297   slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
6298
6299   i = s;
6300   while (string[start] && i--)
6301     ADVANCE_CHAR (string, slen, start);
6302   stop = start;
6303   i = e - s;
6304   while (string[stop] && i--)
6305     ADVANCE_CHAR (string, slen, stop);
6306   tt = substring (string, start, stop);
6307   return tt;
6308 }
6309 #endif
6310   
6311 /* Process a variable substring expansion: ${name:e1[:e2]}.  If VARNAME
6312    is `@', use the positional parameters; otherwise, use the value of
6313    VARNAME.  If VARNAME is an array variable, use the array elements. */
6314
6315 static char *
6316 parameter_brace_substring (varname, value, ind, substr, quoted, flags)
6317      char *varname, *value;
6318      int ind;
6319      char *substr;
6320      int quoted, flags;
6321 {
6322   intmax_t e1, e2;
6323   int vtype, r, starsub;
6324   char *temp, *val, *tt, *oname;
6325   SHELL_VAR *v;
6326
6327   if (value == 0)
6328     return ((char *)NULL);
6329
6330   oname = this_command_name;
6331   this_command_name = varname;
6332
6333   vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
6334   if (vtype == -1)
6335     {
6336       this_command_name = oname;
6337       return ((char *)NULL);
6338     }
6339
6340   starsub = vtype & VT_STARSUB;
6341   vtype &= ~VT_STARSUB;
6342
6343   r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
6344   this_command_name = oname;
6345   if (r <= 0)
6346     return ((r == 0) ? &expand_param_error : (char *)NULL);
6347
6348   switch (vtype)
6349     {
6350     case VT_VARIABLE:
6351     case VT_ARRAYMEMBER:
6352 #if defined (HANDLE_MULTIBYTE)
6353       if (MB_CUR_MAX > 1)
6354         tt = mb_substring (val, e1, e2);
6355       else
6356 #endif
6357       tt = substring (val, e1, e2);
6358
6359       if (vtype == VT_VARIABLE)
6360         FREE (val);
6361       if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6362         temp = quote_string (tt);
6363       else
6364         temp = tt ? quote_escapes (tt) : (char *)NULL;
6365       FREE (tt);
6366       break;
6367     case VT_POSPARMS:
6368       tt = pos_params (varname, e1, e2, quoted);
6369       if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
6370         {
6371           temp = tt ? quote_escapes (tt) : (char *)NULL;
6372           FREE (tt);
6373         }
6374       else
6375         temp = tt;
6376       break;
6377 #if defined (ARRAY_VARS)
6378     case VT_ARRAYVAR:
6379       if (assoc_p (v))
6380         /* we convert to list and take first e2 elements starting at e1th
6381            element -- officially undefined for now */   
6382         temp = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted);
6383       else
6384       /* We want E2 to be the number of elements desired (arrays can be sparse,
6385          so verify_substring_values just returns the numbers specified and we
6386          rely on array_subrange to understand how to deal with them). */
6387         temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
6388       /* array_subrange now calls array_quote_escapes as appropriate, so the
6389          caller no longer needs to. */
6390       break;
6391 #endif
6392     default:
6393       temp = (char *)NULL;
6394     }
6395
6396   return temp;
6397 }
6398
6399 /****************************************************************/
6400 /*                                                              */
6401 /* Functions to perform pattern substitution on variable values */
6402 /*                                                              */
6403 /****************************************************************/
6404
6405 static int
6406 shouldexp_replacement (s)
6407      char *s;
6408 {
6409   register char *p;
6410
6411   for (p = s; p && *p; p++)
6412     {
6413       if (*p == '\\')
6414         p++;
6415       else if (*p == '&')
6416         return 1;
6417     }
6418   return 0;
6419 }
6420
6421 char *
6422 pat_subst (string, pat, rep, mflags)
6423      char *string, *pat, *rep;
6424      int mflags;
6425 {
6426   char *ret, *s, *e, *str, *rstr, *mstr;
6427   int rsize, rptr, l, replen, mtype, rxpand, rslen, mlen;
6428
6429   if (string  == 0)
6430     return (savestring (""));
6431
6432   mtype = mflags & MATCH_TYPEMASK;
6433
6434 #if 0   /* bash-4.2 ? */
6435   rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0;
6436 #else
6437   rxpand = 0;
6438 #endif
6439
6440   /* Special cases:
6441    *    1.  A null pattern with mtype == MATCH_BEG means to prefix STRING
6442    *        with REP and return the result.
6443    *    2.  A null pattern with mtype == MATCH_END means to append REP to
6444    *        STRING and return the result.
6445    * These don't understand or process `&' in the replacement string.
6446    */
6447   if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
6448     {
6449       replen = STRLEN (rep);
6450       l = STRLEN (string);
6451       ret = (char *)xmalloc (replen + l + 2);
6452       if (replen == 0)
6453         strcpy (ret, string);
6454       else if (mtype == MATCH_BEG)
6455         {
6456           strcpy (ret, rep);
6457           strcpy (ret + replen, string);
6458         }
6459       else
6460         {
6461           strcpy (ret, string);
6462           strcpy (ret + l, rep);
6463         }
6464       return (ret);
6465     }
6466
6467   ret = (char *)xmalloc (rsize = 64);
6468   ret[0] = '\0';
6469
6470   for (replen = STRLEN (rep), rptr = 0, str = string;;)
6471     {
6472       if (match_pattern (str, pat, mtype, &s, &e) == 0)
6473         break;
6474       l = s - str;
6475
6476       if (rxpand)
6477         {
6478           int x;
6479           mlen = e - s;
6480           mstr = xmalloc (mlen + 1);
6481           for (x = 0; x < mlen; x++)
6482             mstr[x] = s[x];
6483           mstr[mlen] = '\0';
6484           rstr = strcreplace (rep, '&', mstr, 0);
6485           rslen = strlen (rstr);
6486         }
6487       else
6488         {
6489           rstr = rep;
6490           rslen = replen;
6491         }
6492         
6493       RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
6494
6495       /* OK, now copy the leading unmatched portion of the string (from
6496          str to s) to ret starting at rptr (the current offset).  Then copy
6497          the replacement string at ret + rptr + (s - str).  Increment
6498          rptr (if necessary) and str and go on. */
6499       if (l)
6500         {
6501           strncpy (ret + rptr, str, l);
6502           rptr += l;
6503         }
6504       if (replen)
6505         {
6506           strncpy (ret + rptr, rstr, rslen);
6507           rptr += rslen;
6508         }
6509       str = e;          /* e == end of match */
6510
6511       if (rstr != rep)
6512         free (rstr);
6513
6514       if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
6515         break;
6516
6517       if (s == e)
6518         {
6519           /* On a zero-length match, make sure we copy one character, since
6520              we increment one character to avoid infinite recursion. */
6521           RESIZE_MALLOCED_BUFFER (ret, rptr, 1, rsize, 64);
6522           ret[rptr++] = *str++;
6523           e++;          /* avoid infinite recursion on zero-length match */
6524         }
6525     }
6526
6527   /* Now copy the unmatched portion of the input string */
6528   if (str && *str)
6529     {
6530       RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
6531       strcpy (ret + rptr, str);
6532     }
6533   else
6534     ret[rptr] = '\0';
6535
6536   return ret;
6537 }
6538
6539 /* Do pattern match and replacement on the positional parameters. */
6540 static char *
6541 pos_params_pat_subst (string, pat, rep, mflags)
6542      char *string, *pat, *rep;
6543      int mflags;
6544 {
6545   WORD_LIST *save, *params;
6546   WORD_DESC *w;
6547   char *ret;
6548   int pchar, qflags;
6549
6550   save = params = list_rest_of_args ();
6551   if (save == 0)
6552     return ((char *)NULL);
6553
6554   for ( ; params; params = params->next)
6555     {
6556       ret = pat_subst (params->word->word, pat, rep, mflags);
6557       w = alloc_word_desc ();
6558       w->word = ret ? ret : savestring ("");
6559       dispose_word (params->word);
6560       params->word = w;
6561     }
6562
6563   pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6564   qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6565
6566 #if 0
6567   if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
6568     ret = string_list_dollar_star (quote_list (save));
6569   else if ((mflags & MATCH_STARSUB) == MATCH_STARSUB)
6570     ret = string_list_dollar_star (save);
6571   else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED)
6572     ret = string_list_dollar_at (save, qflags);
6573   else
6574     ret = string_list_dollar_star (save);
6575 #else
6576   ret = string_list_pos_params (pchar, save, qflags);
6577 #endif
6578
6579   dispose_words (save);
6580
6581   return (ret);
6582 }
6583
6584 /* Perform pattern substitution on VALUE, which is the expansion of
6585    VARNAME.  PATSUB is an expression supplying the pattern to match
6586    and the string to substitute.  QUOTED is a flags word containing
6587    the type of quoting currently in effect. */
6588 static char *
6589 parameter_brace_patsub (varname, value, ind, patsub, quoted, flags)
6590      char *varname, *value;
6591      int ind;
6592      char *patsub;
6593      int quoted, flags;
6594 {
6595   int vtype, mflags, starsub, delim;
6596   char *val, *temp, *pat, *rep, *p, *lpatsub, *tt;
6597   SHELL_VAR *v;
6598
6599   if (value == 0)
6600     return ((char *)NULL);
6601
6602   this_command_name = varname;
6603
6604   vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
6605   if (vtype == -1)
6606     return ((char *)NULL);
6607
6608   starsub = vtype & VT_STARSUB;
6609   vtype &= ~VT_STARSUB;
6610
6611   mflags = 0;
6612   if (patsub && *patsub == '/')
6613     {
6614       mflags |= MATCH_GLOBREP;
6615       patsub++;
6616     }
6617
6618   /* Malloc this because expand_string_if_necessary or one of the expansion
6619      functions in its call chain may free it on a substitution error. */
6620   lpatsub = savestring (patsub);
6621
6622   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6623     mflags |= MATCH_QUOTED;
6624
6625   if (starsub)
6626     mflags |= MATCH_STARSUB;
6627
6628   /* If the pattern starts with a `/', make sure we skip over it when looking
6629      for the replacement delimiter. */
6630 #if 0
6631   if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL))
6632     *rep++ = '\0';
6633   else
6634     rep = (char *)NULL;
6635 #else
6636   delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
6637   if (lpatsub[delim] == '/')
6638     {
6639       lpatsub[delim] = 0;
6640       rep = lpatsub + delim + 1;
6641     }
6642   else
6643     rep = (char *)NULL;
6644 #endif
6645
6646   if (rep && *rep == '\0')
6647     rep = (char *)NULL;
6648
6649   /* Perform the same expansions on the pattern as performed by the
6650      pattern removal expansions. */
6651   pat = getpattern (lpatsub, quoted, 1);
6652
6653   if (rep)
6654     {
6655       if ((mflags & MATCH_QUOTED) == 0)
6656         rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
6657       else
6658         rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
6659     }
6660
6661   /* ksh93 doesn't allow the match specifier to be a part of the expanded
6662      pattern.  This is an extension.  Make sure we don't anchor the pattern
6663      at the beginning or end of the string if we're doing global replacement,
6664      though. */
6665   p = pat;
6666   if (mflags & MATCH_GLOBREP)
6667     mflags |= MATCH_ANY;
6668   else if (pat && pat[0] == '#')
6669     {
6670       mflags |= MATCH_BEG;
6671       p++;
6672     }
6673   else if (pat && pat[0] == '%')
6674     {
6675       mflags |= MATCH_END;
6676       p++;
6677     }
6678   else
6679     mflags |= MATCH_ANY;
6680
6681   /* OK, we now want to substitute REP for PAT in VAL.  If
6682      flags & MATCH_GLOBREP is non-zero, the substitution is done
6683      everywhere, otherwise only the first occurrence of PAT is
6684      replaced.  The pattern matching code doesn't understand
6685      CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
6686      values passed in (VT_VARIABLE) so the pattern substitution
6687      code works right.  We need to requote special chars after
6688      we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
6689      other cases if QUOTED == 0, since the posparams and arrays
6690      indexed by * or @ do special things when QUOTED != 0. */
6691
6692   switch (vtype)
6693     {
6694     case VT_VARIABLE:
6695     case VT_ARRAYMEMBER:
6696       temp = pat_subst (val, p, rep, mflags);
6697       if (vtype == VT_VARIABLE)
6698         FREE (val);
6699       if (temp)
6700         {
6701           tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
6702           free (temp);
6703           temp = tt;
6704         }
6705       break;
6706     case VT_POSPARMS:
6707       temp = pos_params_pat_subst (val, p, rep, mflags);
6708       if (temp && (mflags & MATCH_QUOTED) == 0)
6709         {
6710           tt = quote_escapes (temp);
6711           free (temp);
6712           temp = tt;
6713         }
6714       break;
6715 #if defined (ARRAY_VARS)
6716     case VT_ARRAYVAR:
6717       temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags)
6718                          : array_patsub (array_cell (v), p, rep, mflags);
6719       /* Don't call quote_escapes anymore; array_patsub calls
6720          array_quote_escapes as appropriate before adding the
6721          space separators; ditto for assoc_patsub. */
6722       break;
6723 #endif
6724     }
6725
6726   FREE (pat);
6727   FREE (rep);
6728   free (lpatsub);
6729
6730   return temp;
6731 }
6732
6733 /****************************************************************/
6734 /*                                                              */
6735 /*   Functions to perform case modification on variable values  */
6736 /*                                                              */
6737 /****************************************************************/
6738
6739 /* Do case modification on the positional parameters. */
6740
6741 static char *
6742 pos_params_modcase (string, pat, modop, mflags)
6743      char *string, *pat;
6744      int modop;
6745      int mflags;
6746 {
6747   WORD_LIST *save, *params;
6748   WORD_DESC *w;
6749   char *ret;
6750   int pchar, qflags;
6751
6752   save = params = list_rest_of_args ();
6753   if (save == 0)
6754     return ((char *)NULL);
6755
6756   for ( ; params; params = params->next)
6757     {
6758       ret = sh_modcase (params->word->word, pat, modop);
6759       w = alloc_word_desc ();
6760       w->word = ret ? ret : savestring ("");
6761       dispose_word (params->word);
6762       params->word = w;
6763     }
6764
6765   pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6766   qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6767
6768   ret = string_list_pos_params (pchar, save, qflags);
6769   dispose_words (save);
6770
6771   return (ret);
6772 }
6773
6774 /* Perform case modification on VALUE, which is the expansion of
6775    VARNAME.  MODSPEC is an expression supplying the type of modification
6776    to perform.  QUOTED is a flags word containing the type of quoting
6777    currently in effect. */
6778 static char *
6779 parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, flags)
6780      char *varname, *value;
6781      int ind, modspec;
6782      char *patspec;
6783      int quoted, flags;
6784 {
6785   int vtype, starsub, modop, mflags, x;
6786   char *val, *temp, *pat, *p, *lpat, *tt;
6787   SHELL_VAR *v;
6788
6789   if (value == 0)
6790     return ((char *)NULL);
6791
6792   this_command_name = varname;
6793
6794   vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
6795   if (vtype == -1)
6796     return ((char *)NULL);
6797
6798   starsub = vtype & VT_STARSUB;
6799   vtype &= ~VT_STARSUB;
6800
6801   modop = 0;
6802   mflags = 0;
6803   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6804     mflags |= MATCH_QUOTED;
6805   if (starsub)
6806     mflags |= MATCH_STARSUB;
6807   
6808   p = patspec;
6809   if (modspec == '^')
6810     {
6811       x = p && p[0] == modspec;
6812       modop = x ? CASE_UPPER : CASE_UPFIRST;
6813       p += x;
6814     }
6815   else if (modspec == ',')
6816     {
6817       x = p && p[0] == modspec;
6818       modop = x ? CASE_LOWER : CASE_LOWFIRST;
6819       p += x;
6820     }
6821   else if (modspec == '~')
6822     {
6823       x = p && p[0] == modspec;
6824       modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
6825       p += x;
6826     }
6827     
6828   lpat = p ? savestring (p) : 0;
6829   /* Perform the same expansions on the pattern as performed by the
6830      pattern removal expansions.  FOR LATER */
6831   pat = lpat ? getpattern (lpat, quoted, 1) : 0;
6832
6833   /* OK, now we do the case modification. */
6834   switch (vtype)
6835     {
6836     case VT_VARIABLE:
6837     case VT_ARRAYMEMBER:
6838       temp = sh_modcase (val, pat, modop);
6839       if (vtype == VT_VARIABLE)
6840         FREE (val);
6841       if (temp)
6842         {
6843           tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
6844           free (temp);
6845           temp = tt;
6846         }
6847       break;
6848
6849     case VT_POSPARMS:
6850       temp = pos_params_modcase (val, pat, modop, mflags);
6851       if (temp && (mflags & MATCH_QUOTED)  == 0)
6852         {
6853           tt = quote_escapes (temp);
6854           free (temp);
6855           temp = tt;
6856         }
6857       break;
6858
6859 #if defined (ARRAY_VARS)
6860     case VT_ARRAYVAR:
6861       temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
6862                          : array_modcase (array_cell (v), pat, modop, mflags);
6863       /* Don't call quote_escapes; array_modcase calls array_quote_escapes
6864          as appropriate before adding the space separators; ditto for
6865          assoc_modcase. */
6866       break;
6867 #endif
6868     }
6869
6870   FREE (pat);
6871   free (lpat);
6872
6873   return temp;
6874 }
6875
6876 /* Check for unbalanced parens in S, which is the contents of $(( ... )).  If
6877    any occur, this must be a nested command substitution, so return 0.
6878    Otherwise, return 1.  A valid arithmetic expression must always have a
6879    ( before a matching ), so any cases where there are more right parens
6880    means that this must not be an arithmetic expression, though the parser
6881    will not accept it without a balanced total number of parens. */
6882 static int
6883 chk_arithsub (s, len)
6884      const char *s;
6885      int len;
6886 {
6887   int i, count;
6888   DECLARE_MBSTATE;
6889
6890   i = count = 0;
6891   while (i < len)
6892     {
6893       if (s[i] == LPAREN)
6894         count++;
6895       else if (s[i] == RPAREN)
6896         {
6897           count--;
6898           if (count < 0)
6899             return 0;
6900         }
6901
6902       switch (s[i])
6903         {
6904         default:
6905           ADVANCE_CHAR (s, len, i);
6906           break;
6907
6908         case '\\':
6909           i++;
6910           if (s[i])
6911             ADVANCE_CHAR (s, len, i);
6912           break;
6913
6914         case '\'':
6915           i = skip_single_quoted (s, len, ++i);
6916           break;
6917
6918         case '"':
6919           i = skip_double_quoted ((char *)s, len, ++i);
6920           break;
6921         }
6922     }
6923
6924   return (count == 0);
6925 }
6926
6927 /****************************************************************/
6928 /*                                                              */
6929 /*      Functions to perform parameter expansion on a string    */
6930 /*                                                              */
6931 /****************************************************************/
6932
6933 /* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
6934 static WORD_DESC *
6935 parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
6936      char *string;
6937      int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at, pflags;
6938 {
6939   int check_nullness, var_is_set, var_is_null, var_is_special;
6940   int want_substring, want_indir, want_patsub, want_casemod;
6941   char *name, *value, *temp, *temp1;
6942   WORD_DESC *tdesc, *ret;
6943   int t_index, sindex, c, tflag, modspec;
6944   intmax_t number;
6945   arrayind_t ind;
6946
6947   temp = temp1 = value = (char *)NULL;
6948   var_is_set = var_is_null = var_is_special = check_nullness = 0;
6949   want_substring = want_indir = want_patsub = want_casemod = 0;
6950
6951   sindex = *indexp;
6952   t_index = ++sindex;
6953   /* ${#var} doesn't have any of the other parameter expansions on it. */
6954   if (string[t_index] == '#' && legal_variable_starter (string[t_index+1]))             /* {{ */
6955     name = string_extract (string, &t_index, "}", SX_VARNAME);
6956   else
6957 #if defined (CASEMOD_EXPANSIONS)
6958     /* To enable case-toggling expansions using the `~' operator character
6959        change the 1 to 0. */
6960 #  if defined (CASEMOD_CAPCASE)
6961     name = string_extract (string, &t_index, "#%^,~:-=?+/}", SX_VARNAME);
6962 #  else
6963     name = string_extract (string, &t_index, "#%^,:-=?+/}", SX_VARNAME);
6964 #  endif /* CASEMOD_CAPCASE */
6965 #else
6966     name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME);
6967 #endif /* CASEMOD_EXPANSIONS */
6968
6969   ret = 0;
6970   tflag = 0;
6971
6972   ind = INTMAX_MIN;
6973
6974   /* If the name really consists of a special variable, then make sure
6975      that we have the entire name.  We don't allow indirect references
6976      to special variables except `#', `?', `@' and `*'. */
6977   if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
6978       (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
6979     {
6980       t_index++;
6981       free (name);
6982       temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
6983       name = (char *)xmalloc (3 + (strlen (temp1)));
6984       *name = string[sindex];
6985       if (string[sindex] == '!')
6986         {
6987           /* indirect reference of $#, $?, $@, or $* */
6988           name[1] = string[sindex + 1];
6989           strcpy (name + 2, temp1);
6990         }
6991       else      
6992         strcpy (name + 1, temp1);
6993       free (temp1);
6994     }
6995   sindex = t_index;
6996
6997   /* Find out what character ended the variable name.  Then
6998      do the appropriate thing. */
6999   if (c = string[sindex])
7000     sindex++;
7001
7002   /* If c is followed by one of the valid parameter expansion
7003      characters, move past it as normal.  If not, assume that
7004      a substring specification is being given, and do not move
7005      past it. */
7006   if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
7007     {
7008       check_nullness++;
7009       if (c = string[sindex])
7010         sindex++;
7011     }
7012   else if (c == ':' && string[sindex] != RBRACE)
7013     want_substring = 1;
7014   else if (c == '/' && string[sindex] != RBRACE)
7015     want_patsub = 1;
7016 #if defined (CASEMOD_EXPANSIONS)
7017   else if (c == '^' || c == ',' || c == '~')
7018     {
7019       modspec = c;
7020       want_casemod = 1;
7021     }
7022 #endif
7023
7024   /* Catch the valid and invalid brace expressions that made it through the
7025      tests above. */
7026   /* ${#-} is a valid expansion and means to take the length of $-.
7027      Similarly for ${#?} and ${##}... */
7028   if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
7029         VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
7030     {
7031       name = (char *)xrealloc (name, 3);
7032       name[1] = c;
7033       name[2] = '\0';
7034       c = string[sindex++];
7035     }
7036
7037   /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
7038   if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
7039         member (c, "%:=+/") && string[sindex] == RBRACE)
7040     {
7041       temp = (char *)NULL;
7042       goto bad_substitution;
7043     }
7044
7045   /* Indirect expansion begins with a `!'.  A valid indirect expansion is
7046      either a variable name, one of the positional parameters or a special
7047      variable that expands to one of the positional parameters. */
7048   want_indir = *name == '!' &&
7049     (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
7050                                         || VALID_INDIR_PARAM (name[1]));
7051
7052   /* Determine the value of this variable. */
7053
7054   /* Check for special variables, directly referenced. */
7055   if (SPECIAL_VAR (name, want_indir))
7056     var_is_special++;
7057
7058   /* Check for special expansion things, like the length of a parameter */
7059   if (*name == '#' && name[1])
7060     {
7061       /* If we are not pointing at the character just after the
7062          closing brace, then we haven't gotten all of the name.
7063          Since it begins with a special character, this is a bad
7064          substitution.  Also check NAME for validity before trying
7065          to go on. */
7066       if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
7067         {
7068           temp = (char *)NULL;
7069           goto bad_substitution;
7070         }
7071
7072       number = parameter_brace_expand_length (name);
7073       if (number == INTMAX_MIN && unbound_vars_is_error)
7074         {
7075           last_command_exit_value = EXECUTION_FAILURE;
7076           err_unboundvar (name+1);
7077           free (name);
7078           return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7079         }
7080       free (name);
7081
7082       *indexp = sindex;
7083       if (number < 0)
7084         return (&expand_wdesc_error);
7085       else
7086         {
7087           ret = alloc_word_desc ();
7088           ret->word = itos (number);
7089           return ret;
7090         }
7091     }
7092
7093   /* ${@} is identical to $@. */
7094   if (name[0] == '@' && name[1] == '\0')
7095     {
7096       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7097         *quoted_dollar_atp = 1;
7098
7099       if (contains_dollar_at)
7100         *contains_dollar_at = 1;
7101     }
7102
7103   /* Process ${!PREFIX*} expansion. */
7104   if (want_indir && string[sindex - 1] == RBRACE &&
7105       (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
7106       legal_variable_starter ((unsigned char) name[1]))
7107     {
7108       char **x;
7109       WORD_LIST *xlist;
7110
7111       temp1 = savestring (name + 1);
7112       number = strlen (temp1);
7113       temp1[number - 1] = '\0';
7114       x = all_variables_matching_prefix (temp1);
7115       xlist = strvec_to_word_list (x, 0, 0);
7116       if (string[sindex - 2] == '*')
7117         temp = string_list_dollar_star (xlist);
7118       else
7119         {
7120           temp = string_list_dollar_at (xlist, quoted);
7121           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7122             *quoted_dollar_atp = 1;
7123           if (contains_dollar_at)
7124             *contains_dollar_at = 1;
7125         }
7126       free (x);
7127       dispose_words (xlist);
7128       free (temp1);
7129       *indexp = sindex;
7130
7131       ret = alloc_word_desc ();
7132       ret->word = temp;
7133       return ret;
7134     }
7135
7136 #if defined (ARRAY_VARS)      
7137   /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */
7138   if (want_indir && string[sindex - 1] == RBRACE &&
7139       string[sindex - 2] == ']' && valid_array_reference (name+1))
7140     {
7141       char *x, *x1;
7142
7143       temp1 = savestring (name + 1);
7144       x = array_variable_name (temp1, &x1, (int *)0);   /* [ */
7145       FREE (x);
7146       if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']')
7147         {
7148           temp = array_keys (temp1, quoted);    /* handles assoc vars too */
7149           if (x1[0] == '@')
7150             {
7151               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7152                 *quoted_dollar_atp = 1;
7153               if (contains_dollar_at)
7154                 *contains_dollar_at = 1;
7155             }       
7156
7157           free (temp1);
7158           *indexp = sindex;
7159
7160           ret = alloc_word_desc ();
7161           ret->word = temp;
7162           return ret;
7163         }
7164
7165       free (temp1);
7166     }
7167 #endif /* ARRAY_VARS */
7168       
7169   /* Make sure that NAME is valid before trying to go on. */
7170   if (valid_brace_expansion_word (want_indir ? name + 1 : name,
7171                                         var_is_special) == 0)
7172     {
7173       temp = (char *)NULL;
7174       goto bad_substitution;
7175     }
7176
7177   if (want_indir)
7178     tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
7179   else
7180     tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&PF_NOSPLIT2), &ind);
7181
7182   if (tdesc)
7183     {
7184       temp = tdesc->word;
7185       tflag = tdesc->flags;
7186       dispose_word_desc (tdesc);
7187     }
7188   else
7189     temp = (char  *)0;
7190
7191 #if defined (ARRAY_VARS)
7192   if (valid_array_reference (name))
7193     chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at);
7194 #endif
7195
7196   var_is_set = temp != (char *)0;
7197   var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
7198
7199   /* Get the rest of the stuff inside the braces. */
7200   if (c && c != RBRACE)
7201     {
7202       /* Extract the contents of the ${ ... } expansion
7203          according to the Posix.2 rules. */
7204       value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
7205       if (string[sindex] == RBRACE)
7206         sindex++;
7207       else
7208         goto bad_substitution;
7209     }
7210   else
7211     value = (char *)NULL;
7212
7213   *indexp = sindex;
7214
7215   /* All the cases where an expansion can possibly generate an unbound
7216      variable error. */
7217   if (want_substring || want_patsub || want_casemod || c == '#' || c == '%' || c == RBRACE)
7218     {
7219       if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
7220         {
7221           last_command_exit_value = EXECUTION_FAILURE;
7222           err_unboundvar (name);
7223           FREE (value);
7224           FREE (temp);
7225           free (name);
7226           return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7227         }
7228     }
7229     
7230   /* If this is a substring spec, process it and add the result. */
7231   if (want_substring)
7232     {
7233       temp1 = parameter_brace_substring (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7234       FREE (name);
7235       FREE (value);
7236       FREE (temp);
7237
7238       if (temp1 == &expand_param_error)
7239         return (&expand_wdesc_error);
7240       else if (temp1 == &expand_param_fatal)
7241         return (&expand_wdesc_fatal);
7242
7243       ret = alloc_word_desc ();
7244       ret->word = temp1;
7245       if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7246         ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7247       return ret;
7248     }
7249   else if (want_patsub)
7250     {
7251       temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7252       FREE (name);
7253       FREE (value);
7254       FREE (temp);
7255
7256       if (temp1 == &expand_param_error)
7257         return (&expand_wdesc_error);
7258       else if (temp1 == &expand_param_fatal)
7259         return (&expand_wdesc_fatal);
7260
7261       ret = alloc_word_desc ();
7262       ret->word = temp1;
7263       ret = alloc_word_desc ();
7264       ret->word = temp1;
7265       if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7266         ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7267       return ret;
7268     }
7269 #if defined (CASEMOD_EXPANSIONS)
7270   else if (want_casemod)
7271     {
7272       temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7273       FREE (name);
7274       FREE (value);
7275       FREE (temp);
7276
7277       if (temp1 == &expand_param_error)
7278         return (&expand_wdesc_error);
7279       else if (temp1 == &expand_param_fatal)
7280         return (&expand_wdesc_fatal);
7281
7282       ret = alloc_word_desc ();
7283       ret->word = temp1;
7284       if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7285         ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7286       return ret;
7287     }
7288 #endif
7289
7290   /* Do the right thing based on which character ended the variable name. */
7291   switch (c)
7292     {
7293     default:
7294     case '\0':
7295     bad_substitution:
7296       last_command_exit_value = EXECUTION_FAILURE;
7297       report_error (_("%s: bad substitution"), string ? string : "??");
7298       FREE (value);
7299       FREE (temp);
7300       free (name);
7301       return &expand_wdesc_error;
7302
7303     case RBRACE:
7304       break;
7305
7306     case '#':   /* ${param#[#]pattern} */
7307     case '%':   /* ${param%[%]pattern} */
7308       if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
7309         {
7310           FREE (value);
7311           break;
7312         }
7313       temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7314       free (temp);
7315       free (value);
7316       free (name);
7317
7318       ret = alloc_word_desc ();
7319       ret->word = temp1;
7320       if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7321         ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7322       return ret;
7323
7324     case '-':
7325     case '=':
7326     case '?':
7327     case '+':
7328       if (var_is_set && var_is_null == 0)
7329         {
7330           /* If the operator is `+', we don't want the value of the named
7331              variable for anything, just the value of the right hand side. */
7332           if (c == '+')
7333             {
7334               /* XXX -- if we're double-quoted and the named variable is "$@",
7335                         we want to turn off any special handling of "$@" --
7336                         we're not using it, so whatever is on the rhs applies. */
7337               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7338                 *quoted_dollar_atp = 0;
7339               if (contains_dollar_at)
7340                 *contains_dollar_at = 0;
7341
7342               FREE (temp);
7343               if (value)
7344                 {
7345                   /* From Posix discussion on austin-group list.  Issue 221
7346                      requires that backslashes escaping `}' inside
7347                      double-quoted ${...} be removed. */
7348                   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7349                     quoted |= Q_DOLBRACE;
7350                   ret = parameter_brace_expand_rhs (name, value, c,
7351                                                     quoted,
7352                                                     quoted_dollar_atp,
7353                                                     contains_dollar_at);
7354                   /* XXX - fix up later, esp. noting presence of
7355                            W_HASQUOTEDNULL in ret->flags */
7356                   free (value);
7357                 }
7358               else
7359                 temp = (char *)NULL;
7360             }
7361           else
7362             {
7363               FREE (value);
7364             }
7365           /* Otherwise do nothing; just use the value in TEMP. */
7366         }
7367       else      /* VAR not set or VAR is NULL. */
7368         {
7369           FREE (temp);
7370           temp = (char *)NULL;
7371           if (c == '=' && var_is_special)
7372             {
7373               report_error (_("$%s: cannot assign in this way"), name);
7374               free (name);
7375               free (value);
7376               return &expand_wdesc_error;
7377             }
7378           else if (c == '?')
7379             {
7380               parameter_brace_expand_error (name, value);
7381               return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7382             }
7383           else if (c != '+')
7384             {
7385               /* XXX -- if we're double-quoted and the named variable is "$@",
7386                         we want to turn off any special handling of "$@" --
7387                         we're not using it, so whatever is on the rhs applies. */
7388               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7389                 *quoted_dollar_atp = 0;
7390               if (contains_dollar_at)
7391                 *contains_dollar_at = 0;
7392
7393               /* From Posix discussion on austin-group list.  Issue 221 requires
7394                  that backslashes escaping `}' inside double-quoted ${...} be
7395                  removed. */
7396               if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7397                 quoted |= Q_DOLBRACE;
7398               ret = parameter_brace_expand_rhs (name, value, c, quoted,
7399                                                 quoted_dollar_atp,
7400                                                 contains_dollar_at);
7401               /* XXX - fix up later, esp. noting presence of
7402                        W_HASQUOTEDNULL in tdesc->flags */
7403             }
7404           free (value);
7405         }
7406
7407       break;
7408     }
7409   free (name);
7410
7411   if (ret == 0)
7412     {
7413       ret = alloc_word_desc ();
7414       ret->flags = tflag;
7415       ret->word = temp;
7416     }
7417   return (ret);
7418 }
7419
7420 /* Expand a single ${xxx} expansion.  The braces are optional.  When
7421    the braces are used, parameter_brace_expand() does the work,
7422    possibly calling param_expand recursively. */
7423 static WORD_DESC *
7424 param_expand (string, sindex, quoted, expanded_something,
7425               contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
7426               pflags)
7427      char *string;
7428      int *sindex, quoted, *expanded_something, *contains_dollar_at;
7429      int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
7430 {
7431   char *temp, *temp1, uerror[3];
7432   int zindex, t_index, expok;
7433   unsigned char c;
7434   intmax_t number;
7435   SHELL_VAR *var;
7436   WORD_LIST *list;
7437   WORD_DESC *tdesc, *ret;
7438   int tflag;
7439
7440   zindex = *sindex;
7441   c = string[++zindex];
7442
7443   temp = (char *)NULL;
7444   ret = tdesc = (WORD_DESC *)NULL;
7445   tflag = 0;
7446
7447   /* Do simple cases first. Switch on what follows '$'. */
7448   switch (c)
7449     {
7450     /* $0 .. $9? */
7451     case '0':
7452     case '1':
7453     case '2':
7454     case '3':
7455     case '4':
7456     case '5':
7457     case '6':
7458     case '7':
7459     case '8':
7460     case '9':
7461       temp1 = dollar_vars[TODIGIT (c)];
7462       if (unbound_vars_is_error && temp1 == (char *)NULL)
7463         {
7464           uerror[0] = '$';
7465           uerror[1] = c;
7466           uerror[2] = '\0';
7467           last_command_exit_value = EXECUTION_FAILURE;
7468           err_unboundvar (uerror);
7469           return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7470         }
7471       if (temp1)
7472         temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7473                   ? quote_string (temp1)
7474                   : quote_escapes (temp1);
7475       else
7476         temp = (char *)NULL;
7477
7478       break;
7479
7480     /* $$ -- pid of the invoking shell. */
7481     case '$':
7482       temp = itos (dollar_dollar_pid);
7483       break;
7484
7485     /* $# -- number of positional parameters. */
7486     case '#':
7487       temp = itos (number_of_args ());
7488       break;
7489
7490     /* $? -- return value of the last synchronous command. */
7491     case '?':
7492       temp = itos (last_command_exit_value);
7493       break;
7494
7495     /* $- -- flags supplied to the shell on invocation or by `set'. */
7496     case '-':
7497       temp = which_set_flags ();
7498       break;
7499
7500       /* $! -- Pid of the last asynchronous command. */
7501     case '!':
7502       /* If no asynchronous pids have been created, expand to nothing.
7503          If `set -u' has been executed, and no async processes have
7504          been created, this is an expansion error. */
7505       if (last_asynchronous_pid == NO_PID)
7506         {
7507           if (expanded_something)
7508             *expanded_something = 0;
7509           temp = (char *)NULL;
7510           if (unbound_vars_is_error)
7511             {
7512               uerror[0] = '$';
7513               uerror[1] = c;
7514               uerror[2] = '\0';
7515               last_command_exit_value = EXECUTION_FAILURE;
7516               err_unboundvar (uerror);
7517               return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7518             }
7519         }
7520       else
7521         temp = itos (last_asynchronous_pid);
7522       break;
7523
7524     /* The only difference between this and $@ is when the arg is quoted. */
7525     case '*':           /* `$*' */
7526       list = list_rest_of_args ();
7527
7528 #if 0
7529       /* According to austin-group posix proposal by Geoff Clare in
7530          <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
7531
7532         "The shell shall write a message to standard error and
7533          immediately exit when it tries to expand an unset parameter
7534          other than the '@' and '*' special parameters."
7535       */
7536
7537       if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
7538         {
7539           uerror[0] = '$';
7540           uerror[1] = '*';
7541           uerror[2] = '\0';
7542           last_command_exit_value = EXECUTION_FAILURE;
7543           err_unboundvar (uerror);
7544           return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7545         }
7546 #endif
7547
7548       /* If there are no command-line arguments, this should just
7549          disappear if there are other characters in the expansion,
7550          even if it's quoted. */
7551       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
7552         temp = (char *)NULL;
7553       else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
7554         {
7555           /* If we have "$*" we want to make a string of the positional
7556              parameters, separated by the first character of $IFS, and
7557              quote the whole string, including the separators.  If IFS
7558              is unset, the parameters are separated by ' '; if $IFS is
7559              null, the parameters are concatenated. */
7560           temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list) : string_list (list);
7561           if (temp)
7562             {
7563               temp1 = quote_string (temp);
7564               if (*temp == 0)
7565                 tflag |= W_HASQUOTEDNULL;
7566               free (temp);
7567               temp = temp1;
7568             }
7569         }
7570       else
7571         {
7572           /* We check whether or not we're eventually going to split $* here,
7573              for example when IFS is empty and we are processing the rhs of
7574              an assignment statement.  In that case, we don't separate the
7575              arguments at all.  Otherwise, if the $* is not quoted it is
7576              identical to $@ */
7577 #if 1
7578 #  if defined (HANDLE_MULTIBYTE)
7579           if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
7580 #  else
7581           if (expand_no_split_dollar_star && ifs_firstc == 0)
7582 #  endif
7583             temp = string_list_dollar_star (list);
7584           else
7585             temp = string_list_dollar_at (list, quoted);
7586 #else
7587           temp = string_list_dollar_at (list, quoted);
7588 #endif
7589           if (expand_no_split_dollar_star == 0 && contains_dollar_at)
7590             *contains_dollar_at = 1;
7591         }
7592
7593       dispose_words (list);
7594       break;
7595
7596     /* When we have "$@" what we want is "$1" "$2" "$3" ... This
7597        means that we have to turn quoting off after we split into
7598        the individually quoted arguments so that the final split
7599        on the first character of $IFS is still done.  */
7600     case '@':           /* `$@' */
7601       list = list_rest_of_args ();
7602
7603 #if 0
7604       /* According to austin-group posix proposal by Geoff Clare in
7605          <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
7606
7607         "The shell shall write a message to standard error and
7608          immediately exit when it tries to expand an unset parameter
7609          other than the '@' and '*' special parameters."
7610       */
7611
7612       if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
7613         {
7614           uerror[0] = '$';
7615           uerror[1] = '@';
7616           uerror[2] = '\0';
7617           last_command_exit_value = EXECUTION_FAILURE;
7618           err_unboundvar (uerror);
7619           return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7620         }
7621 #endif
7622
7623       /* We want to flag the fact that we saw this.  We can't turn
7624          off quoting entirely, because other characters in the
7625          string might need it (consider "\"$@\""), but we need some
7626          way to signal that the final split on the first character
7627          of $IFS should be done, even though QUOTED is 1. */
7628       /* XXX - should this test include Q_PATQUOTE? */
7629       if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7630         *quoted_dollar_at_p = 1;
7631       if (contains_dollar_at)
7632         *contains_dollar_at = 1;
7633
7634 #if 0
7635       if (pflags & PF_NOSPLIT2)
7636         temp = string_list_internal (quoted ? quote_list (list) : list, " ");
7637       else
7638 #endif
7639       /* We want to separate the positional parameters with the first
7640          character of $IFS in case $IFS is something other than a space.
7641          We also want to make sure that splitting is done no matter what --
7642          according to POSIX.2, this expands to a list of the positional
7643          parameters no matter what IFS is set to. */
7644       temp = string_list_dollar_at (list, quoted);
7645
7646       dispose_words (list);
7647       break;
7648
7649     case LBRACE:
7650       tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
7651                                       quoted_dollar_at_p,
7652                                       contains_dollar_at);
7653
7654       if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
7655         return (tdesc);
7656       temp = tdesc ? tdesc->word : (char *)0;
7657
7658       /* XXX */
7659       /* Quoted nulls should be removed if there is anything else
7660          in the string. */
7661       /* Note that we saw the quoted null so we can add one back at
7662          the end of this function if there are no other characters
7663          in the string, discard TEMP, and go on.  The exception to
7664          this is when we have "${@}" and $1 is '', since $@ needs
7665          special handling. */
7666       if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
7667         {
7668           if (had_quoted_null_p)
7669             *had_quoted_null_p = 1;
7670           if (*quoted_dollar_at_p == 0)
7671             {
7672               free (temp);
7673               tdesc->word = temp = (char *)NULL;
7674             }
7675             
7676         }
7677
7678       ret = tdesc;
7679       goto return0;
7680
7681     /* Do command or arithmetic substitution. */
7682     case LPAREN:
7683       /* We have to extract the contents of this paren substitution. */
7684       t_index = zindex + 1;
7685       temp = extract_command_subst (string, &t_index, 0);
7686       zindex = t_index;
7687
7688       /* For Posix.2-style `$(( ))' arithmetic substitution,
7689          extract the expression and pass it to the evaluator. */
7690       if (temp && *temp == LPAREN)
7691         {
7692           char *temp2;
7693           temp1 = temp + 1;
7694           temp2 = savestring (temp1);
7695           t_index = strlen (temp2) - 1;
7696
7697           if (temp2[t_index] != RPAREN)
7698             {
7699               free (temp2);
7700               goto comsub;
7701             }
7702
7703           /* Cut off ending `)' */
7704           temp2[t_index] = '\0';
7705
7706           if (chk_arithsub (temp2, t_index) == 0)
7707             {
7708               free (temp2);
7709 #if 0
7710               internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
7711 #endif
7712               goto comsub;
7713             }
7714
7715           /* Expand variables found inside the expression. */
7716           temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
7717           free (temp2);
7718
7719 arithsub:
7720           /* No error messages. */
7721           this_command_name = (char *)NULL;
7722           number = evalexp (temp1, &expok);
7723           free (temp);
7724           free (temp1);
7725           if (expok == 0)
7726             {
7727               if (interactive_shell == 0 && posixly_correct)
7728                 {
7729                   last_command_exit_value = EXECUTION_FAILURE;
7730                   return (&expand_wdesc_fatal);
7731                 }
7732               else
7733                 return (&expand_wdesc_error);
7734             }
7735           temp = itos (number);
7736           break;
7737         }
7738
7739 comsub:
7740       if (pflags & PF_NOCOMSUB)
7741         /* we need zindex+1 because string[zindex] == RPAREN */
7742         temp1 = substring (string, *sindex, zindex+1);
7743       else
7744         {
7745           tdesc = command_substitute (temp, quoted);
7746           temp1 = tdesc ? tdesc->word : (char *)NULL;
7747           if (tdesc)
7748             dispose_word_desc (tdesc);
7749         }
7750       FREE (temp);
7751       temp = temp1;
7752       break;
7753
7754     /* Do POSIX.2d9-style arithmetic substitution.  This will probably go
7755        away in a future bash release. */
7756     case '[':
7757       /* Extract the contents of this arithmetic substitution. */
7758       t_index = zindex + 1;
7759       temp = extract_arithmetic_subst (string, &t_index);
7760       zindex = t_index;
7761       if (temp == 0)
7762         {
7763           temp = savestring (string);
7764           if (expanded_something)
7765             *expanded_something = 0;
7766           goto return0;
7767         }         
7768
7769        /* Do initial variable expansion. */
7770       temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES);
7771
7772       goto arithsub;
7773
7774     default:
7775       /* Find the variable in VARIABLE_LIST. */
7776       temp = (char *)NULL;
7777
7778       for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
7779         ;
7780       temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
7781
7782       /* If this isn't a variable name, then just output the `$'. */
7783       if (temp1 == 0 || *temp1 == '\0')
7784         {
7785           FREE (temp1);
7786           temp = (char *)xmalloc (2);
7787           temp[0] = '$';
7788           temp[1] = '\0';
7789           if (expanded_something)
7790             *expanded_something = 0;
7791           goto return0;
7792         }
7793
7794       /* If the variable exists, return its value cell. */
7795       var = find_variable (temp1);
7796
7797       if (var && invisible_p (var) == 0 && var_isset (var))
7798         {
7799 #if defined (ARRAY_VARS)
7800           if (assoc_p (var) || array_p (var))
7801             {
7802               temp = array_p (var) ? array_reference (array_cell (var), 0)
7803                                    : assoc_reference (assoc_cell (var), "0");
7804               if (temp)
7805                 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7806                           ? quote_string (temp)
7807                           : quote_escapes (temp);
7808               else if (unbound_vars_is_error)
7809                 goto unbound_variable;
7810             }
7811           else
7812 #endif
7813             {
7814               temp = value_cell (var);
7815
7816               temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7817                         ? quote_string (temp)
7818                         : quote_escapes (temp);
7819             }
7820
7821           free (temp1);
7822
7823           goto return0;
7824         }
7825
7826       temp = (char *)NULL;
7827
7828 unbound_variable:
7829       if (unbound_vars_is_error)
7830         {
7831           last_command_exit_value = EXECUTION_FAILURE;
7832           err_unboundvar (temp1);
7833         }
7834       else
7835         {
7836           free (temp1);
7837           goto return0;
7838         }
7839
7840       free (temp1);
7841       last_command_exit_value = EXECUTION_FAILURE;
7842       return ((unbound_vars_is_error && interactive_shell == 0)
7843                 ? &expand_wdesc_fatal
7844                 : &expand_wdesc_error);
7845     }
7846
7847   if (string[zindex])
7848     zindex++;
7849
7850 return0:
7851   *sindex = zindex;
7852
7853   if (ret == 0)
7854     {
7855       ret = alloc_word_desc ();
7856       ret->flags = tflag;       /* XXX */
7857       ret->word = temp;
7858     }
7859   return ret;
7860 }
7861
7862 /* Make a word list which is the result of parameter and variable
7863    expansion, command substitution, arithmetic substitution, and
7864    quote removal of WORD.  Return a pointer to a WORD_LIST which is
7865    the result of the expansion.  If WORD contains a null word, the
7866    word list returned is also null.
7867
7868    QUOTED contains flag values defined in shell.h.
7869
7870    ISEXP is used to tell expand_word_internal that the word should be
7871    treated as the result of an expansion.  This has implications for
7872    how IFS characters in the word are treated.
7873
7874    CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
7875    they point to an integer value which receives information about expansion.
7876    CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
7877    EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
7878    else zero.
7879
7880    This only does word splitting in the case of $@ expansion.  In that
7881    case, we split on ' '. */
7882
7883 /* Values for the local variable quoted_state. */
7884 #define UNQUOTED         0
7885 #define PARTIALLY_QUOTED 1
7886 #define WHOLLY_QUOTED    2
7887
7888 static WORD_LIST *
7889 expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
7890      WORD_DESC *word;
7891      int quoted, isexp;
7892      int *contains_dollar_at;
7893      int *expanded_something;
7894 {
7895   WORD_LIST *list;
7896   WORD_DESC *tword;
7897
7898   /* The intermediate string that we build while expanding. */
7899   char *istring;
7900
7901   /* The current size of the above object. */
7902   int istring_size;
7903
7904   /* Index into ISTRING. */
7905   int istring_index;
7906
7907   /* Temporary string storage. */
7908   char *temp, *temp1;
7909
7910   /* The text of WORD. */
7911   register char *string;
7912
7913   /* The size of STRING. */
7914   size_t string_size;
7915
7916   /* The index into STRING. */
7917   int sindex;
7918
7919   /* This gets 1 if we see a $@ while quoted. */
7920   int quoted_dollar_at;
7921
7922   /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
7923      whether WORD contains no quoting characters, a partially quoted
7924      string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
7925   int quoted_state;
7926
7927   /* State flags */
7928   int had_quoted_null;
7929   int has_dollar_at, temp_has_dollar_at;
7930   int tflag;
7931   int pflags;                   /* flags passed to param_expand */
7932
7933   int assignoff;                /* If assignment, offset of `=' */
7934
7935   register unsigned char c;     /* Current character. */
7936   int t_index;                  /* For calls to string_extract_xxx. */
7937
7938   char twochars[2];
7939
7940   DECLARE_MBSTATE;
7941
7942   istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
7943   istring[istring_index = 0] = '\0';
7944   quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
7945   quoted_state = UNQUOTED;
7946
7947   string = word->word;
7948   if (string == 0)
7949     goto finished_with_string;
7950   /* Don't need the string length for the SADD... and COPY_ macros unless
7951      multibyte characters are possible. */
7952   string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1;
7953
7954   if (contains_dollar_at)
7955     *contains_dollar_at = 0;
7956
7957   assignoff = -1;
7958
7959   /* Begin the expansion. */
7960
7961   for (sindex = 0; ;)
7962     {
7963       c = string[sindex];
7964
7965       /* Case on toplevel character. */
7966       switch (c)
7967         {
7968         case '\0':
7969           goto finished_with_string;
7970
7971         case CTLESC:
7972           sindex++;
7973 #if HANDLE_MULTIBYTE
7974           if (MB_CUR_MAX > 1 && string[sindex])
7975             {
7976               SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7977             }
7978           else
7979 #endif
7980             {
7981               temp = (char *)xmalloc (3);
7982               temp[0] = CTLESC;
7983               temp[1] = c = string[sindex];
7984               temp[2] = '\0';
7985             }
7986
7987 dollar_add_string:
7988           if (string[sindex])
7989             sindex++;
7990
7991 add_string:
7992           if (temp)
7993             {
7994               istring = sub_append_string (temp, istring, &istring_index, &istring_size);
7995               temp = (char *)0;
7996             }
7997
7998           break;
7999
8000 #if defined (PROCESS_SUBSTITUTION)
8001           /* Process substitution. */
8002         case '<':
8003         case '>':
8004           {
8005             if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || posixly_correct)
8006               {
8007                 sindex--;       /* add_character: label increments sindex */
8008                 goto add_character;
8009               }
8010             else
8011               t_index = sindex + 1; /* skip past both '<' and LPAREN */
8012
8013             temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/
8014             sindex = t_index;
8015
8016             /* If the process substitution specification is `<()', we want to
8017                open the pipe for writing in the child and produce output; if
8018                it is `>()', we want to open the pipe for reading in the child
8019                and consume input. */
8020             temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
8021
8022             FREE (temp1);
8023
8024             goto dollar_add_string;
8025           }
8026 #endif /* PROCESS_SUBSTITUTION */
8027
8028         case '=':
8029           /* Posix.2 section 3.6.1 says that tildes following `=' in words
8030              which are not assignment statements are not expanded.  If the
8031              shell isn't in posix mode, though, we perform tilde expansion
8032              on `likely candidate' unquoted assignment statements (flags
8033              include W_ASSIGNMENT but not W_QUOTED).  A likely candidate
8034              contains an unquoted :~ or =~.  Something to think about: we
8035              now have a flag that says  to perform tilde expansion on arguments
8036              to `assignment builtins' like declare and export that look like
8037              assignment statements.  We now do tilde expansion on such words
8038              even in POSIX mode. */     
8039           if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
8040             {
8041               if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8042                 goto add_ifs_character;
8043               else
8044                 goto add_character;
8045             }
8046           /* If we're not in posix mode or forcing assignment-statement tilde
8047              expansion, note where the `=' appears in the word and prepare to
8048              do tilde expansion following the first `='. */
8049           if ((word->flags & W_ASSIGNMENT) &&
8050               (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
8051               assignoff == -1 && sindex > 0)
8052             assignoff = sindex;
8053           if (sindex == assignoff && string[sindex+1] == '~')   /* XXX */
8054             word->flags |= W_ITILDE;
8055 #if 0
8056           else if ((word->flags & W_ASSIGNMENT) &&
8057                    (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
8058                    string[sindex+1] == '~')
8059             word->flags |= W_ITILDE;
8060 #endif
8061           if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8062             goto add_ifs_character;
8063           else
8064             goto add_character;
8065
8066         case ':':
8067           if (word->flags & W_NOTILDE)
8068             {
8069               if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8070                 goto add_ifs_character;
8071               else
8072                 goto add_character;
8073             }
8074
8075           if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) &&
8076               string[sindex+1] == '~')
8077             word->flags |= W_ITILDE;
8078
8079           if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8080             goto add_ifs_character;
8081           else
8082             goto add_character;
8083
8084         case '~':
8085           /* If the word isn't supposed to be tilde expanded, or we're not
8086              at the start of a word or after an unquoted : or = in an
8087              assignment statement, we don't do tilde expansion. */
8088           if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
8089               (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
8090               (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8091             {
8092               word->flags &= ~W_ITILDE;
8093               if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
8094                 goto add_ifs_character;
8095               else
8096                 goto add_character;
8097             }
8098
8099           if (word->flags & W_ASSIGNRHS)
8100             tflag = 2;
8101           else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
8102             tflag = 1;
8103           else
8104             tflag = 0;
8105
8106           temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
8107             
8108           word->flags &= ~W_ITILDE;
8109
8110           if (temp && *temp && t_index > 0)
8111             {
8112               temp1 = bash_tilde_expand (temp, tflag);
8113               if  (temp1 && *temp1 == '~' && STREQ (temp, temp1))
8114                 {
8115                   FREE (temp);
8116                   FREE (temp1);
8117                   goto add_character;           /* tilde expansion failed */
8118                 }
8119               free (temp);
8120               temp = temp1;
8121               sindex += t_index;
8122               goto add_quoted_string;           /* XXX was add_string */
8123             }
8124           else
8125             {
8126               FREE (temp);
8127               goto add_character;
8128             }
8129         
8130         case '$':
8131           if (expanded_something)
8132             *expanded_something = 1;
8133
8134           temp_has_dollar_at = 0;
8135           pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
8136           if (word->flags & W_NOSPLIT2)
8137             pflags |= PF_NOSPLIT2;
8138           tword = param_expand (string, &sindex, quoted, expanded_something,
8139                                &temp_has_dollar_at, &quoted_dollar_at,
8140                                &had_quoted_null, pflags);
8141           has_dollar_at += temp_has_dollar_at;
8142
8143           if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
8144             {
8145               free (string);
8146               free (istring);
8147               return ((tword == &expand_wdesc_error) ? &expand_word_error
8148                                                      : &expand_word_fatal);
8149             }
8150           if (contains_dollar_at && has_dollar_at)
8151             *contains_dollar_at = 1;
8152
8153           if (tword && (tword->flags & W_HASQUOTEDNULL))
8154             had_quoted_null = 1;
8155
8156           temp = tword->word;
8157           dispose_word_desc (tword);
8158
8159           /* Kill quoted nulls; we will add them back at the end of
8160              expand_word_internal if nothing else in the string */
8161           if (had_quoted_null && temp && QUOTED_NULL (temp))
8162             {
8163               FREE (temp);
8164               temp = (char *)NULL;
8165             }
8166
8167           goto add_string;
8168           break;
8169
8170         case '`':               /* Backquoted command substitution. */
8171           {
8172             t_index = sindex++;
8173
8174             temp = string_extract (string, &sindex, "`", SX_REQMATCH);
8175             /* The test of sindex against t_index is to allow bare instances of
8176                ` to pass through, for backwards compatibility. */
8177             if (temp == &extract_string_error || temp == &extract_string_fatal)
8178               {
8179                 if (sindex - 1 == t_index)
8180                   {
8181                     sindex = t_index;
8182                     goto add_character;
8183                   }
8184                 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
8185                 free (string);
8186                 free (istring);
8187                 return ((temp == &extract_string_error) ? &expand_word_error
8188                                                         : &expand_word_fatal);
8189               }
8190                 
8191             if (expanded_something)
8192               *expanded_something = 1;
8193
8194             if (word->flags & W_NOCOMSUB)
8195               /* sindex + 1 because string[sindex] == '`' */
8196               temp1 = substring (string, t_index, sindex + 1);
8197             else
8198               {
8199                 de_backslash (temp);
8200                 tword = command_substitute (temp, quoted);
8201                 temp1 = tword ? tword->word : (char *)NULL;
8202                 if (tword)
8203                   dispose_word_desc (tword);
8204               }
8205             FREE (temp);
8206             temp = temp1;
8207             goto dollar_add_string;
8208           }
8209
8210         case '\\':
8211           if (string[sindex + 1] == '\n')
8212             {
8213               sindex += 2;
8214               continue;
8215             }
8216
8217           c = string[++sindex];
8218
8219           if (quoted & Q_HERE_DOCUMENT)
8220             tflag = CBSHDOC;
8221           else if (quoted & Q_DOUBLE_QUOTES)
8222             tflag = CBSDQUOTE;
8223           else
8224             tflag = 0;
8225
8226           /* From Posix discussion on austin-group list:  Backslash escaping
8227              a } in ${...} is removed.  Issue 0000221 */
8228           if ((quoted & Q_DOLBRACE) && c == RBRACE)
8229             {
8230               SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
8231             }
8232           else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
8233             {
8234               SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
8235             }
8236           else if (c == 0)
8237             {
8238               c = CTLNUL;
8239               sindex--;         /* add_character: label increments sindex */
8240               goto add_character;
8241             }
8242           else
8243             {
8244               SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
8245             }
8246
8247           sindex++;
8248 add_twochars:
8249           /* BEFORE jumping here, we need to increment sindex if appropriate */
8250           RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
8251                                   DEFAULT_ARRAY_SIZE);
8252           istring[istring_index++] = twochars[0];
8253           istring[istring_index++] = twochars[1];
8254           istring[istring_index] = '\0';
8255
8256           break;
8257
8258         case '"':
8259 #if 0
8260           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
8261 #else
8262           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8263 #endif
8264             goto add_character;
8265
8266           t_index = ++sindex;
8267           temp = string_extract_double_quoted (string, &sindex, 0);
8268
8269           /* If the quotes surrounded the entire string, then the
8270              whole word was quoted. */
8271           quoted_state = (t_index == 1 && string[sindex] == '\0')
8272                             ? WHOLLY_QUOTED
8273                             : PARTIALLY_QUOTED;
8274
8275           if (temp && *temp)
8276             {
8277               tword = alloc_word_desc ();
8278               tword->word = temp;
8279
8280               temp = (char *)NULL;
8281
8282               temp_has_dollar_at = 0;   /* XXX */
8283               /* Need to get W_HASQUOTEDNULL flag through this function. */
8284               list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL);
8285               has_dollar_at += temp_has_dollar_at;
8286
8287               if (list == &expand_word_error || list == &expand_word_fatal)
8288                 {
8289                   free (istring);
8290                   free (string);
8291                   /* expand_word_internal has already freed temp_word->word
8292                      for us because of the way it prints error messages. */
8293                   tword->word = (char *)NULL;
8294                   dispose_word (tword);
8295                   return list;
8296                 }
8297
8298               dispose_word (tword);
8299
8300               /* "$@" (a double-quoted dollar-at) expands into nothing,
8301                  not even a NULL word, when there are no positional
8302                  parameters. */
8303               if (list == 0 && has_dollar_at)
8304                 {
8305                   quoted_dollar_at++;
8306                   break;
8307                 }
8308
8309               /* If we get "$@", we know we have expanded something, so we
8310                  need to remember it for the final split on $IFS.  This is
8311                  a special case; it's the only case where a quoted string
8312                  can expand into more than one word.  It's going to come back
8313                  from the above call to expand_word_internal as a list with
8314                  a single word, in which all characters are quoted and
8315                  separated by blanks.  What we want to do is to turn it back
8316                  into a list for the next piece of code. */
8317               if (list)
8318                 dequote_list (list);
8319
8320               if (list && list->word && (list->word->flags & W_HASQUOTEDNULL))
8321                 had_quoted_null = 1;
8322
8323               if (has_dollar_at)
8324                 {
8325                   quoted_dollar_at++;
8326                   if (contains_dollar_at)
8327                     *contains_dollar_at = 1;
8328                   if (expanded_something)
8329                     *expanded_something = 1;
8330                 }
8331             }
8332           else
8333             {
8334               /* What we have is "".  This is a minor optimization. */
8335               FREE (temp);
8336               list = (WORD_LIST *)NULL;
8337             }
8338
8339           /* The code above *might* return a list (consider the case of "$@",
8340              where it returns "$1", "$2", etc.).  We can't throw away the
8341              rest of the list, and we have to make sure each word gets added
8342              as quoted.  We test on tresult->next:  if it is non-NULL, we
8343              quote the whole list, save it to a string with string_list, and
8344              add that string. We don't need to quote the results of this
8345              (and it would be wrong, since that would quote the separators
8346              as well), so we go directly to add_string. */
8347           if (list)
8348             {
8349               if (list->next)
8350                 {
8351 #if 0
8352                   if (quoted_dollar_at && (word->flags & W_NOSPLIT2))
8353                     temp = string_list_internal (quote_list (list), " ");
8354                   else
8355 #endif
8356                   /* Testing quoted_dollar_at makes sure that "$@" is
8357                      split correctly when $IFS does not contain a space. */
8358                   temp = quoted_dollar_at
8359                                 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES)
8360                                 : string_list (quote_list (list));
8361                   dispose_words (list);
8362                   goto add_string;
8363                 }
8364               else
8365                 {
8366                   temp = savestring (list->word->word);
8367                   tflag = list->word->flags;
8368                   dispose_words (list);
8369
8370                   /* If the string is not a quoted null string, we want
8371                      to remove any embedded unquoted CTLNUL characters.
8372                      We do not want to turn quoted null strings back into
8373                      the empty string, though.  We do this because we
8374                      want to remove any quoted nulls from expansions that
8375                      contain other characters.  For example, if we have
8376                      x"$*"y or "x$*y" and there are no positional parameters,
8377                      the $* should expand into nothing. */
8378                   /* We use the W_HASQUOTEDNULL flag to differentiate the
8379                      cases:  a quoted null character as above and when
8380                      CTLNUL is contained in the (non-null) expansion
8381                      of some variable.  We use the had_quoted_null flag to
8382                      pass the value through this function to its caller. */
8383                   if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
8384                     remove_quoted_nulls (temp); /* XXX */
8385                 }
8386             }
8387           else
8388             temp = (char *)NULL;
8389
8390           /* We do not want to add quoted nulls to strings that are only
8391              partially quoted; we can throw them away. */
8392           if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
8393             continue;
8394
8395         add_quoted_string:
8396
8397           if (temp)
8398             {
8399               temp1 = temp;
8400               temp = quote_string (temp);
8401               free (temp1);
8402               goto add_string;
8403             }
8404           else
8405             {
8406               /* Add NULL arg. */
8407               c = CTLNUL;
8408               sindex--;         /* add_character: label increments sindex */
8409               goto add_character;
8410             }
8411
8412           /* break; */
8413
8414         case '\'':
8415 #if 0
8416           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
8417 #else
8418           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8419 #endif
8420             goto add_character;
8421
8422           t_index = ++sindex;
8423           temp = string_extract_single_quoted (string, &sindex);
8424
8425           /* If the entire STRING was surrounded by single quotes,
8426              then the string is wholly quoted. */
8427           quoted_state = (t_index == 1 && string[sindex] == '\0')
8428                             ? WHOLLY_QUOTED
8429                             : PARTIALLY_QUOTED;
8430
8431           /* If all we had was '', it is a null expansion. */
8432           if (*temp == '\0')
8433             {
8434               free (temp);
8435               temp = (char *)NULL;
8436             }
8437           else
8438             remove_quoted_escapes (temp);       /* ??? */
8439
8440           /* We do not want to add quoted nulls to strings that are only
8441              partially quoted; such nulls are discarded. */
8442           if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
8443             continue;
8444
8445           /* If we have a quoted null expansion, add a quoted NULL to istring. */
8446           if (temp == 0)
8447             {
8448               c = CTLNUL;
8449               sindex--;         /* add_character: label increments sindex */
8450               goto add_character;
8451             }
8452           else
8453             goto add_quoted_string;
8454
8455           /* break; */
8456
8457         default:
8458           /* This is the fix for " $@ " */
8459         add_ifs_character:
8460           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c)))
8461             {
8462               if (string[sindex])       /* from old goto dollar_add_string */
8463                 sindex++;
8464               if (c == 0)
8465                 {
8466                   c = CTLNUL;
8467                   goto add_character;
8468                 }
8469               else
8470                 {
8471 #if HANDLE_MULTIBYTE
8472                   if (MB_CUR_MAX > 1)
8473                     sindex--;
8474
8475                   if (MB_CUR_MAX > 1)
8476                     {
8477                       SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
8478                     }
8479                   else
8480 #endif
8481                     {
8482                       twochars[0] = CTLESC;
8483                       twochars[1] = c;
8484                       goto add_twochars;
8485                     }
8486                 }
8487             }
8488
8489           SADD_MBCHAR (temp, string, sindex, string_size);
8490
8491         add_character:
8492           RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
8493                                   DEFAULT_ARRAY_SIZE);
8494           istring[istring_index++] = c;
8495           istring[istring_index] = '\0';
8496
8497           /* Next character. */
8498           sindex++;
8499         }
8500     }
8501
8502 finished_with_string:
8503   /* OK, we're ready to return.  If we have a quoted string, and
8504      quoted_dollar_at is not set, we do no splitting at all; otherwise
8505      we split on ' '.  The routines that call this will handle what to
8506      do if nothing has been expanded. */
8507
8508   /* Partially and wholly quoted strings which expand to the empty
8509      string are retained as an empty arguments.  Unquoted strings
8510      which expand to the empty string are discarded.  The single
8511      exception is the case of expanding "$@" when there are no
8512      positional parameters.  In that case, we discard the expansion. */
8513
8514   /* Because of how the code that handles "" and '' in partially
8515      quoted strings works, we need to make ISTRING into a QUOTED_NULL
8516      if we saw quoting characters, but the expansion was empty.
8517      "" and '' are tossed away before we get to this point when
8518      processing partially quoted strings.  This makes "" and $xxx""
8519      equivalent when xxx is unset.  We also look to see whether we
8520      saw a quoted null from a ${} expansion and add one back if we
8521      need to. */
8522
8523   /* If we expand to nothing and there were no single or double quotes
8524      in the word, we throw it away.  Otherwise, we return a NULL word.
8525      The single exception is for $@ surrounded by double quotes when
8526      there are no positional parameters.  In that case, we also throw
8527      the word away. */
8528
8529   if (*istring == '\0')
8530     {
8531       if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
8532         {
8533           istring[0] = CTLNUL;
8534           istring[1] = '\0';
8535           tword = make_bare_word (istring);
8536           tword->flags |= W_HASQUOTEDNULL;              /* XXX */
8537           list = make_word_list (tword, (WORD_LIST *)NULL);
8538           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8539             tword->flags |= W_QUOTED;
8540         }
8541       /* According to sh, ksh, and Posix.2, if a word expands into nothing
8542          and a double-quoted "$@" appears anywhere in it, then the entire
8543          word is removed. */
8544       else  if (quoted_state == UNQUOTED || quoted_dollar_at)
8545         list = (WORD_LIST *)NULL;
8546 #if 0
8547       else
8548         {
8549           tword = make_bare_word (istring);
8550           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8551             tword->flags |= W_QUOTED;
8552           list = make_word_list (tword, (WORD_LIST *)NULL);
8553         }
8554 #else
8555       else
8556         list = (WORD_LIST *)NULL;
8557 #endif
8558     }
8559   else if (word->flags & W_NOSPLIT)
8560     {
8561       tword = make_bare_word (istring);
8562       if (word->flags & W_ASSIGNMENT)
8563         tword->flags |= W_ASSIGNMENT;   /* XXX */
8564       if (word->flags & W_COMPASSIGN)
8565         tword->flags |= W_COMPASSIGN;   /* XXX */
8566       if (word->flags & W_NOGLOB)
8567         tword->flags |= W_NOGLOB;       /* XXX */
8568       if (word->flags & W_NOEXPAND)
8569         tword->flags |= W_NOEXPAND;     /* XXX */
8570       if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8571         tword->flags |= W_QUOTED;
8572       if (had_quoted_null && QUOTED_NULL (istring))
8573         tword->flags |= W_HASQUOTEDNULL;
8574       list = make_word_list (tword, (WORD_LIST *)NULL);
8575     }
8576   else
8577     {
8578       char *ifs_chars;
8579
8580       ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
8581
8582       /* If we have $@, we need to split the results no matter what.  If
8583          IFS is unset or NULL, string_list_dollar_at has separated the
8584          positional parameters with a space, so we split on space (we have
8585          set ifs_chars to " \t\n" above if ifs is unset).  If IFS is set,
8586          string_list_dollar_at has separated the positional parameters
8587          with the first character of $IFS, so we split on $IFS. */
8588       if (has_dollar_at && ifs_chars)
8589         list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
8590       else
8591         {
8592           tword = make_bare_word (istring);
8593           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
8594             tword->flags |= W_QUOTED;
8595           if (word->flags & W_ASSIGNMENT)
8596             tword->flags |= W_ASSIGNMENT;
8597           if (word->flags & W_COMPASSIGN)
8598             tword->flags |= W_COMPASSIGN;
8599           if (word->flags & W_NOGLOB)
8600             tword->flags |= W_NOGLOB;
8601           if (word->flags & W_NOEXPAND)
8602             tword->flags |= W_NOEXPAND;
8603           if (had_quoted_null && QUOTED_NULL (istring))
8604             tword->flags |= W_HASQUOTEDNULL;    /* XXX */
8605           list = make_word_list (tword, (WORD_LIST *)NULL);
8606         }
8607     }
8608
8609   free (istring);
8610   return (list);
8611 }
8612
8613 /* **************************************************************** */
8614 /*                                                                  */
8615 /*                 Functions for Quote Removal                      */
8616 /*                                                                  */
8617 /* **************************************************************** */
8618
8619 /* Perform quote removal on STRING.  If QUOTED > 0, assume we are obeying the
8620    backslash quoting rules for within double quotes or a here document. */
8621 char *
8622 string_quote_removal (string, quoted)
8623      char *string;
8624      int quoted;
8625 {
8626   size_t slen;
8627   char *r, *result_string, *temp, *send;
8628   int sindex, tindex, dquote;
8629   unsigned char c;
8630   DECLARE_MBSTATE;
8631
8632   /* The result can be no longer than the original string. */
8633   slen = strlen (string);
8634   send = string + slen;
8635
8636   r = result_string = (char *)xmalloc (slen + 1);
8637
8638   for (dquote = sindex = 0; c = string[sindex];)
8639     {
8640       switch (c)
8641         {
8642         case '\\':
8643           c = string[++sindex];
8644           if (c == 0)
8645             {
8646               *r++ = '\\';
8647               break;
8648             }
8649           if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
8650             *r++ = '\\';
8651           /* FALLTHROUGH */
8652
8653         default:
8654           SCOPY_CHAR_M (r, string, send, sindex);
8655           break;
8656
8657         case '\'':
8658           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
8659             {
8660               *r++ = c;
8661               sindex++;
8662               break;
8663             }
8664           tindex = sindex + 1;
8665           temp = string_extract_single_quoted (string, &tindex);
8666           if (temp)
8667             {
8668               strcpy (r, temp);
8669               r += strlen (r);
8670               free (temp);
8671             }
8672           sindex = tindex;
8673           break;
8674
8675         case '"':
8676           dquote = 1 - dquote;
8677           sindex++;
8678           break;
8679         }
8680     }
8681     *r = '\0';
8682     return (result_string);
8683 }
8684
8685 #if 0
8686 /* UNUSED */
8687 /* Perform quote removal on word WORD.  This allocates and returns a new
8688    WORD_DESC *. */
8689 WORD_DESC *
8690 word_quote_removal (word, quoted)
8691      WORD_DESC *word;
8692      int quoted;
8693 {
8694   WORD_DESC *w;
8695   char *t;
8696
8697   t = string_quote_removal (word->word, quoted);
8698   w = alloc_word_desc ();
8699   w->word = t ? t : savestring ("");
8700   return (w);
8701 }
8702
8703 /* Perform quote removal on all words in LIST.  If QUOTED is non-zero,
8704    the members of the list are treated as if they are surrounded by
8705    double quotes.  Return a new list, or NULL if LIST is NULL. */
8706 WORD_LIST *
8707 word_list_quote_removal (list, quoted)
8708      WORD_LIST *list;
8709      int quoted;
8710 {
8711   WORD_LIST *result, *t, *tresult, *e;
8712
8713   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
8714     {
8715       tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
8716 #if 0
8717       result = (WORD_LIST *) list_append (result, tresult);
8718 #else
8719       if (result == 0)
8720         result = e = tresult;
8721       else
8722         {
8723           e->next = tresult;
8724           while (e->next)
8725             e = e->next;
8726         }
8727 #endif
8728     }
8729   return (result);
8730 }
8731 #endif
8732
8733 /*******************************************
8734  *                                         *
8735  *    Functions to perform word splitting  *
8736  *                                         *
8737  *******************************************/
8738
8739 void
8740 setifs (v)
8741      SHELL_VAR *v;
8742 {
8743   char *t;
8744   unsigned char uc;
8745
8746   ifs_var = v;
8747   ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
8748
8749   /* Should really merge ifs_cmap with sh_syntaxtab.  XXX - doesn't yet
8750      handle multibyte chars in IFS */
8751   memset (ifs_cmap, '\0', sizeof (ifs_cmap));
8752   for (t = ifs_value ; t && *t; t++)
8753     {
8754       uc = *t;
8755       ifs_cmap[uc] = 1;
8756     }
8757
8758 #if defined (HANDLE_MULTIBYTE)
8759   if (ifs_value == 0)
8760     {
8761       ifs_firstc[0] = '\0';
8762       ifs_firstc_len = 1;
8763     }
8764   else
8765     {
8766       size_t ifs_len;
8767       ifs_len = strnlen (ifs_value, MB_CUR_MAX);
8768       ifs_firstc_len = MBLEN (ifs_value, ifs_len);
8769       if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
8770         {
8771           ifs_firstc[0] = ifs_value[0];
8772           ifs_firstc[1] = '\0';
8773           ifs_firstc_len = 1;
8774         }
8775       else
8776         memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
8777     }
8778 #else
8779   ifs_firstc = ifs_value ? *ifs_value : 0;
8780 #endif
8781 }
8782
8783 char *
8784 getifs ()
8785 {
8786   return ifs_value;
8787 }
8788
8789 /* This splits a single word into a WORD LIST on $IFS, but only if the word
8790    is not quoted.  list_string () performs quote removal for us, even if we
8791    don't do any splitting. */
8792 WORD_LIST *
8793 word_split (w, ifs_chars)
8794      WORD_DESC *w;
8795      char *ifs_chars;
8796 {
8797   WORD_LIST *result;
8798
8799   if (w)
8800     {
8801       char *xifs;
8802
8803       xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
8804       result = list_string (w->word, xifs, w->flags & W_QUOTED);
8805     }
8806   else
8807     result = (WORD_LIST *)NULL;
8808
8809   return (result);
8810 }
8811
8812 /* Perform word splitting on LIST and return the RESULT.  It is possible
8813    to return (WORD_LIST *)NULL. */
8814 static WORD_LIST *
8815 word_list_split (list)
8816      WORD_LIST *list;
8817 {
8818   WORD_LIST *result, *t, *tresult, *e;
8819
8820   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
8821     {
8822       tresult = word_split (t->word, ifs_value);
8823       if (result == 0)
8824         result = e = tresult;
8825       else
8826         {
8827           e->next = tresult;
8828           while (e->next)
8829             e = e->next;
8830         }
8831     }
8832   return (result);
8833 }
8834
8835 /**************************************************
8836  *                                                *
8837  *    Functions to expand an entire WORD_LIST     *
8838  *                                                *
8839  **************************************************/
8840
8841 /* Do any word-expansion-specific cleanup and jump to top_level */
8842 static void
8843 exp_jump_to_top_level (v)
8844      int v;
8845 {
8846   set_pipestatus_from_exit (last_command_exit_value);
8847
8848   /* Cleanup code goes here. */
8849   expand_no_split_dollar_star = 0;      /* XXX */
8850   expanding_redir = 0;
8851   assigning_in_environment = 0;
8852
8853   if (parse_and_execute_level == 0)
8854     top_level_cleanup ();                       /* from sig.c */
8855
8856   jump_to_top_level (v);
8857 }
8858
8859 /* Put NLIST (which is a WORD_LIST * of only one element) at the front of
8860    ELIST, and set ELIST to the new list. */
8861 #define PREPEND_LIST(nlist, elist) \
8862         do { nlist->next = elist; elist = nlist; } while (0)
8863
8864 /* Separate out any initial variable assignments from TLIST.  If set -k has
8865    been executed, remove all assignment statements from TLIST.  Initial
8866    variable assignments and other environment assignments are placed
8867    on SUBST_ASSIGN_VARLIST. */
8868 static WORD_LIST *
8869 separate_out_assignments (tlist)
8870      WORD_LIST *tlist;
8871 {
8872   register WORD_LIST *vp, *lp;
8873
8874   if (tlist == 0)
8875     return ((WORD_LIST *)NULL);
8876
8877   if (subst_assign_varlist)
8878     dispose_words (subst_assign_varlist);       /* Clean up after previous error */
8879
8880   subst_assign_varlist = (WORD_LIST *)NULL;
8881   vp = lp = tlist;
8882
8883   /* Separate out variable assignments at the start of the command.
8884      Loop invariant: vp->next == lp
8885      Loop postcondition:
8886         lp = list of words left after assignment statements skipped
8887         tlist = original list of words
8888   */
8889   while (lp && (lp->word->flags & W_ASSIGNMENT))
8890     {
8891       vp = lp;
8892       lp = lp->next;
8893     }
8894
8895   /* If lp != tlist, we have some initial assignment statements.
8896      We make SUBST_ASSIGN_VARLIST point to the list of assignment
8897      words and TLIST point to the remaining words.  */
8898   if (lp != tlist)
8899     {
8900       subst_assign_varlist = tlist;
8901       /* ASSERT(vp->next == lp); */
8902       vp->next = (WORD_LIST *)NULL;     /* terminate variable list */
8903       tlist = lp;                       /* remainder of word list */
8904     }
8905
8906   /* vp == end of variable list */
8907   /* tlist == remainder of original word list without variable assignments */
8908   if (!tlist)
8909     /* All the words in tlist were assignment statements */
8910     return ((WORD_LIST *)NULL);
8911
8912   /* ASSERT(tlist != NULL); */
8913   /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
8914
8915   /* If the -k option is in effect, we need to go through the remaining
8916      words, separate out the assignment words, and place them on
8917      SUBST_ASSIGN_VARLIST. */
8918   if (place_keywords_in_env)
8919     {
8920       WORD_LIST *tp;    /* tp == running pointer into tlist */
8921
8922       tp = tlist;
8923       lp = tlist->next;
8924
8925       /* Loop Invariant: tp->next == lp */
8926       /* Loop postcondition: tlist == word list without assignment statements */
8927       while (lp)
8928         {
8929           if (lp->word->flags & W_ASSIGNMENT)
8930             {
8931               /* Found an assignment statement, add this word to end of
8932                  subst_assign_varlist (vp). */
8933               if (!subst_assign_varlist)
8934                 subst_assign_varlist = vp = lp;
8935               else
8936                 {
8937                   vp->next = lp;
8938                   vp = lp;
8939                 }
8940
8941               /* Remove the word pointed to by LP from TLIST. */
8942               tp->next = lp->next;
8943               /* ASSERT(vp == lp); */
8944               lp->next = (WORD_LIST *)NULL;
8945               lp = tp->next;
8946             }
8947           else
8948             {
8949               tp = lp;
8950               lp = lp->next;
8951             }
8952         }
8953     }
8954   return (tlist);
8955 }
8956
8957 #define WEXP_VARASSIGN  0x001
8958 #define WEXP_BRACEEXP   0x002
8959 #define WEXP_TILDEEXP   0x004
8960 #define WEXP_PARAMEXP   0x008
8961 #define WEXP_PATHEXP    0x010
8962
8963 /* All of the expansions, including variable assignments at the start of
8964    the list. */
8965 #define WEXP_ALL        (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
8966
8967 /* All of the expansions except variable assignments at the start of
8968    the list. */
8969 #define WEXP_NOVARS     (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
8970
8971 /* All of the `shell expansions': brace expansion, tilde expansion, parameter
8972    expansion, command substitution, arithmetic expansion, word splitting, and
8973    quote removal. */
8974 #define WEXP_SHELLEXP   (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
8975
8976 /* Take the list of words in LIST and do the various substitutions.  Return
8977    a new list of words which is the expanded list, and without things like
8978    variable assignments. */
8979
8980 WORD_LIST *
8981 expand_words (list)
8982      WORD_LIST *list;
8983 {
8984   return (expand_word_list_internal (list, WEXP_ALL));
8985 }
8986
8987 /* Same as expand_words (), but doesn't hack variable or environment
8988    variables. */
8989 WORD_LIST *
8990 expand_words_no_vars (list)
8991      WORD_LIST *list;
8992 {
8993   return (expand_word_list_internal (list, WEXP_NOVARS));
8994 }
8995
8996 WORD_LIST *
8997 expand_words_shellexp (list)
8998      WORD_LIST *list;
8999 {
9000   return (expand_word_list_internal (list, WEXP_SHELLEXP));
9001 }
9002
9003 static WORD_LIST *
9004 glob_expand_word_list (tlist, eflags)
9005      WORD_LIST *tlist;
9006      int eflags;
9007 {
9008   char **glob_array, *temp_string;
9009   register int glob_index;
9010   WORD_LIST *glob_list, *output_list, *disposables, *next;
9011   WORD_DESC *tword;
9012
9013   output_list = disposables = (WORD_LIST *)NULL;
9014   glob_array = (char **)NULL;
9015   while (tlist)
9016     {
9017       /* For each word, either globbing is attempted or the word is
9018          added to orig_list.  If globbing succeeds, the results are
9019          added to orig_list and the word (tlist) is added to the list
9020          of disposable words.  If globbing fails and failed glob
9021          expansions are left unchanged (the shell default), the
9022          original word is added to orig_list.  If globbing fails and
9023          failed glob expansions are removed, the original word is
9024          added to the list of disposable words.  orig_list ends up
9025          in reverse order and requires a call to REVERSE_LIST to
9026          be set right.  After all words are examined, the disposable
9027          words are freed. */
9028       next = tlist->next;
9029
9030       /* If the word isn't an assignment and contains an unquoted
9031          pattern matching character, then glob it. */
9032       if ((tlist->word->flags & W_NOGLOB) == 0 &&
9033           unquoted_glob_pattern_p (tlist->word->word))
9034         {
9035           glob_array = shell_glob_filename (tlist->word->word);
9036
9037           /* Handle error cases.
9038              I don't think we should report errors like "No such file
9039              or directory".  However, I would like to report errors
9040              like "Read failed". */
9041
9042           if (glob_array == 0 || GLOB_FAILED (glob_array))
9043             {
9044               glob_array = (char **)xmalloc (sizeof (char *));
9045               glob_array[0] = (char *)NULL;
9046             }
9047
9048           /* Dequote the current word in case we have to use it. */
9049           if (glob_array[0] == NULL)
9050             {
9051               temp_string = dequote_string (tlist->word->word);
9052               free (tlist->word->word);
9053               tlist->word->word = temp_string;
9054             }
9055
9056           /* Make the array into a word list. */
9057           glob_list = (WORD_LIST *)NULL;
9058           for (glob_index = 0; glob_array[glob_index]; glob_index++)
9059             {
9060               tword = make_bare_word (glob_array[glob_index]);
9061               tword->flags |= W_GLOBEXP;        /* XXX */
9062               glob_list = make_word_list (tword, glob_list);
9063             }
9064
9065           if (glob_list)
9066             {
9067               output_list = (WORD_LIST *)list_append (glob_list, output_list);
9068               PREPEND_LIST (tlist, disposables);
9069             }
9070           else if (fail_glob_expansion != 0)
9071             {
9072               report_error (_("no match: %s"), tlist->word->word);
9073               exp_jump_to_top_level (DISCARD);
9074             }
9075           else if (allow_null_glob_expansion == 0)
9076             {
9077               /* Failed glob expressions are left unchanged. */
9078               PREPEND_LIST (tlist, output_list);
9079             }
9080           else
9081             {
9082               /* Failed glob expressions are removed. */
9083               PREPEND_LIST (tlist, disposables);
9084             }
9085         }
9086       else
9087         {
9088           /* Dequote the string. */
9089           temp_string = dequote_string (tlist->word->word);
9090           free (tlist->word->word);
9091           tlist->word->word = temp_string;
9092           PREPEND_LIST (tlist, output_list);
9093         }
9094
9095       strvec_dispose (glob_array);
9096       glob_array = (char **)NULL;
9097
9098       tlist = next;
9099     }
9100
9101   if (disposables)
9102     dispose_words (disposables);
9103
9104   if (output_list)
9105     output_list = REVERSE_LIST (output_list, WORD_LIST *);
9106
9107   return (output_list);
9108 }
9109
9110 #if defined (BRACE_EXPANSION)
9111 static WORD_LIST *
9112 brace_expand_word_list (tlist, eflags)
9113      WORD_LIST *tlist;
9114      int eflags;
9115 {
9116   register char **expansions;
9117   char *temp_string;
9118   WORD_LIST *disposables, *output_list, *next;
9119   WORD_DESC *w;
9120   int eindex;
9121
9122   for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
9123     {
9124       next = tlist->next;
9125
9126       if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
9127         {
9128 /*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
9129           PREPEND_LIST (tlist, output_list);
9130           continue;
9131         }
9132           
9133       /* Only do brace expansion if the word has a brace character.  If
9134          not, just add the word list element to BRACES and continue.  In
9135          the common case, at least when running shell scripts, this will
9136          degenerate to a bunch of calls to `mbschr', and then what is
9137          basically a reversal of TLIST into BRACES, which is corrected
9138          by a call to REVERSE_LIST () on BRACES when the end of TLIST
9139          is reached. */
9140       if (mbschr (tlist->word->word, LBRACE))
9141         {
9142           expansions = brace_expand (tlist->word->word);
9143
9144           for (eindex = 0; temp_string = expansions[eindex]; eindex++)
9145             {
9146               w = make_word (temp_string);
9147               /* If brace expansion didn't change the word, preserve
9148                  the flags.  We may want to preserve the flags
9149                  unconditionally someday -- XXX */
9150               if (STREQ (temp_string, tlist->word->word))
9151                 w->flags = tlist->word->flags;
9152               output_list = make_word_list (w, output_list);
9153               free (expansions[eindex]);
9154             }
9155           free (expansions);
9156
9157           /* Add TLIST to the list of words to be freed after brace
9158              expansion has been performed. */
9159           PREPEND_LIST (tlist, disposables);
9160         }
9161       else
9162         PREPEND_LIST (tlist, output_list);
9163     }
9164
9165   if (disposables)
9166     dispose_words (disposables);
9167
9168   if (output_list)
9169     output_list = REVERSE_LIST (output_list, WORD_LIST *);
9170
9171   return (output_list);
9172 }
9173 #endif
9174
9175 #if defined (ARRAY_VARS)
9176 /* Take WORD, a compound associative array assignment, and internally run
9177    'declare -A w', where W is the variable name portion of WORD. */
9178 static int
9179 make_internal_declare (word, option)
9180      char *word;
9181      char *option;
9182 {
9183   int t;
9184   WORD_LIST *wl;
9185   WORD_DESC *w;
9186
9187   w = make_word (word);
9188
9189   t = assignment (w->word, 0);
9190   w->word[t] = '\0';
9191
9192   wl = make_word_list (w, (WORD_LIST *)NULL);
9193   wl = make_word_list (make_word (option), wl);
9194
9195   return (declare_builtin (wl));  
9196 }  
9197 #endif
9198
9199 static WORD_LIST *
9200 shell_expand_word_list (tlist, eflags)
9201      WORD_LIST *tlist;
9202      int eflags;
9203 {
9204   WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list;
9205   int expanded_something, has_dollar_at;
9206   char *temp_string;
9207
9208   /* We do tilde expansion all the time.  This is what 1003.2 says. */
9209   new_list = (WORD_LIST *)NULL;
9210   for (orig_list = tlist; tlist; tlist = next)
9211     {
9212       temp_string = tlist->word->word;
9213
9214       next = tlist->next;
9215
9216 #if defined (ARRAY_VARS)
9217       /* If this is a compound array assignment to a builtin that accepts
9218          such assignments (e.g., `declare'), take the assignment and perform
9219          it separately, handling the semantics of declarations inside shell
9220          functions.  This avoids the double-evaluation of such arguments,
9221          because `declare' does some evaluation of compound assignments on
9222          its own. */
9223       if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
9224         {
9225           int t;
9226
9227           if (tlist->word->flags & W_ASSIGNASSOC)
9228             make_internal_declare (tlist->word->word, "-A");
9229
9230           t = do_word_assignment (tlist->word, 0);
9231           if (t == 0)
9232             {
9233               last_command_exit_value = EXECUTION_FAILURE;
9234               exp_jump_to_top_level (DISCARD);
9235             }
9236
9237           /* Now transform the word as ksh93 appears to do and go on */
9238           t = assignment (tlist->word->word, 0);
9239           tlist->word->word[t] = '\0';
9240           tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC);
9241         }
9242 #endif
9243
9244       expanded_something = 0;
9245       expanded = expand_word_internal
9246         (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
9247
9248       if (expanded == &expand_word_error || expanded == &expand_word_fatal)
9249         {
9250           /* By convention, each time this error is returned,
9251              tlist->word->word has already been freed. */
9252           tlist->word->word = (char *)NULL;
9253
9254           /* Dispose our copy of the original list. */
9255           dispose_words (orig_list);
9256           /* Dispose the new list we're building. */
9257           dispose_words (new_list);
9258
9259           last_command_exit_value = EXECUTION_FAILURE;
9260           if (expanded == &expand_word_error)
9261             exp_jump_to_top_level (DISCARD);
9262           else
9263             exp_jump_to_top_level (FORCE_EOF);
9264         }
9265
9266       /* Don't split words marked W_NOSPLIT. */
9267       if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
9268         {
9269           temp_list = word_list_split (expanded);
9270           dispose_words (expanded);
9271         }
9272       else
9273         {
9274           /* If no parameter expansion, command substitution, process
9275              substitution, or arithmetic substitution took place, then
9276              do not do word splitting.  We still have to remove quoted
9277              null characters from the result. */
9278           word_list_remove_quoted_nulls (expanded);
9279           temp_list = expanded;
9280         }
9281
9282       expanded = REVERSE_LIST (temp_list, WORD_LIST *);
9283       new_list = (WORD_LIST *)list_append (expanded, new_list);
9284     }
9285
9286   if (orig_list)  
9287     dispose_words (orig_list);
9288
9289   if (new_list)
9290     new_list = REVERSE_LIST (new_list, WORD_LIST *);
9291
9292   return (new_list);
9293 }
9294
9295 /* The workhorse for expand_words () and expand_words_no_vars ().
9296    First arg is LIST, a WORD_LIST of words.
9297    Second arg EFLAGS is a flags word controlling which expansions are
9298    performed.
9299
9300    This does all of the substitutions: brace expansion, tilde expansion,
9301    parameter expansion, command substitution, arithmetic expansion,
9302    process substitution, word splitting, and pathname expansion, according
9303    to the bits set in EFLAGS.  Words with the W_QUOTED or W_NOSPLIT bits
9304    set, or for which no expansion is done, do not undergo word splitting.
9305    Words with the W_NOGLOB bit set do not undergo pathname expansion. */
9306 static WORD_LIST *
9307 expand_word_list_internal (list, eflags)
9308      WORD_LIST *list;
9309      int eflags;
9310 {
9311   WORD_LIST *new_list, *temp_list;
9312   int tint;
9313
9314   if (list == 0)
9315     return ((WORD_LIST *)NULL);
9316
9317   garglist = new_list = copy_word_list (list);
9318   if (eflags & WEXP_VARASSIGN)
9319     {
9320       garglist = new_list = separate_out_assignments (new_list);
9321       if (new_list == 0)
9322         {
9323           if (subst_assign_varlist)
9324             {
9325               /* All the words were variable assignments, so they are placed
9326                  into the shell's environment. */
9327               for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
9328                 {
9329                   this_command_name = (char *)NULL;     /* no arithmetic errors */
9330                   tint = do_word_assignment (temp_list->word, 0);
9331                   /* Variable assignment errors in non-interactive shells
9332                      running in Posix.2 mode cause the shell to exit. */
9333                   if (tint == 0)
9334                     {
9335                       last_command_exit_value = EXECUTION_FAILURE;
9336                       if (interactive_shell == 0 && posixly_correct)
9337                         exp_jump_to_top_level (FORCE_EOF);
9338                       else
9339                         exp_jump_to_top_level (DISCARD);
9340                     }
9341                 }
9342               dispose_words (subst_assign_varlist);
9343               subst_assign_varlist = (WORD_LIST *)NULL;
9344             }
9345           return ((WORD_LIST *)NULL);
9346         }
9347     }
9348
9349   /* Begin expanding the words that remain.  The expansions take place on
9350      things that aren't really variable assignments. */
9351
9352 #if defined (BRACE_EXPANSION)
9353   /* Do brace expansion on this word if there are any brace characters
9354      in the string. */
9355   if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
9356     new_list = brace_expand_word_list (new_list, eflags);
9357 #endif /* BRACE_EXPANSION */
9358
9359   /* Perform the `normal' shell expansions: tilde expansion, parameter and
9360      variable substitution, command substitution, arithmetic expansion,
9361      and word splitting. */
9362   new_list = shell_expand_word_list (new_list, eflags);
9363
9364   /* Okay, we're almost done.  Now let's just do some filename
9365      globbing. */
9366   if (new_list)
9367     {
9368       if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
9369         /* Glob expand the word list unless globbing has been disabled. */
9370         new_list = glob_expand_word_list (new_list, eflags);
9371       else
9372         /* Dequote the words, because we're not performing globbing. */
9373         new_list = dequote_list (new_list);
9374     }
9375
9376   if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
9377     {
9378       sh_wassign_func_t *assign_func;
9379       int is_special_builtin, is_builtin_or_func;
9380
9381       /* If the remainder of the words expand to nothing, Posix.2 requires
9382          that the variable and environment assignments affect the shell's
9383          environment. */
9384       assign_func = new_list ? assign_in_env : do_word_assignment;
9385       tempenv_assign_error = 0;
9386
9387       is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
9388       /* Posix says that special builtins exit if a variable assignment error
9389          occurs in an assignment preceding it. */
9390       is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
9391       
9392       for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
9393         {
9394           this_command_name = (char *)NULL;
9395           assigning_in_environment = (assign_func == assign_in_env);
9396           tint = (*assign_func) (temp_list->word, is_builtin_or_func);
9397           assigning_in_environment = 0;
9398           /* Variable assignment errors in non-interactive shells running
9399              in Posix.2 mode cause the shell to exit. */
9400           if (tint == 0)
9401             {
9402               if (assign_func == do_word_assignment)
9403                 {
9404                   last_command_exit_value = EXECUTION_FAILURE;
9405                   if (interactive_shell == 0 && posixly_correct && is_special_builtin)
9406                     exp_jump_to_top_level (FORCE_EOF);
9407                   else
9408                     exp_jump_to_top_level (DISCARD);
9409                 }
9410               else
9411                 tempenv_assign_error++;
9412             }
9413         }
9414
9415       dispose_words (subst_assign_varlist);
9416       subst_assign_varlist = (WORD_LIST *)NULL;
9417     }
9418
9419 #if 0
9420   tint = list_length (new_list) + 1;
9421   RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
9422   for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next)
9423     glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0';
9424   glob_argv_flags[tint] = '\0';
9425 #endif
9426
9427   return (new_list);
9428 }