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