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