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