Bash-4.2 patch 32
[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   result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
5128
5129 #if !defined (HAVE_DEV_FD)
5130   /* Make sure we close the named pipe in the child before we exit. */
5131   close (open_for_read_in_child ? 0 : 1);
5132 #endif /* !HAVE_DEV_FD */
5133
5134   exit (result);
5135   /*NOTREACHED*/
5136 }
5137 #endif /* PROCESS_SUBSTITUTION */
5138
5139 /***********************************/
5140 /*                                 */
5141 /*      Command Substitution       */
5142 /*                                 */
5143 /***********************************/
5144
5145 static char *
5146 read_comsub (fd, quoted, rflag)
5147      int fd, quoted;
5148      int *rflag;
5149 {
5150   char *istring, buf[128], *bufp, *s;
5151   int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul;
5152   ssize_t bufn;
5153
5154   istring = (char *)NULL;
5155   istring_index = istring_size = bufn = tflag = 0;
5156
5157   for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
5158     skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
5159
5160   /* Read the output of the command through the pipe.  This may need to be
5161      changed to understand multibyte characters in the future. */
5162   while (1)
5163     {
5164       if (fd < 0)
5165         break;
5166       if (--bufn <= 0)
5167         {
5168           bufn = zread (fd, buf, sizeof (buf));
5169           if (bufn <= 0) 
5170             break;
5171           bufp = buf;
5172         }
5173       c = *bufp++;
5174
5175       if (c == 0)
5176         {
5177 #if 0
5178           internal_warning ("read_comsub: ignored null byte in input");
5179 #endif
5180           continue;
5181         }
5182
5183       /* Add the character to ISTRING, possibly after resizing it. */
5184       RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
5185
5186       /* This is essentially quote_string inline */
5187       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
5188         istring[istring_index++] = CTLESC;
5189       /* Escape CTLESC and CTLNUL in the output to protect those characters
5190          from the rest of the word expansions (word splitting and globbing.)
5191          This is essentially quote_escapes inline. */
5192       else if (skip_ctlesc == 0 && c == CTLESC)
5193         {
5194           tflag |= W_HASCTLESC;
5195           istring[istring_index++] = CTLESC;
5196         }
5197       else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
5198         istring[istring_index++] = CTLESC;
5199
5200       istring[istring_index++] = c;
5201
5202 #if 0
5203 #if defined (__CYGWIN__)
5204       if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r')
5205         {
5206           istring_index--;
5207           istring[istring_index - 1] = '\n';
5208         }
5209 #endif
5210 #endif
5211     }
5212
5213   if (istring)
5214     istring[istring_index] = '\0';
5215
5216   /* If we read no output, just return now and save ourselves some
5217      trouble. */
5218   if (istring_index == 0)
5219     {
5220       FREE (istring);
5221       if (rflag)
5222         *rflag = tflag;
5223       return (char *)NULL;
5224     }
5225
5226   /* Strip trailing newlines from the output of the command. */
5227   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5228     {
5229       while (istring_index > 0)
5230         {
5231           if (istring[istring_index - 1] == '\n')
5232             {
5233               --istring_index;
5234
5235               /* If the newline was quoted, remove the quoting char. */
5236               if (istring[istring_index - 1] == CTLESC)
5237                 --istring_index;
5238             }
5239           else
5240             break;
5241         }
5242       istring[istring_index] = '\0';
5243     }
5244   else
5245     strip_trailing (istring, istring_index - 1, 1);
5246
5247   if (rflag)
5248     *rflag = tflag;
5249   return istring;
5250 }
5251
5252 /* Perform command substitution on STRING.  This returns a WORD_DESC * with the
5253    contained string possibly quoted. */
5254 WORD_DESC *
5255 command_substitute (string, quoted)
5256      char *string;
5257      int quoted;
5258 {
5259   pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
5260   char *istring;
5261   int result, fildes[2], function_value, pflags, rc, tflag;
5262   WORD_DESC *ret;
5263
5264   istring = (char *)NULL;
5265
5266   /* Don't fork () if there is no need to.  In the case of no command to
5267      run, just return NULL. */
5268   if (!string || !*string || (string[0] == '\n' && !string[1]))
5269     return ((WORD_DESC *)NULL);
5270
5271   if (wordexp_only && read_but_dont_execute)
5272     {
5273       last_command_exit_value = EX_WEXPCOMSUB;
5274       jump_to_top_level (EXITPROG);
5275     }
5276
5277   /* We're making the assumption here that the command substitution will
5278      eventually run a command from the file system.  Since we'll run
5279      maybe_make_export_env in this subshell before executing that command,
5280      the parent shell and any other shells it starts will have to remake
5281      the environment.  If we make it before we fork, other shells won't
5282      have to.  Don't bother if we have any temporary variable assignments,
5283      though, because the export environment will be remade after this
5284      command completes anyway, but do it if all the words to be expanded
5285      are variable assignments. */
5286   if (subst_assign_varlist == 0 || garglist == 0)
5287     maybe_make_export_env ();   /* XXX */
5288
5289   /* Flags to pass to parse_and_execute() */
5290   pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
5291
5292   /* Pipe the output of executing STRING into the current shell. */
5293   if (pipe (fildes) < 0)
5294     {
5295       sys_error (_("cannot make pipe for command substitution"));
5296       goto error_exit;
5297     }
5298
5299   old_pid = last_made_pid;
5300 #if defined (JOB_CONTROL)
5301   old_pipeline_pgrp = pipeline_pgrp;
5302   /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */
5303   if ((subshell_environment & SUBSHELL_PIPE) == 0)
5304     pipeline_pgrp = shell_pgrp;
5305   cleanup_the_pipeline ();
5306 #endif /* JOB_CONTROL */
5307
5308   old_async_pid = last_asynchronous_pid;
5309   pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC);
5310   last_asynchronous_pid = old_async_pid;
5311
5312   if (pid == 0)
5313     {
5314       /* Reset the signal handlers in the child, but don't free the
5315          trap strings.  Set a flag noting that we have to free the
5316          trap strings if we run trap to change a signal disposition. */
5317       reset_signal_handlers ();
5318       subshell_environment |= SUBSHELL_RESETTRAP;
5319     }
5320
5321 #if defined (JOB_CONTROL)
5322   /* XXX DO THIS ONLY IN PARENT ? XXX */
5323   set_sigchld_handler ();
5324   stop_making_children ();
5325   if (pid != 0)
5326     pipeline_pgrp = old_pipeline_pgrp;
5327 #else
5328   stop_making_children ();
5329 #endif /* JOB_CONTROL */
5330
5331   if (pid < 0)
5332     {
5333       sys_error (_("cannot make child for command substitution"));
5334     error_exit:
5335
5336       FREE (istring);
5337       close (fildes[0]);
5338       close (fildes[1]);
5339       return ((WORD_DESC *)NULL);
5340     }
5341
5342   if (pid == 0)
5343     {
5344       set_sigint_handler ();    /* XXX */
5345
5346       free_pushed_string_input ();
5347
5348       if (dup2 (fildes[1], 1) < 0)
5349         {
5350           sys_error (_("command_substitute: cannot duplicate pipe as fd 1"));
5351           exit (EXECUTION_FAILURE);
5352         }
5353
5354       /* If standard output is closed in the parent shell
5355          (such as after `exec >&-'), file descriptor 1 will be
5356          the lowest available file descriptor, and end up in
5357          fildes[0].  This can happen for stdin and stderr as well,
5358          but stdout is more important -- it will cause no output
5359          to be generated from this command. */
5360       if ((fildes[1] != fileno (stdin)) &&
5361           (fildes[1] != fileno (stdout)) &&
5362           (fildes[1] != fileno (stderr)))
5363         close (fildes[1]);
5364
5365       if ((fildes[0] != fileno (stdin)) &&
5366           (fildes[0] != fileno (stdout)) &&
5367           (fildes[0] != fileno (stderr)))
5368         close (fildes[0]);
5369
5370 #ifdef __CYGWIN__
5371       /* Let stdio know the fd may have changed from text to binary mode, and
5372          make sure to preserve stdout line buffering. */
5373       freopen (NULL, "w", stdout);
5374       sh_setlinebuf (stdout);
5375 #endif /* __CYGWIN__ */
5376
5377       /* The currently executing shell is not interactive. */
5378       interactive = 0;
5379
5380       /* This is a subshell environment. */
5381       subshell_environment |= SUBSHELL_COMSUB;
5382
5383       /* When not in POSIX mode, command substitution does not inherit
5384          the -e flag. */
5385       if (posixly_correct == 0)
5386         exit_immediately_on_error = 0;
5387
5388       remove_quoted_escapes (string);
5389
5390       startup_state = 2;        /* see if we can avoid a fork */
5391       /* Give command substitution a place to jump back to on failure,
5392          so we don't go back up to main (). */
5393       result = setjmp (top_level);
5394
5395       /* If we're running a command substitution inside a shell function,
5396          trap `return' so we don't return from the function in the subshell
5397          and go off to never-never land. */
5398       if (result == 0 && return_catch_flag)
5399         function_value = setjmp (return_catch);
5400       else
5401         function_value = 0;
5402
5403       if (result == ERREXIT)
5404         rc = last_command_exit_value;
5405       else if (result == EXITPROG)
5406         rc = last_command_exit_value;
5407       else if (result)
5408         rc = EXECUTION_FAILURE;
5409       else if (function_value)
5410         rc = return_catch_value;
5411       else
5412         {
5413           subshell_level++;
5414           rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
5415           subshell_level--;
5416         }
5417
5418       last_command_exit_value = rc;
5419       rc = run_exit_trap ();
5420 #if defined (PROCESS_SUBSTITUTION)
5421       unlink_fifo_list ();
5422 #endif
5423       exit (rc);
5424     }
5425   else
5426     {
5427 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
5428       close_pgrp_pipe ();
5429 #endif /* JOB_CONTROL && PGRP_PIPE */
5430
5431       close (fildes[1]);
5432
5433       tflag = 0;
5434       istring = read_comsub (fildes[0], quoted, &tflag);
5435
5436       close (fildes[0]);
5437
5438       current_command_subst_pid = pid;
5439       last_command_exit_value = wait_for (pid);
5440       last_command_subst_pid = pid;
5441       last_made_pid = old_pid;
5442
5443 #if defined (JOB_CONTROL)
5444       /* If last_command_exit_value > 128, then the substituted command
5445          was terminated by a signal.  If that signal was SIGINT, then send
5446          SIGINT to ourselves.  This will break out of loops, for instance. */
5447       if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
5448         kill (getpid (), SIGINT);
5449
5450       /* wait_for gives the terminal back to shell_pgrp.  If some other
5451          process group should have it, give it away to that group here.
5452          pipeline_pgrp is non-zero only while we are constructing a
5453          pipline, so what we are concerned about is whether or not that
5454          pipeline was started in the background.  A pipeline started in
5455          the background should never get the tty back here. */
5456       if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0)
5457         give_terminal_to (pipeline_pgrp, 0);
5458 #endif /* JOB_CONTROL */
5459
5460       ret = alloc_word_desc ();
5461       ret->word = istring;
5462       ret->flags = tflag;
5463
5464       return ret;
5465     }
5466 }
5467
5468 /********************************************************
5469  *                                                      *
5470  *      Utility functions for parameter expansion       *
5471  *                                                      *
5472  ********************************************************/
5473
5474 #if defined (ARRAY_VARS)
5475
5476 static arrayind_t
5477 array_length_reference (s)
5478      char *s;
5479 {
5480   int len;
5481   arrayind_t ind;
5482   char *akey;
5483   char *t, c;
5484   ARRAY *array;
5485   HASH_TABLE *h;
5486   SHELL_VAR *var;
5487
5488   var = array_variable_part (s, &t, &len);
5489
5490   /* If unbound variables should generate an error, report one and return
5491      failure. */
5492   if ((var == 0 || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
5493     {
5494       c = *--t;
5495       *t = '\0';
5496       last_command_exit_value = EXECUTION_FAILURE;
5497       err_unboundvar (s);
5498       *t = c;
5499       return (-1);
5500     }
5501   else if (var == 0)
5502     return 0;
5503
5504   /* We support a couple of expansions for variables that are not arrays.
5505      We'll return the length of the value for v[0], and 1 for v[@] or
5506      v[*].  Return 0 for everything else. */
5507
5508   array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
5509   h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
5510
5511   if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
5512     {
5513       if (assoc_p (var))
5514         return (h ? assoc_num_elements (h) : 0);
5515       else if (array_p (var))
5516         return (array ? array_num_elements (array) : 0);
5517       else
5518         return (var_isset (var) ? 1 : 0);
5519     }
5520
5521   if (assoc_p (var))
5522     {
5523       t[len - 1] = '\0';
5524       akey = expand_assignment_string_to_string (t, 0); /* [ */
5525       t[len - 1] = ']';
5526       if (akey == 0 || *akey == 0)
5527         {
5528           err_badarraysub (t);
5529           return (-1);
5530         }
5531       t = assoc_reference (assoc_cell (var), akey);
5532     }
5533   else
5534     {
5535       ind = array_expand_index (t, len);
5536       if (ind < 0)
5537         {
5538           err_badarraysub (t);
5539           return (-1);
5540         }
5541       if (array_p (var))
5542         t = array_reference (array, ind);
5543       else
5544         t = (ind == 0) ? value_cell (var) : (char *)NULL;
5545     }
5546
5547   len = MB_STRLEN (t);
5548   return (len);
5549 }
5550 #endif /* ARRAY_VARS */
5551
5552 static int
5553 valid_brace_expansion_word (name, var_is_special)
5554      char *name;
5555      int var_is_special;
5556 {
5557   if (DIGIT (*name) && all_digits (name))
5558     return 1;
5559   else if (var_is_special)
5560     return 1;
5561 #if defined (ARRAY_VARS)
5562   else if (valid_array_reference (name))
5563     return 1;
5564 #endif /* ARRAY_VARS */
5565   else if (legal_identifier (name))
5566     return 1;
5567   else
5568     return 0;
5569 }
5570
5571 static int
5572 chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at)
5573      char *name;
5574      int quoted;
5575      int *quoted_dollar_atp, *contains_dollar_at;
5576 {
5577   char *temp1;
5578
5579   if (name == 0)
5580     {
5581       if (quoted_dollar_atp)
5582         *quoted_dollar_atp = 0;
5583       if (contains_dollar_at)
5584         *contains_dollar_at = 0;
5585       return 0;
5586     }
5587
5588   /* check for $@ and $* */
5589   if (name[0] == '@' && name[1] == 0)
5590     {
5591       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5592         *quoted_dollar_atp = 1;
5593       if (contains_dollar_at)
5594         *contains_dollar_at = 1;
5595       return 1;
5596     }
5597   else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
5598     {
5599       if (contains_dollar_at)
5600         *contains_dollar_at = 1;
5601       return 1;
5602     }
5603
5604   /* Now check for ${array[@]} and ${array[*]} */
5605 #if defined (ARRAY_VARS)
5606   else if (valid_array_reference (name))
5607     {
5608       temp1 = mbschr (name, '[');
5609       if (temp1 && temp1[1] == '@' && temp1[2] == ']')
5610         {
5611           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5612             *quoted_dollar_atp = 1;
5613           if (contains_dollar_at)
5614             *contains_dollar_at = 1;
5615           return 1;
5616         }       /* [ */
5617       /* ${array[*]}, when unquoted, should be treated like ${array[@]},
5618          which should result in separate words even when IFS is unset. */
5619       if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0)
5620         {
5621           if (contains_dollar_at)
5622             *contains_dollar_at = 1;
5623           return 1;
5624         }
5625     }
5626 #endif
5627   return 0;
5628 }
5629
5630 /* Parameter expand NAME, and return a new string which is the expansion,
5631    or NULL if there was no expansion.
5632    VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
5633    the shell, e.g., "@", "$", "*", etc.  QUOTED, if non-zero, means that
5634    NAME was found inside of a double-quoted expression. */
5635 static WORD_DESC *
5636 parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp)
5637      char *name;
5638      int var_is_special, quoted, pflags;
5639      arrayind_t *indp;
5640 {
5641   WORD_DESC *ret;
5642   char *temp, *tt;
5643   intmax_t arg_index;
5644   SHELL_VAR *var;
5645   int atype, rflags;
5646   arrayind_t ind;
5647
5648   ret = 0;
5649   temp = 0;
5650   rflags = 0;
5651
5652   if (indp)
5653     *indp = INTMAX_MIN;
5654
5655   /* Handle multiple digit arguments, as in ${11}. */  
5656   if (legal_number (name, &arg_index))
5657     {
5658       tt = get_dollar_var_value (arg_index);
5659       if (tt)
5660         temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5661                   ? quote_string (tt)
5662                   : quote_escapes (tt);
5663       else
5664         temp = (char *)NULL;
5665       FREE (tt);
5666     }
5667   else if (var_is_special)      /* ${@} */
5668     {
5669       int sindex;
5670       tt = (char *)xmalloc (2 + strlen (name));
5671       tt[sindex = 0] = '$';
5672       strcpy (tt + 1, name);
5673
5674       ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
5675                           (int *)NULL, (int *)NULL, pflags);
5676       free (tt);
5677     }
5678 #if defined (ARRAY_VARS)
5679   else if (valid_array_reference (name))
5680     {
5681       temp = array_value (name, quoted, 0, &atype, &ind);
5682       if (atype == 0 && temp)
5683         {
5684           temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5685                     ? quote_string (temp)
5686                     : quote_escapes (temp);
5687           rflags |= W_ARRAYIND;
5688           if (indp)
5689             *indp = ind;
5690         }                 
5691       else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5692         rflags |= W_HASQUOTEDNULL;
5693     }
5694 #endif
5695   else if (var = find_variable (name))
5696     {
5697       if (var_isset (var) && invisible_p (var) == 0)
5698         {
5699 #if defined (ARRAY_VARS)
5700           if (assoc_p (var))
5701             temp = assoc_reference (assoc_cell (var), "0");
5702           else if (array_p (var))
5703             temp = array_reference (array_cell (var), 0);
5704           else
5705             temp = value_cell (var);
5706 #else
5707           temp = value_cell (var);
5708 #endif
5709
5710           if (temp)
5711             temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5712                       ? quote_string (temp)
5713                       : quote_escapes (temp);
5714         }
5715       else
5716         temp = (char *)NULL;
5717     }
5718   else
5719     temp = (char *)NULL;
5720
5721   if (ret == 0)
5722     {
5723       ret = alloc_word_desc ();
5724       ret->word = temp;
5725       ret->flags |= rflags;
5726     }
5727   return ret;
5728 }
5729
5730 /* Expand an indirect reference to a variable: ${!NAME} expands to the
5731    value of the variable whose name is the value of NAME. */
5732 static WORD_DESC *
5733 parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at)
5734      char *name;
5735      int var_is_special, quoted;
5736      int *quoted_dollar_atp, *contains_dollar_at;
5737 {
5738   char *temp, *t;
5739   WORD_DESC *w;
5740
5741   w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND, 0);
5742   t = w->word;
5743   /* Have to dequote here if necessary */
5744   if (t)
5745     {
5746       temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
5747                 ? dequote_string (t)
5748                 : dequote_escapes (t);
5749       free (t);
5750       t = temp;
5751     }
5752   dispose_word_desc (w);
5753
5754   chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at);
5755   if (t == 0)
5756     return (WORD_DESC *)NULL;
5757
5758   w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0, 0);
5759   free (t);
5760
5761   return w;
5762 }
5763
5764 /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
5765    depending on the value of C, the separating character.  C can be one of
5766    "-", "+", or "=".  QUOTED is true if the entire brace expression occurs
5767    between double quotes. */
5768 static WORD_DESC *
5769 parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
5770      char *name, *value;
5771      int c, quoted, *qdollaratp, *hasdollarat;
5772 {
5773   WORD_DESC *w;
5774   WORD_LIST *l;
5775   char *t, *t1, *temp;
5776   int hasdol;
5777
5778   /* If the entire expression is between double quotes, we want to treat
5779      the value as a double-quoted string, with the exception that we strip
5780      embedded unescaped double quotes (for sh backwards compatibility). */
5781   if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
5782     {
5783       hasdol = 0;
5784       temp = string_extract_double_quoted (value, &hasdol, 1);
5785     }
5786   else
5787     temp = value;
5788
5789   w = alloc_word_desc ();
5790   hasdol = 0;
5791   /* XXX was 0 not quoted */
5792   l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL)
5793             : (WORD_LIST *)0;
5794   if (hasdollarat)
5795     *hasdollarat = hasdol || (l && l->next);
5796   if (temp != value)
5797     free (temp);
5798   if (l)
5799     {
5800       /* The expansion of TEMP returned something.  We need to treat things
5801           slightly differently if HASDOL is non-zero.  If we have "$@", the
5802           individual words have already been quoted.  We need to turn them
5803           into a string with the words separated by the first character of
5804           $IFS without any additional quoting, so string_list_dollar_at won't
5805           do the right thing.  We use string_list_dollar_star instead. */
5806       temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l);
5807
5808       /* If l->next is not null, we know that TEMP contained "$@", since that
5809          is the only expansion that creates more than one word. */
5810       if (qdollaratp && ((hasdol && quoted) || l->next))
5811         *qdollaratp = 1;
5812       /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
5813          a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
5814          flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
5815          expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5816          (which is more paranoia than anything else), we need to return the
5817          quoted null string and set the flags to indicate it. */
5818       if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL(temp) && QUOTED_NULL(l->word->word) && (l->word->flags & W_HASQUOTEDNULL))
5819         {
5820           w->flags |= W_HASQUOTEDNULL;
5821         }
5822       dispose_words (l);
5823     }
5824   else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol)
5825     {
5826       /* The brace expansion occurred between double quotes and there was
5827          a $@ in TEMP.  It does not matter if the $@ is quoted, as long as
5828          it does not expand to anything.  In this case, we want to return
5829          a quoted empty string. */
5830       temp = make_quoted_char ('\0');
5831       w->flags |= W_HASQUOTEDNULL;
5832     }
5833   else
5834     temp = (char *)NULL;
5835
5836   if (c == '-' || c == '+')
5837     {
5838       w->word = temp;
5839       return w;
5840     }
5841
5842   /* c == '=' */
5843   t = temp ? savestring (temp) : savestring ("");
5844   t1 = dequote_string (t);
5845   free (t);
5846 #if defined (ARRAY_VARS)
5847   if (valid_array_reference (name))
5848     assign_array_element (name, t1, 0);
5849   else
5850 #endif /* ARRAY_VARS */
5851   bind_variable (name, t1, 0);
5852
5853   /* From Posix group discussion Feb-March 2010.  Issue 7 0000221 */
5854   free (temp);
5855
5856   w->word = t1;
5857   return w;
5858 }
5859
5860 /* Deal with the right hand side of a ${name:?value} expansion in the case
5861    that NAME is null or not set.  If VALUE is non-null it is expanded and
5862    used as the error message to print, otherwise a standard message is
5863    printed. */
5864 static void
5865 parameter_brace_expand_error (name, value)
5866      char *name, *value;
5867 {
5868   WORD_LIST *l;
5869   char *temp;
5870
5871   if (value && *value)
5872     {
5873       l = expand_string (value, 0);
5874       temp =  string_list (l);
5875       report_error ("%s: %s", name, temp ? temp : "");  /* XXX was value not "" */
5876       FREE (temp);
5877       dispose_words (l);
5878     }
5879   else
5880     report_error (_("%s: parameter null or not set"), name);
5881
5882   /* Free the data we have allocated during this expansion, since we
5883      are about to longjmp out. */
5884   free (name);
5885   FREE (value);
5886 }
5887
5888 /* Return 1 if NAME is something for which parameter_brace_expand_length is
5889    OK to do. */
5890 static int
5891 valid_length_expression (name)
5892      char *name;
5893 {
5894   return (name[1] == '\0' ||                                    /* ${#} */
5895           ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') ||  /* special param */
5896           (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
5897 #if defined (ARRAY_VARS)
5898           valid_array_reference (name + 1) ||                   /* ${#a[7]} */
5899 #endif
5900           legal_identifier (name + 1));                         /* ${#PS1} */
5901 }
5902
5903 /* Handle the parameter brace expansion that requires us to return the
5904    length of a parameter. */
5905 static intmax_t
5906 parameter_brace_expand_length (name)
5907      char *name;
5908 {
5909   char *t, *newname;
5910   intmax_t number, arg_index;
5911   WORD_LIST *list;
5912 #if defined (ARRAY_VARS)
5913   SHELL_VAR *var;
5914 #endif
5915
5916   if (name[1] == '\0')                  /* ${#} */
5917     number = number_of_args ();
5918   else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0')       /* ${#@}, ${#*} */
5919     number = number_of_args ();
5920   else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
5921     {
5922       /* Take the lengths of some of the shell's special parameters. */
5923       switch (name[1])
5924         {
5925         case '-':
5926           t = which_set_flags ();
5927           break;
5928         case '?':
5929           t = itos (last_command_exit_value);
5930           break;
5931         case '$':
5932           t = itos (dollar_dollar_pid);
5933           break;
5934         case '!':
5935           if (last_asynchronous_pid == NO_PID)
5936             t = (char *)NULL;   /* XXX - error if set -u set? */
5937           else
5938             t = itos (last_asynchronous_pid);
5939           break;
5940         case '#':
5941           t = itos (number_of_args ());
5942           break;
5943         }
5944       number = STRLEN (t);
5945       FREE (t);
5946     }
5947 #if defined (ARRAY_VARS)
5948   else if (valid_array_reference (name + 1))
5949     number = array_length_reference (name + 1);
5950 #endif /* ARRAY_VARS */
5951   else
5952     {
5953       number = 0;
5954
5955       if (legal_number (name + 1, &arg_index))          /* ${#1} */
5956         {
5957           t = get_dollar_var_value (arg_index);
5958           if (t == 0 && unbound_vars_is_error)
5959             return INTMAX_MIN;
5960           number = MB_STRLEN (t);
5961           FREE (t);
5962         }
5963 #if defined (ARRAY_VARS)
5964       else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
5965         {
5966           if (assoc_p (var))
5967             t = assoc_reference (assoc_cell (var), "0");
5968           else
5969             t = array_reference (array_cell (var), 0);
5970           if (t == 0 && unbound_vars_is_error)
5971             return INTMAX_MIN;
5972           number = MB_STRLEN (t);
5973         }
5974 #endif
5975       else                              /* ${#PS1} */
5976         {
5977           newname = savestring (name);
5978           newname[0] = '$';
5979           list = expand_string (newname, Q_DOUBLE_QUOTES);
5980           t = list ? string_list (list) : (char *)NULL;
5981           free (newname);
5982           if (list)
5983             dispose_words (list);
5984
5985           number = t ? MB_STRLEN (t) : 0;
5986           FREE (t);
5987         }
5988     }
5989
5990   return (number);
5991 }
5992
5993 /* Skip characters in SUBSTR until DELIM.  SUBSTR is an arithmetic expression,
5994    so we do some ad-hoc parsing of an arithmetic expression to find
5995    the first DELIM, instead of using strchr(3).  Two rules:
5996         1.  If the substring contains a `(', read until closing `)'.
5997         2.  If the substring contains a `?', read past one `:' for each `?'.
5998 */
5999
6000 static char *
6001 skiparith (substr, delim)
6002      char *substr;
6003      int delim;
6004 {
6005   size_t sublen;
6006   int skipcol, pcount, i;
6007   DECLARE_MBSTATE;
6008
6009   sublen = strlen (substr);
6010   i = skipcol = pcount = 0;
6011   while (substr[i])
6012     {
6013       /* Balance parens */
6014       if (substr[i] == LPAREN)
6015         {
6016           pcount++;
6017           i++;
6018           continue;
6019         }
6020       if (substr[i] == RPAREN && pcount)
6021         {
6022           pcount--;
6023           i++;
6024           continue;
6025         }
6026       if (pcount)
6027         {
6028           ADVANCE_CHAR (substr, sublen, i);
6029           continue;
6030         }
6031
6032       /* Skip one `:' for each `?' */
6033       if (substr[i] == ':' && skipcol)
6034         {
6035           skipcol--;
6036           i++;
6037           continue;
6038         }
6039       if (substr[i] == delim)
6040         break;
6041       if (substr[i] == '?')
6042         {
6043           skipcol++;
6044           i++;
6045           continue;
6046         }
6047       ADVANCE_CHAR (substr, sublen, i);
6048     }
6049
6050   return (substr + i);
6051 }
6052
6053 /* Verify and limit the start and end of the desired substring.  If
6054    VTYPE == 0, a regular shell variable is being used; if it is 1,
6055    then the positional parameters are being used; if it is 2, then
6056    VALUE is really a pointer to an array variable that should be used.
6057    Return value is 1 if both values were OK, 0 if there was a problem
6058    with an invalid expression, or -1 if the values were out of range. */
6059 static int
6060 verify_substring_values (v, value, substr, vtype, e1p, e2p)
6061      SHELL_VAR *v;
6062      char *value, *substr;
6063      int vtype;
6064      intmax_t *e1p, *e2p;
6065 {
6066   char *t, *temp1, *temp2;
6067   arrayind_t len;
6068   int expok;
6069 #if defined (ARRAY_VARS)
6070  ARRAY *a;
6071  HASH_TABLE *h;
6072 #endif
6073
6074   /* duplicate behavior of strchr(3) */
6075   t = skiparith (substr, ':');
6076   if (*t && *t == ':')
6077     *t = '\0';
6078   else
6079     t = (char *)0;
6080
6081   temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES);
6082   *e1p = evalexp (temp1, &expok);
6083   free (temp1);
6084   if (expok == 0)
6085     return (0);
6086
6087   len = -1;     /* paranoia */
6088   switch (vtype)
6089     {
6090     case VT_VARIABLE:
6091     case VT_ARRAYMEMBER:
6092       len = MB_STRLEN (value);
6093       break;
6094     case VT_POSPARMS:
6095       len = number_of_args () + 1;
6096       if (*e1p == 0)
6097         len++;          /* add one arg if counting from $0 */
6098       break;
6099 #if defined (ARRAY_VARS)
6100     case VT_ARRAYVAR:
6101       /* For arrays, the first value deals with array indices.  Negative
6102          offsets count from one past the array's maximum index.  Associative
6103          arrays treat the number of elements as the maximum index. */
6104       if (assoc_p (v))
6105         {
6106           h = assoc_cell (v);
6107           len = assoc_num_elements (h) + (*e1p < 0);
6108         }
6109       else
6110         {
6111           a = (ARRAY *)value;
6112           len = array_max_index (a) + (*e1p < 0);       /* arrays index from 0 to n - 1 */
6113         }
6114       break;
6115 #endif
6116     }
6117
6118   if (len == -1)        /* paranoia */
6119     return -1;
6120
6121   if (*e1p < 0)         /* negative offsets count from end */
6122     *e1p += len;
6123
6124   if (*e1p > len || *e1p < 0)
6125     return (-1);
6126
6127 #if defined (ARRAY_VARS)
6128   /* For arrays, the second offset deals with the number of elements. */
6129   if (vtype == VT_ARRAYVAR)
6130     len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
6131 #endif
6132
6133   if (t)
6134     {
6135       t++;
6136       temp2 = savestring (t);
6137       temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
6138       free (temp2);
6139       t[-1] = ':';
6140       *e2p = evalexp (temp1, &expok);
6141       free (temp1);
6142       if (expok == 0)
6143         return (0);
6144       if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
6145         {
6146           internal_error (_("%s: substring expression < 0"), t);
6147           return (0);
6148         }
6149 #if defined (ARRAY_VARS)
6150       /* In order to deal with sparse arrays, push the intelligence about how
6151          to deal with the number of elements desired down to the array-
6152          specific functions.  */
6153       if (vtype != VT_ARRAYVAR)
6154 #endif
6155         {
6156           if (*e2p < 0)
6157             {
6158               *e2p += len;
6159               if (*e2p < 0 || *e2p < *e1p)
6160                 {
6161                   internal_error (_("%s: substring expression < 0"), t);
6162                   return (0);
6163                 }
6164             }
6165           else
6166             *e2p += *e1p;               /* want E2 chars starting at E1 */
6167           if (*e2p > len)
6168             *e2p = len;
6169         }
6170     }
6171   else
6172     *e2p = len;
6173
6174   return (1);
6175 }
6176
6177 /* Return the type of variable specified by VARNAME (simple variable,
6178    positional param, or array variable).  Also return the value specified
6179    by VARNAME (value of a variable or a reference to an array element).
6180    QUOTED is the standard description of quoting state, using Q_* defines.
6181    FLAGS is currently a set of flags to pass to array_value.  If IND is
6182    non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
6183    passed to array_value so the array index is not computed again.
6184    If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
6185    characters in the value are quoted with CTLESC and takes appropriate
6186    steps.  For convenience, *VALP is set to the dequoted VALUE. */
6187 static int
6188 get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
6189      char *varname, *value;
6190      arrayind_t ind;
6191      int quoted, flags;
6192      SHELL_VAR **varp;
6193      char **valp;
6194 {
6195   int vtype;
6196   char *temp;
6197 #if defined (ARRAY_VARS)
6198   SHELL_VAR *v;
6199 #endif
6200   arrayind_t lind;
6201
6202   /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
6203   vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0';
6204   if (vtype == VT_POSPARMS && varname[0] == '*')
6205     vtype |= VT_STARSUB;
6206   *varp = (SHELL_VAR *)NULL;
6207
6208 #if defined (ARRAY_VARS)
6209   if (valid_array_reference (varname))
6210     {
6211       v = array_variable_part (varname, &temp, (int *)0);
6212       /* If we want to signal array_value to use an already-computed index,
6213          set LIND to that index */
6214       lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0;
6215       if (v && (array_p (v) || assoc_p (v)))
6216         { /* [ */
6217           if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
6218             {
6219               /* Callers have to differentiate betwen indexed and associative */
6220               vtype = VT_ARRAYVAR;
6221               if (temp[0] == '*')
6222                 vtype |= VT_STARSUB;
6223               *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
6224             }
6225           else
6226             {
6227               vtype = VT_ARRAYMEMBER;
6228               *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
6229             }
6230           *varp = v;
6231         }
6232       else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']'))
6233         {
6234           vtype = VT_VARIABLE;
6235           *varp = v;
6236           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6237             *valp = dequote_string (value);
6238           else
6239             *valp = dequote_escapes (value);
6240         }
6241       else
6242         {
6243           vtype = VT_ARRAYMEMBER;
6244           *varp = v;
6245           *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
6246         }
6247     }
6248   else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
6249     {
6250       vtype = VT_ARRAYMEMBER;
6251       *varp = v;
6252       *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
6253     }
6254   else
6255 #endif
6256     {
6257       if (value && vtype == VT_VARIABLE)
6258         {
6259           if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6260             *valp = dequote_string (value);
6261           else
6262             *valp = dequote_escapes (value);
6263         }
6264       else
6265         *valp = value;
6266     }
6267
6268   return vtype;
6269 }
6270
6271 /******************************************************/
6272 /*                                                    */
6273 /* Functions to extract substrings of variable values */
6274 /*                                                    */
6275 /******************************************************/
6276
6277 #if defined (HANDLE_MULTIBYTE)
6278 /* Character-oriented rather than strictly byte-oriented substrings.  S and
6279    E, rather being strict indices into STRING, indicate character (possibly
6280    multibyte character) positions that require calculation.
6281    Used by the ${param:offset[:length]} expansion. */
6282 static char *
6283 mb_substring (string, s, e)
6284      char *string;
6285      int s, e;
6286 {
6287   char *tt;
6288   int start, stop, i, slen;
6289   DECLARE_MBSTATE;
6290
6291   start = 0;
6292   /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
6293   slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
6294
6295   i = s;
6296   while (string[start] && i--)
6297     ADVANCE_CHAR (string, slen, start);
6298   stop = start;
6299   i = e - s;
6300   while (string[stop] && i--)
6301     ADVANCE_CHAR (string, slen, stop);
6302   tt = substring (string, start, stop);
6303   return tt;
6304 }
6305 #endif
6306   
6307 /* Process a variable substring expansion: ${name:e1[:e2]}.  If VARNAME
6308    is `@', use the positional parameters; otherwise, use the value of
6309    VARNAME.  If VARNAME is an array variable, use the array elements. */
6310
6311 static char *
6312 parameter_brace_substring (varname, value, ind, substr, quoted, flags)
6313      char *varname, *value;
6314      int ind;
6315      char *substr;
6316      int quoted, flags;
6317 {
6318   intmax_t e1, e2;
6319   int vtype, r, starsub;
6320   char *temp, *val, *tt, *oname;
6321   SHELL_VAR *v;
6322
6323   if (value == 0)
6324     return ((char *)NULL);
6325
6326   oname = this_command_name;
6327   this_command_name = varname;
6328
6329   vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
6330   if (vtype == -1)
6331     {
6332       this_command_name = oname;
6333       return ((char *)NULL);
6334     }
6335
6336   starsub = vtype & VT_STARSUB;
6337   vtype &= ~VT_STARSUB;
6338
6339   r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
6340   this_command_name = oname;
6341   if (r <= 0)
6342     return ((r == 0) ? &expand_param_error : (char *)NULL);
6343
6344   switch (vtype)
6345     {
6346     case VT_VARIABLE:
6347     case VT_ARRAYMEMBER:
6348 #if defined (HANDLE_MULTIBYTE)
6349       if (MB_CUR_MAX > 1)
6350         tt = mb_substring (val, e1, e2);
6351       else
6352 #endif
6353       tt = substring (val, e1, e2);
6354
6355       if (vtype == VT_VARIABLE)
6356         FREE (val);
6357       if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6358         temp = quote_string (tt);
6359       else
6360         temp = tt ? quote_escapes (tt) : (char *)NULL;
6361       FREE (tt);
6362       break;
6363     case VT_POSPARMS:
6364       tt = pos_params (varname, e1, e2, quoted);
6365       if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
6366         {
6367           temp = tt ? quote_escapes (tt) : (char *)NULL;
6368           FREE (tt);
6369         }
6370       else
6371         temp = tt;
6372       break;
6373 #if defined (ARRAY_VARS)
6374     case VT_ARRAYVAR:
6375       if (assoc_p (v))
6376         /* we convert to list and take first e2 elements starting at e1th
6377            element -- officially undefined for now */   
6378         temp = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted);
6379       else
6380       /* We want E2 to be the number of elements desired (arrays can be sparse,
6381          so verify_substring_values just returns the numbers specified and we
6382          rely on array_subrange to understand how to deal with them). */
6383         temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
6384       /* array_subrange now calls array_quote_escapes as appropriate, so the
6385          caller no longer needs to. */
6386       break;
6387 #endif
6388     default:
6389       temp = (char *)NULL;
6390     }
6391
6392   return temp;
6393 }
6394
6395 /****************************************************************/
6396 /*                                                              */
6397 /* Functions to perform pattern substitution on variable values */
6398 /*                                                              */
6399 /****************************************************************/
6400
6401 static int
6402 shouldexp_replacement (s)
6403      char *s;
6404 {
6405   register char *p;
6406
6407   for (p = s; p && *p; p++)
6408     {
6409       if (*p == '\\')
6410         p++;
6411       else if (*p == '&')
6412         return 1;
6413     }
6414   return 0;
6415 }
6416
6417 char *
6418 pat_subst (string, pat, rep, mflags)
6419      char *string, *pat, *rep;
6420      int mflags;
6421 {
6422   char *ret, *s, *e, *str, *rstr, *mstr;
6423   int rsize, rptr, l, replen, mtype, rxpand, rslen, mlen;
6424
6425   if (string  == 0)
6426     return (savestring (""));
6427
6428   mtype = mflags & MATCH_TYPEMASK;
6429
6430 #if 0   /* bash-4.2 ? */
6431   rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0;
6432 #else
6433   rxpand = 0;
6434 #endif
6435
6436   /* Special cases:
6437    *    1.  A null pattern with mtype == MATCH_BEG means to prefix STRING
6438    *        with REP and return the result.
6439    *    2.  A null pattern with mtype == MATCH_END means to append REP to
6440    *        STRING and return the result.
6441    * These don't understand or process `&' in the replacement string.
6442    */
6443   if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
6444     {
6445       replen = STRLEN (rep);
6446       l = STRLEN (string);
6447       ret = (char *)xmalloc (replen + l + 2);
6448       if (replen == 0)
6449         strcpy (ret, string);
6450       else if (mtype == MATCH_BEG)
6451         {
6452           strcpy (ret, rep);
6453           strcpy (ret + replen, string);
6454         }
6455       else
6456         {
6457           strcpy (ret, string);
6458           strcpy (ret + l, rep);
6459         }
6460       return (ret);
6461     }
6462
6463   ret = (char *)xmalloc (rsize = 64);
6464   ret[0] = '\0';
6465
6466   for (replen = STRLEN (rep), rptr = 0, str = string;;)
6467     {
6468       if (match_pattern (str, pat, mtype, &s, &e) == 0)
6469         break;
6470       l = s - str;
6471
6472       if (rxpand)
6473         {
6474           int x;
6475           mlen = e - s;
6476           mstr = xmalloc (mlen + 1);
6477           for (x = 0; x < mlen; x++)
6478             mstr[x] = s[x];
6479           mstr[mlen] = '\0';
6480           rstr = strcreplace (rep, '&', mstr, 0);
6481           rslen = strlen (rstr);
6482         }
6483       else
6484         {
6485           rstr = rep;
6486           rslen = replen;
6487         }
6488         
6489       RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
6490
6491       /* OK, now copy the leading unmatched portion of the string (from
6492          str to s) to ret starting at rptr (the current offset).  Then copy
6493          the replacement string at ret + rptr + (s - str).  Increment
6494          rptr (if necessary) and str and go on. */
6495       if (l)
6496         {
6497           strncpy (ret + rptr, str, l);
6498           rptr += l;
6499         }
6500       if (replen)
6501         {
6502           strncpy (ret + rptr, rstr, rslen);
6503           rptr += rslen;
6504         }
6505       str = e;          /* e == end of match */
6506
6507       if (rstr != rep)
6508         free (rstr);
6509
6510       if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
6511         break;
6512
6513       if (s == e)
6514         {
6515           /* On a zero-length match, make sure we copy one character, since
6516              we increment one character to avoid infinite recursion. */
6517           RESIZE_MALLOCED_BUFFER (ret, rptr, 1, rsize, 64);
6518           ret[rptr++] = *str++;
6519           e++;          /* avoid infinite recursion on zero-length match */
6520         }
6521     }
6522
6523   /* Now copy the unmatched portion of the input string */
6524   if (str && *str)
6525     {
6526       RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
6527       strcpy (ret + rptr, str);
6528     }
6529   else
6530     ret[rptr] = '\0';
6531
6532   return ret;
6533 }
6534
6535 /* Do pattern match and replacement on the positional parameters. */
6536 static char *
6537 pos_params_pat_subst (string, pat, rep, mflags)
6538      char *string, *pat, *rep;
6539      int mflags;
6540 {
6541   WORD_LIST *save, *params;
6542   WORD_DESC *w;
6543   char *ret;
6544   int pchar, qflags;
6545
6546   save = params = list_rest_of_args ();
6547   if (save == 0)
6548     return ((char *)NULL);
6549
6550   for ( ; params; params = params->next)
6551     {
6552       ret = pat_subst (params->word->word, pat, rep, mflags);
6553       w = alloc_word_desc ();
6554       w->word = ret ? ret : savestring ("");
6555       dispose_word (params->word);
6556       params->word = w;
6557     }
6558
6559   pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6560   qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6561
6562 #if 0
6563   if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
6564     ret = string_list_dollar_star (quote_list (save));
6565   else if ((mflags & MATCH_STARSUB) == MATCH_STARSUB)
6566     ret = string_list_dollar_star (save);
6567   else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED)
6568     ret = string_list_dollar_at (save, qflags);
6569   else
6570     ret = string_list_dollar_star (save);
6571 #else
6572   ret = string_list_pos_params (pchar, save, qflags);
6573 #endif
6574
6575   dispose_words (save);
6576
6577   return (ret);
6578 }
6579
6580 /* Perform pattern substitution on VALUE, which is the expansion of
6581    VARNAME.  PATSUB is an expression supplying the pattern to match
6582    and the string to substitute.  QUOTED is a flags word containing
6583    the type of quoting currently in effect. */
6584 static char *
6585 parameter_brace_patsub (varname, value, ind, patsub, quoted, flags)
6586      char *varname, *value;
6587      int ind;
6588      char *patsub;
6589      int quoted, flags;
6590 {
6591   int vtype, mflags, starsub, delim;
6592   char *val, *temp, *pat, *rep, *p, *lpatsub, *tt;
6593   SHELL_VAR *v;
6594
6595   if (value == 0)
6596     return ((char *)NULL);
6597
6598   this_command_name = varname;
6599
6600   vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
6601   if (vtype == -1)
6602     return ((char *)NULL);
6603
6604   starsub = vtype & VT_STARSUB;
6605   vtype &= ~VT_STARSUB;
6606
6607   mflags = 0;
6608   if (patsub && *patsub == '/')
6609     {
6610       mflags |= MATCH_GLOBREP;
6611       patsub++;
6612     }
6613
6614   /* Malloc this because expand_string_if_necessary or one of the expansion
6615      functions in its call chain may free it on a substitution error. */
6616   lpatsub = savestring (patsub);
6617
6618   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6619     mflags |= MATCH_QUOTED;
6620
6621   if (starsub)
6622     mflags |= MATCH_STARSUB;
6623
6624   /* If the pattern starts with a `/', make sure we skip over it when looking
6625      for the replacement delimiter. */
6626 #if 0
6627   if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL))
6628     *rep++ = '\0';
6629   else
6630     rep = (char *)NULL;
6631 #else
6632   delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
6633   if (lpatsub[delim] == '/')
6634     {
6635       lpatsub[delim] = 0;
6636       rep = lpatsub + delim + 1;
6637     }
6638   else
6639     rep = (char *)NULL;
6640 #endif
6641
6642   if (rep && *rep == '\0')
6643     rep = (char *)NULL;
6644
6645   /* Perform the same expansions on the pattern as performed by the
6646      pattern removal expansions. */
6647   pat = getpattern (lpatsub, quoted, 1);
6648
6649   if (rep)
6650     {
6651       if ((mflags & MATCH_QUOTED) == 0)
6652         rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
6653       else
6654         rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
6655     }
6656
6657   /* ksh93 doesn't allow the match specifier to be a part of the expanded
6658      pattern.  This is an extension.  Make sure we don't anchor the pattern
6659      at the beginning or end of the string if we're doing global replacement,
6660      though. */
6661   p = pat;
6662   if (mflags & MATCH_GLOBREP)
6663     mflags |= MATCH_ANY;
6664   else if (pat && pat[0] == '#')
6665     {
6666       mflags |= MATCH_BEG;
6667       p++;
6668     }
6669   else if (pat && pat[0] == '%')
6670     {
6671       mflags |= MATCH_END;
6672       p++;
6673     }
6674   else
6675     mflags |= MATCH_ANY;
6676
6677   /* OK, we now want to substitute REP for PAT in VAL.  If
6678      flags & MATCH_GLOBREP is non-zero, the substitution is done
6679      everywhere, otherwise only the first occurrence of PAT is
6680      replaced.  The pattern matching code doesn't understand
6681      CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
6682      values passed in (VT_VARIABLE) so the pattern substitution
6683      code works right.  We need to requote special chars after
6684      we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
6685      other cases if QUOTED == 0, since the posparams and arrays
6686      indexed by * or @ do special things when QUOTED != 0. */
6687
6688   switch (vtype)
6689     {
6690     case VT_VARIABLE:
6691     case VT_ARRAYMEMBER:
6692       temp = pat_subst (val, p, rep, mflags);
6693       if (vtype == VT_VARIABLE)
6694         FREE (val);
6695       if (temp)
6696         {
6697           tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
6698           free (temp);
6699           temp = tt;
6700         }
6701       break;
6702     case VT_POSPARMS:
6703       temp = pos_params_pat_subst (val, p, rep, mflags);
6704       if (temp && (mflags & MATCH_QUOTED) == 0)
6705         {
6706           tt = quote_escapes (temp);
6707           free (temp);
6708           temp = tt;
6709         }
6710       break;
6711 #if defined (ARRAY_VARS)
6712     case VT_ARRAYVAR:
6713       temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags)
6714                          : array_patsub (array_cell (v), p, rep, mflags);
6715       /* Don't call quote_escapes anymore; array_patsub calls
6716          array_quote_escapes as appropriate before adding the
6717          space separators; ditto for assoc_patsub. */
6718       break;
6719 #endif
6720     }
6721
6722   FREE (pat);
6723   FREE (rep);
6724   free (lpatsub);
6725
6726   return temp;
6727 }
6728
6729 /****************************************************************/
6730 /*                                                              */
6731 /*   Functions to perform case modification on variable values  */
6732 /*                                                              */
6733 /****************************************************************/
6734
6735 /* Do case modification on the positional parameters. */
6736
6737 static char *
6738 pos_params_modcase (string, pat, modop, mflags)
6739      char *string, *pat;
6740      int modop;
6741      int mflags;
6742 {
6743   WORD_LIST *save, *params;
6744   WORD_DESC *w;
6745   char *ret;
6746   int pchar, qflags;
6747
6748   save = params = list_rest_of_args ();
6749   if (save == 0)
6750     return ((char *)NULL);
6751
6752   for ( ; params; params = params->next)
6753     {
6754       ret = sh_modcase (params->word->word, pat, modop);
6755       w = alloc_word_desc ();
6756       w->word = ret ? ret : savestring ("");
6757       dispose_word (params->word);
6758       params->word = w;
6759     }
6760
6761   pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6762   qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6763
6764   ret = string_list_pos_params (pchar, save, qflags);
6765   dispose_words (save);
6766
6767   return (ret);
6768 }
6769
6770 /* Perform case modification on VALUE, which is the expansion of
6771    VARNAME.  MODSPEC is an expression supplying the type of modification
6772    to perform.  QUOTED is a flags word containing the type of quoting
6773    currently in effect. */
6774 static char *
6775 parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, flags)
6776      char *varname, *value;
6777      int ind, modspec;
6778      char *patspec;
6779      int quoted, flags;
6780 {
6781   int vtype, starsub, modop, mflags, x;
6782   char *val, *temp, *pat, *p, *lpat, *tt;
6783   SHELL_VAR *v;
6784
6785   if (value == 0)
6786     return ((char *)NULL);
6787
6788   this_command_name = varname;
6789
6790   vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
6791   if (vtype == -1)
6792     return ((char *)NULL);
6793
6794   starsub = vtype & VT_STARSUB;
6795   vtype &= ~VT_STARSUB;
6796
6797   modop = 0;
6798   mflags = 0;
6799   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6800     mflags |= MATCH_QUOTED;
6801   if (starsub)
6802     mflags |= MATCH_STARSUB;
6803   
6804   p = patspec;
6805   if (modspec == '^')
6806     {
6807       x = p && p[0] == modspec;
6808       modop = x ? CASE_UPPER : CASE_UPFIRST;
6809       p += x;
6810     }
6811   else if (modspec == ',')
6812     {
6813       x = p && p[0] == modspec;
6814       modop = x ? CASE_LOWER : CASE_LOWFIRST;
6815       p += x;
6816     }
6817   else if (modspec == '~')
6818     {
6819       x = p && p[0] == modspec;
6820       modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
6821       p += x;
6822     }
6823     
6824   lpat = p ? savestring (p) : 0;
6825   /* Perform the same expansions on the pattern as performed by the
6826      pattern removal expansions.  FOR LATER */
6827   pat = lpat ? getpattern (lpat, quoted, 1) : 0;
6828
6829   /* OK, now we do the case modification. */
6830   switch (vtype)
6831     {
6832     case VT_VARIABLE:
6833     case VT_ARRAYMEMBER:
6834       temp = sh_modcase (val, pat, modop);
6835       if (vtype == VT_VARIABLE)
6836         FREE (val);
6837       if (temp)
6838         {
6839           tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
6840           free (temp);
6841           temp = tt;
6842         }
6843       break;
6844
6845     case VT_POSPARMS:
6846       temp = pos_params_modcase (val, pat, modop, mflags);
6847       if (temp && (mflags & MATCH_QUOTED)  == 0)
6848         {
6849           tt = quote_escapes (temp);
6850           free (temp);
6851           temp = tt;
6852         }
6853       break;
6854
6855 #if defined (ARRAY_VARS)
6856     case VT_ARRAYVAR:
6857       temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
6858                          : array_modcase (array_cell (v), pat, modop, mflags);
6859       /* Don't call quote_escapes; array_modcase calls array_quote_escapes
6860          as appropriate before adding the space separators; ditto for
6861          assoc_modcase. */
6862       break;
6863 #endif
6864     }
6865
6866   FREE (pat);
6867   free (lpat);
6868
6869   return temp;
6870 }
6871
6872 /* Check for unbalanced parens in S, which is the contents of $(( ... )).  If
6873    any occur, this must be a nested command substitution, so return 0.
6874    Otherwise, return 1.  A valid arithmetic expression must always have a
6875    ( before a matching ), so any cases where there are more right parens
6876    means that this must not be an arithmetic expression, though the parser
6877    will not accept it without a balanced total number of parens. */
6878 static int
6879 chk_arithsub (s, len)
6880      const char *s;
6881      int len;
6882 {
6883   int i, count;
6884   DECLARE_MBSTATE;
6885
6886   i = count = 0;
6887   while (i < len)
6888     {
6889       if (s[i] == LPAREN)
6890         count++;
6891       else if (s[i] == RPAREN)
6892         {
6893           count--;
6894           if (count < 0)
6895             return 0;
6896         }
6897
6898       switch (s[i])
6899         {
6900         default:
6901           ADVANCE_CHAR (s, len, i);
6902           break;
6903
6904         case '\\':
6905           i++;
6906           if (s[i])
6907             ADVANCE_CHAR (s, len, i);
6908           break;
6909
6910         case '\'':
6911           i = skip_single_quoted (s, len, ++i);
6912           break;
6913
6914         case '"':
6915           i = skip_double_quoted ((char *)s, len, ++i);
6916           break;
6917         }
6918     }
6919
6920   return (count == 0);
6921 }
6922
6923 /****************************************************************/
6924 /*                                                              */
6925 /*      Functions to perform parameter expansion on a string    */
6926 /*                                                              */
6927 /****************************************************************/
6928
6929 /* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
6930 static WORD_DESC *
6931 parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
6932      char *string;
6933      int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at, pflags;
6934 {
6935   int check_nullness, var_is_set, var_is_null, var_is_special;
6936   int want_substring, want_indir, want_patsub, want_casemod;
6937   char *name, *value, *temp, *temp1;
6938   WORD_DESC *tdesc, *ret;
6939   int t_index, sindex, c, tflag, modspec;
6940   intmax_t number;
6941   arrayind_t ind;
6942
6943   temp = temp1 = value = (char *)NULL;
6944   var_is_set = var_is_null = var_is_special = check_nullness = 0;
6945   want_substring = want_indir = want_patsub = want_casemod = 0;
6946
6947   sindex = *indexp;
6948   t_index = ++sindex;
6949   /* ${#var} doesn't have any of the other parameter expansions on it. */
6950   if (string[t_index] == '#' && legal_variable_starter (string[t_index+1]))             /* {{ */
6951     name = string_extract (string, &t_index, "}", SX_VARNAME);
6952   else
6953 #if defined (CASEMOD_EXPANSIONS)
6954     /* To enable case-toggling expansions using the `~' operator character
6955        change the 1 to 0. */
6956 #  if defined (CASEMOD_CAPCASE)
6957     name = string_extract (string, &t_index, "#%^,~:-=?+/}", SX_VARNAME);
6958 #  else
6959     name = string_extract (string, &t_index, "#%^,:-=?+/}", SX_VARNAME);
6960 #  endif /* CASEMOD_CAPCASE */
6961 #else
6962     name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME);
6963 #endif /* CASEMOD_EXPANSIONS */
6964
6965   ret = 0;
6966   tflag = 0;
6967
6968   ind = INTMAX_MIN;
6969
6970   /* If the name really consists of a special variable, then make sure
6971      that we have the entire name.  We don't allow indirect references
6972      to special variables except `#', `?', `@' and `*'. */
6973   if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
6974       (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
6975     {
6976       t_index++;
6977       free (name);
6978       temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
6979       name = (char *)xmalloc (3 + (strlen (temp1)));
6980       *name = string[sindex];
6981       if (string[sindex] == '!')
6982         {
6983           /* indirect reference of $#, $?, $@, or $* */
6984           name[1] = string[sindex + 1];
6985           strcpy (name + 2, temp1);
6986         }
6987       else      
6988         strcpy (name + 1, temp1);
6989       free (temp1);
6990     }
6991   sindex = t_index;
6992
6993   /* Find out what character ended the variable name.  Then
6994      do the appropriate thing. */
6995   if (c = string[sindex])
6996     sindex++;
6997
6998   /* If c is followed by one of the valid parameter expansion
6999      characters, move past it as normal.  If not, assume that
7000      a substring specification is being given, and do not move
7001      past it. */
7002   if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
7003     {
7004       check_nullness++;
7005       if (c = string[sindex])
7006         sindex++;
7007     }
7008   else if (c == ':' && string[sindex] != RBRACE)
7009     want_substring = 1;
7010   else if (c == '/' && string[sindex] != RBRACE)
7011     want_patsub = 1;
7012 #if defined (CASEMOD_EXPANSIONS)
7013   else if (c == '^' || c == ',' || c == '~')
7014     {
7015       modspec = c;
7016       want_casemod = 1;
7017     }
7018 #endif
7019
7020   /* Catch the valid and invalid brace expressions that made it through the
7021      tests above. */
7022   /* ${#-} is a valid expansion and means to take the length of $-.
7023      Similarly for ${#?} and ${##}... */
7024   if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
7025         VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
7026     {
7027       name = (char *)xrealloc (name, 3);
7028       name[1] = c;
7029       name[2] = '\0';
7030       c = string[sindex++];
7031     }
7032
7033   /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
7034   if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
7035         member (c, "%:=+/") && string[sindex] == RBRACE)
7036     {
7037       temp = (char *)NULL;
7038       goto bad_substitution;
7039     }
7040
7041   /* Indirect expansion begins with a `!'.  A valid indirect expansion is
7042      either a variable name, one of the positional parameters or a special
7043      variable that expands to one of the positional parameters. */
7044   want_indir = *name == '!' &&
7045     (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
7046                                         || VALID_INDIR_PARAM (name[1]));
7047
7048   /* Determine the value of this variable. */
7049
7050   /* Check for special variables, directly referenced. */
7051   if (SPECIAL_VAR (name, want_indir))
7052     var_is_special++;
7053
7054   /* Check for special expansion things, like the length of a parameter */
7055   if (*name == '#' && name[1])
7056     {
7057       /* If we are not pointing at the character just after the
7058          closing brace, then we haven't gotten all of the name.
7059          Since it begins with a special character, this is a bad
7060          substitution.  Also check NAME for validity before trying
7061          to go on. */
7062       if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
7063         {
7064           temp = (char *)NULL;
7065           goto bad_substitution;
7066         }
7067
7068       number = parameter_brace_expand_length (name);
7069       if (number == INTMAX_MIN && unbound_vars_is_error)
7070         {
7071           last_command_exit_value = EXECUTION_FAILURE;
7072           err_unboundvar (name+1);
7073           free (name);
7074           return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7075         }
7076       free (name);
7077
7078       *indexp = sindex;
7079       if (number < 0)
7080         return (&expand_wdesc_error);
7081       else
7082         {
7083           ret = alloc_word_desc ();
7084           ret->word = itos (number);
7085           return ret;
7086         }
7087     }
7088
7089   /* ${@} is identical to $@. */
7090   if (name[0] == '@' && name[1] == '\0')
7091     {
7092       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7093         *quoted_dollar_atp = 1;
7094
7095       if (contains_dollar_at)
7096         *contains_dollar_at = 1;
7097     }
7098
7099   /* Process ${!PREFIX*} expansion. */
7100   if (want_indir && string[sindex - 1] == RBRACE &&
7101       (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
7102       legal_variable_starter ((unsigned char) name[1]))
7103     {
7104       char **x;
7105       WORD_LIST *xlist;
7106
7107       temp1 = savestring (name + 1);
7108       number = strlen (temp1);
7109       temp1[number - 1] = '\0';
7110       x = all_variables_matching_prefix (temp1);
7111       xlist = strvec_to_word_list (x, 0, 0);
7112       if (string[sindex - 2] == '*')
7113         temp = string_list_dollar_star (xlist);
7114       else
7115         {
7116           temp = string_list_dollar_at (xlist, quoted);
7117           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7118             *quoted_dollar_atp = 1;
7119           if (contains_dollar_at)
7120             *contains_dollar_at = 1;
7121         }
7122       free (x);
7123       dispose_words (xlist);
7124       free (temp1);
7125       *indexp = sindex;
7126
7127       ret = alloc_word_desc ();
7128       ret->word = temp;
7129       return ret;
7130     }
7131
7132 #if defined (ARRAY_VARS)      
7133   /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */
7134   if (want_indir && string[sindex - 1] == RBRACE &&
7135       string[sindex - 2] == ']' && valid_array_reference (name+1))
7136     {
7137       char *x, *x1;
7138
7139       temp1 = savestring (name + 1);
7140       x = array_variable_name (temp1, &x1, (int *)0);   /* [ */
7141       FREE (x);
7142       if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']')
7143         {
7144           temp = array_keys (temp1, quoted);    /* handles assoc vars too */
7145           if (x1[0] == '@')
7146             {
7147               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7148                 *quoted_dollar_atp = 1;
7149               if (contains_dollar_at)
7150                 *contains_dollar_at = 1;
7151             }       
7152
7153           free (temp1);
7154           *indexp = sindex;
7155
7156           ret = alloc_word_desc ();
7157           ret->word = temp;
7158           return ret;
7159         }
7160
7161       free (temp1);
7162     }
7163 #endif /* ARRAY_VARS */
7164       
7165   /* Make sure that NAME is valid before trying to go on. */
7166   if (valid_brace_expansion_word (want_indir ? name + 1 : name,
7167                                         var_is_special) == 0)
7168     {
7169       temp = (char *)NULL;
7170       goto bad_substitution;
7171     }
7172
7173   if (want_indir)
7174     tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
7175   else
7176     tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&PF_NOSPLIT2), &ind);
7177
7178   if (tdesc)
7179     {
7180       temp = tdesc->word;
7181       tflag = tdesc->flags;
7182       dispose_word_desc (tdesc);
7183     }
7184   else
7185     temp = (char  *)0;
7186
7187 #if defined (ARRAY_VARS)
7188   if (valid_array_reference (name))
7189     chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at);
7190 #endif
7191
7192   var_is_set = temp != (char *)0;
7193   var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
7194
7195   /* Get the rest of the stuff inside the braces. */
7196   if (c && c != RBRACE)
7197     {
7198       /* Extract the contents of the ${ ... } expansion
7199          according to the Posix.2 rules. */
7200       value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
7201       if (string[sindex] == RBRACE)
7202         sindex++;
7203       else
7204         goto bad_substitution;
7205     }
7206   else
7207     value = (char *)NULL;
7208
7209   *indexp = sindex;
7210
7211   /* All the cases where an expansion can possibly generate an unbound
7212      variable error. */
7213   if (want_substring || want_patsub || want_casemod || c == '#' || c == '%' || c == RBRACE)
7214     {
7215       if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
7216         {
7217           last_command_exit_value = EXECUTION_FAILURE;
7218           err_unboundvar (name);
7219           FREE (value);
7220           FREE (temp);
7221           free (name);
7222           return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7223         }
7224     }
7225     
7226   /* If this is a substring spec, process it and add the result. */
7227   if (want_substring)
7228     {
7229       temp1 = parameter_brace_substring (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7230       FREE (name);
7231       FREE (value);
7232       FREE (temp);
7233
7234       if (temp1 == &expand_param_error)
7235         return (&expand_wdesc_error);
7236       else if (temp1 == &expand_param_fatal)
7237         return (&expand_wdesc_fatal);
7238
7239       ret = alloc_word_desc ();
7240       ret->word = temp1;
7241       if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7242         ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7243       return ret;
7244     }
7245   else if (want_patsub)
7246     {
7247       temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7248       FREE (name);
7249       FREE (value);
7250       FREE (temp);
7251
7252       if (temp1 == &expand_param_error)
7253         return (&expand_wdesc_error);
7254       else if (temp1 == &expand_param_fatal)
7255         return (&expand_wdesc_fatal);
7256
7257       ret = alloc_word_desc ();
7258       ret->word = temp1;
7259       ret = alloc_word_desc ();
7260       ret->word = temp1;
7261       if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7262         ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7263       return ret;
7264     }
7265 #if defined (CASEMOD_EXPANSIONS)
7266   else if (want_casemod)
7267     {
7268       temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7269       FREE (name);
7270       FREE (value);
7271       FREE (temp);
7272
7273       if (temp1 == &expand_param_error)
7274         return (&expand_wdesc_error);
7275       else if (temp1 == &expand_param_fatal)
7276         return (&expand_wdesc_fatal);
7277
7278       ret = alloc_word_desc ();
7279       ret->word = temp1;
7280       if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7281         ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7282       return ret;
7283     }
7284 #endif
7285
7286   /* Do the right thing based on which character ended the variable name. */
7287   switch (c)
7288     {
7289     default:
7290     case '\0':
7291     bad_substitution:
7292       last_command_exit_value = EXECUTION_FAILURE;
7293       report_error (_("%s: bad substitution"), string ? string : "??");
7294       FREE (value);
7295       FREE (temp);
7296       free (name);
7297       return &expand_wdesc_error;
7298
7299     case RBRACE:
7300       break;
7301
7302     case '#':   /* ${param#[#]pattern} */
7303     case '%':   /* ${param%[%]pattern} */
7304       if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
7305         {
7306           FREE (value);
7307           break;
7308         }
7309       temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7310       free (temp);
7311       free (value);
7312       free (name);
7313
7314       ret = alloc_word_desc ();
7315       ret->word = temp1;
7316       if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7317         ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7318       return ret;
7319
7320     case '-':
7321     case '=':
7322     case '?':
7323     case '+':
7324       if (var_is_set && var_is_null == 0)
7325         {
7326           /* If the operator is `+', we don't want the value of the named
7327              variable for anything, just the value of the right hand side. */
7328           if (c == '+')
7329             {
7330               /* XXX -- if we're double-quoted and the named variable is "$@",
7331                         we want to turn off any special handling of "$@" --
7332                         we're not using it, so whatever is on the rhs applies. */
7333               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7334                 *quoted_dollar_atp = 0;
7335               if (contains_dollar_at)
7336                 *contains_dollar_at = 0;
7337
7338               FREE (temp);
7339               if (value)
7340                 {
7341                   /* From Posix discussion on austin-group list.  Issue 221
7342                      requires that backslashes escaping `}' inside
7343                      double-quoted ${...} be removed. */
7344                   if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7345                     quoted |= Q_DOLBRACE;
7346                   ret = parameter_brace_expand_rhs (name, value, c,
7347                                                     quoted,
7348                                                     quoted_dollar_atp,
7349                                                     contains_dollar_at);
7350                   /* XXX - fix up later, esp. noting presence of
7351                            W_HASQUOTEDNULL in ret->flags */
7352                   free (value);
7353                 }
7354               else
7355                 temp = (char *)NULL;
7356             }
7357           else
7358             {
7359               FREE (value);
7360             }
7361           /* Otherwise do nothing; just use the value in TEMP. */
7362         }
7363       else      /* VAR not set or VAR is NULL. */
7364         {
7365           FREE (temp);
7366           temp = (char *)NULL;
7367           if (c == '=' && var_is_special)
7368             {
7369               report_error (_("$%s: cannot assign in this way"), name);
7370               free (name);
7371               free (value);
7372               return &expand_wdesc_error;
7373             }
7374           else if (c == '?')
7375             {
7376               parameter_brace_expand_error (name, value);
7377               return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7378             }
7379           else if (c != '+')
7380             {
7381               /* XXX -- if we're double-quoted and the named variable is "$@",
7382                         we want to turn off any special handling of "$@" --
7383                         we're not using it, so whatever is on the rhs applies. */
7384               if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7385                 *quoted_dollar_atp = 0;
7386               if (contains_dollar_at)
7387                 *contains_dollar_at = 0;
7388
7389               /* From Posix discussion on austin-group list.  Issue 221 requires
7390                  that backslashes escaping `}' inside double-quoted ${...} be
7391                  removed. */
7392               if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7393                 quoted |= Q_DOLBRACE;
7394               ret = parameter_brace_expand_rhs (name, value, c, quoted,
7395                                                 quoted_dollar_atp,
7396                                                 contains_dollar_at);
7397               /* XXX - fix up later, esp. noting presence of
7398                        W_HASQUOTEDNULL in tdesc->flags */
7399             }
7400           free (value);
7401         }
7402
7403       break;
7404     }
7405   free (name);
7406
7407   if (ret == 0)
7408     {
7409       ret = alloc_word_desc ();
7410       ret->flags = tflag;
7411       ret->word = temp;
7412     }
7413   return (ret);
7414 }
7415
7416 /* Expand a single ${xxx} expansion.  The braces are optional.  When
7417    the braces are used, parameter_brace_expand() does the work,
7418    possibly calling param_expand recursively. */
7419 static WORD_DESC *
7420 param_expand (string, sindex, quoted, expanded_something,
7421               contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
7422               pflags)
7423      char *string;
7424      int *sindex, quoted, *expanded_something, *contains_dollar_at;
7425      int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
7426 {
7427   char *temp, *temp1, uerror[3];
7428   int zindex, t_index, expok;
7429   unsigned char c;
7430   intmax_t number;
7431   SHELL_VAR *var;
7432   WORD_LIST *list;
7433   WORD_DESC *tdesc, *ret;
7434   int tflag;
7435
7436   zindex = *sindex;
7437   c = string[++zindex];
7438
7439   temp = (char *)NULL;
7440   ret = tdesc = (WORD_DESC *)NULL;
7441   tflag = 0;
7442
7443   /* Do simple cases first. Switch on what follows '$'. */
7444   switch (c)
7445     {
7446     /* $0 .. $9? */
7447     case '0':
7448     case '1':
7449     case '2':
7450     case '3':
7451     case '4':
7452     case '5':
7453     case '6':
7454     case '7':
7455     case '8':
7456     case '9':
7457       temp1 = dollar_vars[TODIGIT (c)];
7458       if (unbound_vars_is_error && temp1 == (char *)NULL)
7459         {
7460           uerror[0] = '$';
7461           uerror[1] = c;
7462           uerror[2] = '\0';
7463           last_command_exit_value = EXECUTION_FAILURE;
7464           err_unboundvar (uerror);
7465           return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7466         }
7467       if (temp1)
7468         temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7469                   ? quote_string (temp1)
7470                   : quote_escapes (temp1);
7471       else
7472         temp = (char *)NULL;
7473
7474       break;
7475
7476     /* $$ -- pid of the invoking shell. */
7477     case '$':
7478       temp = itos (dollar_dollar_pid);
7479       break;
7480
7481     /* $# -- number of positional parameters. */
7482     case '#':
7483       temp = itos (number_of_args ());
7484       break;
7485
7486     /* $? -- return value of the last synchronous command. */
7487     case '?':
7488       temp = itos (last_command_exit_value);
7489       break;
7490
7491     /* $- -- flags supplied to the shell on invocation or by `set'. */
7492     case '-':
7493       temp = which_set_flags ();
7494       break;
7495
7496       /* $! -- Pid of the last asynchronous command. */
7497     case '!':
7498       /* If no asynchronous pids have been created, expand to nothing.
7499          If `set -u' has been executed, and no async processes have
7500          been created, this is an expansion error. */
7501       if (last_asynchronous_pid == NO_PID)
7502         {
7503           if (expanded_something)
7504             *expanded_something = 0;
7505           temp = (char *)NULL;
7506           if (unbound_vars_is_error)
7507             {
7508               uerror[0] = '$';
7509               uerror[1] = c;
7510               uerror[2] = '\0';
7511               last_command_exit_value = EXECUTION_FAILURE;
7512               err_unboundvar (uerror);
7513               return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7514             }
7515         }
7516       else
7517         temp = itos (last_asynchronous_pid);
7518       break;
7519
7520     /* The only difference between this and $@ is when the arg is quoted. */
7521     case '*':           /* `$*' */
7522       list = list_rest_of_args ();
7523
7524 #if 0
7525       /* According to austin-group posix proposal by Geoff Clare in
7526          <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
7527
7528         "The shell shall write a message to standard error and
7529          immediately exit when it tries to expand an unset parameter
7530          other than the '@' and '*' special parameters."
7531       */
7532
7533       if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
7534         {
7535           uerror[0] = '$';
7536           uerror[1] = '*';
7537           uerror[2] = '\0';
7538           last_command_exit_value = EXECUTION_FAILURE;
7539           err_unboundvar (uerror);
7540           return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7541         }
7542 #endif
7543
7544       /* If there are no command-line arguments, this should just
7545          disappear if there are other characters in the expansion,
7546          even if it's quoted. */
7547       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
7548         temp = (char *)NULL;
7549       else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
7550         {
7551           /* If we have "$*" we want to make a string of the positional
7552              parameters, separated by the first character of $IFS, and
7553              quote the whole string, including the separators.  If IFS
7554              is unset, the parameters are separated by ' '; if $IFS is
7555              null, the parameters are concatenated. */
7556           temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list) : string_list (list);
7557           if (temp)
7558             {
7559               temp1 = quote_string (temp);
7560               if (*temp == 0)
7561                 tflag |= W_HASQUOTEDNULL;
7562               free (temp);
7563               temp = temp1;
7564             }
7565         }
7566       else
7567         {
7568           /* We check whether or not we're eventually going to split $* here,
7569              for example when IFS is empty and we are processing the rhs of
7570              an assignment statement.  In that case, we don't separate the
7571              arguments at all.  Otherwise, if the $* is not quoted it is
7572              identical to $@ */
7573 #if 1
7574 #  if defined (HANDLE_MULTIBYTE)
7575           if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
7576 #  else
7577           if (expand_no_split_dollar_star && ifs_firstc == 0)
7578 #  endif
7579             temp = string_list_dollar_star (list);
7580           else
7581             temp = string_list_dollar_at (list, quoted);
7582 #else
7583           temp = string_list_dollar_at (list, quoted);
7584 #endif
7585           if (expand_no_split_dollar_star == 0 && contains_dollar_at)
7586             *contains_dollar_at = 1;
7587         }
7588
7589       dispose_words (list);
7590       break;
7591
7592     /* When we have "$@" what we want is "$1" "$2" "$3" ... This
7593        means that we have to turn quoting off after we split into
7594        the individually quoted arguments so that the final split
7595        on the first character of $IFS is still done.  */
7596     case '@':           /* `$@' */
7597       list = list_rest_of_args ();
7598
7599 #if 0
7600       /* According to austin-group posix proposal by Geoff Clare in
7601          <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
7602
7603         "The shell shall write a message to standard error and
7604          immediately exit when it tries to expand an unset parameter
7605          other than the '@' and '*' special parameters."
7606       */
7607
7608       if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
7609         {
7610           uerror[0] = '$';
7611           uerror[1] = '@';
7612           uerror[2] = '\0';
7613           last_command_exit_value = EXECUTION_FAILURE;
7614           err_unboundvar (uerror);
7615           return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7616         }
7617 #endif
7618
7619       /* We want to flag the fact that we saw this.  We can't turn
7620          off quoting entirely, because other characters in the
7621          string might need it (consider "\"$@\""), but we need some
7622          way to signal that the final split on the first character
7623          of $IFS should be done, even though QUOTED is 1. */
7624       /* XXX - should this test include Q_PATQUOTE? */
7625       if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7626         *quoted_dollar_at_p = 1;
7627       if (contains_dollar_at)
7628         *contains_dollar_at = 1;
7629
7630 #if 0
7631       if (pflags & PF_NOSPLIT2)
7632         temp = string_list_internal (quoted ? quote_list (list) : list, " ");
7633       else
7634 #endif
7635       /* We want to separate the positional parameters with the first
7636          character of $IFS in case $IFS is something other than a space.
7637          We also want to make sure that splitting is done no matter what --
7638          according to POSIX.2, this expands to a list of the positional
7639          parameters no matter what IFS is set to. */
7640       temp = string_list_dollar_at (list, quoted);
7641
7642       dispose_words (list);
7643       break;
7644
7645     case LBRACE:
7646       tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
7647                                       quoted_dollar_at_p,
7648                                       contains_dollar_at);
7649
7650       if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
7651         return (tdesc);
7652       temp = tdesc ? tdesc->word : (char *)0;
7653
7654       /* XXX */
7655       /* Quoted nulls should be removed if there is anything else
7656          in the string. */
7657       /* Note that we saw the quoted null so we can add one back at
7658          the end of this function if there are no other characters
7659          in the string, discard TEMP, and go on.  The exception to
7660          this is when we have "${@}" and $1 is '', since $@ needs
7661          special handling. */
7662       if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
7663         {
7664           if (had_quoted_null_p)
7665             *had_quoted_null_p = 1;
7666           if (*quoted_dollar_at_p == 0)
7667             {
7668               free (temp);
7669               tdesc->word = temp = (char *)NULL;
7670             }
7671             
7672         }
7673
7674       ret = tdesc;
7675       goto return0;
7676
7677     /* Do command or arithmetic substitution. */
7678     case LPAREN:
7679       /* We have to extract the contents of this paren substitution. */
7680       t_index = zindex + 1;
7681       temp = extract_command_subst (string, &t_index, 0);
7682       zindex = t_index;
7683
7684       /* For Posix.2-style `$(( ))' arithmetic substitution,
7685          extract the expression and pass it to the evaluator. */
7686       if (temp && *temp == LPAREN)
7687         {
7688           char *temp2;
7689           temp1 = temp + 1;
7690           temp2 = savestring (temp1);
7691           t_index = strlen (temp2) - 1;
7692
7693           if (temp2[t_index] != RPAREN)
7694             {
7695               free (temp2);
7696               goto comsub;
7697             }
7698
7699           /* Cut off ending `)' */
7700           temp2[t_index] = '\0';
7701
7702           if (chk_arithsub (temp2, t_index) == 0)
7703             {
7704               free (temp2);
7705 #if 0
7706               internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
7707 #endif
7708               goto comsub;
7709             }
7710
7711           /* Expand variables found inside the expression. */
7712           temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
7713           free (temp2);
7714
7715 arithsub:
7716           /* No error messages. */
7717           this_command_name = (char *)NULL;
7718           number = evalexp (temp1, &expok);
7719           free (temp);
7720           free (temp1);
7721           if (expok == 0)
7722             {
7723               if (interactive_shell == 0 && posixly_correct)
7724                 {
7725                   last_command_exit_value = EXECUTION_FAILURE;
7726                   return (&expand_wdesc_fatal);
7727                 }
7728               else
7729                 return (&expand_wdesc_error);
7730             }
7731           temp = itos (number);
7732           break;
7733         }
7734
7735 comsub:
7736       if (pflags & PF_NOCOMSUB)
7737         /* we need zindex+1 because string[zindex] == RPAREN */
7738         temp1 = substring (string, *sindex, zindex+1);
7739       else
7740         {
7741           tdesc = command_substitute (temp, quoted);
7742           temp1 = tdesc ? tdesc->word : (char *)NULL;
7743           if (tdesc)
7744             dispose_word_desc (tdesc);
7745         }
7746       FREE (temp);
7747       temp = temp1;
7748       break;
7749
7750     /* Do POSIX.2d9-style arithmetic substitution.  This will probably go
7751        away in a future bash release. */
7752     case '[':
7753       /* Extract the contents of this arithmetic substitution. */
7754       t_index = zindex + 1;
7755       temp = extract_arithmetic_subst (string, &t_index);
7756       zindex = t_index;
7757       if (temp == 0)
7758         {
7759           temp = savestring (string);
7760           if (expanded_something)
7761             *expanded_something = 0;
7762           goto return0;
7763         }         
7764
7765        /* Do initial variable expansion. */
7766       temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES);
7767
7768       goto arithsub;
7769
7770     default:
7771       /* Find the variable in VARIABLE_LIST. */
7772       temp = (char *)NULL;
7773
7774       for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
7775         ;
7776       temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
7777
7778       /* If this isn't a variable name, then just output the `$'. */
7779       if (temp1 == 0 || *temp1 == '\0')
7780         {
7781           FREE (temp1);
7782           temp = (char *)xmalloc (2);
7783           temp[0] = '$';
7784           temp[1] = '\0';
7785           if (expanded_something)
7786             *expanded_something = 0;
7787           goto return0;
7788         }
7789
7790       /* If the variable exists, return its value cell. */
7791       var = find_variable (temp1);
7792
7793       if (var && invisible_p (var) == 0 && var_isset (var))
7794         {
7795 #if defined (ARRAY_VARS)
7796           if (assoc_p (var) || array_p (var))
7797             {
7798               temp = array_p (var) ? array_reference (array_cell (var), 0)
7799                                    : assoc_reference (assoc_cell (var), "0");
7800               if (temp)
7801                 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7802                           ? quote_string (temp)
7803                           : quote_escapes (temp);
7804               else if (unbound_vars_is_error)
7805                 goto unbound_variable;
7806             }
7807           else
7808 #endif
7809             {
7810               temp = value_cell (var);
7811
7812               temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7813                         ? quote_string (temp)
7814                         : quote_escapes (temp);
7815             }
7816
7817           free (temp1);
7818
7819           goto return0;
7820         }
7821
7822       temp = (char *)NULL;
7823
7824 unbound_variable:
7825       if (unbound_vars_is_error)
7826         {
7827           last_command_exit_value = EXECUTION_FAILURE;
7828           err_unboundvar (temp1);
7829         }
7830       else
7831         {
7832           free (temp1);
7833           goto return0;
7834         }
7835
7836       free (temp1);
7837       last_command_exit_value = EXECUTION_FAILURE;
7838       return ((unbound_vars_is_error && interactive_shell == 0)
7839                 ? &expand_wdesc_fatal
7840                 : &expand_wdesc_error);
7841     }
7842
7843   if (string[zindex])
7844     zindex++;
7845
7846 return0:
7847   *sindex = zindex;
7848
7849   if (ret == 0)
7850     {
7851       ret = alloc_word_desc ();
7852       ret->flags = tflag;       /* XXX */
7853       ret->word = temp;
7854     }
7855   return ret;
7856 }
7857
7858 /* Make a word list which is the result of parameter and variable
7859    expansion, command substitution, arithmetic substitution, and
7860    quote removal of WORD.  Return a pointer to a WORD_LIST which is
7861    the result of the expansion.  If WORD contains a null word, the
7862    word list returned is also null.
7863
7864    QUOTED contains flag values defined in shell.h.
7865
7866    ISEXP is used to tell expand_word_internal that the word should be
7867    treated as the result of an expansion.  This has implications for
7868    how IFS characters in the word are treated.
7869
7870    CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
7871    they point to an integer value which receives information about expansion.
7872    CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
7873    EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
7874    else zero.
7875
7876    This only does word splitting in the case of $@ expansion.  In that
7877    case, we split on ' '. */
7878
7879 /* Values for the local variable quoted_state. */
7880 #define UNQUOTED         0
7881 #define PARTIALLY_QUOTED 1
7882 #define WHOLLY_QUOTED    2
7883
7884 static WORD_LIST *
7885 expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
7886      WORD_DESC *word;
7887      int quoted, isexp;
7888      int *contains_dollar_at;
7889      int *expanded_something;
7890 {
7891   WORD_LIST *list;
7892   WORD_DESC *tword;
7893
7894   /* The intermediate string that we build while expanding. */
7895   char *istring;
7896
7897   /* The current size of the above object. */
7898   int istring_size;
7899
7900   /* Index into ISTRING. */
7901   int istring_index;
7902
7903   /* Temporary string storage. */
7904   char *temp, *temp1;
7905
7906   /* The text of WORD. */
7907   register char *string;
7908
7909   /* The size of STRING. */
7910   size_t string_size;
7911
7912   /* The index into STRING. */
7913   int sindex;
7914
7915   /* This gets 1 if we see a $@ while quoted. */
7916   int quoted_dollar_at;
7917
7918   /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
7919      whether WORD contains no quoting characters, a partially quoted
7920      string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
7921   int quoted_state;
7922
7923   /* State flags */
7924   int had_quoted_null;
7925   int has_dollar_at;
7926   int tflag;
7927   int pflags;                   /* flags passed to param_expand */
7928
7929   int assignoff;                /* If assignment, offset of `=' */
7930
7931   register unsigned char c;     /* Current character. */
7932   int t_index;                  /* For calls to string_extract_xxx. */
7933
7934   char twochars[2];
7935
7936   DECLARE_MBSTATE;
7937
7938   istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
7939   istring[istring_index = 0] = '\0';
7940   quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
7941   quoted_state = UNQUOTED;
7942
7943   string = word->word;
7944   if (string == 0)
7945     goto finished_with_string;
7946   /* Don't need the string length for the SADD... and COPY_ macros unless
7947      multibyte characters are possible. */
7948   string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1;
7949
7950   if (contains_dollar_at)
7951     *contains_dollar_at = 0;
7952
7953   assignoff = -1;
7954
7955   /* Begin the expansion. */
7956
7957   for (sindex = 0; ;)
7958     {
7959       c = string[sindex];
7960
7961       /* Case on toplevel character. */
7962       switch (c)
7963         {
7964         case '\0':
7965           goto finished_with_string;
7966
7967         case CTLESC:
7968           sindex++;
7969 #if HANDLE_MULTIBYTE
7970           if (MB_CUR_MAX > 1 && string[sindex])
7971             {
7972               SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7973             }
7974           else
7975 #endif
7976             {
7977               temp = (char *)xmalloc (3);
7978               temp[0] = CTLESC;
7979               temp[1] = c = string[sindex];
7980               temp[2] = '\0';
7981             }
7982
7983 dollar_add_string:
7984           if (string[sindex])
7985             sindex++;
7986
7987 add_string:
7988           if (temp)
7989             {
7990               istring = sub_append_string (temp, istring, &istring_index, &istring_size);
7991               temp = (char *)0;
7992             }
7993
7994           break;
7995
7996 #if defined (PROCESS_SUBSTITUTION)
7997           /* Process substitution. */
7998         case '<':
7999         case '>':
8000           {
8001             if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || posixly_correct)
8002               {
8003                 sindex--;       /* add_character: label increments sindex */
8004                 goto add_character;
8005               }
8006             else
8007               t_index = sindex + 1; /* skip past both '<' and LPAREN */
8008
8009             temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/
8010             sindex = t_index;
8011
8012             /* If the process substitution specification is `<()', we want to
8013                open the pipe for writing in the child and produce output; if
8014                it is `>()', we want to open the pipe for reading in the child
8015                and consume input. */
8016             temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
8017
8018             FREE (temp1);
8019
8020             goto dollar_add_string;
8021           }
8022 #endif /* PROCESS_SUBSTITUTION */
8023
8024         case '=':
8025           /* Posix.2 section 3.6.1 says that tildes following `=' in words
8026              which are not assignment statements are not expanded.  If the
8027              shell isn't in posix mode, though, we perform tilde expansion
8028              on `likely candidate' unquoted assignment statements (flags
8029              include W_ASSIGNMENT but not W_QUOTED).  A likely candidate
8030              contains an unquoted :~ or =~.  Something to think about: we
8031              now have a flag that says  to perform tilde expansion on arguments
8032              to `assignment builtins' like declare and export that look like
8033              assignment statements.  We now do tilde expansion on such words
8034              even in POSIX mode. */     
8035           if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
8036             {
8037               if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8038                 goto add_ifs_character;
8039               else
8040                 goto add_character;
8041             }
8042           /* If we're not in posix mode or forcing assignment-statement tilde
8043              expansion, note where the `=' appears in the word and prepare to
8044              do tilde expansion following the first `='. */
8045           if ((word->flags & W_ASSIGNMENT) &&
8046               (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
8047               assignoff == -1 && sindex > 0)
8048             assignoff = sindex;
8049           if (sindex == assignoff && string[sindex+1] == '~')   /* XXX */
8050             word->flags |= W_ITILDE;
8051 #if 0
8052           else if ((word->flags & W_ASSIGNMENT) &&
8053                    (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
8054                    string[sindex+1] == '~')
8055             word->flags |= W_ITILDE;
8056 #endif
8057           if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8058             goto add_ifs_character;
8059           else
8060             goto add_character;
8061
8062         case ':':
8063           if (word->flags & W_NOTILDE)
8064             {
8065               if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8066                 goto add_ifs_character;
8067               else
8068                 goto add_character;
8069             }
8070
8071           if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) &&
8072               string[sindex+1] == '~')
8073             word->flags |= W_ITILDE;
8074
8075           if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8076             goto add_ifs_character;
8077           else
8078             goto add_character;
8079
8080         case '~':
8081           /* If the word isn't supposed to be tilde expanded, or we're not
8082              at the start of a word or after an unquoted : or = in an
8083              assignment statement, we don't do tilde expansion. */
8084           if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
8085               (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
8086               (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8087             {
8088               word->flags &= ~W_ITILDE;
8089               if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
8090                 goto add_ifs_character;
8091               else
8092                 goto add_character;
8093             }
8094
8095           if (word->flags & W_ASSIGNRHS)
8096             tflag = 2;
8097           else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
8098             tflag = 1;
8099           else
8100             tflag = 0;
8101
8102           temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
8103             
8104           word->flags &= ~W_ITILDE;
8105
8106           if (temp && *temp && t_index > 0)
8107             {
8108               temp1 = bash_tilde_expand (temp, tflag);
8109               if  (temp1 && *temp1 == '~' && STREQ (temp, temp1))
8110                 {
8111                   FREE (temp);
8112                   FREE (temp1);
8113                   goto add_character;           /* tilde expansion failed */
8114                 }
8115               free (temp);
8116               temp = temp1;
8117               sindex += t_index;
8118               goto add_quoted_string;           /* XXX was add_string */
8119             }
8120           else
8121             {
8122               FREE (temp);
8123               goto add_character;
8124             }
8125         
8126         case '$':
8127           if (expanded_something)
8128             *expanded_something = 1;
8129
8130           has_dollar_at = 0;
8131           pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
8132           if (word->flags & W_NOSPLIT2)
8133             pflags |= PF_NOSPLIT2;
8134           tword = param_expand (string, &sindex, quoted, expanded_something,
8135                                &has_dollar_at, &quoted_dollar_at,
8136                                &had_quoted_null, pflags);
8137
8138           if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
8139             {
8140               free (string);
8141               free (istring);
8142               return ((tword == &expand_wdesc_error) ? &expand_word_error
8143                                                      : &expand_word_fatal);
8144             }
8145           if (contains_dollar_at && has_dollar_at)
8146             *contains_dollar_at = 1;
8147
8148           if (tword && (tword->flags & W_HASQUOTEDNULL))
8149             had_quoted_null = 1;
8150
8151           temp = tword->word;
8152           dispose_word_desc (tword);
8153
8154           /* Kill quoted nulls; we will add them back at the end of
8155              expand_word_internal if nothing else in the string */
8156           if (had_quoted_null && temp && QUOTED_NULL (temp))
8157             {
8158               FREE (temp);
8159               temp = (char *)NULL;
8160             }
8161
8162           goto add_string;
8163           break;
8164
8165         case '`':               /* Backquoted command substitution. */
8166           {
8167             t_index = sindex++;
8168
8169             temp = string_extract (string, &sindex, "`", SX_REQMATCH);
8170             /* The test of sindex against t_index is to allow bare instances of
8171                ` to pass through, for backwards compatibility. */
8172             if (temp == &extract_string_error || temp == &extract_string_fatal)
8173               {
8174                 if (sindex - 1 == t_index)
8175                   {
8176                     sindex = t_index;
8177                     goto add_character;
8178                   }
8179                 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
8180                 free (string);
8181                 free (istring);
8182                 return ((temp == &extract_string_error) ? &expand_word_error
8183                                                         : &expand_word_fatal);
8184               }
8185                 
8186             if (expanded_something)
8187               *expanded_something = 1;
8188
8189             if (word->flags & W_NOCOMSUB)
8190               /* sindex + 1 because string[sindex] == '`' */
8191               temp1 = substring (string, t_index, sindex + 1);
8192             else
8193               {
8194                 de_backslash (temp);
8195                 tword = command_substitute (temp, quoted);
8196                 temp1 = tword ? tword->word : (char *)NULL;
8197                 if (tword)
8198                   dispose_word_desc (tword);
8199               }
8200             FREE (temp);
8201             temp = temp1;
8202             goto dollar_add_string;
8203           }
8204
8205         case '\\':
8206           if (string[sindex + 1] == '\n')
8207             {
8208               sindex += 2;
8209               continue;
8210             }
8211
8212           c = string[++sindex];
8213
8214           if (quoted & Q_HERE_DOCUMENT)
8215             tflag = CBSHDOC;
8216           else if (quoted & Q_DOUBLE_QUOTES)
8217             tflag = CBSDQUOTE;
8218           else
8219             tflag = 0;
8220
8221           /* From Posix discussion on austin-group list:  Backslash escaping
8222              a } in ${...} is removed.  Issue 0000221 */
8223           if ((quoted & Q_DOLBRACE) && c == RBRACE)
8224             {
8225               SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
8226             }
8227           else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
8228             {
8229               SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
8230             }
8231           else if (c == 0)
8232             {
8233               c = CTLNUL;
8234               sindex--;         /* add_character: label increments sindex */
8235               goto add_character;
8236             }
8237           else
8238             {
8239               SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
8240             }
8241
8242           sindex++;
8243 add_twochars:
8244           /* BEFORE jumping here, we need to increment sindex if appropriate */
8245           RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
8246                                   DEFAULT_ARRAY_SIZE);
8247           istring[istring_index++] = twochars[0];
8248           istring[istring_index++] = twochars[1];
8249           istring[istring_index] = '\0';
8250
8251           break;
8252
8253         case '"':
8254 #if 0
8255           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
8256 #else
8257           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8258 #endif
8259             goto add_character;
8260
8261           t_index = ++sindex;
8262           temp = string_extract_double_quoted (string, &sindex, 0);
8263
8264           /* If the quotes surrounded the entire string, then the
8265              whole word was quoted. */
8266           quoted_state = (t_index == 1 && string[sindex] == '\0')
8267                             ? WHOLLY_QUOTED
8268                             : PARTIALLY_QUOTED;
8269
8270           if (temp && *temp)
8271             {
8272               tword = alloc_word_desc ();
8273               tword->word = temp;
8274
8275               temp = (char *)NULL;
8276
8277               has_dollar_at = 0;
8278               /* Need to get W_HASQUOTEDNULL flag through this function. */
8279               list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL);
8280
8281               if (list == &expand_word_error || list == &expand_word_fatal)
8282                 {
8283                   free (istring);
8284                   free (string);
8285                   /* expand_word_internal has already freed temp_word->word
8286                      for us because of the way it prints error messages. */
8287                   tword->word = (char *)NULL;
8288                   dispose_word (tword);
8289                   return list;
8290                 }
8291
8292               dispose_word (tword);
8293
8294               /* "$@" (a double-quoted dollar-at) expands into nothing,
8295                  not even a NULL word, when there are no positional
8296                  parameters. */
8297               if (list == 0 && has_dollar_at)
8298                 {
8299                   quoted_dollar_at++;
8300                   break;
8301                 }
8302
8303               /* If we get "$@", we know we have expanded something, so we
8304                  need to remember it for the final split on $IFS.  This is
8305                  a special case; it's the only case where a quoted string
8306                  can expand into more than one word.  It's going to come back
8307                  from the above call to expand_word_internal as a list with
8308                  a single word, in which all characters are quoted and
8309                  separated by blanks.  What we want to do is to turn it back
8310                  into a list for the next piece of code. */
8311               if (list)
8312                 dequote_list (list);
8313
8314               if (list && list->word && (list->word->flags & W_HASQUOTEDNULL))
8315                 had_quoted_null = 1;
8316
8317               if (has_dollar_at)
8318                 {
8319                   quoted_dollar_at++;
8320                   if (contains_dollar_at)
8321                     *contains_dollar_at = 1;
8322                   if (expanded_something)
8323                     *expanded_something = 1;
8324                 }
8325             }
8326           else
8327             {
8328               /* What we have is "".  This is a minor optimization. */
8329               FREE (temp);
8330               list = (WORD_LIST *)NULL;
8331             }
8332
8333           /* The code above *might* return a list (consider the case of "$@",
8334              where it returns "$1", "$2", etc.).  We can't throw away the
8335              rest of the list, and we have to make sure each word gets added
8336              as quoted.  We test on tresult->next:  if it is non-NULL, we
8337              quote the whole list, save it to a string with string_list, and
8338              add that string. We don't need to quote the results of this
8339              (and it would be wrong, since that would quote the separators
8340              as well), so we go directly to add_string. */
8341           if (list)
8342             {
8343               if (list->next)
8344                 {
8345 #if 0
8346                   if (quoted_dollar_at && (word->flags & W_NOSPLIT2))
8347                     temp = string_list_internal (quote_list (list), " ");
8348                   else
8349 #endif
8350                   /* Testing quoted_dollar_at makes sure that "$@" is
8351                      split correctly when $IFS does not contain a space. */
8352                   temp = quoted_dollar_at
8353                                 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES)
8354                                 : string_list (quote_list (list));
8355                   dispose_words (list);
8356                   goto add_string;
8357                 }
8358               else
8359                 {
8360                   temp = savestring (list->word->word);
8361                   tflag = list->word->flags;
8362                   dispose_words (list);
8363
8364                   /* If the string is not a quoted null string, we want
8365                      to remove any embedded unquoted CTLNUL characters.
8366                      We do not want to turn quoted null strings back into
8367                      the empty string, though.  We do this because we
8368                      want to remove any quoted nulls from expansions that
8369                      contain other characters.  For example, if we have
8370                      x"$*"y or "x$*y" and there are no positional parameters,
8371                      the $* should expand into nothing. */
8372                   /* We use the W_HASQUOTEDNULL flag to differentiate the
8373                      cases:  a quoted null character as above and when
8374                      CTLNUL is contained in the (non-null) expansion
8375                      of some variable.  We use the had_quoted_null flag to
8376                      pass the value through this function to its caller. */
8377                   if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
8378                     remove_quoted_nulls (temp); /* XXX */
8379                 }
8380             }
8381           else
8382             temp = (char *)NULL;
8383
8384           /* We do not want to add quoted nulls to strings that are only
8385              partially quoted; we can throw them away. */
8386           if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
8387             continue;
8388
8389         add_quoted_string:
8390
8391           if (temp)
8392             {
8393               temp1 = temp;
8394               temp = quote_string (temp);
8395               free (temp1);
8396               goto add_string;
8397             }
8398           else
8399             {
8400               /* Add NULL arg. */
8401               c = CTLNUL;
8402               sindex--;         /* add_character: label increments sindex */
8403               goto add_character;
8404             }
8405
8406           /* break; */
8407
8408         case '\'':
8409 #if 0
8410           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
8411 #else
8412           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8413 #endif
8414             goto add_character;
8415
8416           t_index = ++sindex;
8417           temp = string_extract_single_quoted (string, &sindex);
8418
8419           /* If the entire STRING was surrounded by single quotes,
8420              then the string is wholly quoted. */
8421           quoted_state = (t_index == 1 && string[sindex] == '\0')
8422                             ? WHOLLY_QUOTED
8423                             : PARTIALLY_QUOTED;
8424
8425           /* If all we had was '', it is a null expansion. */
8426           if (*temp == '\0')
8427             {
8428               free (temp);
8429               temp = (char *)NULL;
8430             }
8431           else
8432             remove_quoted_escapes (temp);       /* ??? */
8433
8434           /* We do not want to add quoted nulls to strings that are only
8435              partially quoted; such nulls are discarded. */
8436           if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
8437             continue;
8438
8439           /* If we have a quoted null expansion, add a quoted NULL to istring. */
8440           if (temp == 0)
8441             {
8442               c = CTLNUL;
8443               sindex--;         /* add_character: label increments sindex */
8444               goto add_character;
8445             }
8446           else
8447             goto add_quoted_string;
8448
8449           /* break; */
8450
8451         default:
8452           /* This is the fix for " $@ " */
8453         add_ifs_character:
8454           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c)))
8455             {
8456               if (string[sindex])       /* from old goto dollar_add_string */
8457                 sindex++;
8458               if (c == 0)
8459                 {
8460                   c = CTLNUL;
8461                   goto add_character;
8462                 }
8463               else
8464                 {
8465 #if HANDLE_MULTIBYTE
8466                   if (MB_CUR_MAX > 1)
8467                     sindex--;
8468
8469                   if (MB_CUR_MAX > 1)
8470                     {
8471                       SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
8472                     }
8473                   else
8474 #endif
8475                     {
8476                       twochars[0] = CTLESC;
8477                       twochars[1] = c;
8478                       goto add_twochars;
8479                     }
8480                 }
8481             }
8482
8483           SADD_MBCHAR (temp, string, sindex, string_size);
8484
8485         add_character:
8486           RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
8487                                   DEFAULT_ARRAY_SIZE);
8488           istring[istring_index++] = c;
8489           istring[istring_index] = '\0';
8490
8491           /* Next character. */
8492           sindex++;
8493         }
8494     }
8495
8496 finished_with_string:
8497   /* OK, we're ready to return.  If we have a quoted string, and
8498      quoted_dollar_at is not set, we do no splitting at all; otherwise
8499      we split on ' '.  The routines that call this will handle what to
8500      do if nothing has been expanded. */
8501
8502   /* Partially and wholly quoted strings which expand to the empty
8503      string are retained as an empty arguments.  Unquoted strings
8504      which expand to the empty string are discarded.  The single
8505      exception is the case of expanding "$@" when there are no
8506      positional parameters.  In that case, we discard the expansion. */
8507
8508   /* Because of how the code that handles "" and '' in partially
8509      quoted strings works, we need to make ISTRING into a QUOTED_NULL
8510      if we saw quoting characters, but the expansion was empty.
8511      "" and '' are tossed away before we get to this point when
8512      processing partially quoted strings.  This makes "" and $xxx""
8513      equivalent when xxx is unset.  We also look to see whether we
8514      saw a quoted null from a ${} expansion and add one back if we
8515      need to. */
8516
8517   /* If we expand to nothing and there were no single or double quotes
8518      in the word, we throw it away.  Otherwise, we return a NULL word.
8519      The single exception is for $@ surrounded by double quotes when
8520      there are no positional parameters.  In that case, we also throw
8521      the word away. */
8522
8523   if (*istring == '\0')
8524     {
8525       if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
8526         {
8527           istring[0] = CTLNUL;
8528           istring[1] = '\0';
8529           tword = make_bare_word (istring);
8530           tword->flags |= W_HASQUOTEDNULL;              /* XXX */
8531           list = make_word_list (tword, (WORD_LIST *)NULL);
8532           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8533             tword->flags |= W_QUOTED;
8534         }
8535       /* According to sh, ksh, and Posix.2, if a word expands into nothing
8536          and a double-quoted "$@" appears anywhere in it, then the entire
8537          word is removed. */
8538       else  if (quoted_state == UNQUOTED || quoted_dollar_at)
8539         list = (WORD_LIST *)NULL;
8540 #if 0
8541       else
8542         {
8543           tword = make_bare_word (istring);
8544           if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8545             tword->flags |= W_QUOTED;
8546           list = make_word_list (tword, (WORD_LIST *)NULL);
8547         }
8548 #else
8549       else
8550         list = (WORD_LIST *)NULL;
8551 #endif
8552     }
8553   else if (word->flags & W_NOSPLIT)
8554     {
8555       tword = make_bare_word (istring);
8556       if (word->flags & W_ASSIGNMENT)
8557         tword->flags |= W_ASSIGNMENT;   /* XXX */
8558       if (word->flags & W_COMPASSIGN)
8559         tword->flags |= W_COMPASSIGN;   /* XXX */
8560       if (word->flags & W_NOGLOB)
8561         tword->flags |= W_NOGLOB;       /* XXX */
8562       if (word->flags & W_NOEXPAND)
8563         tword->flags |= W_NOEXPAND;     /* XXX */
8564       if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8565         tword->flags |= W_QUOTED;
8566       if (had_quoted_null && QUOTED_NULL (istring))
8567         tword->flags |= W_HASQUOTEDNULL;
8568       list = make_word_list (tword, (WORD_LIST *)NULL);
8569     }
8570   else
8571     {
8572       char *ifs_chars;
8573
8574       ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
8575
8576       /* If we have $@, we need to split the results no matter what.  If
8577          IFS is unset or NULL, string_list_dollar_at has separated the
8578          positional parameters with a space, so we split on space (we have
8579          set ifs_chars to " \t\n" above if ifs is unset).  If IFS is set,
8580          string_list_dollar_at has separated the positional parameters
8581          with the first character of $IFS, so we split on $IFS. */
8582       if (has_dollar_at && ifs_chars)
8583         list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
8584       else
8585         {
8586           tword = make_bare_word (istring);
8587           if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
8588             tword->flags |= W_QUOTED;
8589           if (word->flags & W_ASSIGNMENT)
8590             tword->flags |= W_ASSIGNMENT;
8591           if (word->flags & W_COMPASSIGN)
8592             tword->flags |= W_COMPASSIGN;
8593           if (word->flags & W_NOGLOB)
8594             tword->flags |= W_NOGLOB;
8595           if (word->flags & W_NOEXPAND)
8596             tword->flags |= W_NOEXPAND;
8597           if (had_quoted_null && QUOTED_NULL (istring))
8598             tword->flags |= W_HASQUOTEDNULL;    /* XXX */
8599           list = make_word_list (tword, (WORD_LIST *)NULL);
8600         }
8601     }
8602
8603   free (istring);
8604   return (list);
8605 }
8606
8607 /* **************************************************************** */
8608 /*                                                                  */
8609 /*                 Functions for Quote Removal                      */
8610 /*                                                                  */
8611 /* **************************************************************** */
8612
8613 /* Perform quote removal on STRING.  If QUOTED > 0, assume we are obeying the
8614    backslash quoting rules for within double quotes or a here document. */
8615 char *
8616 string_quote_removal (string, quoted)
8617      char *string;
8618      int quoted;
8619 {
8620   size_t slen;
8621   char *r, *result_string, *temp, *send;
8622   int sindex, tindex, dquote;
8623   unsigned char c;
8624   DECLARE_MBSTATE;
8625
8626   /* The result can be no longer than the original string. */
8627   slen = strlen (string);
8628   send = string + slen;
8629
8630   r = result_string = (char *)xmalloc (slen + 1);
8631
8632   for (dquote = sindex = 0; c = string[sindex];)
8633     {
8634       switch (c)
8635         {
8636         case '\\':
8637           c = string[++sindex];
8638           if (c == 0)
8639             {
8640               *r++ = '\\';
8641               break;
8642             }
8643           if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
8644             *r++ = '\\';
8645           /* FALLTHROUGH */
8646
8647         default:
8648           SCOPY_CHAR_M (r, string, send, sindex);
8649           break;
8650
8651         case '\'':
8652           if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
8653             {
8654               *r++ = c;
8655               sindex++;
8656               break;
8657             }
8658           tindex = sindex + 1;
8659           temp = string_extract_single_quoted (string, &tindex);
8660           if (temp)
8661             {
8662               strcpy (r, temp);
8663               r += strlen (r);
8664               free (temp);
8665             }
8666           sindex = tindex;
8667           break;
8668
8669         case '"':
8670           dquote = 1 - dquote;
8671           sindex++;
8672           break;
8673         }
8674     }
8675     *r = '\0';
8676     return (result_string);
8677 }
8678
8679 #if 0
8680 /* UNUSED */
8681 /* Perform quote removal on word WORD.  This allocates and returns a new
8682    WORD_DESC *. */
8683 WORD_DESC *
8684 word_quote_removal (word, quoted)
8685      WORD_DESC *word;
8686      int quoted;
8687 {
8688   WORD_DESC *w;
8689   char *t;
8690
8691   t = string_quote_removal (word->word, quoted);
8692   w = alloc_word_desc ();
8693   w->word = t ? t : savestring ("");
8694   return (w);
8695 }
8696
8697 /* Perform quote removal on all words in LIST.  If QUOTED is non-zero,
8698    the members of the list are treated as if they are surrounded by
8699    double quotes.  Return a new list, or NULL if LIST is NULL. */
8700 WORD_LIST *
8701 word_list_quote_removal (list, quoted)
8702      WORD_LIST *list;
8703      int quoted;
8704 {
8705   WORD_LIST *result, *t, *tresult, *e;
8706
8707   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
8708     {
8709       tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
8710 #if 0
8711       result = (WORD_LIST *) list_append (result, tresult);
8712 #else
8713       if (result == 0)
8714         result = e = tresult;
8715       else
8716         {
8717           e->next = tresult;
8718           while (e->next)
8719             e = e->next;
8720         }
8721 #endif
8722     }
8723   return (result);
8724 }
8725 #endif
8726
8727 /*******************************************
8728  *                                         *
8729  *    Functions to perform word splitting  *
8730  *                                         *
8731  *******************************************/
8732
8733 void
8734 setifs (v)
8735      SHELL_VAR *v;
8736 {
8737   char *t;
8738   unsigned char uc;
8739
8740   ifs_var = v;
8741   ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
8742
8743   /* Should really merge ifs_cmap with sh_syntaxtab.  XXX - doesn't yet
8744      handle multibyte chars in IFS */
8745   memset (ifs_cmap, '\0', sizeof (ifs_cmap));
8746   for (t = ifs_value ; t && *t; t++)
8747     {
8748       uc = *t;
8749       ifs_cmap[uc] = 1;
8750     }
8751
8752 #if defined (HANDLE_MULTIBYTE)
8753   if (ifs_value == 0)
8754     {
8755       ifs_firstc[0] = '\0';
8756       ifs_firstc_len = 1;
8757     }
8758   else
8759     {
8760       size_t ifs_len;
8761       ifs_len = strnlen (ifs_value, MB_CUR_MAX);
8762       ifs_firstc_len = MBLEN (ifs_value, ifs_len);
8763       if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
8764         {
8765           ifs_firstc[0] = ifs_value[0];
8766           ifs_firstc[1] = '\0';
8767           ifs_firstc_len = 1;
8768         }
8769       else
8770         memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
8771     }
8772 #else
8773   ifs_firstc = ifs_value ? *ifs_value : 0;
8774 #endif
8775 }
8776
8777 char *
8778 getifs ()
8779 {
8780   return ifs_value;
8781 }
8782
8783 /* This splits a single word into a WORD LIST on $IFS, but only if the word
8784    is not quoted.  list_string () performs quote removal for us, even if we
8785    don't do any splitting. */
8786 WORD_LIST *
8787 word_split (w, ifs_chars)
8788      WORD_DESC *w;
8789      char *ifs_chars;
8790 {
8791   WORD_LIST *result;
8792
8793   if (w)
8794     {
8795       char *xifs;
8796
8797       xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
8798       result = list_string (w->word, xifs, w->flags & W_QUOTED);
8799     }
8800   else
8801     result = (WORD_LIST *)NULL;
8802
8803   return (result);
8804 }
8805
8806 /* Perform word splitting on LIST and return the RESULT.  It is possible
8807    to return (WORD_LIST *)NULL. */
8808 static WORD_LIST *
8809 word_list_split (list)
8810      WORD_LIST *list;
8811 {
8812   WORD_LIST *result, *t, *tresult, *e;
8813
8814   for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
8815     {
8816       tresult = word_split (t->word, ifs_value);
8817       if (result == 0)
8818         result = e = tresult;
8819       else
8820         {
8821           e->next = tresult;
8822           while (e->next)
8823             e = e->next;
8824         }
8825     }
8826   return (result);
8827 }
8828
8829 /**************************************************
8830  *                                                *
8831  *    Functions to expand an entire WORD_LIST     *
8832  *                                                *
8833  **************************************************/
8834
8835 /* Do any word-expansion-specific cleanup and jump to top_level */
8836 static void
8837 exp_jump_to_top_level (v)
8838      int v;
8839 {
8840   set_pipestatus_from_exit (last_command_exit_value);
8841
8842   /* Cleanup code goes here. */
8843   expand_no_split_dollar_star = 0;      /* XXX */
8844   expanding_redir = 0;
8845   assigning_in_environment = 0;
8846
8847   if (parse_and_execute_level == 0)
8848     top_level_cleanup ();                       /* from sig.c */
8849
8850   jump_to_top_level (v);
8851 }
8852
8853 /* Put NLIST (which is a WORD_LIST * of only one element) at the front of
8854    ELIST, and set ELIST to the new list. */
8855 #define PREPEND_LIST(nlist, elist) \
8856         do { nlist->next = elist; elist = nlist; } while (0)
8857
8858 /* Separate out any initial variable assignments from TLIST.  If set -k has
8859    been executed, remove all assignment statements from TLIST.  Initial
8860    variable assignments and other environment assignments are placed
8861    on SUBST_ASSIGN_VARLIST. */
8862 static WORD_LIST *
8863 separate_out_assignments (tlist)
8864      WORD_LIST *tlist;
8865 {
8866   register WORD_LIST *vp, *lp;
8867
8868   if (tlist == 0)
8869     return ((WORD_LIST *)NULL);
8870
8871   if (subst_assign_varlist)
8872     dispose_words (subst_assign_varlist);       /* Clean up after previous error */
8873
8874   subst_assign_varlist = (WORD_LIST *)NULL;
8875   vp = lp = tlist;
8876
8877   /* Separate out variable assignments at the start of the command.
8878      Loop invariant: vp->next == lp
8879      Loop postcondition:
8880         lp = list of words left after assignment statements skipped
8881         tlist = original list of words
8882   */
8883   while (lp && (lp->word->flags & W_ASSIGNMENT))
8884     {
8885       vp = lp;
8886       lp = lp->next;
8887     }
8888
8889   /* If lp != tlist, we have some initial assignment statements.
8890      We make SUBST_ASSIGN_VARLIST point to the list of assignment
8891      words and TLIST point to the remaining words.  */
8892   if (lp != tlist)
8893     {
8894       subst_assign_varlist = tlist;
8895       /* ASSERT(vp->next == lp); */
8896       vp->next = (WORD_LIST *)NULL;     /* terminate variable list */
8897       tlist = lp;                       /* remainder of word list */
8898     }
8899
8900   /* vp == end of variable list */
8901   /* tlist == remainder of original word list without variable assignments */
8902   if (!tlist)
8903     /* All the words in tlist were assignment statements */
8904     return ((WORD_LIST *)NULL);
8905
8906   /* ASSERT(tlist != NULL); */
8907   /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
8908
8909   /* If the -k option is in effect, we need to go through the remaining
8910      words, separate out the assignment words, and place them on
8911      SUBST_ASSIGN_VARLIST. */
8912   if (place_keywords_in_env)
8913     {
8914       WORD_LIST *tp;    /* tp == running pointer into tlist */
8915
8916       tp = tlist;
8917       lp = tlist->next;
8918
8919       /* Loop Invariant: tp->next == lp */
8920       /* Loop postcondition: tlist == word list without assignment statements */
8921       while (lp)
8922         {
8923           if (lp->word->flags & W_ASSIGNMENT)
8924             {
8925               /* Found an assignment statement, add this word to end of
8926                  subst_assign_varlist (vp). */
8927               if (!subst_assign_varlist)
8928                 subst_assign_varlist = vp = lp;
8929               else
8930                 {
8931                   vp->next = lp;
8932                   vp = lp;
8933                 }
8934
8935               /* Remove the word pointed to by LP from TLIST. */
8936               tp->next = lp->next;
8937               /* ASSERT(vp == lp); */
8938               lp->next = (WORD_LIST *)NULL;
8939               lp = tp->next;
8940             }
8941           else
8942             {
8943               tp = lp;
8944               lp = lp->next;
8945             }
8946         }
8947     }
8948   return (tlist);
8949 }
8950
8951 #define WEXP_VARASSIGN  0x001
8952 #define WEXP_BRACEEXP   0x002
8953 #define WEXP_TILDEEXP   0x004
8954 #define WEXP_PARAMEXP   0x008
8955 #define WEXP_PATHEXP    0x010
8956
8957 /* All of the expansions, including variable assignments at the start of
8958    the list. */
8959 #define WEXP_ALL        (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
8960
8961 /* All of the expansions except variable assignments at the start of
8962    the list. */
8963 #define WEXP_NOVARS     (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
8964
8965 /* All of the `shell expansions': brace expansion, tilde expansion, parameter
8966    expansion, command substitution, arithmetic expansion, word splitting, and
8967    quote removal. */
8968 #define WEXP_SHELLEXP   (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
8969
8970 /* Take the list of words in LIST and do the various substitutions.  Return
8971    a new list of words which is the expanded list, and without things like
8972    variable assignments. */
8973
8974 WORD_LIST *
8975 expand_words (list)
8976      WORD_LIST *list;
8977 {
8978   return (expand_word_list_internal (list, WEXP_ALL));
8979 }
8980
8981 /* Same as expand_words (), but doesn't hack variable or environment
8982    variables. */
8983 WORD_LIST *
8984 expand_words_no_vars (list)
8985      WORD_LIST *list;
8986 {
8987   return (expand_word_list_internal (list, WEXP_NOVARS));
8988 }
8989
8990 WORD_LIST *
8991 expand_words_shellexp (list)
8992      WORD_LIST *list;
8993 {
8994   return (expand_word_list_internal (list, WEXP_SHELLEXP));
8995 }
8996
8997 static WORD_LIST *
8998 glob_expand_word_list (tlist, eflags)
8999      WORD_LIST *tlist;
9000      int eflags;
9001 {
9002   char **glob_array, *temp_string;
9003   register int glob_index;
9004   WORD_LIST *glob_list, *output_list, *disposables, *next;
9005   WORD_DESC *tword;
9006
9007   output_list = disposables = (WORD_LIST *)NULL;
9008   glob_array = (char **)NULL;
9009   while (tlist)
9010     {
9011       /* For each word, either globbing is attempted or the word is
9012          added to orig_list.  If globbing succeeds, the results are
9013          added to orig_list and the word (tlist) is added to the list
9014          of disposable words.  If globbing fails and failed glob
9015          expansions are left unchanged (the shell default), the
9016          original word is added to orig_list.  If globbing fails and
9017          failed glob expansions are removed, the original word is
9018          added to the list of disposable words.  orig_list ends up
9019          in reverse order and requires a call to REVERSE_LIST to
9020          be set right.  After all words are examined, the disposable
9021          words are freed. */
9022       next = tlist->next;
9023
9024       /* If the word isn't an assignment and contains an unquoted
9025          pattern matching character, then glob it. */
9026       if ((tlist->word->flags & W_NOGLOB) == 0 &&
9027           unquoted_glob_pattern_p (tlist->word->word))
9028         {
9029           glob_array = shell_glob_filename (tlist->word->word);
9030
9031           /* Handle error cases.
9032              I don't think we should report errors like "No such file
9033              or directory".  However, I would like to report errors
9034              like "Read failed". */
9035
9036           if (glob_array == 0 || GLOB_FAILED (glob_array))
9037             {
9038               glob_array = (char **)xmalloc (sizeof (char *));
9039               glob_array[0] = (char *)NULL;
9040             }
9041
9042           /* Dequote the current word in case we have to use it. */
9043           if (glob_array[0] == NULL)
9044             {
9045               temp_string = dequote_string (tlist->word->word);
9046               free (tlist->word->word);
9047               tlist->word->word = temp_string;
9048             }
9049
9050           /* Make the array into a word list. */
9051           glob_list = (WORD_LIST *)NULL;
9052           for (glob_index = 0; glob_array[glob_index]; glob_index++)
9053             {
9054               tword = make_bare_word (glob_array[glob_index]);
9055               tword->flags |= W_GLOBEXP;        /* XXX */
9056               glob_list = make_word_list (tword, glob_list);
9057             }
9058
9059           if (glob_list)
9060             {
9061               output_list = (WORD_LIST *)list_append (glob_list, output_list);
9062               PREPEND_LIST (tlist, disposables);
9063             }
9064           else if (fail_glob_expansion != 0)
9065             {
9066               report_error (_("no match: %s"), tlist->word->word);
9067               exp_jump_to_top_level (DISCARD);
9068             }
9069           else if (allow_null_glob_expansion == 0)
9070             {
9071               /* Failed glob expressions are left unchanged. */
9072               PREPEND_LIST (tlist, output_list);
9073             }
9074           else
9075             {
9076               /* Failed glob expressions are removed. */
9077               PREPEND_LIST (tlist, disposables);
9078             }
9079         }
9080       else
9081         {
9082           /* Dequote the string. */
9083           temp_string = dequote_string (tlist->word->word);
9084           free (tlist->word->word);
9085           tlist->word->word = temp_string;
9086           PREPEND_LIST (tlist, output_list);
9087         }
9088
9089       strvec_dispose (glob_array);
9090       glob_array = (char **)NULL;
9091
9092       tlist = next;
9093     }
9094
9095   if (disposables)
9096     dispose_words (disposables);
9097
9098   if (output_list)
9099     output_list = REVERSE_LIST (output_list, WORD_LIST *);
9100
9101   return (output_list);
9102 }
9103
9104 #if defined (BRACE_EXPANSION)
9105 static WORD_LIST *
9106 brace_expand_word_list (tlist, eflags)
9107      WORD_LIST *tlist;
9108      int eflags;
9109 {
9110   register char **expansions;
9111   char *temp_string;
9112   WORD_LIST *disposables, *output_list, *next;
9113   WORD_DESC *w;
9114   int eindex;
9115
9116   for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
9117     {
9118       next = tlist->next;
9119
9120       if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
9121         {
9122 /*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
9123           PREPEND_LIST (tlist, output_list);
9124           continue;
9125         }
9126           
9127       /* Only do brace expansion if the word has a brace character.  If
9128          not, just add the word list element to BRACES and continue.  In
9129          the common case, at least when running shell scripts, this will
9130          degenerate to a bunch of calls to `mbschr', and then what is
9131          basically a reversal of TLIST into BRACES, which is corrected
9132          by a call to REVERSE_LIST () on BRACES when the end of TLIST
9133          is reached. */
9134       if (mbschr (tlist->word->word, LBRACE))
9135         {
9136           expansions = brace_expand (tlist->word->word);
9137
9138           for (eindex = 0; temp_string = expansions[eindex]; eindex++)
9139             {
9140               w = make_word (temp_string);
9141               /* If brace expansion didn't change the word, preserve
9142                  the flags.  We may want to preserve the flags
9143                  unconditionally someday -- XXX */
9144               if (STREQ (temp_string, tlist->word->word))
9145                 w->flags = tlist->word->flags;
9146               output_list = make_word_list (w, output_list);
9147               free (expansions[eindex]);
9148             }
9149           free (expansions);
9150
9151           /* Add TLIST to the list of words to be freed after brace
9152              expansion has been performed. */
9153           PREPEND_LIST (tlist, disposables);
9154         }
9155       else
9156         PREPEND_LIST (tlist, output_list);
9157     }
9158
9159   if (disposables)
9160     dispose_words (disposables);
9161
9162   if (output_list)
9163     output_list = REVERSE_LIST (output_list, WORD_LIST *);
9164
9165   return (output_list);
9166 }
9167 #endif
9168
9169 #if defined (ARRAY_VARS)
9170 /* Take WORD, a compound associative array assignment, and internally run
9171    'declare -A w', where W is the variable name portion of WORD. */
9172 static int
9173 make_internal_declare (word, option)
9174      char *word;
9175      char *option;
9176 {
9177   int t;
9178   WORD_LIST *wl;
9179   WORD_DESC *w;
9180
9181   w = make_word (word);
9182
9183   t = assignment (w->word, 0);
9184   w->word[t] = '\0';
9185
9186   wl = make_word_list (w, (WORD_LIST *)NULL);
9187   wl = make_word_list (make_word (option), wl);
9188
9189   return (declare_builtin (wl));  
9190 }  
9191 #endif
9192
9193 static WORD_LIST *
9194 shell_expand_word_list (tlist, eflags)
9195      WORD_LIST *tlist;
9196      int eflags;
9197 {
9198   WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list;
9199   int expanded_something, has_dollar_at;
9200   char *temp_string;
9201
9202   /* We do tilde expansion all the time.  This is what 1003.2 says. */
9203   new_list = (WORD_LIST *)NULL;
9204   for (orig_list = tlist; tlist; tlist = next)
9205     {
9206       temp_string = tlist->word->word;
9207
9208       next = tlist->next;
9209
9210 #if defined (ARRAY_VARS)
9211       /* If this is a compound array assignment to a builtin that accepts
9212          such assignments (e.g., `declare'), take the assignment and perform
9213          it separately, handling the semantics of declarations inside shell
9214          functions.  This avoids the double-evaluation of such arguments,
9215          because `declare' does some evaluation of compound assignments on
9216          its own. */
9217       if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
9218         {
9219           int t;
9220
9221           if (tlist->word->flags & W_ASSIGNASSOC)
9222             make_internal_declare (tlist->word->word, "-A");
9223
9224           t = do_word_assignment (tlist->word, 0);
9225           if (t == 0)
9226             {
9227               last_command_exit_value = EXECUTION_FAILURE;
9228               exp_jump_to_top_level (DISCARD);
9229             }
9230
9231           /* Now transform the word as ksh93 appears to do and go on */
9232           t = assignment (tlist->word->word, 0);
9233           tlist->word->word[t] = '\0';
9234           tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC);
9235         }
9236 #endif
9237
9238       expanded_something = 0;
9239       expanded = expand_word_internal
9240         (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
9241
9242       if (expanded == &expand_word_error || expanded == &expand_word_fatal)
9243         {
9244           /* By convention, each time this error is returned,
9245              tlist->word->word has already been freed. */
9246           tlist->word->word = (char *)NULL;
9247
9248           /* Dispose our copy of the original list. */
9249           dispose_words (orig_list);
9250           /* Dispose the new list we're building. */
9251           dispose_words (new_list);
9252
9253           last_command_exit_value = EXECUTION_FAILURE;
9254           if (expanded == &expand_word_error)
9255             exp_jump_to_top_level (DISCARD);
9256           else
9257             exp_jump_to_top_level (FORCE_EOF);
9258         }
9259
9260       /* Don't split words marked W_NOSPLIT. */
9261       if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
9262         {
9263           temp_list = word_list_split (expanded);
9264           dispose_words (expanded);
9265         }
9266       else
9267         {
9268           /* If no parameter expansion, command substitution, process
9269              substitution, or arithmetic substitution took place, then
9270              do not do word splitting.  We still have to remove quoted
9271              null characters from the result. */
9272           word_list_remove_quoted_nulls (expanded);
9273           temp_list = expanded;
9274         }
9275
9276       expanded = REVERSE_LIST (temp_list, WORD_LIST *);
9277       new_list = (WORD_LIST *)list_append (expanded, new_list);
9278     }
9279
9280   if (orig_list)  
9281     dispose_words (orig_list);
9282
9283   if (new_list)
9284     new_list = REVERSE_LIST (new_list, WORD_LIST *);
9285
9286   return (new_list);
9287 }
9288
9289 /* The workhorse for expand_words () and expand_words_no_vars ().
9290    First arg is LIST, a WORD_LIST of words.
9291    Second arg EFLAGS is a flags word controlling which expansions are
9292    performed.
9293
9294    This does all of the substitutions: brace expansion, tilde expansion,
9295    parameter expansion, command substitution, arithmetic expansion,
9296    process substitution, word splitting, and pathname expansion, according
9297    to the bits set in EFLAGS.  Words with the W_QUOTED or W_NOSPLIT bits
9298    set, or for which no expansion is done, do not undergo word splitting.
9299    Words with the W_NOGLOB bit set do not undergo pathname expansion. */
9300 static WORD_LIST *
9301 expand_word_list_internal (list, eflags)
9302      WORD_LIST *list;
9303      int eflags;
9304 {
9305   WORD_LIST *new_list, *temp_list;
9306   int tint;
9307
9308   if (list == 0)
9309     return ((WORD_LIST *)NULL);
9310
9311   garglist = new_list = copy_word_list (list);
9312   if (eflags & WEXP_VARASSIGN)
9313     {
9314       garglist = new_list = separate_out_assignments (new_list);
9315       if (new_list == 0)
9316         {
9317           if (subst_assign_varlist)
9318             {
9319               /* All the words were variable assignments, so they are placed
9320                  into the shell's environment. */
9321               for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
9322                 {
9323                   this_command_name = (char *)NULL;     /* no arithmetic errors */
9324                   tint = do_word_assignment (temp_list->word, 0);
9325                   /* Variable assignment errors in non-interactive shells
9326                      running in Posix.2 mode cause the shell to exit. */
9327                   if (tint == 0)
9328                     {
9329                       last_command_exit_value = EXECUTION_FAILURE;
9330                       if (interactive_shell == 0 && posixly_correct)
9331                         exp_jump_to_top_level (FORCE_EOF);
9332                       else
9333                         exp_jump_to_top_level (DISCARD);
9334                     }
9335                 }
9336               dispose_words (subst_assign_varlist);
9337               subst_assign_varlist = (WORD_LIST *)NULL;
9338             }
9339           return ((WORD_LIST *)NULL);
9340         }
9341     }
9342
9343   /* Begin expanding the words that remain.  The expansions take place on
9344      things that aren't really variable assignments. */
9345
9346 #if defined (BRACE_EXPANSION)
9347   /* Do brace expansion on this word if there are any brace characters
9348      in the string. */
9349   if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
9350     new_list = brace_expand_word_list (new_list, eflags);
9351 #endif /* BRACE_EXPANSION */
9352
9353   /* Perform the `normal' shell expansions: tilde expansion, parameter and
9354      variable substitution, command substitution, arithmetic expansion,
9355      and word splitting. */
9356   new_list = shell_expand_word_list (new_list, eflags);
9357
9358   /* Okay, we're almost done.  Now let's just do some filename
9359      globbing. */
9360   if (new_list)
9361     {
9362       if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
9363         /* Glob expand the word list unless globbing has been disabled. */
9364         new_list = glob_expand_word_list (new_list, eflags);
9365       else
9366         /* Dequote the words, because we're not performing globbing. */
9367         new_list = dequote_list (new_list);
9368     }
9369
9370   if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
9371     {
9372       sh_wassign_func_t *assign_func;
9373       int is_special_builtin, is_builtin_or_func;
9374
9375       /* If the remainder of the words expand to nothing, Posix.2 requires
9376          that the variable and environment assignments affect the shell's
9377          environment. */
9378       assign_func = new_list ? assign_in_env : do_word_assignment;
9379       tempenv_assign_error = 0;
9380
9381       is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
9382       /* Posix says that special builtins exit if a variable assignment error
9383          occurs in an assignment preceding it. */
9384       is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
9385       
9386       for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
9387         {
9388           this_command_name = (char *)NULL;
9389           assigning_in_environment = (assign_func == assign_in_env);
9390           tint = (*assign_func) (temp_list->word, is_builtin_or_func);
9391           assigning_in_environment = 0;
9392           /* Variable assignment errors in non-interactive shells running
9393              in Posix.2 mode cause the shell to exit. */
9394           if (tint == 0)
9395             {
9396               if (assign_func == do_word_assignment)
9397                 {
9398                   last_command_exit_value = EXECUTION_FAILURE;
9399                   if (interactive_shell == 0 && posixly_correct && is_special_builtin)
9400                     exp_jump_to_top_level (FORCE_EOF);
9401                   else
9402                     exp_jump_to_top_level (DISCARD);
9403                 }
9404               else
9405                 tempenv_assign_error++;
9406             }
9407         }
9408
9409       dispose_words (subst_assign_varlist);
9410       subst_assign_varlist = (WORD_LIST *)NULL;
9411     }
9412
9413 #if 0
9414   tint = list_length (new_list) + 1;
9415   RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
9416   for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next)
9417     glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0';
9418   glob_argv_flags[tint] = '\0';
9419 #endif
9420
9421   return (new_list);
9422 }