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