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