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