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