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