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