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