]> git.ipfire.org Git - thirdparty/bash.git/blame - subst.c
Bash-5.2 patch 26: fix typo when specifying readline's custom color prefix
[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
74091dd4 7/* Copyright (C) 1987-2022 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"
74091dd4 48#include "redir.h"
726f6388
JA
49#include "flags.h"
50#include "jobs.h"
51#include "execute_cmd.h"
52#include "filecntl.h"
ccc6cda3
JA
53#include "trap.h"
54#include "pathexp.h"
55#include "mailcheck.h"
56
7117c2d2 57#include "shmbutil.h"
a0c0a00f
CR
58#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
59# include <mbstr.h> /* mbschr */
60#endif
495aee44 61#include "typemax.h"
7117c2d2 62
ccc6cda3
JA
63#include "builtins/getopt.h"
64#include "builtins/common.h"
726f6388 65
3185942a
JA
66#include "builtins/builtext.h"
67
cce855bc 68#include <tilde/tilde.h>
f73dda09 69#include <glob/strmatch.h>
ccc6cda3
JA
70
71#if !defined (errno)
72extern int errno;
73#endif /* !errno */
726f6388
JA
74
75/* The size that strings change by. */
d166f048 76#define DEFAULT_INITIAL_ARRAY_SIZE 112
ccc6cda3
JA
77#define DEFAULT_ARRAY_SIZE 128
78
79/* Variable types. */
80#define VT_VARIABLE 0
81#define VT_POSPARMS 1
82#define VT_ARRAYVAR 2
d166f048 83#define VT_ARRAYMEMBER 3
3185942a 84#define VT_ASSOCVAR 4
726f6388 85
b80f6443
JA
86#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
87
ccc6cda3
JA
88/* Flags for quoted_strchr */
89#define ST_BACKSL 0x01
90#define ST_CTLESC 0x02
7117c2d2
JA
91#define ST_SQUOTE 0x04 /* unused yet */
92#define ST_DQUOTE 0x08 /* unused yet */
93
cce855bc
JA
94/* These defs make it easier to use the editor. */
95#define LBRACE '{'
96#define RBRACE '}'
97#define LPAREN '('
98#define RPAREN ')'
ac50fbac
CR
99#define LBRACK '['
100#define RBRACK ']'
726f6388 101
0001803f
CR
102#if defined (HANDLE_MULTIBYTE)
103#define WLPAREN L'('
104#define WRPAREN L')'
105#endif
106
a0c0a00f
CR
107#define DOLLAR_AT_STAR(c) ((c) == '@' || (c) == '*')
108#define STR_DOLLAR_AT_STAR(s) (DOLLAR_AT_STAR ((s)[0]) && (s)[1] == '\0')
109
28ef6c31
JA
110/* Evaluates to 1 if C is one of the shell's special parameters whose length
111 can be taken, but is also one of the special expansion characters. */
112#define VALID_SPECIAL_LENGTH_PARAM(c) \
a0c0a00f 113 ((c) == '-' || (c) == '?' || (c) == '#' || (c) == '@')
28ef6c31
JA
114
115/* Evaluates to 1 if C is one of the shell's special parameters for which an
116 indirect variable reference may be made. */
117#define VALID_INDIR_PARAM(c) \
495aee44 118 ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
28ef6c31
JA
119
120/* Evaluates to 1 if C is one of the OP characters that follows the parameter
121 in ${parameter[:]OPword}. */
7117c2d2 122#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)
28ef6c31 123
bb70624e
JA
124/* Evaluates to 1 if this is one of the shell's special variables. */
125#define SPECIAL_VAR(name, wi) \
a0c0a00f 126 (*name && ((DIGIT (*name) && all_digits (name)) || \
f73dda09 127 (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \
a0c0a00f
CR
128 (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))))
129
130/* This can be used by all of the *_extract_* functions that have a similar
131 structure. It can't just be wrapped in a do...while(0) loop because of
132 the embedded `break'. The dangling else accommodates a trailing semicolon;
133 we could also put in a do ; while (0) */
134
a0c0a00f
CR
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(). */
8868edaf 147typedef WORD_LIST *EXPFUNC PARAMS((char *, int));
f73dda09 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
d233b485
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
74091dd4
CR
190/* If non-zero, perform `&' substitution on the replacement string in the
191 pattern substitution word expansion. */
192int patsub_replacement = 1;
193
726f6388 194/* Extern functions and variables from different files. */
ccc6cda3 195extern struct fd_bitmap *current_fds_to_close;
cce855bc 196extern int wordexp_only;
74091dd4
CR
197extern int singlequote_translations;
198extern int extended_quote;
726f6388 199
a0c0a00f
CR
200#if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION)
201extern PROCESS *last_procsub_child;
202#endif
203
0628567a 204#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)
8868edaf 205extern wchar_t *wcsdup PARAMS((const wchar_t *));
0628567a
JA
206#endif
207
f73dda09 208#if 0
ccc6cda3
JA
209/* Variables to keep track of which words in an expanded word list (the
210 output of expand_word_list_internal) are the result of globbing
f73dda09
JA
211 expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c.
212 (CURRENTLY UNUSED). */
ccc6cda3
JA
213char *glob_argv_flags;
214static int glob_argv_flags_size;
f73dda09 215#endif
726f6388 216
a0c0a00f
CR
217static WORD_LIST *cached_quoted_dollar_at = 0;
218
d233b485 219/* Distinguished error values to return from expansion functions */
726f6388 220static WORD_LIST expand_word_error, expand_word_fatal;
95732b49 221static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
d233b485 222static char expand_param_error, expand_param_fatal, expand_param_unset;
95732b49 223static char extract_string_error, extract_string_fatal;
726f6388 224
d233b485
CR
225/* Set by expand_word_unsplit and several of the expand_string_XXX functions;
226 used to inhibit splitting and re-joining $* on $IFS, primarily when doing
227 assignment statements. The idea is that if we're in a context where this
228 is set, we're not going to be performing word splitting, so we use the same
229 rules to expand $* as we would if it appeared within double quotes. */
28ef6c31 230static int expand_no_split_dollar_star = 0;
bb70624e 231
bb70624e
JA
232/* A WORD_LIST of words to be expanded by expand_word_list_internal,
233 without any leading variable assignments. */
234static WORD_LIST *garglist = (WORD_LIST *)NULL;
b72432fd 235
8868edaf
CR
236static char *quoted_substring PARAMS((char *, int, int));
237static int quoted_strlen PARAMS((char *));
238static char *quoted_strchr PARAMS((char *, int, int));
f73dda09 239
8868edaf
CR
240static char *expand_string_if_necessary PARAMS((char *, int, EXPFUNC *));
241static inline char *expand_string_to_string_internal PARAMS((char *, int, EXPFUNC *));
242static WORD_LIST *call_expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *));
243static WORD_LIST *expand_string_internal PARAMS((char *, int));
244static WORD_LIST *expand_string_leave_quoted PARAMS((char *, int));
245static WORD_LIST *expand_string_for_rhs PARAMS((char *, int, int, int, int *, int *));
246static WORD_LIST *expand_string_for_pat PARAMS((char *, int, int *, int *));
d233b485 247
8868edaf 248static char *quote_escapes_internal PARAMS((const char *, int));
f73dda09 249
8868edaf
CR
250static WORD_LIST *list_quote_escapes PARAMS((WORD_LIST *));
251static WORD_LIST *list_dequote_escapes PARAMS((WORD_LIST *));
ac50fbac 252
8868edaf
CR
253static char *make_quoted_char PARAMS((int));
254static WORD_LIST *quote_list PARAMS((WORD_LIST *));
f73dda09 255
8868edaf
CR
256static int unquoted_substring PARAMS((char *, char *));
257static int unquoted_member PARAMS((int, char *));
f73dda09 258
95732b49 259#if defined (ARRAY_VARS)
8868edaf 260static SHELL_VAR *do_compound_assignment PARAMS((char *, char *, int));
95732b49 261#endif
8868edaf 262static int do_assignment_internal PARAMS((const WORD_DESC *, int));
f73dda09 263
8868edaf
CR
264static char *string_extract_verbatim PARAMS((char *, size_t, int *, char *, int));
265static char *string_extract PARAMS((char *, int *, char *, int));
266static char *string_extract_double_quoted PARAMS((char *, int *, int));
74091dd4 267static inline char *string_extract_single_quoted PARAMS((char *, int *, int));
8868edaf
CR
268static inline int skip_single_quoted PARAMS((const char *, size_t, int, int));
269static int skip_double_quoted PARAMS((char *, size_t, int, int));
270static char *extract_delimited_string PARAMS((char *, int *, char *, char *, char *, int));
74091dd4 271static char *extract_heredoc_dolbrace_string PARAMS((char *, int *, int, int));
8868edaf
CR
272static char *extract_dollar_brace_string PARAMS((char *, int *, int, int));
273static int skip_matched_pair PARAMS((const char *, int, int, int, int));
f73dda09 274
8868edaf 275static char *pos_params PARAMS((char *, int, int, int, int));
f73dda09 276
8868edaf 277static unsigned char *mb_getcharlens PARAMS((char *, int));
b80f6443 278
8868edaf 279static char *remove_upattern PARAMS((char *, char *, int));
0628567a 280#if defined (HANDLE_MULTIBYTE)
8868edaf 281static wchar_t *remove_wpattern PARAMS((wchar_t *, size_t, wchar_t *, int));
b80f6443 282#endif
8868edaf 283static char *remove_pattern PARAMS((char *, char *, int));
b80f6443 284
8868edaf 285static int match_upattern PARAMS((char *, char *, int, char **, char **));
b80f6443 286#if defined (HANDLE_MULTIBYTE)
8868edaf 287static int match_wpattern PARAMS((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
b80f6443 288#endif
8868edaf
CR
289static int match_pattern PARAMS((char *, char *, int, char **, char **));
290static int getpatspec PARAMS((int, char *));
291static char *getpattern PARAMS((char *, int, int));
292static char *variable_remove_pattern PARAMS((char *, char *, int, int));
293static char *list_remove_pattern PARAMS((WORD_LIST *, char *, int, int, int));
294static char *parameter_list_remove_pattern PARAMS((int, char *, int, int));
f73dda09 295#ifdef ARRAY_VARS
8868edaf 296static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int));
f73dda09 297#endif
74091dd4 298static char *parameter_brace_remove_pattern PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
f73dda09 299
8868edaf 300static char *string_var_assignment PARAMS((SHELL_VAR *, char *));
a0c0a00f 301#if defined (ARRAY_VARS)
8868edaf 302static char *array_var_assignment PARAMS((SHELL_VAR *, int, int, int));
a0c0a00f 303#endif
8868edaf
CR
304static char *pos_params_assignment PARAMS((WORD_LIST *, int, int));
305static char *string_transform PARAMS((int, SHELL_VAR *, char *));
306static char *list_transform PARAMS((int, SHELL_VAR *, WORD_LIST *, int, int));
307static char *parameter_list_transform PARAMS((int, int, int));
a0c0a00f 308#if defined ARRAY_VARS
8868edaf 309static char *array_transform PARAMS((int, SHELL_VAR *, int, int));
a0c0a00f 310#endif
74091dd4 311static char *parameter_brace_transform PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int, int));
8868edaf 312static int valid_parameter_transform PARAMS((char *));
a0c0a00f 313
8868edaf 314static char *process_substitute PARAMS((char *, int));
f73dda09 315
74091dd4 316static char *optimize_cat_file PARAMS((REDIRECT *, int, int, int *));
8868edaf 317static char *read_comsub PARAMS((int, int, int, int *));
f73dda09
JA
318
319#ifdef ARRAY_VARS
8868edaf 320static arrayind_t array_length_reference PARAMS((char *));
f73dda09
JA
321#endif
322
8868edaf
CR
323static int valid_brace_expansion_word PARAMS((char *, int));
324static int chk_atstar PARAMS((char *, int, int, int *, int *));
325static int chk_arithsub PARAMS((const char *, int));
b80f6443 326
74091dd4 327static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, array_eltstate_t *));
8868edaf
CR
328static char *parameter_brace_find_indir PARAMS((char *, int, int, int));
329static WORD_DESC *parameter_brace_expand_indir PARAMS((char *, int, int, int, int *, int *));
330static WORD_DESC *parameter_brace_expand_rhs PARAMS((char *, char *, int, int, int, int *, int *));
331static void parameter_brace_expand_error PARAMS((char *, char *, int));
f73dda09 332
8868edaf
CR
333static int valid_length_expression PARAMS((char *));
334static intmax_t parameter_brace_expand_length PARAMS((char *));
f73dda09 335
8868edaf
CR
336static char *skiparith PARAMS((char *, int));
337static int verify_substring_values PARAMS((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
74091dd4 338static int get_var_and_type PARAMS((char *, char *, array_eltstate_t *, int, int, SHELL_VAR **, char **));
8868edaf 339static char *mb_substring PARAMS((char *, int, int));
74091dd4 340static char *parameter_brace_substring PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
495aee44 341
8868edaf 342static int shouldexp_replacement PARAMS((char *));
f73dda09 343
8868edaf 344static char *pos_params_pat_subst PARAMS((char *, char *, char *, int));
f73dda09 345
74091dd4
CR
346static char *expand_string_for_patsub PARAMS((char *, int));
347static char *parameter_brace_patsub PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
f73dda09 348
8868edaf 349static char *pos_params_casemod PARAMS((char *, char *, int, int));
74091dd4 350static char *parameter_brace_casemod PARAMS((char *, char *, array_eltstate_t *, int, char *, int, int, int));
3185942a 351
8868edaf
CR
352static WORD_DESC *parameter_brace_expand PARAMS((char *, int *, int, int, int *, int *));
353static WORD_DESC *param_expand PARAMS((char *, int *, int, int *, int *, int *, int *, int));
f73dda09 354
8868edaf 355static WORD_LIST *expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *));
f73dda09 356
8868edaf 357static WORD_LIST *word_list_split PARAMS((WORD_LIST *));
f73dda09 358
8868edaf 359static void exp_jump_to_top_level PARAMS((int));
b80f6443 360
8868edaf
CR
361static WORD_LIST *separate_out_assignments PARAMS((WORD_LIST *));
362static WORD_LIST *glob_expand_word_list PARAMS((WORD_LIST *, int));
f73dda09 363#ifdef BRACE_EXPANSION
8868edaf 364static WORD_LIST *brace_expand_word_list PARAMS((WORD_LIST *, int));
f73dda09 365#endif
3185942a 366#if defined (ARRAY_VARS)
8868edaf
CR
367static int make_internal_declare PARAMS((char *, char *, char *));
368static void expand_compound_assignment_word PARAMS((WORD_LIST *, int));
369static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *));
3185942a 370#endif
8868edaf
CR
371static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int));
372static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int));
726f6388 373
74091dd4
CR
374static int do_assignment_statements PARAMS((WORD_LIST *, char *, int));
375
726f6388
JA
376/* **************************************************************** */
377/* */
378/* Utility Functions */
379/* */
380/* **************************************************************** */
381
0001803f
CR
382#if defined (DEBUG)
383void
384dump_word_flags (flags)
385 int flags;
386{
387 int f;
388
389 f = flags;
390 fprintf (stderr, "%d -> ", f);
a0c0a00f
CR
391 if (f & W_ARRAYIND)
392 {
393 f &= ~W_ARRAYIND;
394 fprintf (stderr, "W_ARRAYIND%s", f ? "|" : "");
395 }
0001803f
CR
396 if (f & W_ASSIGNASSOC)
397 {
398 f &= ~W_ASSIGNASSOC;
399 fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
400 }
ac50fbac
CR
401 if (f & W_ASSIGNARRAY)
402 {
403 f &= ~W_ASSIGNARRAY;
404 fprintf (stderr, "W_ASSIGNARRAY%s", f ? "|" : "");
405 }
d233b485 406 if (f & W_SAWQUOTEDNULL)
0001803f 407 {
d233b485
CR
408 f &= ~W_SAWQUOTEDNULL;
409 fprintf (stderr, "W_SAWQUOTEDNULL%s", f ? "|" : "");
0001803f
CR
410 }
411 if (f & W_NOPROCSUB)
412 {
413 f &= ~W_NOPROCSUB;
414 fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
415 }
416 if (f & W_DQUOTE)
417 {
418 f &= ~W_DQUOTE;
419 fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
420 }
421 if (f & W_HASQUOTEDNULL)
422 {
423 f &= ~W_HASQUOTEDNULL;
424 fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
425 }
426 if (f & W_ASSIGNARG)
427 {
428 f &= ~W_ASSIGNARG;
429 fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
430 }
431 if (f & W_ASSNBLTIN)
432 {
433 f &= ~W_ASSNBLTIN;
434 fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
435 }
6d41b715
CR
436 if (f & W_ASSNGLOBAL)
437 {
438 f &= ~W_ASSNGLOBAL;
439 fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : "");
440 }
0001803f
CR
441 if (f & W_COMPASSIGN)
442 {
443 f &= ~W_COMPASSIGN;
444 fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
445 }
8868edaf 446 if (f & W_EXPANDRHS)
0001803f 447 {
8868edaf
CR
448 f &= ~W_EXPANDRHS;
449 fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : "");
0001803f 450 }
0001803f
CR
451 if (f & W_NOTILDE)
452 {
453 f &= ~W_NOTILDE;
454 fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
455 }
456 if (f & W_ASSIGNRHS)
457 {
458 f &= ~W_ASSIGNRHS;
459 fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
460 }
d233b485
CR
461 if (f & W_NOASSNTILDE)
462 {
463 f &= ~W_NOASSNTILDE;
464 fprintf (stderr, "W_NOASSNTILDE%s", f ? "|" : "");
465 }
0001803f
CR
466 if (f & W_NOCOMSUB)
467 {
468 f &= ~W_NOCOMSUB;
469 fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
470 }
74091dd4 471 if (f & W_ARRAYREF)
0001803f 472 {
74091dd4
CR
473 f &= ~W_ARRAYREF;
474 fprintf (stderr, "W_ARRAYREF%s", f ? "|" : "");
0001803f
CR
475 }
476 if (f & W_DOLLARAT)
477 {
478 f &= ~W_DOLLARAT;
479 fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
480 }
481 if (f & W_TILDEEXP)
482 {
483 f &= ~W_TILDEEXP;
484 fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
485 }
486 if (f & W_NOSPLIT2)
487 {
488 f &= ~W_NOSPLIT2;
489 fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
490 }
0001803f
CR
491 if (f & W_NOSPLIT)
492 {
493 f &= ~W_NOSPLIT;
494 fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
495 }
ac50fbac 496 if (f & W_NOBRACE)
0001803f 497 {
ac50fbac
CR
498 f &= ~W_NOBRACE;
499 fprintf (stderr, "W_NOBRACE%s", f ? "|" : "");
500 }
501 if (f & W_NOGLOB)
502 {
503 f &= ~W_NOGLOB;
504 fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
505 }
506 if (f & W_SPLITSPACE)
507 {
508 f &= ~W_SPLITSPACE;
509 fprintf (stderr, "W_SPLITSPACE%s", f ? "|" : "");
0001803f
CR
510 }
511 if (f & W_ASSIGNMENT)
512 {
513 f &= ~W_ASSIGNMENT;
514 fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
515 }
516 if (f & W_QUOTED)
517 {
518 f &= ~W_QUOTED;
519 fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
520 }
521 if (f & W_HASDOLLAR)
522 {
523 f &= ~W_HASDOLLAR;
524 fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
525 }
a0c0a00f
CR
526 if (f & W_COMPLETE)
527 {
528 f &= ~W_COMPLETE;
529 fprintf (stderr, "W_COMPLETE%s", f ? "|" : "");
530 }
d233b485
CR
531 if (f & W_CHKLOCAL)
532 {
533 f &= ~W_CHKLOCAL;
534 fprintf (stderr, "W_CHKLOCAL%s", f ? "|" : "");
535 }
8868edaf
CR
536 if (f & W_FORCELOCAL)
537 {
538 f &= ~W_FORCELOCAL;
539 fprintf (stderr, "W_FORCELOCAL%s", f ? "|" : "");
540 }
541
0001803f
CR
542 fprintf (stderr, "\n");
543 fflush (stderr);
544}
545#endif
546
7117c2d2 547#ifdef INCLUDE_UNUSED
ccc6cda3
JA
548static char *
549quoted_substring (string, start, end)
550 char *string;
551 int start, end;
552{
553 register int len, l;
554 register char *result, *s, *r;
555
556 len = end - start;
557
558 /* Move to string[start], skipping quoted characters. */
559 for (s = string, l = 0; *s && l < start; )
560 {
561 if (*s == CTLESC)
562 {
28ef6c31
JA
563 s++;
564 continue;
ccc6cda3
JA
565 }
566 l++;
567 if (*s == 0)
28ef6c31 568 break;
ccc6cda3
JA
569 }
570
f73dda09 571 r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */
ccc6cda3
JA
572
573 /* Copy LEN characters, including quote characters. */
574 s = string + l;
575 for (l = 0; l < len; s++)
576 {
577 if (*s == CTLESC)
28ef6c31 578 *r++ = *s++;
ccc6cda3
JA
579 *r++ = *s;
580 l++;
581 if (*s == 0)
28ef6c31 582 break;
ccc6cda3
JA
583 }
584 *r = '\0';
585 return result;
586}
7117c2d2
JA
587#endif
588
589#ifdef INCLUDE_UNUSED
590/* Return the length of S, skipping over quoted characters */
591static int
592quoted_strlen (s)
593 char *s;
594{
595 register char *p;
596 int i;
597
598 i = 0;
599 for (p = s; *p; p++)
600 {
601 if (*p == CTLESC)
602 {
603 p++;
604 if (*p == 0)
605 return (i + 1);
606 }
607 i++;
608 }
609
610 return i;
611}
612#endif
ccc6cda3 613
d233b485 614#ifdef INCLUDE_UNUSED
ccc6cda3
JA
615/* Find the first occurrence of character C in string S, obeying shell
616 quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
617 characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters
618 escaped with CTLESC are skipped. */
7117c2d2 619static char *
ccc6cda3
JA
620quoted_strchr (s, c, flags)
621 char *s;
622 int c, flags;
623{
624 register char *p;
625
626 for (p = s; *p; p++)
627 {
628 if (((flags & ST_BACKSL) && *p == '\\')
629 || ((flags & ST_CTLESC) && *p == CTLESC))
630 {
631 p++;
632 if (*p == '\0')
633 return ((char *)NULL);
634 continue;
635 }
636 else if (*p == c)
637 return p;
638 }
639 return ((char *)NULL);
640}
641
cce855bc 642/* Return 1 if CHARACTER appears in an unquoted portion of
7117c2d2 643 STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */
cce855bc
JA
644static int
645unquoted_member (character, string)
646 int character;
726f6388
JA
647 char *string;
648{
7117c2d2 649 size_t slen;
cce855bc 650 int sindex, c;
7117c2d2 651 DECLARE_MBSTATE;
726f6388 652
7117c2d2
JA
653 slen = strlen (string);
654 sindex = 0;
655 while (c = string[sindex])
726f6388 656 {
cce855bc
JA
657 if (c == character)
658 return (1);
659
660 switch (c)
ccc6cda3 661 {
cce855bc 662 default:
7117c2d2 663 ADVANCE_CHAR (string, slen, sindex);
cce855bc
JA
664 break;
665
666 case '\\':
667 sindex++;
668 if (string[sindex])
7117c2d2 669 ADVANCE_CHAR (string, slen, sindex);
cce855bc
JA
670 break;
671
672 case '\'':
a0c0a00f 673 sindex = skip_single_quoted (string, slen, ++sindex, 0);
cce855bc
JA
674 break;
675
676 case '"':
a0c0a00f 677 sindex = skip_double_quoted (string, slen, ++sindex, 0);
cce855bc 678 break;
ccc6cda3 679 }
726f6388 680 }
cce855bc 681 return (0);
726f6388
JA
682}
683
cce855bc
JA
684/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
685static int
686unquoted_substring (substr, string)
687 char *substr, *string;
726f6388 688{
7117c2d2 689 size_t slen;
cce855bc 690 int sindex, c, sublen;
7117c2d2 691 DECLARE_MBSTATE;
726f6388 692
cce855bc
JA
693 if (substr == 0 || *substr == '\0')
694 return (0);
695
7117c2d2 696 slen = strlen (string);
cce855bc
JA
697 sublen = strlen (substr);
698 for (sindex = 0; c = string[sindex]; )
726f6388 699 {
cce855bc
JA
700 if (STREQN (string + sindex, substr, sublen))
701 return (1);
702
703 switch (c)
704 {
705 case '\\':
706 sindex++;
cce855bc 707 if (string[sindex])
7117c2d2 708 ADVANCE_CHAR (string, slen, sindex);
cce855bc
JA
709 break;
710
711 case '\'':
a0c0a00f 712 sindex = skip_single_quoted (string, slen, ++sindex, 0);
cce855bc
JA
713 break;
714
715 case '"':
a0c0a00f 716 sindex = skip_double_quoted (string, slen, ++sindex, 0);
cce855bc
JA
717 break;
718
719 default:
7117c2d2 720 ADVANCE_CHAR (string, slen, sindex);
cce855bc
JA
721 break;
722 }
726f6388 723 }
cce855bc 724 return (0);
ccc6cda3 725}
a0c0a00f 726#endif
726f6388 727
cce855bc
JA
728/* Most of the substitutions must be done in parallel. In order
729 to avoid using tons of unclear goto's, I have some functions
730 for manipulating malloc'ed strings. They all take INDX, a
731 pointer to an integer which is the offset into the string
732 where manipulation is taking place. They also take SIZE, a
733 pointer to an integer which is the current length of the
734 character array for this string. */
726f6388 735
cce855bc
JA
736/* Append SOURCE to TARGET at INDEX. SIZE is the current amount
737 of space allocated to TARGET. SOURCE can be NULL, in which
738 case nothing happens. Gets rid of SOURCE by freeing it.
739 Returns TARGET in case the location has changed. */
7117c2d2 740INLINE char *
cce855bc
JA
741sub_append_string (source, target, indx, size)
742 char *source, *target;
74091dd4 743 size_t *indx;
a0c0a00f 744 size_t *size;
cce855bc
JA
745{
746 if (source)
726f6388 747 {
74091dd4 748 size_t n, srclen;
cce855bc
JA
749
750 srclen = STRLEN (source);
74091dd4 751 if (srclen >= (*size - *indx))
726f6388 752 {
cce855bc
JA
753 n = srclen + *indx;
754 n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
f73dda09 755 target = (char *)xrealloc (target, (*size = n));
726f6388 756 }
cce855bc
JA
757
758 FASTCOPY (source, target + *indx, srclen);
759 *indx += srclen;
760 target[*indx] = '\0';
761
762 free (source);
726f6388 763 }
cce855bc
JA
764 return (target);
765}
766
767#if 0
768/* UNUSED */
769/* Append the textual representation of NUMBER to TARGET.
770 INDX and SIZE are as in SUB_APPEND_STRING. */
771char *
772sub_append_number (number, target, indx, size)
7117c2d2 773 intmax_t number;
cce855bc 774 char *target;
74091dd4 775 size_t *indx;
a0c0a00f 776 size_t *size;
cce855bc
JA
777{
778 char *temp;
779
780 temp = itos (number);
781 return (sub_append_string (temp, target, indx, size));
726f6388 782}
d166f048 783#endif
726f6388
JA
784
785/* Extract a substring from STRING, starting at SINDEX and ending with
786 one of the characters in CHARLIST. Don't make the ending character
787 part of the string. Leave SINDEX pointing at the ending character.
3185942a 788 Understand about backslashes in the string. If (flags & SX_VARNAME)
7117c2d2
JA
789 is non-zero, and array variables have been compiled into the shell,
790 everything between a `[' and a corresponding `]' is skipped over.
3185942a
JA
791 If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
792 update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must
95732b49 793 contain a closing character from CHARLIST. */
726f6388 794static char *
7117c2d2 795string_extract (string, sindex, charlist, flags)
f73dda09
JA
796 char *string;
797 int *sindex;
798 char *charlist;
7117c2d2 799 int flags;
726f6388 800{
ccc6cda3 801 register int c, i;
95732b49 802 int found;
7117c2d2 803 size_t slen;
726f6388 804 char *temp;
7117c2d2 805 DECLARE_MBSTATE;
726f6388 806
95732b49 807 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
7117c2d2 808 i = *sindex;
95732b49 809 found = 0;
7117c2d2 810 while (c = string[i])
726f6388
JA
811 {
812 if (c == '\\')
7117c2d2
JA
813 {
814 if (string[i + 1])
815 i++;
816 else
817 break;
818 }
ccc6cda3 819#if defined (ARRAY_VARS)
d233b485 820 else if ((flags & SX_VARNAME) && c == LBRACK)
ccc6cda3
JA
821 {
822 int ni;
823 /* If this is an array subscript, skip over it and continue. */
0001803f 824 ni = skipsubscript (string, i, 0);
d233b485 825 if (string[ni] == RBRACK)
ccc6cda3
JA
826 i = ni;
827 }
828#endif
829 else if (MEMBER (c, charlist))
95732b49
JA
830 {
831 found = 1;
726f6388 832 break;
95732b49 833 }
7117c2d2
JA
834
835 ADVANCE_CHAR (string, slen, i);
726f6388 836 }
bb70624e 837
95732b49
JA
838 /* If we had to have a matching delimiter and didn't find one, return an
839 error and let the caller deal with it. */
3185942a 840 if ((flags & SX_REQMATCH) && found == 0)
95732b49
JA
841 {
842 *sindex = i;
843 return (&extract_string_error);
844 }
845
3185942a 846 temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
726f6388 847 *sindex = i;
95732b49 848
726f6388
JA
849 return (temp);
850}
851
ccc6cda3
JA
852/* Extract the contents of STRING as if it is enclosed in double quotes.
853 SINDEX, when passed in, is the offset of the character immediately
854 following the opening double quote; on exit, SINDEX is left pointing after
855 the closing double quote. If STRIPDQ is non-zero, unquoted double
856 quotes are stripped and the string is terminated by a null byte.
857 Backslashes between the embedded double quotes are processed. If STRIPDQ
858 is zero, an unquoted `"' terminates the string. */
7117c2d2 859static char *
a0c0a00f 860string_extract_double_quoted (string, sindex, flags)
726f6388 861 char *string;
a0c0a00f 862 int *sindex, flags;
726f6388 863{
7117c2d2
JA
864 size_t slen;
865 char *send;
f73dda09
JA
866 int j, i, t;
867 unsigned char c;
ccc6cda3
JA
868 char *temp, *ret; /* The new string we return. */
869 int pass_next, backquote, si; /* State variables for the machine. */
870 int dquote;
a0c0a00f 871 int stripdq;
7117c2d2
JA
872 DECLARE_MBSTATE;
873
874 slen = strlen (string + *sindex) + *sindex;
875 send = string + slen;
726f6388 876
a0c0a00f
CR
877 stripdq = (flags & SX_STRIPDQ);
878
ccc6cda3 879 pass_next = backquote = dquote = 0;
7117c2d2 880 temp = (char *)xmalloc (1 + slen - *sindex);
726f6388 881
7117c2d2
JA
882 j = 0;
883 i = *sindex;
884 while (c = string[i])
726f6388 885 {
ccc6cda3
JA
886 /* Process a character that was quoted by a backslash. */
887 if (pass_next)
726f6388 888 {
495aee44 889 /* XXX - take another look at this in light of Interp 221 */
ccc6cda3 890 /* Posix.2 sez:
726f6388 891
ccc6cda3
JA
892 ``The backslash shall retain its special meaning as an escape
893 character only when followed by one of the characters:
7117c2d2 894 $ ` " \ <newline>''.
726f6388 895
ccc6cda3
JA
896 If STRIPDQ is zero, we handle the double quotes here and let
897 expand_word_internal handle the rest. If STRIPDQ is non-zero,
898 we have already been through one round of backslash stripping,
899 and want to strip these backslashes only if DQUOTE is non-zero,
900 indicating that we are inside an embedded double-quoted string. */
901
d233b485
CR
902 /* If we are in an embedded quoted string, then don't strip
903 backslashes before characters for which the backslash
904 retains its special meaning, but remove backslashes in
905 front of other characters. If we are not in an
906 embedded quoted string, don't strip backslashes at all.
907 This mess is necessary because the string was already
908 surrounded by double quotes (and sh has some really weird
909 quoting rules).
910 The returned string will be run through expansion as if
911 it were double-quoted. */
ccc6cda3 912 if ((stripdq == 0 && c != '"') ||
28ef6c31 913 (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0)))
ccc6cda3 914 temp[j++] = '\\';
ccc6cda3 915 pass_next = 0;
7117c2d2
JA
916
917add_one_character:
918 COPY_CHAR_I (temp, j, string, send, i);
ccc6cda3
JA
919 continue;
920 }
726f6388 921
ccc6cda3
JA
922 /* A backslash protects the next character. The code just above
923 handles preserving the backslash in front of any character but
924 a double quote. */
925 if (c == '\\')
726f6388 926 {
ccc6cda3 927 pass_next++;
7117c2d2 928 i++;
726f6388
JA
929 continue;
930 }
931
ccc6cda3
JA
932 /* Inside backquotes, ``the portion of the quoted string from the
933 initial backquote and the characters up to the next backquote
934 that is not preceded by a backslash, having escape characters
935 removed, defines that command''. */
936 if (backquote)
726f6388 937 {
ccc6cda3
JA
938 if (c == '`')
939 backquote = 0;
d233b485 940 temp[j++] = c; /* COPY_CHAR_I? */
7117c2d2 941 i++;
726f6388
JA
942 continue;
943 }
944
ccc6cda3 945 if (c == '`')
726f6388 946 {
ccc6cda3
JA
947 temp[j++] = c;
948 backquote++;
7117c2d2 949 i++;
ccc6cda3 950 continue;
726f6388
JA
951 }
952
ccc6cda3
JA
953 /* Pass everything between `$(' and the matching `)' or a quoted
954 ${ ... } pair through according to the Posix.2 specification. */
cce855bc 955 if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
726f6388 956 {
b80f6443
JA
957 int free_ret = 1;
958
ccc6cda3 959 si = i + 2;
cce855bc 960 if (string[i + 1] == LPAREN)
a0c0a00f 961 ret = extract_command_subst (string, &si, (flags & SX_COMPLETE));
ccc6cda3 962 else
495aee44 963 ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0);
726f6388 964
ccc6cda3
JA
965 temp[j++] = '$';
966 temp[j++] = string[i + 1];
726f6388 967
b80f6443
JA
968 /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error
969 is set. */
970 if (ret == 0 && no_longjmp_on_fatal_error)
971 {
972 free_ret = 0;
973 ret = string + i + 2;
974 }
975
d233b485 976 /* XXX - CHECK_STRING_OVERRUN here? */
ccc6cda3
JA
977 for (t = 0; ret[t]; t++, j++)
978 temp[j] = ret[t];
b80f6443 979 temp[j] = string[si];
726f6388 980
8868edaf
CR
981 if (si < i + 2) /* we went back? */
982 i += 2;
983 else if (string[si])
b80f6443
JA
984 {
985 j++;
986 i = si + 1;
987 }
988 else
989 i = si;
990
991 if (free_ret)
992 free (ret);
ccc6cda3 993 continue;
726f6388
JA
994 }
995
ccc6cda3 996 /* Add any character but a double quote to the quoted string we're
28ef6c31 997 accumulating. */
ccc6cda3 998 if (c != '"')
7117c2d2 999 goto add_one_character;
ccc6cda3
JA
1000
1001 /* c == '"' */
1002 if (stripdq)
726f6388 1003 {
ccc6cda3 1004 dquote ^= 1;
7117c2d2 1005 i++;
ccc6cda3 1006 continue;
726f6388 1007 }
ccc6cda3
JA
1008
1009 break;
726f6388 1010 }
ccc6cda3 1011 temp[j] = '\0';
726f6388 1012
ccc6cda3
JA
1013 /* Point to after the closing quote. */
1014 if (c)
1015 i++;
726f6388
JA
1016 *sindex = i;
1017
ccc6cda3
JA
1018 return (temp);
1019}
1020
1021/* This should really be another option to string_extract_double_quoted. */
f73dda09 1022static int
a0c0a00f 1023skip_double_quoted (string, slen, sind, flags)
ccc6cda3 1024 char *string;
7117c2d2 1025 size_t slen;
ccc6cda3 1026 int sind;
a0c0a00f 1027 int flags;
ccc6cda3 1028{
f73dda09 1029 int c, i;
ccc6cda3
JA
1030 char *ret;
1031 int pass_next, backquote, si;
7117c2d2 1032 DECLARE_MBSTATE;
ccc6cda3
JA
1033
1034 pass_next = backquote = 0;
7117c2d2
JA
1035 i = sind;
1036 while (c = string[i])
726f6388 1037 {
ccc6cda3
JA
1038 if (pass_next)
1039 {
1040 pass_next = 0;
7117c2d2 1041 ADVANCE_CHAR (string, slen, i);
ccc6cda3
JA
1042 continue;
1043 }
1044 else if (c == '\\')
1045 {
1046 pass_next++;
7117c2d2 1047 i++;
ccc6cda3
JA
1048 continue;
1049 }
1050 else if (backquote)
1051 {
1052 if (c == '`')
1053 backquote = 0;
7117c2d2 1054 ADVANCE_CHAR (string, slen, i);
ccc6cda3
JA
1055 continue;
1056 }
1057 else if (c == '`')
1058 {
1059 backquote++;
7117c2d2 1060 i++;
ccc6cda3
JA
1061 continue;
1062 }
cce855bc 1063 else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
ccc6cda3
JA
1064 {
1065 si = i + 2;
cce855bc 1066 if (string[i + 1] == LPAREN)
a0c0a00f 1067 ret = extract_command_subst (string, &si, SX_NOALLOC|(flags&SX_COMPLETE));
ccc6cda3 1068 else
495aee44 1069 ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC);
ccc6cda3 1070
a0c0a00f
CR
1071 /* These can consume the entire string if they are unterminated */
1072 CHECK_STRING_OVERRUN (i, si, slen, c);
1073
7117c2d2 1074 i = si + 1;
ccc6cda3
JA
1075 continue;
1076 }
1077 else if (c != '"')
7117c2d2
JA
1078 {
1079 ADVANCE_CHAR (string, slen, i);
1080 continue;
1081 }
ccc6cda3
JA
1082 else
1083 break;
726f6388 1084 }
ccc6cda3
JA
1085
1086 if (c)
1087 i++;
1088
1089 return (i);
726f6388
JA
1090}
1091
ccc6cda3
JA
1092/* Extract the contents of STRING as if it is enclosed in single quotes.
1093 SINDEX, when passed in, is the offset of the character immediately
1094 following the opening single quote; on exit, SINDEX is left pointing after
74091dd4
CR
1095 the closing single quote. ALLOWESC allows the single quote to be quoted by
1096 a backslash; it's not used yet. */
ccc6cda3 1097static inline char *
74091dd4 1098string_extract_single_quoted (string, sindex, allowesc)
ccc6cda3
JA
1099 char *string;
1100 int *sindex;
74091dd4 1101 int allowesc;
ccc6cda3 1102{
f73dda09 1103 register int i;
7117c2d2 1104 size_t slen;
ccc6cda3 1105 char *t;
74091dd4 1106 int pass_next;
7117c2d2 1107 DECLARE_MBSTATE;
ccc6cda3 1108
95732b49
JA
1109 /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */
1110 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
7117c2d2 1111 i = *sindex;
74091dd4
CR
1112 pass_next = 0;
1113 while (string[i])
1114 {
1115 if (pass_next)
1116 {
1117 pass_next = 0;
1118 ADVANCE_CHAR (string, slen, i);
1119 continue;
1120 }
1121 if (allowesc && string[i] == '\\')
1122 pass_next++;
1123 else if (string[i] == '\'')
1124 break;
1125 ADVANCE_CHAR (string, slen, i);
1126 }
ccc6cda3 1127
bb70624e 1128 t = substring (string, *sindex, i);
ccc6cda3
JA
1129
1130 if (string[i])
1131 i++;
1132 *sindex = i;
1133
1134 return (t);
1135}
1136
a0c0a00f
CR
1137/* Skip over a single-quoted string. We overload the SX_COMPLETE flag to mean
1138 that we are splitting out words for completion and have encountered a $'...'
1139 string, which allows backslash-escaped single quotes. */
ccc6cda3 1140static inline int
a0c0a00f 1141skip_single_quoted (string, slen, sind, flags)
0628567a 1142 const char *string;
7117c2d2 1143 size_t slen;
ccc6cda3 1144 int sind;
a0c0a00f 1145 int flags;
ccc6cda3 1146{
28ef6c31 1147 register int c;
7117c2d2
JA
1148 DECLARE_MBSTATE;
1149
1150 c = sind;
1151 while (string[c] && string[c] != '\'')
a0c0a00f
CR
1152 {
1153 if ((flags & SX_COMPLETE) && string[c] == '\\' && string[c+1] == '\'' && string[c+2])
1154 ADVANCE_CHAR (string, slen, c);
1155 ADVANCE_CHAR (string, slen, c);
1156 }
ccc6cda3 1157
28ef6c31
JA
1158 if (string[c])
1159 c++;
1160 return c;
ccc6cda3
JA
1161}
1162
1163/* Just like string_extract, but doesn't hack backslashes or any of
bb70624e 1164 that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */
726f6388 1165static char *
3185942a 1166string_extract_verbatim (string, slen, sindex, charlist, flags)
f73dda09 1167 char *string;
95732b49 1168 size_t slen;
ccc6cda3 1169 int *sindex;
f73dda09 1170 char *charlist;
3185942a 1171 int flags;
ccc6cda3 1172{
0001803f 1173 register int i;
95732b49 1174#if defined (HANDLE_MULTIBYTE)
95732b49
JA
1175 wchar_t *wcharlist;
1176#endif
ccc6cda3
JA
1177 int c;
1178 char *temp;
95732b49 1179 DECLARE_MBSTATE;
ccc6cda3 1180
a0c0a00f 1181 if ((flags & SX_NOCTLESC) && charlist[0] == '\'' && charlist[1] == '\0')
ccc6cda3 1182 {
74091dd4 1183 temp = string_extract_single_quoted (string, sindex, 0);
ccc6cda3
JA
1184 --*sindex; /* leave *sindex at separator character */
1185 return temp;
1186 }
1187
8868edaf
CR
1188 /* This can never be called with charlist == NULL. If *charlist == NULL,
1189 we can skip the loop and just return a copy of the string, updating
1190 *sindex */
1191 if (*charlist == 0)
1192 {
1193 temp = string + *sindex;
1194 c = (*sindex == 0) ? slen : STRLEN (temp);
1195 temp = savestring (temp);
1196 *sindex += c;
1197 return temp;
1198 }
1199
95732b49 1200 i = *sindex;
95732b49 1201#if defined (HANDLE_MULTIBYTE)
95732b49
JA
1202 wcharlist = 0;
1203#endif
1204 while (c = string[i])
ccc6cda3 1205 {
95732b49
JA
1206#if defined (HANDLE_MULTIBYTE)
1207 size_t mblength;
1208#endif
3185942a
JA
1209 if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
1210 {
1211 i += 2;
d233b485 1212 CHECK_STRING_OVERRUN (i, i, slen, c);
3185942a
JA
1213 continue;
1214 }
1215 /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
1216 through, to protect the CTLNULs from later calls to
1217 remove_quoted_nulls. */
1218 else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
ccc6cda3 1219 {
95732b49 1220 i += 2;
d233b485 1221 CHECK_STRING_OVERRUN (i, i, slen, c);
ccc6cda3
JA
1222 continue;
1223 }
1224
95732b49 1225#if defined (HANDLE_MULTIBYTE)
d233b485
CR
1226 if (locale_utf8locale && slen > i && UTF8_SINGLEBYTE (string[i]))
1227 mblength = (string[i] != 0) ? 1 : 0;
1228 else
1229 mblength = MBLEN (string + i, slen - i);
95732b49
JA
1230 if (mblength > 1)
1231 {
1232 wchar_t wc;
1233 mblength = mbtowc (&wc, string + i, slen - i);
1234 if (MB_INVALIDCH (mblength))
1235 {
1236 if (MEMBER (c, charlist))
1237 break;
1238 }
1239 else
1240 {
1241 if (wcharlist == 0)
1242 {
1243 size_t len;
1244 len = mbstowcs (wcharlist, charlist, 0);
1245 if (len == -1)
1246 len = 0;
0628567a
JA
1247 wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
1248 mbstowcs (wcharlist, charlist, len + 1);
95732b49
JA
1249 }
1250
1251 if (wcschr (wcharlist, wc))
1252 break;
1253 }
1254 }
1255 else
1256#endif
ccc6cda3
JA
1257 if (MEMBER (c, charlist))
1258 break;
95732b49
JA
1259
1260 ADVANCE_CHAR (string, slen, i);
ccc6cda3
JA
1261 }
1262
95732b49
JA
1263#if defined (HANDLE_MULTIBYTE)
1264 FREE (wcharlist);
1265#endif
1266
bb70624e 1267 temp = substring (string, *sindex, i);
ccc6cda3
JA
1268 *sindex = i;
1269
1270 return (temp);
1271}
1272
1273/* Extract the $( construct in STRING, and return a new string.
1274 Start extracting at (SINDEX) as if we had just seen "$(".
3185942a 1275 Make (SINDEX) get the position of the matching ")". )
0001803f 1276 XFLAGS is additional flags to pass to other extraction functions. */
ccc6cda3 1277char *
3185942a 1278extract_command_subst (string, sindex, xflags)
726f6388
JA
1279 char *string;
1280 int *sindex;
3185942a 1281 int xflags;
726f6388 1282{
a0c0a00f
CR
1283 char *ret;
1284
1285 if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE))
3185942a
JA
1286 return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
1287 else
1288 {
1289 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
a0c0a00f
CR
1290 ret = xparse_dolparen (string, string+*sindex, sindex, xflags);
1291 return ret;
3185942a 1292 }
ccc6cda3
JA
1293}
1294
28ef6c31 1295/* Extract the $[ construct in STRING, and return a new string. (])
ccc6cda3
JA
1296 Start extracting at (SINDEX) as if we had just seen "$[".
1297 Make (SINDEX) get the position of the matching "]". */
1298char *
1299extract_arithmetic_subst (string, sindex)
1300 char *string;
1301 int *sindex;
1302{
7117c2d2 1303 return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/
ccc6cda3
JA
1304}
1305
1306#if defined (PROCESS_SUBSTITUTION)
1307/* Extract the <( or >( construct in STRING, and return a new string.
1308 Start extracting at (SINDEX) as if we had just seen "<(".
cce855bc 1309 Make (SINDEX) get the position of the matching ")". */ /*))*/
ccc6cda3 1310char *
85b94814 1311extract_process_subst (string, starter, sindex, xflags)
ccc6cda3
JA
1312 char *string;
1313 char *starter;
1314 int *sindex;
85b94814 1315 int xflags;
ccc6cda3 1316{
85b94814 1317#if 0
d233b485 1318 /* XXX - check xflags&SX_COMPLETE here? */
ac50fbac 1319 return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND));
85b94814
CR
1320#else
1321 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1322 return (xparse_dolparen (string, string+*sindex, sindex, xflags));
1323#endif
ccc6cda3
JA
1324}
1325#endif /* PROCESS_SUBSTITUTION */
1326
1327#if defined (ARRAY_VARS)
95732b49
JA
1328/* This can be fooled by unquoted right parens in the passed string. If
1329 each caller verifies that the last character in STRING is a right paren,
1330 we don't even need to call extract_delimited_string. */
ccc6cda3
JA
1331char *
1332extract_array_assignment_list (string, sindex)
1333 char *string;
1334 int *sindex;
1335{
95732b49
JA
1336 int slen;
1337 char *ret;
1338
d233b485
CR
1339 slen = strlen (string);
1340 if (string[slen - 1] == RPAREN)
95732b49
JA
1341 {
1342 ret = substring (string, *sindex, slen - 1);
1343 *sindex = slen - 1;
1344 return ret;
1345 }
1346 return 0;
ccc6cda3
JA
1347}
1348#endif
1349
1350/* Extract and create a new string from the contents of STRING, a
1351 character string delimited with OPENER and CLOSER. SINDEX is
1352 the address of an int describing the current offset in STRING;
1353 it should point to just after the first OPENER found. On exit,
1354 SINDEX gets the position of the last character of the matching CLOSER.
1355 If OPENER is more than a single character, ALT_OPENER, if non-null,
1356 contains a character string that can also match CLOSER and thus
1357 needs to be skipped. */
1358static char *
7117c2d2 1359extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
ccc6cda3
JA
1360 char *string;
1361 int *sindex;
1362 char *opener, *alt_opener, *closer;
7117c2d2 1363 int flags;
ccc6cda3
JA
1364{
1365 int i, c, si;
7117c2d2 1366 size_t slen;
ccc6cda3 1367 char *t, *result;
0628567a 1368 int pass_character, nesting_level, in_comment;
ccc6cda3 1369 int len_closer, len_opener, len_alt_opener;
7117c2d2 1370 DECLARE_MBSTATE;
ccc6cda3 1371
7117c2d2 1372 slen = strlen (string + *sindex) + *sindex;
ccc6cda3
JA
1373 len_opener = STRLEN (opener);
1374 len_alt_opener = STRLEN (alt_opener);
1375 len_closer = STRLEN (closer);
726f6388 1376
0628567a 1377 pass_character = in_comment = 0;
726f6388
JA
1378
1379 nesting_level = 1;
ccc6cda3 1380 i = *sindex;
726f6388 1381
ccc6cda3 1382 while (nesting_level)
726f6388 1383 {
ccc6cda3
JA
1384 c = string[i];
1385
a0c0a00f
CR
1386 /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond
1387 the end of the string, catch it and cut the loop. */
1388 if (i > slen)
1389 {
1390 i = slen;
1391 c = string[i = slen];
1392 break;
1393 }
1394
ccc6cda3 1395 if (c == 0)
28ef6c31 1396 break;
ccc6cda3 1397
0628567a
JA
1398 if (in_comment)
1399 {
1400 if (c == '\n')
1401 in_comment = 0;
1402 ADVANCE_CHAR (string, slen, i);
1403 continue;
1404 }
1405
ccc6cda3 1406 if (pass_character) /* previous char was backslash */
726f6388
JA
1407 {
1408 pass_character = 0;
7117c2d2 1409 ADVANCE_CHAR (string, slen, i);
726f6388
JA
1410 continue;
1411 }
1412
0628567a 1413 /* Not exactly right yet; should handle shell metacharacters and
0001803f 1414 multibyte characters, too. See COMMENT_BEGIN define in parse.y */
3185942a 1415 if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
0628567a
JA
1416 {
1417 in_comment = 1;
1418 ADVANCE_CHAR (string, slen, i);
1419 continue;
1420 }
1421
7117c2d2 1422 if (c == CTLESC || c == '\\')
726f6388 1423 {
ccc6cda3
JA
1424 pass_character++;
1425 i++;
1426 continue;
726f6388
JA
1427 }
1428
495aee44
CR
1429 /* Process a nested command substitution, but only if we're parsing an
1430 arithmetic substitution. */
0001803f
CR
1431 if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
1432 {
1433 si = i + 2;
495aee44 1434 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
d233b485 1435 CHECK_STRING_OVERRUN (i, si, slen, c);
0001803f
CR
1436 i = si + 1;
1437 continue;
1438 }
0001803f 1439
ccc6cda3
JA
1440 /* Process a nested OPENER. */
1441 if (STREQN (string + i, opener, len_opener))
726f6388 1442 {
ccc6cda3 1443 si = i + len_opener;
3185942a 1444 t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
d233b485 1445 CHECK_STRING_OVERRUN (i, si, slen, c);
ccc6cda3 1446 i = si + 1;
ccc6cda3 1447 continue;
726f6388
JA
1448 }
1449
ccc6cda3
JA
1450 /* Process a nested ALT_OPENER */
1451 if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
726f6388 1452 {
ccc6cda3 1453 si = i + len_alt_opener;
3185942a 1454 t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
d233b485 1455 CHECK_STRING_OVERRUN (i, si, slen, c);
ccc6cda3 1456 i = si + 1;
726f6388
JA
1457 continue;
1458 }
ccc6cda3
JA
1459
1460 /* If the current substring terminates the delimited string, decrement
1461 the nesting level. */
1462 if (STREQN (string + i, closer, len_closer))
726f6388 1463 {
7117c2d2 1464 i += len_closer - 1; /* move to last byte of the closer */
ccc6cda3
JA
1465 nesting_level--;
1466 if (nesting_level == 0)
1467 break;
726f6388 1468 }
ccc6cda3
JA
1469
1470 /* Pass old-style command substitution through verbatim. */
1471 if (c == '`')
28ef6c31
JA
1472 {
1473 si = i + 1;
3185942a 1474 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
d233b485 1475 CHECK_STRING_OVERRUN (i, si, slen, c);
28ef6c31 1476 i = si + 1;
28ef6c31
JA
1477 continue;
1478 }
ccc6cda3 1479
7117c2d2
JA
1480 /* Pass single-quoted and double-quoted strings through verbatim. */
1481 if (c == '\'' || c == '"')
28ef6c31
JA
1482 {
1483 si = i + 1;
a0c0a00f
CR
1484 i = (c == '\'') ? skip_single_quoted (string, slen, si, 0)
1485 : skip_double_quoted (string, slen, si, 0);
28ef6c31
JA
1486 continue;
1487 }
ccc6cda3 1488
7117c2d2
JA
1489 /* move past this character, which was not special. */
1490 ADVANCE_CHAR (string, slen, i);
726f6388
JA
1491 }
1492
b80f6443 1493 if (c == 0 && nesting_level)
726f6388 1494 {
b80f6443
JA
1495 if (no_longjmp_on_fatal_error == 0)
1496 {
b80f6443 1497 last_command_exit_value = EXECUTION_FAILURE;
ac50fbac 1498 report_error (_("bad substitution: no closing `%s' in %s"), closer, string);
b80f6443
JA
1499 exp_jump_to_top_level (DISCARD);
1500 }
1501 else
1502 {
1503 *sindex = i;
1504 return (char *)NULL;
1505 }
726f6388 1506 }
ccc6cda3 1507
cce855bc 1508 si = i - *sindex - len_closer + 1;
3185942a 1509 if (flags & SX_NOALLOC)
7117c2d2
JA
1510 result = (char *)NULL;
1511 else
1512 {
1513 result = (char *)xmalloc (1 + si);
1514 strncpy (result, string + *sindex, si);
1515 result[si] = '\0';
1516 }
cce855bc
JA
1517 *sindex = i;
1518
726f6388
JA
1519 return (result);
1520}
1521
74091dd4
CR
1522/* A simplified version of extract_dollar_brace_string that exists to handle
1523 $'...' and $"..." quoting in here-documents, since the here-document read
1524 path doesn't. It's separate because we don't want to mess with the fast
1525 common path. We already know we're going to allocate and return a new
1526 string and quoted == Q_HERE_DOCUMENT. We might be able to cut it down
1527 some more, but extracting strings and adding them as we go adds complexity.
1528 This needs to match the logic in parse.y:parse_matched_pair so we get
1529 consistent behavior between here-documents and double-quoted strings. */
1530static char *
1531extract_heredoc_dolbrace_string (string, sindex, quoted, flags)
1532 char *string;
1533 int *sindex, quoted, flags;
1534{
1535 register int i, c;
1536 size_t slen, tlen, result_index, result_size;
1537 int pass_character, nesting_level, si, dolbrace_state;
1538 char *result, *t, *send;
1539 DECLARE_MBSTATE;
1540
1541 pass_character = 0;
1542 nesting_level = 1;
1543 slen = strlen (string + *sindex) + *sindex;
1544 send = string + slen;
1545
1546 result_size = slen;
1547 result_index = 0;
1548 result = xmalloc (result_size + 1);
1549
1550 /* This function isn't called if this condition is not true initially. */
1551 dolbrace_state = DOLBRACE_QUOTE;
1552
1553 i = *sindex;
1554 while (c = string[i])
1555 {
1556 if (pass_character)
1557 {
1558 pass_character = 0;
1559 RESIZE_MALLOCED_BUFFER (result, result_index, locale_mb_cur_max + 1, result_size, 64);
1560 COPY_CHAR_I (result, result_index, string, send, i);
1561 continue;
1562 }
1563
1564 /* CTLESCs and backslashes quote the next character. */
1565 if (c == CTLESC || c == '\\')
1566 {
1567 pass_character++;
1568 RESIZE_MALLOCED_BUFFER (result, result_index, 2, result_size, 64);
1569 result[result_index++] = c;
1570 i++;
1571 continue;
1572 }
1573
1574 /* The entire reason we have this separate function right here. */
1575 if (c == '$' && string[i+1] == '\'')
1576 {
1577 char *ttrans;
1578 int ttranslen;
1579
1580 if ((posixly_correct || extended_quote == 0) && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2)
1581 {
1582 RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, 64);
1583 result[result_index++] = '$';
1584 result[result_index++] = '\'';
1585 i += 2;
1586 continue;
1587 }
1588
1589 si = i + 2;
1590 t = string_extract_single_quoted (string, &si, 1); /* XXX */
1591 CHECK_STRING_OVERRUN (i, si, slen, c);
1592
1593 tlen = si - i - 2; /* -2 since si is one after the close quote */
1594 ttrans = ansiexpand (t, 0, tlen, &ttranslen);
1595 free (t);
1596
1597 /* needed to correctly quote any embedded single quotes. */
1598 if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2)
1599 {
1600 t = sh_single_quote (ttrans);
1601 tlen = strlen (t);
1602 free (ttrans);
1603 }
1604 else if (extended_quote) /* dolbrace_state == DOLBRACE_PARAM */
1605 {
1606 /* This matches what parse.y:parse_matched_pair() does */
1607 t = ttrans;
1608 tlen = strlen (t);
1609 }
1610
1611 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 1, result_size, 64);
1612 strncpy (result + result_index, t, tlen);
1613 result_index += tlen;
1614 free (t);
1615 i = si;
1616 continue;
1617 }
1618
1619#if defined (TRANSLATABLE_STRINGS)
1620 if (c == '$' && string[i+1] == '"')
1621 {
1622 char *ttrans;
1623 int ttranslen;
1624
1625 si = i + 2;
1626 t = string_extract_double_quoted (string, &si, flags); /* XXX */
1627 CHECK_STRING_OVERRUN (i, si, slen, c);
1628
1629 tlen = si - i - 2; /* -2 since si is one after the close quote */
1630 ttrans = locale_expand (t, 0, tlen, line_number, &ttranslen);
1631 free (t);
1632
1633 t = singlequote_translations ? sh_single_quote (ttrans) : sh_mkdoublequoted (ttrans, ttranslen, 0);
1634 tlen = strlen (t);
1635 free (ttrans);
1636
1637 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 1, result_size, 64);
1638 strncpy (result + result_index, t, tlen);
1639 result_index += tlen;
1640 free (t);
1641 i = si;
1642 continue;
1643 }
1644#endif /* TRANSLATABLE_STRINGS */
1645
1646 if (c == '$' && string[i+1] == LBRACE)
1647 {
1648 nesting_level++;
1649 RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, 64);
1650 result[result_index++] = c;
1651 result[result_index++] = string[i+1];
1652 i += 2;
1653 if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2 || dolbrace_state == DOLBRACE_WORD)
1654 dolbrace_state = DOLBRACE_PARAM;
1655 continue;
1656 }
1657
1658 if (c == RBRACE)
1659 {
1660 nesting_level--;
1661 if (nesting_level == 0)
1662 break;
1663 RESIZE_MALLOCED_BUFFER (result, result_index, 2, result_size, 64);
1664 result[result_index++] = c;
1665 i++;
1666 continue;
1667 }
1668
1669 /* Pass the contents of old-style command substitutions through
1670 verbatim. */
1671 if (c == '`')
1672 {
1673 si = i + 1;
1674 t = string_extract (string, &si, "`", flags); /* already know (flags & SX_NOALLOC) == 0) */
1675 CHECK_STRING_OVERRUN (i, si, slen, c);
1676
1677 tlen = si - i - 1;
1678 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 3, result_size, 64);
1679 result[result_index++] = c;
1680 strncpy (result + result_index, t, tlen);
1681 result_index += tlen;
1682 result[result_index++] = string[si];
1683 free (t);
1684 i = si + 1;
1685 continue;
1686 }
1687
1688 /* Pass the contents of new-style command substitutions and
1689 arithmetic substitutions through verbatim. */
1690 if (string[i] == '$' && string[i+1] == LPAREN)
1691 {
1692 si = i + 2;
1693 t = extract_command_subst (string, &si, flags);
1694 CHECK_STRING_OVERRUN (i, si, slen, c);
1695
2bb3cbef 1696 tlen = si - i - 2;
74091dd4
CR
1697 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 4, result_size, 64);
1698 result[result_index++] = c;
1699 result[result_index++] = LPAREN;
1700 strncpy (result + result_index, t, tlen);
1701 result_index += tlen;
1702 result[result_index++] = string[si];
1703 free (t);
1704 i = si + 1;
1705 continue;
1706 }
1707
1708#if defined (PROCESS_SUBSTITUTION)
1709 /* Technically this should only work at the start of a word */
1710 if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN)
1711 {
1712 si = i + 2;
1713 t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags);
1714 CHECK_STRING_OVERRUN (i, si, slen, c);
1715
2bb3cbef 1716 tlen = si - i - 2;
74091dd4
CR
1717 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 4, result_size, 64);
1718 result[result_index++] = c;
1719 result[result_index++] = LPAREN;
1720 strncpy (result + result_index, t, tlen);
1721 result_index += tlen;
1722 result[result_index++] = string[si];
1723 free (t);
1724 i = si + 1;
1725 continue;
1726 }
1727#endif
1728
1729 if (c == '\'' && posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE)
1730 {
1731 COPY_CHAR_I (result, result_index, string, send, i);
1732 continue;
1733 }
1734
1735 /* Pass the contents of single and double-quoted strings through verbatim. */
1736 if (c == '"' || c == '\'')
1737 {
1738 si = i + 1;
1739 if (c == '"')
1740 t = string_extract_double_quoted (string, &si, flags);
1741 else
1742 t = string_extract_single_quoted (string, &si, 0);
1743 CHECK_STRING_OVERRUN (i, si, slen, c);
1744
1745 tlen = si - i - 2; /* -2 since si is one after the close quote */
1746 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 3, result_size, 64);
1747 result[result_index++] = c;
1748 strncpy (result + result_index, t, tlen);
1749 result_index += tlen;
1750 result[result_index++] = string[si - 1];
1751 free (t);
1752 i = si;
1753 continue;
1754 }
1755
1756 /* copy this character, which was not special. */
1757 COPY_CHAR_I (result, result_index, string, send, i);
1758
1759 /* This logic must agree with parse.y:parse_matched_pair, since they
1760 share the same defines. */
1761 if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
1762 dolbrace_state = DOLBRACE_QUOTE;
1763 else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
1764 dolbrace_state = DOLBRACE_QUOTE;
1765 else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
1766 dolbrace_state = DOLBRACE_QUOTE2; /* XXX */
1767 else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
1768 dolbrace_state = DOLBRACE_QUOTE;
1769 else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
1770 dolbrace_state = DOLBRACE_QUOTE;
1771 /* This is intended to handle all of the [:]op expansions and the substring/
1772 length/pattern removal/pattern substitution expansions. */
1773 else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
1774 dolbrace_state = DOLBRACE_OP;
1775 else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
1776 dolbrace_state = DOLBRACE_WORD;
1777 }
1778
1779 if (c == 0 && nesting_level)
1780 {
1781 free (result);
1782 if (no_longjmp_on_fatal_error == 0)
1783 { /* { */
1784 last_command_exit_value = EXECUTION_FAILURE;
1785 report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
1786 exp_jump_to_top_level (DISCARD);
1787 }
1788 else
1789 {
1790 *sindex = i;
1791 return ((char *)NULL);
1792 }
1793 }
1794
1795 *sindex = i;
1796 result[result_index] = '\0';
1797
1798 return (result);
1799}
1800
30e948e8
CR
1801#define PARAMEXPNEST_MAX 32 // for now
1802static int dbstate[PARAMEXPNEST_MAX];
1803
ccc6cda3
JA
1804/* Extract a parameter expansion expression within ${ and } from STRING.
1805 Obey the Posix.2 rules for finding the ending `}': count braces while
1806 skipping over enclosed quoted strings and command substitutions.
1807 SINDEX is the address of an int describing the current offset in STRING;
1808 it should point to just after the first `{' found. On exit, SINDEX
1809 gets the position of the matching `}'. QUOTED is non-zero if this
1810 occurs inside double quotes. */
1811/* XXX -- this is very similar to extract_delimited_string -- XXX */
726f6388 1812static char *
7117c2d2 1813extract_dollar_brace_string (string, sindex, quoted, flags)
726f6388 1814 char *string;
7117c2d2 1815 int *sindex, quoted, flags;
726f6388 1816{
f73dda09 1817 register int i, c;
7117c2d2 1818 size_t slen;
495aee44 1819 int pass_character, nesting_level, si, dolbrace_state;
ccc6cda3 1820 char *result, *t;
7117c2d2 1821 DECLARE_MBSTATE;
726f6388 1822
495aee44 1823 /* The handling of dolbrace_state needs to agree with the code in parse.y:
49ed961b
CR
1824 parse_matched_pair(). The different initial value is to handle the
1825 case where this function is called to parse the word in
1826 ${param op word} (SX_WORD). */
1827 dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM;
1828 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP))
1829 dolbrace_state = DOLBRACE_QUOTE;
495aee44 1830
74091dd4
CR
1831 if (quoted == Q_HERE_DOCUMENT && dolbrace_state == DOLBRACE_QUOTE && (flags & SX_NOALLOC) == 0)
1832 return (extract_heredoc_dolbrace_string (string, sindex, quoted, flags));
1833
30e948e8
CR
1834 dbstate[0] = dolbrace_state;
1835
74091dd4
CR
1836 pass_character = 0;
1837 nesting_level = 1;
1838 slen = strlen (string + *sindex) + *sindex;
1839
7117c2d2
JA
1840 i = *sindex;
1841 while (c = string[i])
726f6388 1842 {
ccc6cda3 1843 if (pass_character)
726f6388 1844 {
ccc6cda3 1845 pass_character = 0;
7117c2d2 1846 ADVANCE_CHAR (string, slen, i);
ccc6cda3
JA
1847 continue;
1848 }
726f6388 1849
cce855bc
JA
1850 /* CTLESCs and backslashes quote the next character. */
1851 if (c == CTLESC || c == '\\')
726f6388 1852 {
ccc6cda3 1853 pass_character++;
7117c2d2 1854 i++;
726f6388
JA
1855 continue;
1856 }
1857
cce855bc 1858 if (string[i] == '$' && string[i+1] == LBRACE)
726f6388 1859 {
30e948e8
CR
1860 if (nesting_level < PARAMEXPNEST_MAX)
1861 dbstate[nesting_level] = dolbrace_state;
ccc6cda3 1862 nesting_level++;
7117c2d2 1863 i += 2;
74091dd4
CR
1864 if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_WORD)
1865 dolbrace_state = DOLBRACE_PARAM;
726f6388
JA
1866 continue;
1867 }
1868
cce855bc 1869 if (c == RBRACE)
726f6388 1870 {
ccc6cda3
JA
1871 nesting_level--;
1872 if (nesting_level == 0)
1873 break;
30e948e8 1874 dolbrace_state = (nesting_level < PARAMEXPNEST_MAX) ? dbstate[nesting_level] : dbstate[0]; /* Guess using initial state */
7117c2d2 1875 i++;
726f6388
JA
1876 continue;
1877 }
1878
ccc6cda3
JA
1879 /* Pass the contents of old-style command substitutions through
1880 verbatim. */
1881 if (c == '`')
726f6388 1882 {
ccc6cda3 1883 si = i + 1;
3185942a 1884 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
a0c0a00f
CR
1885
1886 CHECK_STRING_OVERRUN (i, si, slen, c);
d233b485 1887
7117c2d2 1888 i = si + 1;
ccc6cda3
JA
1889 continue;
1890 }
726f6388 1891
cce855bc
JA
1892 /* Pass the contents of new-style command substitutions and
1893 arithmetic substitutions through verbatim. */
1894 if (string[i] == '$' && string[i+1] == LPAREN)
ccc6cda3 1895 {
726f6388 1896 si = i + 2;
3185942a 1897 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
d233b485
CR
1898
1899 CHECK_STRING_OVERRUN (i, si, slen, c);
1900
1901 i = si + 1;
1902 continue;
1903 }
1904
1905#if defined (PROCESS_SUBSTITUTION)
1906 /* Technically this should only work at the start of a word */
1907 if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN)
1908 {
1909 si = i + 2;
1910 t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags|SX_NOALLOC);
1911
1912 CHECK_STRING_OVERRUN (i, si, slen, c);
1913
7117c2d2 1914 i = si + 1;
726f6388
JA
1915 continue;
1916 }
d233b485 1917#endif
726f6388 1918
495aee44
CR
1919 /* Pass the contents of double-quoted strings through verbatim. */
1920 if (c == '"')
1921 {
1922 si = i + 1;
a0c0a00f 1923 i = skip_double_quoted (string, slen, si, 0);
495aee44
CR
1924 /* skip_XXX_quoted leaves index one past close quote */
1925 continue;
1926 }
1927
1928 if (c == '\'')
1929 {
1930/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
ac50fbac 1931 if (posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
495aee44
CR
1932 ADVANCE_CHAR (string, slen, i);
1933 else
1934 {
1935 si = i + 1;
a0c0a00f 1936 i = skip_single_quoted (string, slen, si, 0);
495aee44
CR
1937 }
1938
1939 continue;
1940 }
7117c2d2 1941
d233b485
CR
1942#if defined (ARRAY_VARS)
1943 if (c == LBRACK && dolbrace_state == DOLBRACE_PARAM)
1944 {
1945 si = skipsubscript (string, i, 0);
1946 CHECK_STRING_OVERRUN (i, si, slen, c);
1947 if (string[si] == RBRACK)
1948 c = string[i = si];
1949 }
1950#endif
1951
7117c2d2
JA
1952 /* move past this character, which was not special. */
1953 ADVANCE_CHAR (string, slen, i);
495aee44
CR
1954
1955 /* This logic must agree with parse.y:parse_matched_pair, since they
1956 share the same defines. */
1957 if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
1958 dolbrace_state = DOLBRACE_QUOTE;
1959 else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
1960 dolbrace_state = DOLBRACE_QUOTE;
1961 else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
ac50fbac 1962 dolbrace_state = DOLBRACE_QUOTE2; /* XXX */
495aee44
CR
1963 else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
1964 dolbrace_state = DOLBRACE_QUOTE;
1965 else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
1966 dolbrace_state = DOLBRACE_QUOTE;
a0c0a00f
CR
1967 /* This is intended to handle all of the [:]op expansions and the substring/
1968 length/pattern removal/pattern substitution expansions. */
495aee44
CR
1969 else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
1970 dolbrace_state = DOLBRACE_OP;
1971 else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
1972 dolbrace_state = DOLBRACE_WORD;
cce855bc 1973 }
726f6388 1974
b80f6443 1975 if (c == 0 && nesting_level)
cce855bc 1976 {
b80f6443
JA
1977 if (no_longjmp_on_fatal_error == 0)
1978 { /* { */
b80f6443 1979 last_command_exit_value = EXECUTION_FAILURE;
ac50fbac 1980 report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
b80f6443
JA
1981 exp_jump_to_top_level (DISCARD);
1982 }
1983 else
1984 {
1985 *sindex = i;
1986 return ((char *)NULL);
1987 }
726f6388 1988 }
726f6388 1989
3185942a 1990 result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
726f6388
JA
1991 *sindex = i;
1992
ccc6cda3 1993 return (result);
726f6388
JA
1994}
1995
ccc6cda3
JA
1996/* Remove backslashes which are quoting backquotes from STRING. Modifies
1997 STRING, and returns a pointer to it. */
1998char *
1999de_backslash (string)
726f6388 2000 char *string;
ccc6cda3 2001{
7117c2d2
JA
2002 register size_t slen;
2003 register int i, j, prev_i;
2004 DECLARE_MBSTATE;
726f6388 2005
7117c2d2
JA
2006 slen = strlen (string);
2007 i = j = 0;
2008
2009 /* Loop copying string[i] to string[j], i >= j. */
2010 while (i < slen)
2011 {
2012 if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
ccc6cda3 2013 string[i + 1] == '$'))
7117c2d2
JA
2014 i++;
2015 prev_i = i;
2016 ADVANCE_CHAR (string, slen, i);
2017 if (j < prev_i)
b80f6443 2018 do string[j++] = string[prev_i++]; while (prev_i < i);
7117c2d2 2019 else
b80f6443 2020 j = i;
7117c2d2
JA
2021 }
2022 string[j] = '\0';
2023
ccc6cda3
JA
2024 return (string);
2025}
726f6388 2026
ccc6cda3 2027#if 0
cce855bc 2028/*UNUSED*/
ccc6cda3
JA
2029/* Replace instances of \! in a string with !. */
2030void
2031unquote_bang (string)
2032 char *string;
2033{
2034 register int i, j;
2035 register char *temp;
726f6388 2036
f73dda09 2037 temp = (char *)xmalloc (1 + strlen (string));
726f6388 2038
ccc6cda3
JA
2039 for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
2040 {
2041 if (string[i] == '\\' && string[i + 1] == '!')
2042 {
2043 temp[j] = '!';
2044 i++;
2045 }
2046 }
2047 strcpy (string, temp);
2048 free (temp);
726f6388 2049}
ccc6cda3 2050#endif
726f6388 2051
a0c0a00f 2052#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = oldjmp; return (x); } while (0)
3185942a 2053
74091dd4
CR
2054/* When FLAGS & 2 == 0, this function assumes STRING[I] == OPEN; when
2055 FLAGS & 2 != 0, it assumes STRING[I] points to one character past OPEN;
2056 returns with STRING[RET] == close; used to parse array subscripts.
2057 FLAGS & 1 means not to attempt to skip over matched pairs of quotes or
2058 backquotes, or skip word expansions; it is intended to be used after
2059 expansion has been performed and during final assignment parsing (see
2060 arrayfunc.c:assign_compound_array_list()) or during execution by a builtin
2061 which has already undergone word expansion. */
89a92869
CR
2062static int
2063skip_matched_pair (string, start, open, close, flags)
2064 const char *string;
2065 int start, open, close, flags;
2066{
a0c0a00f 2067 int i, pass_next, backq, si, c, count, oldjmp;
89a92869
CR
2068 size_t slen;
2069 char *temp, *ss;
2070 DECLARE_MBSTATE;
2071
2072 slen = strlen (string + start) + start;
a0c0a00f 2073 oldjmp = no_longjmp_on_fatal_error;
89a92869
CR
2074 no_longjmp_on_fatal_error = 1;
2075
74091dd4
CR
2076 /* Move to the first character after a leading OPEN. If FLAGS&2, we assume
2077 that START already points to that character. If not, we need to skip over
2078 it here. */
2079 i = (flags & 2) ? start : start + 1;
89a92869
CR
2080 count = 1;
2081 pass_next = backq = 0;
2082 ss = (char *)string;
2083 while (c = string[i])
2084 {
2085 if (pass_next)
2086 {
2087 pass_next = 0;
2088 if (c == 0)
2089 CQ_RETURN(i);
2090 ADVANCE_CHAR (string, slen, i);
2091 continue;
2092 }
d233b485 2093 else if ((flags & 1) == 0 && c == '\\')
89a92869
CR
2094 {
2095 pass_next = 1;
2096 i++;
2097 continue;
2098 }
2099 else if (backq)
2100 {
2101 if (c == '`')
2102 backq = 0;
2103 ADVANCE_CHAR (string, slen, i);
2104 continue;
2105 }
0001803f 2106 else if ((flags & 1) == 0 && c == '`')
89a92869
CR
2107 {
2108 backq = 1;
2109 i++;
2110 continue;
2111 }
0001803f 2112 else if ((flags & 1) == 0 && c == open)
89a92869
CR
2113 {
2114 count++;
2115 i++;
2116 continue;
2117 }
2118 else if (c == close)
2119 {
2120 count--;
2121 if (count == 0)
2122 break;
2123 i++;
2124 continue;
2125 }
0001803f 2126 else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
89a92869 2127 {
a0c0a00f
CR
2128 i = (c == '\'') ? skip_single_quoted (ss, slen, ++i, 0)
2129 : skip_double_quoted (ss, slen, ++i, 0);
89a92869
CR
2130 /* no increment, the skip functions increment past the closing quote. */
2131 }
74091dd4 2132 else if ((flags & 1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
89a92869
CR
2133 {
2134 si = i + 2;
2135 if (string[si] == '\0')
2136 CQ_RETURN(si);
2137
d233b485 2138 /* XXX - extract_command_subst here? */
89a92869
CR
2139 if (string[i+1] == LPAREN)
2140 temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
2141 else
2142 temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
a0c0a00f
CR
2143
2144 CHECK_STRING_OVERRUN (i, si, slen, c);
2145
89a92869
CR
2146 i = si;
2147 if (string[i] == '\0') /* don't increment i past EOS in loop */
2148 break;
2149 i++;
2150 continue;
2151 }
2152 else
2153 ADVANCE_CHAR (string, slen, i);
2154 }
2155
2156 CQ_RETURN(i);
2157}
2158
2159#if defined (ARRAY_VARS)
74091dd4 2160/* FLAGS has 1 as a reserved value, since skip_matched_pair uses it for
d233b485 2161 skipping over quoted strings and taking the first instance of the
74091dd4
CR
2162 closing character. FLAGS & 2 means that STRING[START] points one
2163 character past the open bracket; FLAGS & 2 == 0 means that STRING[START]
2164 points to the open bracket. skip_matched_pair knows how to deal with this. */
89a92869 2165int
0001803f 2166skipsubscript (string, start, flags)
89a92869 2167 const char *string;
0001803f 2168 int start, flags;
89a92869 2169{
0001803f 2170 return (skip_matched_pair (string, start, '[', ']', flags));
89a92869
CR
2171}
2172#endif
2173
3185942a
JA
2174/* Skip characters in STRING until we find a character in DELIMS, and return
2175 the index of that character. START is the index into string at which we
2176 begin. This is similar in spirit to strpbrk, but it returns an index into
2177 STRING and takes a starting index. This little piece of code knows quite
2178 a lot of shell syntax. It's very similar to skip_double_quoted and other
2179 functions of that ilk. */
2180int
2181skip_to_delim (string, start, delims, flags)
2182 char *string;
2183 int start;
2184 char *delims;
2185 int flags;
2186{
a0c0a00f
CR
2187 int i, pass_next, backq, dquote, si, c, oldjmp;
2188 int invert, skipquote, skipcmd, noprocsub, completeflag;
2189 int arithexp, skipcol;
3185942a 2190 size_t slen;
495aee44 2191 char *temp, open[3];
3185942a
JA
2192 DECLARE_MBSTATE;
2193
2194 slen = strlen (string + start) + start;
a0c0a00f 2195 oldjmp = no_longjmp_on_fatal_error;
3185942a
JA
2196 if (flags & SD_NOJMP)
2197 no_longjmp_on_fatal_error = 1;
2198 invert = (flags & SD_INVERT);
0001803f 2199 skipcmd = (flags & SD_NOSKIPCMD) == 0;
a0c0a00f
CR
2200 noprocsub = (flags & SD_NOPROCSUB);
2201 completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0;
2202
2203 arithexp = (flags & SD_ARITHEXP);
2204 skipcol = 0;
3185942a
JA
2205
2206 i = start;
a0c0a00f 2207 pass_next = backq = dquote = 0;
3185942a
JA
2208 while (c = string[i])
2209 {
0001803f
CR
2210 /* If this is non-zero, we should not let quote characters be delimiters
2211 and the current character is a single or double quote. We should not
2212 test whether or not it's a delimiter until after we skip single- or
2213 double-quoted strings. */
2214 skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
3185942a
JA
2215 if (pass_next)
2216 {
2217 pass_next = 0;
2218 if (c == 0)
2219 CQ_RETURN(i);
2220 ADVANCE_CHAR (string, slen, i);
2221 continue;
2222 }
2223 else if (c == '\\')
2224 {
2225 pass_next = 1;
2226 i++;
2227 continue;
2228 }
2229 else if (backq)
2230 {
2231 if (c == '`')
2232 backq = 0;
2233 ADVANCE_CHAR (string, slen, i);
2234 continue;
2235 }
2236 else if (c == '`')
2237 {
2238 backq = 1;
2239 i++;
2240 continue;
2241 }
a0c0a00f 2242 else if (arithexp && skipcol && c == ':')
3185942a 2243 {
a0c0a00f
CR
2244 skipcol--;
2245 i++;
2246 continue;
3185942a 2247 }
a0c0a00f
CR
2248 else if (arithexp && c == '?')
2249 {
2250 skipcol++;
2251 i++;
2252 continue;
2253 }
2254 else if (skipquote == 0 && invert == 0 && member (c, delims))
2255 break;
2256 /* the usual case is to use skip_xxx_quoted, but we don't skip over double
2257 quoted strings when looking for the history expansion character as a
2258 delimiter. */
2259 /* special case for programmable completion which takes place before
2260 parser converts backslash-escaped single quotes between $'...' to
2261 `regular' single-quoted strings. */
2262 else if (completeflag && i > 0 && string[i-1] == '$' && c == '\'')
2263 i = skip_single_quoted (string, slen, ++i, SX_COMPLETE);
2264 else if (c == '\'')
2265 i = skip_single_quoted (string, slen, ++i, 0);
2266 else if (c == '"')
2267 i = skip_double_quoted (string, slen, ++i, completeflag);
2268 else if (c == LPAREN && arithexp)
2269 {
2270 si = i + 1;
2271 if (string[si] == '\0')
2272 CQ_RETURN(si);
2273
2274 temp = extract_delimited_string (string, &si, "(", "(", ")", SX_NOALLOC); /* ) */
2275 i = si;
2276 if (string[i] == '\0') /* don't increment i past EOS in loop */
2277 break;
2278 i++;
2279 continue;
2280 }
0001803f 2281 else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
3185942a
JA
2282 {
2283 si = i + 2;
2284 if (string[si] == '\0')
2285 CQ_RETURN(si);
2286
2287 if (string[i+1] == LPAREN)
74091dd4 2288 temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND|completeflag); /* ) */
3185942a
JA
2289 else
2290 temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
d233b485 2291 CHECK_STRING_OVERRUN (i, si, slen, c);
3185942a
JA
2292 i = si;
2293 if (string[i] == '\0') /* don't increment i past EOS in loop */
2294 break;
2295 i++;
2296 continue;
2297 }
0001803f 2298#if defined (PROCESS_SUBSTITUTION)
a0c0a00f 2299 else if (skipcmd && noprocsub == 0 && (c == '<' || c == '>') && string[i+1] == LPAREN)
0001803f
CR
2300 {
2301 si = i + 2;
2302 if (string[si] == '\0')
2303 CQ_RETURN(si);
d233b485 2304
a0c0a00f 2305 temp = extract_delimited_string (string, &si, (c == '<') ? "<(" : ">(", "(", ")", SX_COMMAND|SX_NOALLOC); /* )) */
d233b485 2306 CHECK_STRING_OVERRUN (i, si, slen, c);
0001803f
CR
2307 i = si;
2308 if (string[i] == '\0')
2309 break;
2310 i++;
2311 continue;
2312 }
2313#endif /* PROCESS_SUBSTITUTION */
495aee44
CR
2314#if defined (EXTENDED_GLOB)
2315 else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@"))
2316 {
2317 si = i + 2;
2318 if (string[si] == '\0')
2319 CQ_RETURN(si);
2320
2321 open[0] = c;
2322 open[1] = LPAREN;
2323 open[2] = '\0';
2324 temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */
2325
d233b485 2326 CHECK_STRING_OVERRUN (i, si, slen, c);
495aee44
CR
2327 i = si;
2328 if (string[i] == '\0') /* don't increment i past EOS in loop */
2329 break;
2330 i++;
2331 continue;
2332 }
2333#endif
ac50fbac
CR
2334 else if ((flags & SD_GLOB) && c == LBRACK)
2335 {
2336 si = i + 1;
2337 if (string[si] == '\0')
2338 CQ_RETURN(si);
2339
2340 temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */
2341
2342 i = si;
2343 if (string[i] == '\0') /* don't increment i past EOS in loop */
2344 break;
2345 i++;
2346 continue;
2347 }
0001803f 2348 else if ((skipquote || invert) && (member (c, delims) == 0))
3185942a
JA
2349 break;
2350 else
2351 ADVANCE_CHAR (string, slen, i);
2352 }
2353
2354 CQ_RETURN(i);
2355}
2356
a0c0a00f
CR
2357#if defined (BANG_HISTORY)
2358/* Skip to the history expansion character (delims[0]), paying attention to
2359 quoted strings and command and process substitution. This is a stripped-
2360 down version of skip_to_delims. The essential difference is that this
2361 resets the quoting state when starting a command substitution */
2362int
2363skip_to_histexp (string, start, delims, flags)
2364 char *string;
2365 int start;
2366 char *delims;
2367 int flags;
2368{
d233b485 2369 int i, pass_next, backq, dquote, c, oldjmp;
a0c0a00f
CR
2370 int histexp_comsub, histexp_backq, old_dquote;
2371 size_t slen;
a0c0a00f
CR
2372 DECLARE_MBSTATE;
2373
2374 slen = strlen (string + start) + start;
2375 oldjmp = no_longjmp_on_fatal_error;
2376 if (flags & SD_NOJMP)
2377 no_longjmp_on_fatal_error = 1;
2378
2379 histexp_comsub = histexp_backq = old_dquote = 0;
2380
2381 i = start;
2382 pass_next = backq = dquote = 0;
2383 while (c = string[i])
2384 {
2385 if (pass_next)
2386 {
2387 pass_next = 0;
2388 if (c == 0)
2389 CQ_RETURN(i);
2390 ADVANCE_CHAR (string, slen, i);
2391 continue;
2392 }
2393 else if (c == '\\')
2394 {
2395 pass_next = 1;
2396 i++;
2397 continue;
2398 }
2399 else if (backq && c == '`')
2400 {
2401 backq = 0;
2402 histexp_backq--;
2403 dquote = old_dquote;
2404 i++;
2405 continue;
2406 }
2407 else if (c == '`')
2408 {
2409 backq = 1;
2410 histexp_backq++;
2411 old_dquote = dquote; /* simple - one level for now */
2412 dquote = 0;
2413 i++;
2414 continue;
2415 }
2416 /* When in double quotes, act as if the double quote is a member of
2417 history_no_expand_chars, like the history library does */
2418 else if (dquote && c == delims[0] && string[i+1] == '"')
2419 {
2420 i++;
2421 continue;
2422 }
2423 else if (c == delims[0])
2424 break;
2425 /* the usual case is to use skip_xxx_quoted, but we don't skip over double
2426 quoted strings when looking for the history expansion character as a
2427 delimiter. */
2428 else if (dquote && c == '\'')
2429 {
2430 i++;
2431 continue;
2432 }
2433 else if (c == '\'')
2434 i = skip_single_quoted (string, slen, ++i, 0);
2435 /* The posixly_correct test makes posix-mode shells allow double quotes
2436 to quote the history expansion character */
2437 else if (posixly_correct == 0 && c == '"')
2438 {
2439 dquote = 1 - dquote;
2440 i++;
2441 continue;
2442 }
2443 else if (c == '"')
2444 i = skip_double_quoted (string, slen, ++i, 0);
2445#if defined (PROCESS_SUBSTITUTION)
2446 else if ((c == '$' || c == '<' || c == '>') && string[i+1] == LPAREN && string[i+2] != LPAREN)
2447#else
2448 else if (c == '$' && string[i+1] == LPAREN && string[i+2] != LPAREN)
2449#endif
2450 {
2451 if (string[i+2] == '\0')
2452 CQ_RETURN(i+2);
2453 i += 2;
2454 histexp_comsub++;
2455 old_dquote = dquote;
2456 dquote = 0;
2457 }
2458 else if (histexp_comsub && c == RPAREN)
2459 {
2460 histexp_comsub--;
2461 dquote = old_dquote;
2462 i++;
2463 continue;
2464 }
2465 else if (backq) /* placeholder */
2466 {
2467 ADVANCE_CHAR (string, slen, i);
2468 continue;
2469 }
2470 else
2471 ADVANCE_CHAR (string, slen, i);
2472 }
2473
2474 CQ_RETURN(i);
2475}
2476#endif /* BANG_HISTORY */
2477
ccc6cda3 2478#if defined (READLINE)
726f6388
JA
2479/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
2480 an unclosed quoted string), or if the character at EINDEX is quoted
28ef6c31 2481 by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various
b72432fd 2482 single and double-quoted string parsing functions should not return an
7117c2d2
JA
2483 error if there are unclosed quotes or braces. The characters that this
2484 recognizes need to be the same as the contents of
2485 rl_completer_quote_characters. */
b72432fd 2486
726f6388
JA
2487int
2488char_is_quoted (string, eindex)
2489 char *string;
2490 int eindex;
2491{
a0c0a00f 2492 int i, pass_next, c, oldjmp;
7117c2d2
JA
2493 size_t slen;
2494 DECLARE_MBSTATE;
726f6388 2495
7117c2d2 2496 slen = strlen (string);
a0c0a00f 2497 oldjmp = no_longjmp_on_fatal_error;
28ef6c31 2498 no_longjmp_on_fatal_error = 1;
7117c2d2 2499 i = pass_next = 0;
74091dd4
CR
2500
2501 /* If we have an open quoted string from a previous line, see if it's
2502 closed before string[eindex], so we don't interpret that close quote
2503 as starting a new quoted string. */
2504 if (current_command_line_count > 0 && dstack.delimiter_depth > 0)
2505 {
2506 c = dstack.delimiters[dstack.delimiter_depth - 1];
2507 if (c == '\'')
2508 i = skip_single_quoted (string, slen, 0, 0);
2509 else if (c == '"')
2510 i = skip_double_quoted (string, slen, 0, SX_COMPLETE);
2511 if (i > eindex)
2512 CQ_RETURN (1);
2513 }
2514
7117c2d2 2515 while (i <= eindex)
726f6388 2516 {
7117c2d2
JA
2517 c = string[i];
2518
726f6388
JA
2519 if (pass_next)
2520 {
2521 pass_next = 0;
2522 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
b72432fd 2523 CQ_RETURN(1);
7117c2d2 2524 ADVANCE_CHAR (string, slen, i);
726f6388
JA
2525 continue;
2526 }
7117c2d2 2527 else if (c == '\\')
ccc6cda3
JA
2528 {
2529 pass_next = 1;
7117c2d2 2530 i++;
ccc6cda3
JA
2531 continue;
2532 }
a0c0a00f
CR
2533 else if (c == '$' && string[i+1] == '\'' && string[i+2])
2534 {
2535 i += 2;
2536 i = skip_single_quoted (string, slen, i, SX_COMPLETE);
2537 if (i > eindex)
2538 CQ_RETURN (i);
2539 }
7117c2d2
JA
2540 else if (c == '\'' || c == '"')
2541 {
a0c0a00f
CR
2542 i = (c == '\'') ? skip_single_quoted (string, slen, ++i, 0)
2543 : skip_double_quoted (string, slen, ++i, SX_COMPLETE);
7117c2d2
JA
2544 if (i > eindex)
2545 CQ_RETURN(1);
2546 /* no increment, the skip_xxx functions go one past end */
2547 }
2548 else
2549 ADVANCE_CHAR (string, slen, i);
726f6388 2550 }
7117c2d2 2551
b72432fd 2552 CQ_RETURN(0);
726f6388
JA
2553}
2554
726f6388
JA
2555int
2556unclosed_pair (string, eindex, openstr)
2557 char *string;
2558 int eindex;
2559 char *openstr;
2560{
ccc6cda3 2561 int i, pass_next, openc, olen;
7117c2d2
JA
2562 size_t slen;
2563 DECLARE_MBSTATE;
726f6388 2564
7117c2d2 2565 slen = strlen (string);
726f6388 2566 olen = strlen (openstr);
7117c2d2
JA
2567 i = pass_next = openc = 0;
2568 while (i <= eindex)
726f6388
JA
2569 {
2570 if (pass_next)
2571 {
2572 pass_next = 0;
2573 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
2574 return 0;
7117c2d2
JA
2575 ADVANCE_CHAR (string, slen, i);
2576 continue;
2577 }
2578 else if (string[i] == '\\')
2579 {
2580 pass_next = 1;
2581 i++;
726f6388
JA
2582 continue;
2583 }
2584 else if (STREQN (string + i, openstr, olen))
2585 {
2586 openc = 1 - openc;
7117c2d2 2587 i += olen;
726f6388 2588 }
a0c0a00f 2589 /* XXX - may want to handle $'...' specially here */
ccc6cda3 2590 else if (string[i] == '\'' || string[i] == '"')
726f6388 2591 {
a0c0a00f
CR
2592 i = (string[i] == '\'') ? skip_single_quoted (string, slen, i, 0)
2593 : skip_double_quoted (string, slen, i, SX_COMPLETE);
726f6388
JA
2594 if (i > eindex)
2595 return 0;
2596 }
7117c2d2
JA
2597 else
2598 ADVANCE_CHAR (string, slen, i);
726f6388
JA
2599 }
2600 return (openc);
2601}
bb70624e 2602
bb70624e
JA
2603/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
2604 individual words. If DELIMS is NULL, the current value of $IFS is used
b80f6443
JA
2605 to split the string, and the function follows the shell field splitting
2606 rules. SENTINEL is an index to look for. NWP, if non-NULL,
bb70624e
JA
2607 gets the number of words in the returned list. CWP, if non-NULL, gets
2608 the index of the word containing SENTINEL. Non-whitespace chars in
d233b485 2609 DELIMS delimit separate fields. This is used by programmable completion. */
bb70624e 2610WORD_LIST *
0001803f 2611split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
bb70624e
JA
2612 char *string;
2613 int slen;
74091dd4 2614 const char *delims;
0001803f 2615 int sentinel, flags;
bb70624e
JA
2616 int *nwp, *cwp;
2617{
0001803f 2618 int ts, te, i, nw, cw, ifs_split, dflags;
f73dda09 2619 char *token, *d, *d2;
bb70624e
JA
2620 WORD_LIST *ret, *tl;
2621
2622 if (string == 0 || *string == '\0')
2623 {
2624 if (nwp)
2625 *nwp = 0;
2626 if (cwp)
2627 *cwp = 0;
2628 return ((WORD_LIST *)NULL);
2629 }
2630
74091dd4 2631 d = (delims == 0) ? ifs_value : (char *)delims;
b80f6443 2632 ifs_split = delims == 0;
bb70624e
JA
2633
2634 /* Make d2 the non-whitespace characters in delims */
2635 d2 = 0;
2636 if (delims)
2637 {
95732b49
JA
2638 size_t slength;
2639#if defined (HANDLE_MULTIBYTE)
2640 size_t mblength = 1;
2641#endif
2642 DECLARE_MBSTATE;
2643
2644 slength = strlen (delims);
2645 d2 = (char *)xmalloc (slength + 1);
2646 i = ts = 0;
2647 while (delims[i])
bb70624e 2648 {
95732b49 2649#if defined (HANDLE_MULTIBYTE)
0628567a
JA
2650 mbstate_t state_bak;
2651 state_bak = state;
95732b49
JA
2652 mblength = MBRLEN (delims + i, slength, &state);
2653 if (MB_INVALIDCH (mblength))
2654 state = state_bak;
2655 else if (mblength > 1)
2656 {
2657 memcpy (d2 + ts, delims + i, mblength);
2658 ts += mblength;
2659 i += mblength;
2660 slength -= mblength;
2661 continue;
2662 }
2663#endif
2664 if (whitespace (delims[i]) == 0)
bb70624e 2665 d2[ts++] = delims[i];
95732b49
JA
2666
2667 i++;
2668 slength--;
bb70624e
JA
2669 }
2670 d2[ts] = '\0';
2671 }
2672
2673 ret = (WORD_LIST *)NULL;
2674
0001803f 2675 /* Remove sequences of whitespace characters at the start of the string, as
b80f6443
JA
2676 long as those characters are delimiters. */
2677 for (i = 0; member (string[i], d) && spctabnl (string[i]); i++)
bb70624e
JA
2678 ;
2679 if (string[i] == '\0')
a0c0a00f
CR
2680 {
2681 FREE (d2);
2682 return (ret);
2683 }
bb70624e
JA
2684
2685 ts = i;
2686 nw = 0;
2687 cw = -1;
0001803f 2688 dflags = flags|SD_NOJMP;
bb70624e
JA
2689 while (1)
2690 {
0001803f 2691 te = skip_to_delim (string, ts, d, dflags);
bb70624e
JA
2692
2693 /* If we have a non-whitespace delimiter character, use it to make a
2694 separate field. This is just about what $IFS splitting does and
2695 is closer to the behavior of the shell parser. */
28ef6c31 2696 if (ts == te && d2 && member (string[ts], d2))
bb70624e
JA
2697 {
2698 te = ts + 1;
b80f6443
JA
2699 /* If we're using IFS splitting, the non-whitespace delimiter char
2700 and any additional IFS whitespace delimits a field. */
2701 if (ifs_split)
d233b485 2702 while (member (string[te], d) && spctabnl (string[te]) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
b80f6443
JA
2703 te++;
2704 else
d233b485 2705 while (member (string[te], d2) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
b80f6443 2706 te++;
bb70624e
JA
2707 }
2708
2709 token = substring (string, ts, te);
2710
8868edaf 2711 ret = add_string_to_list (token, ret); /* XXX */
bb70624e
JA
2712 free (token);
2713 nw++;
2714
2715 if (sentinel >= ts && sentinel <= te)
2716 cw = nw;
2717
2718 /* If the cursor is at whitespace just before word start, set the
28ef6c31 2719 sentinel word to the current word. */
bb70624e
JA
2720 if (cwp && cw == -1 && sentinel == ts-1)
2721 cw = nw;
2722
2723 /* If the cursor is at whitespace between two words, make a new, empty
28ef6c31
JA
2724 word, add it before (well, after, since the list is in reverse order)
2725 the word we just added, and set the current word to that one. */
bb70624e 2726 if (cwp && cw == -1 && sentinel < ts)
28ef6c31 2727 {
7117c2d2 2728 tl = make_word_list (make_word (""), ret->next);
28ef6c31
JA
2729 ret->next = tl;
2730 cw = nw;
2731 nw++;
2732 }
bb70624e
JA
2733
2734 if (string[te] == 0)
2735 break;
2736
b80f6443 2737 i = te;
d233b485
CR
2738 /* XXX - honor SD_NOQUOTEDELIM here */
2739 while (member (string[i], d) && (ifs_split || spctabnl(string[i])) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
bb70624e
JA
2740 i++;
2741
2742 if (string[i])
2743 ts = i;
2744 else
2745 break;
2746 }
2747
2748 /* Special case for SENTINEL at the end of STRING. If we haven't found
2749 the word containing SENTINEL yet, and the index we're looking for is at
0001803f
CR
2750 the end of STRING (or past the end of the previously-found token,
2751 possible if the end of the line is composed solely of IFS whitespace)
2752 add an additional null argument and set the current word pointer to that. */
2753 if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
bb70624e
JA
2754 {
2755 if (whitespace (string[sentinel - 1]))
28ef6c31
JA
2756 {
2757 token = "";
2758 ret = add_string_to_list (token, ret);
2759 nw++;
2760 }
bb70624e
JA
2761 cw = nw;
2762 }
2763
2764 if (nwp)
2765 *nwp = nw;
2766 if (cwp)
2767 *cwp = cw;
2768
ac50fbac
CR
2769 FREE (d2);
2770
bb70624e
JA
2771 return (REVERSE_LIST (ret, WORD_LIST *));
2772}
726f6388
JA
2773#endif /* READLINE */
2774
ccc6cda3
JA
2775#if 0
2776/* UNUSED */
726f6388
JA
2777/* Extract the name of the variable to bind to from the assignment string. */
2778char *
2779assignment_name (string)
2780 char *string;
2781{
ccc6cda3 2782 int offset;
726f6388
JA
2783 char *temp;
2784
b80f6443 2785 offset = assignment (string, 0);
ccc6cda3 2786 if (offset == 0)
726f6388 2787 return (char *)NULL;
bb70624e 2788 temp = substring (string, 0, offset);
726f6388
JA
2789 return (temp);
2790}
ccc6cda3 2791#endif
726f6388 2792
cce855bc
JA
2793/* **************************************************************** */
2794/* */
2795/* Functions to convert strings to WORD_LISTs and vice versa */
2796/* */
2797/* **************************************************************** */
2798
726f6388
JA
2799/* Return a single string of all the words in LIST. SEP is the separator
2800 to put between individual elements of LIST in the output string. */
7117c2d2 2801char *
726f6388
JA
2802string_list_internal (list, sep)
2803 WORD_LIST *list;
2804 char *sep;
2805{
2806 register WORD_LIST *t;
2807 char *result, *r;
a0c0a00f 2808 size_t word_len, sep_len, result_size;
726f6388 2809
ccc6cda3 2810 if (list == 0)
726f6388
JA
2811 return ((char *)NULL);
2812
b80f6443
JA
2813 /* Short-circuit quickly if we don't need to separate anything. */
2814 if (list->next == 0)
2815 return (savestring (list->word->word));
2816
726f6388
JA
2817 /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
2818 sep_len = STRLEN (sep);
2819 result_size = 0;
2820
2821 for (t = list; t; t = t->next)
2822 {
2823 if (t != list)
2824 result_size += sep_len;
2825 result_size += strlen (t->word->word);
2826 }
2827
f73dda09 2828 r = result = (char *)xmalloc (result_size + 1);
726f6388
JA
2829
2830 for (t = list; t; t = t->next)
2831 {
2832 if (t != list && sep_len)
2833 {
ccc6cda3
JA
2834 if (sep_len > 1)
2835 {
2836 FASTCOPY (sep, r, sep_len);
2837 r += sep_len;
2838 }
2839 else
2840 *r++ = sep[0];
726f6388
JA
2841 }
2842
2843 word_len = strlen (t->word->word);
2844 FASTCOPY (t->word->word, r, word_len);
2845 r += word_len;
2846 }
2847
ccc6cda3 2848 *r = '\0';
726f6388
JA
2849 return (result);
2850}
2851
2852/* Return a single string of all the words present in LIST, separating
2853 each word with a space. */
2854char *
2855string_list (list)
2856 WORD_LIST *list;
2857{
2858 return (string_list_internal (list, " "));
2859}
2860
3185942a
JA
2861/* An external interface that can be used by the rest of the shell to
2862 obtain a string containing the first character in $IFS. Handles all
2863 the multibyte complications. If LENP is non-null, it is set to the
2864 length of the returned string. */
2865char *
2866ifs_firstchar (lenp)
2867 int *lenp;
2868{
2869 char *ret;
2870 int len;
2871
2872 ret = xmalloc (MB_LEN_MAX + 1);
2873#if defined (HANDLE_MULTIBYTE)
2874 if (ifs_firstc_len == 1)
2875 {
2876 ret[0] = ifs_firstc[0];
2877 ret[1] = '\0';
2878 len = ret[0] ? 1 : 0;
2879 }
2880 else
2881 {
2882 memcpy (ret, ifs_firstc, ifs_firstc_len);
2883 ret[len = ifs_firstc_len] = '\0';
2884 }
2885#else
2886 ret[0] = ifs_firstc;
2887 ret[1] = '\0';
2888 len = ret[0] ? 0 : 1;
2889#endif
2890
2891 if (lenp)
2892 *lenp = len;
2893
2894 return ret;
2895}
2896
726f6388
JA
2897/* Return a single string of all the words present in LIST, obeying the
2898 quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
2899 expansion [of $*] appears within a double quoted string, it expands
2900 to a single field with the value of each parameter separated by the
2901 first character of the IFS variable, or by a <space> if IFS is unset." */
d233b485
CR
2902/* Posix interpretation 888 changes this when IFS is null by specifying
2903 that when unquoted, this expands to separate arguments */
f73dda09 2904char *
d233b485 2905string_list_dollar_star (list, quoted, flags)
726f6388 2906 WORD_LIST *list;
d233b485 2907 int quoted, flags;
726f6388 2908{
0628567a 2909 char *ret;
95732b49 2910#if defined (HANDLE_MULTIBYTE)
0628567a 2911# if defined (__GNUC__)
95732b49 2912 char sep[MB_CUR_MAX + 1];
0628567a
JA
2913# else
2914 char *sep = 0;
2915# endif
95732b49 2916#else
7117c2d2 2917 char sep[2];
95732b49 2918#endif
726f6388 2919
95732b49 2920#if defined (HANDLE_MULTIBYTE)
0628567a
JA
2921# if !defined (__GNUC__)
2922 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2923# endif /* !__GNUC__ */
95732b49
JA
2924 if (ifs_firstc_len == 1)
2925 {
2926 sep[0] = ifs_firstc[0];
2927 sep[1] = '\0';
2928 }
2929 else
2930 {
2931 memcpy (sep, ifs_firstc, ifs_firstc_len);
2932 sep[ifs_firstc_len] = '\0';
2933 }
2934#else
7117c2d2 2935 sep[0] = ifs_firstc;
726f6388 2936 sep[1] = '\0';
95732b49 2937#endif
726f6388 2938
0628567a
JA
2939 ret = string_list_internal (list, sep);
2940#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2941 free (sep);
2942#endif
2943 return ret;
726f6388
JA
2944}
2945
cce855bc
JA
2946/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
2947 is non-zero, the $@ appears within double quotes, and we should quote
2948 the list before converting it into a string. If IFS is unset, and the
2949 word is not quoted, we just need to quote CTLESC and CTLNUL characters
2950 in the words in the list, because the default value of $IFS is
2951 <space><tab><newline>, IFS characters in the words in the list should
2952 also be split. If IFS is null, and the word is not quoted, we need
2953 to quote the words in the list to preserve the positional parameters
a0c0a00f
CR
2954 exactly.
2955 Valid values for the FLAGS argument are the PF_ flags in command.h,
2956 the only one we care about is PF_ASSIGNRHS. $@ is supposed to expand
2957 to the positional parameters separated by spaces no matter what IFS is
2958 set to if in a context where word splitting is not performed. The only
2959 one that we didn't handle before is assignment statement arguments to
2960 declaration builtins like `declare'. */
f73dda09 2961char *
a0c0a00f 2962string_list_dollar_at (list, quoted, flags)
cce855bc
JA
2963 WORD_LIST *list;
2964 int quoted;
a0c0a00f 2965 int flags;
cce855bc 2966{
95732b49
JA
2967 char *ifs, *ret;
2968#if defined (HANDLE_MULTIBYTE)
0628567a 2969# if defined (__GNUC__)
95732b49 2970 char sep[MB_CUR_MAX + 1];
0628567a
JA
2971# else
2972 char *sep = 0;
2973# endif /* !__GNUC__ */
95732b49
JA
2974#else
2975 char sep[2];
2976#endif
cce855bc
JA
2977 WORD_LIST *tlist;
2978
7117c2d2
JA
2979 /* XXX this could just be ifs = ifs_value; */
2980 ifs = ifs_var ? value_cell (ifs_var) : (char *)0;
cce855bc 2981
95732b49 2982#if defined (HANDLE_MULTIBYTE)
0628567a
JA
2983# if !defined (__GNUC__)
2984 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2985# endif /* !__GNUC__ */
d233b485
CR
2986 /* XXX - testing PF_ASSIGNRHS to make sure positional parameters are
2987 separated with a space even when word splitting will not occur. */
a0c0a00f
CR
2988 if (flags & PF_ASSIGNRHS)
2989 {
2990 sep[0] = ' ';
2991 sep[1] = '\0';
2992 }
2993 else if (ifs && *ifs)
95732b49
JA
2994 {
2995 if (ifs_firstc_len == 1)
2996 {
2997 sep[0] = ifs_firstc[0];
2998 sep[1] = '\0';
2999 }
3000 else
3001 {
3002 memcpy (sep, ifs_firstc, ifs_firstc_len);
3003 sep[ifs_firstc_len] = '\0';
3004 }
3005 }
3006 else
3007 {
3008 sep[0] = ' ';
3009 sep[1] = '\0';
3010 }
d233b485
CR
3011#else /* !HANDLE_MULTIBYTE */
3012 /* XXX - PF_ASSIGNRHS means no word splitting, so we want positional
3013 parameters separated by a space. */
a0c0a00f 3014 sep[0] = ((flags & PF_ASSIGNRHS) || ifs == 0 || *ifs == 0) ? ' ' : *ifs;
cce855bc 3015 sep[1] = '\0';
d233b485 3016#endif /* !HANDLE_MULTIBYTE */
cce855bc 3017
f1be666c
JA
3018 /* XXX -- why call quote_list if ifs == 0? we can get away without doing
3019 it now that quote_escapes quotes spaces */
0001803f 3020 tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
cce855bc
JA
3021 ? quote_list (list)
3022 : list_quote_escapes (list);
0628567a
JA
3023
3024 ret = string_list_internal (tlist, sep);
3025#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
3026 free (sep);
3027#endif
3028 return ret;
cce855bc
JA
3029}
3030
ac50fbac 3031/* Turn the positional parameters into a string, understanding quoting and
3185942a
JA
3032 the various subtleties of using the first character of $IFS as the
3033 separator. Calls string_list_dollar_at, string_list_dollar_star, and
3034 string_list as appropriate. */
8868edaf
CR
3035/* This needs to fully understand the additional contexts where word
3036 splitting does not occur (W_ASSIGNRHS, etc.) */
3185942a 3037char *
8868edaf 3038string_list_pos_params (pchar, list, quoted, pflags)
3185942a
JA
3039 int pchar;
3040 WORD_LIST *list;
8868edaf 3041 int quoted, pflags;
3185942a
JA
3042{
3043 char *ret;
3044 WORD_LIST *tlist;
3045
3046 if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
3047 {
3048 tlist = quote_list (list);
3049 word_list_remove_quoted_nulls (tlist);
d233b485 3050 ret = string_list_dollar_star (tlist, 0, 0);
3185942a
JA
3051 }
3052 else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
3053 {
3054 tlist = quote_list (list);
3055 word_list_remove_quoted_nulls (tlist);
3056 ret = string_list (tlist);
3057 }
d233b485
CR
3058 else if (pchar == '*' && quoted == 0 && ifs_is_null) /* XXX */
3059 ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
8868edaf
CR
3060 else if (pchar == '*' && quoted == 0 && (pflags & PF_ASSIGNRHS)) /* XXX */
3061 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
3062 else if (pchar == '*')
3063 {
3064 /* Even when unquoted, string_list_dollar_star does the right thing
3065 making sure that the first character of $IFS is used as the
3066 separator. */
d233b485 3067 ret = string_list_dollar_star (list, quoted, 0);
3185942a
JA
3068 }
3069 else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
3070 /* We use string_list_dollar_at, but only if the string is quoted, since
3071 that quotes the escapes if it's not, which we don't want. We could
3072 use string_list (the old code did), but that doesn't do the right
3073 thing if the first character of $IFS is not a space. We use
3074 string_list_dollar_star if the string is unquoted so we make sure that
3075 the elements of $@ are separated by the first character of $IFS for
3076 later splitting. */
a0c0a00f 3077 ret = string_list_dollar_at (list, quoted, 0);
d233b485
CR
3078 else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */
3079 ret = string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
8868edaf
CR
3080 else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS))
3081 ret = string_list_dollar_at (list, quoted, pflags); /* Posix interp 888 */
3185942a 3082 else if (pchar == '@')
d233b485 3083 ret = string_list_dollar_star (list, quoted, 0);
3185942a
JA
3084 else
3085 ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
3086
3087 return ret;
3088}
3089
726f6388
JA
3090/* Return the list of words present in STRING. Separate the string into
3091 words at any of the characters found in SEPARATORS. If QUOTED is
3092 non-zero then word in the list will have its quoted flag set, otherwise
3093 the quoted flag is left as make_word () deemed fit.
3094
3095 This obeys the P1003.2 word splitting semantics. If `separators' is
3096 exactly <space><tab><newline>, then the splitting algorithm is that of
3097 the Bourne shell, which treats any sequence of characters from `separators'
3098 as a delimiter. If IFS is unset, which results in `separators' being set
3099 to "", no splitting occurs. If separators has some other value, the
3100 following rules are applied (`IFS white space' means zero or more
3101 occurrences of <space>, <tab>, or <newline>, as long as those characters
3102 are in `separators'):
3103
3104 1) IFS white space is ignored at the start and the end of the
3105 string.
3106 2) Each occurrence of a character in `separators' that is not
3107 IFS white space, along with any adjacent occurrences of
3108 IFS white space delimits a field.
3109 3) Any nonzero-length sequence of IFS white space delimits a field.
3110 */
3111
3112/* BEWARE! list_string strips null arguments. Don't call it twice and
3113 expect to have "" preserved! */
3114
726f6388
JA
3115/* This performs word splitting and quoted null character removal on
3116 STRING. */
b80f6443
JA
3117#define issep(c) \
3118 (((separators)[0]) ? ((separators)[1] ? isifs(c) \
3119 : (c) == (separators)[0]) \
3120 : 0)
726f6388 3121
d233b485
CR
3122/* member of the space character class in the current locale */
3123#define ifs_whitespace(c) ISSPACE(c)
3124
3125/* "adjacent IFS white space" */
3126#define ifs_whitesep(c) ((sh_style_split || separators == 0) ? spctabnl (c) \
3127 : ifs_whitespace (c))
3128
726f6388
JA
3129WORD_LIST *
3130list_string (string, separators, quoted)
3131 register char *string, *separators;
3132 int quoted;
3133{
ccc6cda3
JA
3134 WORD_LIST *result;
3135 WORD_DESC *t;
3136 char *current_word, *s;
8868edaf 3137 int sindex, sh_style_split, whitesep, xflags, free_word;
95732b49 3138 size_t slen;
726f6388
JA
3139
3140 if (!string || !*string)
3141 return ((WORD_LIST *)NULL);
3142
7117c2d2
JA
3143 sh_style_split = separators && separators[0] == ' ' &&
3144 separators[1] == '\t' &&
3145 separators[2] == '\n' &&
3146 separators[3] == '\0';
3185942a
JA
3147 for (xflags = 0, s = ifs_value; s && *s; s++)
3148 {
3149 if (*s == CTLESC) xflags |= SX_NOCTLESC;
3150 else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
3151 }
726f6388 3152
95732b49 3153 slen = 0;
726f6388
JA
3154 /* Remove sequences of whitespace at the beginning of STRING, as
3155 long as those characters appear in IFS. Do not do this if
d233b485
CR
3156 STRING is quoted or if there are no separator characters. We use the
3157 Posix definition of whitespace as a member of the space character
3158 class in the current locale. */
8868edaf 3159#if 0
726f6388 3160 if (!quoted || !separators || !*separators)
8868edaf
CR
3161#else
3162 /* issep() requires that separators be non-null, and always returns 0 if
3163 separator is the empty string, so don't bother if we get an empty string
3164 for separators. We already returned NULL above if STRING is empty. */
3165 if (!quoted && separators && *separators)
3166#endif
726f6388 3167 {
d233b485 3168 for (s = string; *s && issep (*s) && ifs_whitespace (*s); s++);
726f6388
JA
3169
3170 if (!*s)
3171 return ((WORD_LIST *)NULL);
3172
3173 string = s;
3174 }
3175
3176 /* OK, now STRING points to a word that does not begin with white space.
3177 The splitting algorithm is:
7117c2d2 3178 extract a word, stopping at a separator
d233b485 3179 skip sequences of whitespace characters as long as they are separators
726f6388 3180 This obeys the field splitting rules in Posix.2. */
d233b485 3181 slen = STRLEN (string);
ccc6cda3 3182 for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
726f6388 3183 {
d233b485
CR
3184 /* Don't need string length in ADVANCE_CHAR unless multibyte chars are
3185 possible, but need it in string_extract_verbatim for bounds checking */
3185942a 3186 current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
ccc6cda3 3187 if (current_word == 0)
726f6388
JA
3188 break;
3189
8868edaf
CR
3190 free_word = 1; /* If non-zero, we free current_word */
3191
726f6388
JA
3192 /* If we have a quoted empty string, add a quoted null argument. We
3193 want to preserve the quoted null character iff this is a quoted
3194 empty string; otherwise the quoted null characters are removed
3195 below. */
3196 if (QUOTED_NULL (current_word))
3197 {
95732b49 3198 t = alloc_word_desc ();
726f6388 3199 t->word = make_quoted_char ('\0');
95732b49 3200 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
726f6388
JA
3201 result = make_word_list (t, result);
3202 }
ccc6cda3 3203 else if (current_word[0] != '\0')
726f6388
JA
3204 {
3205 /* If we have something, then add it regardless. However,
3206 perform quoted null character removal on the current word. */
3207 remove_quoted_nulls (current_word);
8868edaf
CR
3208
3209 /* We don't want to set the word flags based on the string contents
3210 here -- that's mostly for the parser -- so we just allocate a
3211 WORD_DESC *, assign current_word (noting that we don't want to
3212 free it), and skip all of make_word. */
3213 t = alloc_word_desc ();
3214 t->word = current_word;
3215 result = make_word_list (t, result);
3216 free_word = 0;
95732b49 3217 result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */
ccc6cda3
JA
3218 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
3219 result->word->flags |= W_QUOTED;
8868edaf
CR
3220 /* If removing quoted null characters leaves an empty word, note
3221 that we saw this for the caller to act on. */
3222 if (current_word == 0 || current_word[0] == '\0')
3223 result->word->flags |= W_SAWQUOTEDNULL;
726f6388
JA
3224 }
3225
3226 /* If we're not doing sequences of separators in the traditional
3227 Bourne shell style, then add a quoted null argument. */
d233b485 3228 else if (!sh_style_split && !ifs_whitespace (string[sindex]))
726f6388 3229 {
95732b49 3230 t = alloc_word_desc ();
ccc6cda3 3231 t->word = make_quoted_char ('\0');
95732b49 3232 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
ccc6cda3 3233 result = make_word_list (t, result);
726f6388
JA
3234 }
3235
8868edaf
CR
3236 if (free_word)
3237 free (current_word);
726f6388 3238
28ef6c31 3239 /* Note whether or not the separator is IFS whitespace, used later. */
d233b485 3240 whitesep = string[sindex] && ifs_whitesep (string[sindex]);
28ef6c31 3241
726f6388
JA
3242 /* Move past the current separator character. */
3243 if (string[sindex])
95732b49
JA
3244 {
3245 DECLARE_MBSTATE;
3246 ADVANCE_CHAR (string, slen, sindex);
3247 }
726f6388 3248
d233b485 3249 /* Now skip sequences of whitespace characters if they are
726f6388 3250 in the list of separators. */
d233b485 3251 while (string[sindex] && ifs_whitesep (string[sindex]) && issep (string[sindex]))
726f6388 3252 sindex++;
28ef6c31 3253
7117c2d2
JA
3254 /* If the first separator was IFS whitespace and the current character
3255 is a non-whitespace IFS character, it should be part of the current
3256 field delimiter, not a separate delimiter that would result in an
3257 empty field. Look at POSIX.2, 3.6.5, (3)(b). */
d233b485 3258 if (string[sindex] && whitesep && issep (string[sindex]) && !ifs_whitesep (string[sindex]))
95732b49
JA
3259 {
3260 sindex++;
3261 /* An IFS character that is not IFS white space, along with any
3262 adjacent IFS white space, shall delimit a field. (SUSv3) */
d233b485 3263 while (string[sindex] && ifs_whitesep (string[sindex]) && isifs (string[sindex]))
95732b49
JA
3264 sindex++;
3265 }
726f6388
JA
3266 }
3267 return (REVERSE_LIST (result, WORD_LIST *));
3268}
3269
3270/* Parse a single word from STRING, using SEPARATORS to separate fields.
3271 ENDPTR is set to the first character after the word. This is used by
bc007799
CR
3272 the `read' builtin.
3273
3274 This is never called with SEPARATORS != $IFS, and takes advantage of that.
7117c2d2 3275
726f6388
JA
3276 XXX - this function is very similar to list_string; they should be
3277 combined - XXX */
bc007799 3278
d233b485 3279/* character is in $IFS */
bc007799
CR
3280#define islocalsep(c) (local_cmap[(unsigned char)(c)] != 0)
3281
726f6388
JA
3282char *
3283get_word_from_string (stringp, separators, endptr)
3284 char **stringp, *separators, **endptr;
3285{
3286 register char *s;
3287 char *current_word;
3185942a 3288 int sindex, sh_style_split, whitesep, xflags;
bc007799 3289 unsigned char local_cmap[UCHAR_MAX+1]; /* really only need single-byte chars here */
95732b49 3290 size_t slen;
726f6388
JA
3291
3292 if (!stringp || !*stringp || !**stringp)
3293 return ((char *)NULL);
ccc6cda3 3294
7117c2d2
JA
3295 sh_style_split = separators && separators[0] == ' ' &&
3296 separators[1] == '\t' &&
3297 separators[2] == '\n' &&
3298 separators[3] == '\0';
bc007799
CR
3299 memset (local_cmap, '\0', sizeof (local_cmap));
3300 for (xflags = 0, s = separators; s && *s; s++)
3185942a
JA
3301 {
3302 if (*s == CTLESC) xflags |= SX_NOCTLESC;
3303 if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
bc007799 3304 local_cmap[(unsigned char)*s] = 1; /* local charmap of separators */
3185942a 3305 }
726f6388 3306
3185942a 3307 s = *stringp;
95732b49
JA
3308 slen = 0;
3309
726f6388 3310 /* Remove sequences of whitespace at the beginning of STRING, as
bc007799
CR
3311 long as those characters appear in SEPARATORS. This happens if
3312 SEPARATORS == $' \t\n' or if IFS is unset. */
3313 if (sh_style_split || separators == 0)
d233b485
CR
3314 for (; *s && spctabnl (*s) && islocalsep (*s); s++);
3315 else
3316 for (; *s && ifs_whitespace (*s) && islocalsep (*s); s++);
726f6388 3317
d233b485
CR
3318 /* If the string is nothing but whitespace, update it and return. */
3319 if (!*s)
3320 {
3321 *stringp = s;
3322 if (endptr)
3323 *endptr = s;
3324 return ((char *)NULL);
726f6388
JA
3325 }
3326
3327 /* OK, S points to a word that does not begin with white space.
3328 Now extract a word, stopping at a separator, save a pointer to
3329 the first character after the word, then skip sequences of spc,
3330 tab, or nl as long as they are separators.
ccc6cda3 3331
726f6388
JA
3332 This obeys the field splitting rules in Posix.2. */
3333 sindex = 0;
bc007799
CR
3334 /* Don't need string length in ADVANCE_CHAR unless multibyte chars are
3335 possible, but need it in string_extract_verbatim for bounds checking */
3336 slen = STRLEN (s);
3185942a 3337 current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
726f6388
JA
3338
3339 /* Set ENDPTR to the first character after the end of the word. */
3340 if (endptr)
3341 *endptr = s + sindex;
3342
28ef6c31 3343 /* Note whether or not the separator is IFS whitespace, used later. */
d233b485 3344 whitesep = s[sindex] && ifs_whitesep (s[sindex]);
28ef6c31 3345
726f6388
JA
3346 /* Move past the current separator character. */
3347 if (s[sindex])
95732b49
JA
3348 {
3349 DECLARE_MBSTATE;
3350 ADVANCE_CHAR (s, slen, sindex);
3351 }
726f6388
JA
3352
3353 /* Now skip sequences of space, tab, or newline characters if they are
3354 in the list of separators. */
bc007799 3355 while (s[sindex] && spctabnl (s[sindex]) && islocalsep (s[sindex]))
726f6388
JA
3356 sindex++;
3357
28ef6c31
JA
3358 /* If the first separator was IFS whitespace and the current character is
3359 a non-whitespace IFS character, it should be part of the current field
3360 delimiter, not a separate delimiter that would result in an empty field.
3361 Look at POSIX.2, 3.6.5, (3)(b). */
d233b485 3362 if (s[sindex] && whitesep && islocalsep (s[sindex]) && !ifs_whitesep (s[sindex]))
95732b49
JA
3363 {
3364 sindex++;
3365 /* An IFS character that is not IFS white space, along with any adjacent
3366 IFS white space, shall delimit a field. */
d233b485 3367 while (s[sindex] && ifs_whitesep (s[sindex]) && islocalsep(s[sindex]))
95732b49
JA
3368 sindex++;
3369 }
28ef6c31 3370
726f6388
JA
3371 /* Update STRING to point to the next field. */
3372 *stringp = s + sindex;
3373 return (current_word);
3374}
3375
3376/* Remove IFS white space at the end of STRING. Start at the end
3377 of the string and walk backwards until the beginning of the string
3378 or we find a character that's not IFS white space and not CTLESC.
3379 Only let CTLESC escape a white space character if SAW_ESCAPE is
3380 non-zero. */
3381char *
3382strip_trailing_ifs_whitespace (string, separators, saw_escape)
3383 char *string, *separators;
3384 int saw_escape;
3385{
3386 char *s;
ccc6cda3 3387
726f6388 3388 s = string + STRLEN (string) - 1;
7117c2d2 3389 while (s > string && ((spctabnl (*s) && isifs (*s)) ||
726f6388
JA
3390 (saw_escape && *s == CTLESC && spctabnl (s[1]))))
3391 s--;
3392 *++s = '\0';
3393 return string;
3394}
3395
bb70624e
JA
3396#if 0
3397/* UNUSED */
3398/* Split STRING into words at whitespace. Obeys shell-style quoting with
3399 backslashes, single and double quotes. */
ccc6cda3
JA
3400WORD_LIST *
3401list_string_with_quotes (string)
3402 char *string;
3403{
3404 WORD_LIST *list;
3405 char *token, *s;
7117c2d2 3406 size_t s_len;
ccc6cda3
JA
3407 int c, i, tokstart, len;
3408
3409 for (s = string; s && *s && spctabnl (*s); s++)
3410 ;
3411 if (s == 0 || *s == 0)
3412 return ((WORD_LIST *)NULL);
3413
7117c2d2 3414 s_len = strlen (s);
ccc6cda3
JA
3415 tokstart = i = 0;
3416 list = (WORD_LIST *)NULL;
3417 while (1)
3418 {
3419 c = s[i];
3420 if (c == '\\')
3421 {
3422 i++;
3423 if (s[i])
3424 i++;
3425 }
3426 else if (c == '\'')
a0c0a00f 3427 i = skip_single_quoted (s, s_len, ++i, 0);
ccc6cda3 3428 else if (c == '"')
a0c0a00f 3429 i = skip_double_quoted (s, s_len, ++i, 0);
ccc6cda3
JA
3430 else if (c == 0 || spctabnl (c))
3431 {
3432 /* We have found the end of a token. Make a word out of it and
3433 add it to the word list. */
bb70624e 3434 token = substring (s, tokstart, i);
cce855bc 3435 list = add_string_to_list (token, list);
ccc6cda3
JA
3436 free (token);
3437 while (spctabnl (s[i]))
3438 i++;
3439 if (s[i])
3440 tokstart = i;
3441 else
3442 break;
3443 }
3444 else
3445 i++; /* normal character */
3446 }
3447 return (REVERSE_LIST (list, WORD_LIST *));
3448}
bb70624e 3449#endif
d166f048 3450
cce855bc
JA
3451/********************************************************/
3452/* */
3453/* Functions to perform assignment statements */
3454/* */
3455/********************************************************/
d166f048 3456
95732b49
JA
3457#if defined (ARRAY_VARS)
3458static SHELL_VAR *
3459do_compound_assignment (name, value, flags)
3460 char *name, *value;
3461 int flags;
3462{
3463 SHELL_VAR *v;
d233b485 3464 int mklocal, mkassoc, mkglobal, chklocal;
0628567a 3465 WORD_LIST *list;
d233b485 3466 char *newname; /* used for local nameref references */
95732b49
JA
3467
3468 mklocal = flags & ASS_MKLOCAL;
3185942a 3469 mkassoc = flags & ASS_MKASSOC;
ac50fbac 3470 mkglobal = flags & ASS_MKGLOBAL;
d233b485 3471 chklocal = flags & ASS_CHKLOCAL;
95732b49
JA
3472
3473 if (mklocal && variable_context)
3474 {
d233b485
CR
3475 v = find_variable (name); /* follows namerefs */
3476 newname = (v == 0) ? nameref_transform_name (name, flags) : v->name;
a0c0a00f
CR
3477 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3478 {
d233b485 3479 if (readonly_p (v))
a0c0a00f
CR
3480 err_readonly (name);
3481 return (v); /* XXX */
3482 }
3185942a
JA
3483 list = expand_compound_array_assignment (v, value, flags);
3484 if (mkassoc)
d233b485 3485 v = make_local_assoc_variable (newname, 0);
3185942a 3486 else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context)
d233b485 3487 v = make_local_array_variable (newname, 0);
ac50fbac
CR
3488 if (v)
3489 assign_compound_array_list (v, list, flags);
a0c0a00f
CR
3490 if (list)
3491 dispose_words (list);
ac50fbac 3492 }
d233b485
CR
3493 /* In a function but forcing assignment in global context. CHKLOCAL means to
3494 check for an existing local variable first. */
ac50fbac
CR
3495 else if (mkglobal && variable_context)
3496 {
d233b485
CR
3497 v = chklocal ? find_variable (name) : 0;
3498 if (v && (local_p (v) == 0 || v->context != variable_context))
3499 v = 0;
3500 if (v == 0)
3501 v = find_global_variable (name);
a0c0a00f
CR
3502 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3503 {
d233b485 3504 if (readonly_p (v))
a0c0a00f
CR
3505 err_readonly (name);
3506 return (v); /* XXX */
3507 }
d233b485
CR
3508 /* sanity check */
3509 newname = (v == 0) ? nameref_transform_name (name, flags) : name;
ac50fbac
CR
3510 list = expand_compound_array_assignment (v, value, flags);
3511 if (v == 0 && mkassoc)
d233b485 3512 v = make_new_assoc_variable (newname);
ac50fbac
CR
3513 else if (v && mkassoc && assoc_p (v) == 0)
3514 v = convert_var_to_assoc (v);
3515 else if (v == 0)
d233b485 3516 v = make_new_array_variable (newname);
ac50fbac
CR
3517 else if (v && mkassoc == 0 && array_p (v) == 0)
3518 v = convert_var_to_array (v);
3519 if (v)
3520 assign_compound_array_list (v, list, flags);
a0c0a00f
CR
3521 if (list)
3522 dispose_words (list);
95732b49
JA
3523 }
3524 else
a0c0a00f
CR
3525 {
3526 v = assign_array_from_string (name, value, flags);
3527 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3528 {
d233b485 3529 if (readonly_p (v))
a0c0a00f
CR
3530 err_readonly (name);
3531 return (v); /* XXX */
3532 }
3533 }
95732b49
JA
3534
3535 return (v);
3536}
3537#endif
3538
726f6388
JA
3539/* Given STRING, an assignment string, get the value of the right side
3540 of the `=', and bind it to the left side. If EXPAND is true, then
3541 perform parameter expansion, command substitution, and arithmetic
3542 expansion on the right-hand side. Perform tilde expansion in any
3543 case. Do not perform word splitting on the result of expansion. */
3544static int
95732b49
JA
3545do_assignment_internal (word, expand)
3546 const WORD_DESC *word;
726f6388
JA
3547 int expand;
3548{
495aee44
CR
3549 int offset, appendop, assign_list, aflags, retval;
3550 char *name, *value, *temp;
ccc6cda3
JA
3551 SHELL_VAR *entry;
3552#if defined (ARRAY_VARS)
3553 char *t;
b80f6443 3554 int ni;
ccc6cda3 3555#endif
95732b49 3556 const char *string;
ccc6cda3 3557
95732b49
JA
3558 if (word == 0 || word->word == 0)
3559 return 0;
3560
3561 appendop = assign_list = aflags = 0;
3562 string = word->word;
b80f6443 3563 offset = assignment (string, 0);
ccc6cda3
JA
3564 name = savestring (string);
3565 value = (char *)NULL;
726f6388
JA
3566
3567 if (name[offset] == '=')
3568 {
95732b49
JA
3569 if (name[offset - 1] == '+')
3570 {
3571 appendop = 1;
3572 name[offset - 1] = '\0';
3573 }
3574
3575 name[offset] = 0; /* might need this set later */
726f6388
JA
3576 temp = name + offset + 1;
3577
ccc6cda3 3578#if defined (ARRAY_VARS)
95732b49 3579 if (expand && (word->flags & W_COMPASSIGN))
726f6388 3580 {
ccc6cda3 3581 assign_list = ni = 1;
95732b49 3582 value = extract_array_assignment_list (temp, &ni);
ccc6cda3
JA
3583 }
3584 else
3585#endif
ccc6cda3 3586 if (expand && temp[0])
95732b49 3587 value = expand_string_if_necessary (temp, 0, expand_string_assignment);
726f6388
JA
3588 else
3589 value = savestring (temp);
3590 }
3591
3592 if (value == 0)
d166f048 3593 {
f73dda09 3594 value = (char *)xmalloc (1);
d166f048
JA
3595 value[0] = '\0';
3596 }
726f6388 3597
726f6388 3598 if (echo_command_at_execute)
95732b49
JA
3599 {
3600 if (appendop)
3601 name[offset - 1] = '+';
3602 xtrace_print_assignment (name, value, assign_list, 1);
3603 if (appendop)
3604 name[offset - 1] = '\0';
3605 }
726f6388 3606
d166f048 3607#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
ccc6cda3 3608
95732b49
JA
3609 if (appendop)
3610 aflags |= ASS_APPEND;
3611
ccc6cda3 3612#if defined (ARRAY_VARS)
d233b485 3613 if (t = mbschr (name, LBRACK))
ccc6cda3
JA
3614 {
3615 if (assign_list)
3616 {
b80f6443 3617 report_error (_("%s: cannot assign list to array member"), name);
ccc6cda3
JA
3618 ASSIGN_RETURN (0);
3619 }
74091dd4
CR
3620 aflags |= ASS_ALLOWALLSUB; /* allow a[@]=value for existing associative arrays */
3621 entry = assign_array_element (name, value, aflags, (array_eltstate_t *)0);
ccc6cda3 3622 if (entry == 0)
28ef6c31 3623 ASSIGN_RETURN (0);
ccc6cda3
JA
3624 }
3625 else if (assign_list)
95732b49 3626 {
d233b485
CR
3627 if ((word->flags & W_ASSIGNARG) && (word->flags & W_CHKLOCAL))
3628 aflags |= ASS_CHKLOCAL;
6d41b715 3629 if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0)
95732b49 3630 aflags |= ASS_MKLOCAL;
ac50fbac
CR
3631 if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL))
3632 aflags |= ASS_MKGLOBAL;
3185942a
JA
3633 if (word->flags & W_ASSIGNASSOC)
3634 aflags |= ASS_MKASSOC;
95732b49
JA
3635 entry = do_compound_assignment (name, value, aflags);
3636 }
ccc6cda3
JA
3637 else
3638#endif /* ARRAY_VARS */
95732b49 3639 entry = bind_variable (name, value, aflags);
ccc6cda3 3640
8868edaf
CR
3641 if (entry)
3642 stupidly_hack_special_variables (entry->name); /* might be a nameref */
3643 else
3644 stupidly_hack_special_variables (name);
726f6388 3645
3185942a
JA
3646 /* Return 1 if the assignment seems to have been performed correctly. */
3647 if (entry == 0 || readonly_p (entry))
3648 retval = 0; /* assignment failure */
3649 else if (noassign_p (entry))
3650 {
8868edaf 3651 set_exit_status (EXECUTION_FAILURE);
3185942a
JA
3652 retval = 1; /* error status, but not assignment failure */
3653 }
3654 else
3655 retval = 1;
3656
3657 if (entry && retval != 0 && noassign_p (entry) == 0)
3658 VUNSETATTR (entry, att_invisible);
3659
3660 ASSIGN_RETURN (retval);
726f6388
JA
3661}
3662
3663/* Perform the assignment statement in STRING, and expand the
95732b49 3664 right side by doing tilde, command and parameter expansion. */
ccc6cda3 3665int
726f6388 3666do_assignment (string)
95732b49 3667 char *string;
726f6388 3668{
95732b49
JA
3669 WORD_DESC td;
3670
3671 td.flags = W_ASSIGNMENT;
3672 td.word = string;
3673
3674 return do_assignment_internal (&td, 1);
3675}
3676
3677int
495aee44 3678do_word_assignment (word, flags)
95732b49 3679 WORD_DESC *word;
495aee44 3680 int flags;
95732b49
JA
3681{
3682 return do_assignment_internal (word, 1);
726f6388
JA
3683}
3684
3685/* Given STRING, an assignment string, get the value of the right side
95732b49
JA
3686 of the `=', and bind it to the left side. Do not perform any word
3687 expansions on the right hand side. */
ccc6cda3 3688int
726f6388 3689do_assignment_no_expand (string)
95732b49 3690 char *string;
726f6388 3691{
95732b49
JA
3692 WORD_DESC td;
3693
3694 td.flags = W_ASSIGNMENT;
3695 td.word = string;
3696
3697 return (do_assignment_internal (&td, 0));
726f6388
JA
3698}
3699
cce855bc
JA
3700/***************************************************
3701 * *
3702 * Functions to manage the positional parameters *
3703 * *
3704 ***************************************************/
726f6388
JA
3705
3706/* Return the word list that corresponds to `$*'. */
3707WORD_LIST *
3708list_rest_of_args ()
3709{
ccc6cda3 3710 register WORD_LIST *list, *args;
726f6388
JA
3711 int i;
3712
3713 /* Break out of the loop as soon as one of the dollar variables is null. */
ccc6cda3
JA
3714 for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
3715 list = make_word_list (make_bare_word (dollar_vars[i]), list);
3716
3717 for (args = rest_of_args; args; args = args->next)
3718 list = make_word_list (make_bare_word (args->word->word), list);
726f6388 3719
726f6388
JA
3720 return (REVERSE_LIST (list, WORD_LIST *));
3721}
3722
cce855bc
JA
3723/* Return the value of a positional parameter. This handles values > 10. */
3724char *
3725get_dollar_var_value (ind)
7117c2d2 3726 intmax_t ind;
cce855bc
JA
3727{
3728 char *temp;
3729 WORD_LIST *p;
3730
3731 if (ind < 10)
3732 temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
3733 else /* We want something like ${11} */
3734 {
3735 ind -= 10;
3736 for (p = rest_of_args; p && ind--; p = p->next)
28ef6c31 3737 ;
cce855bc
JA
3738 temp = p ? savestring (p->word->word) : (char *)NULL;
3739 }
3740 return (temp);
3741}
3742
726f6388
JA
3743/* Make a single large string out of the dollar digit variables,
3744 and the rest_of_args. If DOLLAR_STAR is 1, then obey the special
3745 case of "$*" with respect to IFS. */
3746char *
3747string_rest_of_args (dollar_star)
3748 int dollar_star;
3749{
ccc6cda3 3750 register WORD_LIST *list;
726f6388
JA
3751 char *string;
3752
ccc6cda3 3753 list = list_rest_of_args ();
d233b485 3754 string = dollar_star ? string_list_dollar_star (list, 0, 0) : string_list (list);
726f6388
JA
3755 dispose_words (list);
3756 return (string);
3757}
3758
cce855bc
JA
3759/* Return a string containing the positional parameters from START to
3760 END, inclusive. If STRING[0] == '*', we obey the rules for $*,
7117c2d2
JA
3761 which only makes a difference if QUOTED is non-zero. If QUOTED includes
3762 Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise
3763 no quoting chars are added. */
cce855bc 3764static char *
8868edaf 3765pos_params (string, start, end, quoted, pflags)
cce855bc 3766 char *string;
8868edaf 3767 int start, end, quoted, pflags;
726f6388 3768{
cce855bc
JA
3769 WORD_LIST *save, *params, *h, *t;
3770 char *ret;
3771 int i;
726f6388 3772
bb70624e
JA
3773 /* see if we can short-circuit. if start == end, we want 0 parameters. */
3774 if (start == end)
3775 return ((char *)NULL);
3776
cce855bc 3777 save = params = list_rest_of_args ();
a0c0a00f 3778 if (save == 0 && start > 0)
cce855bc
JA
3779 return ((char *)NULL);
3780
3185942a
JA
3781 if (start == 0) /* handle ${@:0[:x]} specially */
3782 {
3783 t = make_word_list (make_word (dollar_vars[0]), params);
3784 save = params = t;
3785 }
3786
0001803f 3787 for (i = start ? 1 : 0; params && i < start; i++)
cce855bc
JA
3788 params = params->next;
3789 if (params == 0)
a0c0a00f
CR
3790 {
3791 dispose_words (save);
3792 return ((char *)NULL);
3793 }
cce855bc 3794 for (h = t = params; params && i < end; i++)
d166f048 3795 {
cce855bc
JA
3796 t = params;
3797 params = params->next;
d166f048 3798 }
cce855bc 3799 t->next = (WORD_LIST *)NULL;
3185942a 3800
8868edaf 3801 ret = string_list_pos_params (string[0], h, quoted, pflags);
3185942a 3802
bb70624e
JA
3803 if (t != params)
3804 t->next = params;
726f6388 3805
cce855bc
JA
3806 dispose_words (save);
3807 return (ret);
3808}
3809
3810/******************************************************************/
3811/* */
3812/* Functions to expand strings to strings or WORD_LISTs */
3813/* */
3814/******************************************************************/
3815
3816#if defined (PROCESS_SUBSTITUTION)
95732b49 3817#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~')
cce855bc 3818#else
95732b49 3819#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
cce855bc
JA
3820#endif
3821
ddde6f00
CR
3822/* We don't perform process substitution in arithmetic expressions, so don't
3823 bother checking for it. */
3824#define ARITH_EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
3825
cce855bc
JA
3826/* If there are any characters in STRING that require full expansion,
3827 then call FUNC to expand STRING; otherwise just perform quote
3828 removal if necessary. This returns a new string. */
3829static char *
f73dda09 3830expand_string_if_necessary (string, quoted, func)
cce855bc
JA
3831 char *string;
3832 int quoted;
f73dda09 3833 EXPFUNC *func;
cce855bc
JA
3834{
3835 WORD_LIST *list;
7117c2d2 3836 size_t slen;
cce855bc
JA
3837 int i, saw_quote;
3838 char *ret;
7117c2d2 3839 DECLARE_MBSTATE;
cce855bc 3840
95732b49
JA
3841 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3842 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
7117c2d2
JA
3843 i = saw_quote = 0;
3844 while (string[i])
cce855bc
JA
3845 {
3846 if (EXP_CHAR (string[i]))
3847 break;
3848 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3849 saw_quote = 1;
7117c2d2 3850 ADVANCE_CHAR (string, slen, i);
cce855bc
JA
3851 }
3852
3853 if (string[i])
3854 {
3855 list = (*func) (string, quoted);
3856 if (list)
3857 {
3858 ret = string_list (list);
3859 dispose_words (list);
3860 }
3861 else
3862 ret = (char *)NULL;
3863 }
3864 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3865 ret = string_quote_removal (string, quoted);
3866 else
3867 ret = savestring (string);
7117c2d2 3868
cce855bc
JA
3869 return ret;
3870}
3871
3872static inline char *
f73dda09 3873expand_string_to_string_internal (string, quoted, func)
cce855bc
JA
3874 char *string;
3875 int quoted;
f73dda09 3876 EXPFUNC *func;
cce855bc
JA
3877{
3878 WORD_LIST *list;
3879 char *ret;
3880
3881 if (string == 0 || *string == '\0')
3882 return ((char *)NULL);
3883
3884 list = (*func) (string, quoted);
3885 if (list)
3886 {
3887 ret = string_list (list);
3888 dispose_words (list);
3889 }
3890 else
3891 ret = (char *)NULL;
3892
3893 return (ret);
3894}
3895
f73dda09
JA
3896char *
3897expand_string_to_string (string, quoted)
3898 char *string;
3899 int quoted;
3900{
3901 return (expand_string_to_string_internal (string, quoted, expand_string));
3902}
3903
3904char *
3905expand_string_unsplit_to_string (string, quoted)
3906 char *string;
3907 int quoted;
3908{
3909 return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
3910}
3911
95732b49
JA
3912char *
3913expand_assignment_string_to_string (string, quoted)
3914 char *string;
3915 int quoted;
3916{
3917 return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
3918}
3919
74091dd4
CR
3920/* Kind of like a combination of dequote_string and quote_string_for_globbing;
3921 try to remove CTLESC quoting characters and convert CTLESC escaping a `&'
3922 or a backslash into a backslash. The output of this function must eventually
3923 be processed by strcreplace(). */
3924static char *
3925quote_string_for_repl (string, flags)
3926 char *string;
3927 int flags;
3928{
3929 size_t slen;
3930 char *result, *t;
3931 const char *s, *send;
3932 DECLARE_MBSTATE;
3933
3934 slen = strlen (string);
3935 send = string + slen;
3936
3937 result = (char *)xmalloc (slen * 2 + 1);
3938
3939 if (string[0] == CTLESC && string[1] == 0)
3940 {
3941 result[0] = CTLESC;
3942 result[1] = '\0';
3943 return (result);
3944 }
3945
3946 /* This is awkward. We want to translate CTLESC-\ to \\ if we will
3947 eventually send this string through strcreplace(), which we will do
3948 only if shouldexp_replacement() determines that there is something
3949 to replace. We can either make sure to escape backslashes here and
3950 have shouldexp_replacement() signal that we should send the string to
3951 strcreplace() if it sees an escaped backslash, or we can scan the
3952 string before copying it and turn CTLESC-\ into \\ only if we encounter
3953 a CTLESC-& or a &. This does the former and changes shouldexp_replacement().
3954 If we double the backslashes here, we'll get doubled backslashes in any
3955 result that doesn't get passed to strcreplace(). */
3956
3957 for (s = string, t = result; *s; )
3958 {
3959 /* This function's result has to be processed by strcreplace() */
3960 if (*s == CTLESC && (s[1] == '&' || s[1] == '\\'))
3961 {
3962 *t++ = '\\';
3963 s++;
3964 *t++ = *s++;
3965 continue;
3966 }
3967 /* Dequote it */
3968 if (*s == CTLESC)
3969 {
3970 s++;
3971 if (*s == '\0')
3972 break;
3973 }
3974 COPY_CHAR_P (t, s, send);
3975 }
3976
3977 *t = '\0';
3978 return (result);
3979}
3980
3981/* This does not perform word splitting on the WORD_LIST it returns and
3982 it treats $* as if it were quoted. It dequotes the WORD_LIST, adds
3983 backslash escapes before CTLESC-quoted backslash and `& if
3984 patsub_replacement is enabled. */
3985static char *
3986expand_string_for_patsub (string, quoted)
3987 char *string;
3988 int quoted;
3989{
3990 WORD_LIST *value;
3991 char *ret, *t;
3992
3993 if (string == 0 || *string == '\0')
3994 return (char *)NULL;
3995
3996 value = expand_string_for_pat (string, quoted, (int *)0, (int *)0);
3997
3998 if (value && value->word)
3999 {
4000 remove_quoted_nulls (value->word->word); /* XXX */
4001 value->word->flags &= ~W_HASQUOTEDNULL;
4002 }
4003
4004 if (value)
4005 {
4006 t = (value->next) ? string_list (value) : value->word->word;
4007 ret = quote_string_for_repl (t, quoted);
4008 if (t != value->word->word)
4009 free (t);
4010 dispose_words (value);
4011 }
4012 else
4013 ret = (char *)NULL;
4014
4015 return (ret);
4016}
4017
0628567a
JA
4018char *
4019expand_arith_string (string, quoted)
4020 char *string;
3185942a 4021 int quoted;
0628567a 4022{
ac50fbac
CR
4023 WORD_DESC td;
4024 WORD_LIST *list, *tlist;
4025 size_t slen;
4026 int i, saw_quote;
4027 char *ret;
4028 DECLARE_MBSTATE;
4029
4030 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
4031 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
4032 i = saw_quote = 0;
4033 while (string[i])
4034 {
ddde6f00 4035 if (ARITH_EXP_CHAR (string[i]))
ac50fbac
CR
4036 break;
4037 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
74091dd4 4038 saw_quote = string[i];
ac50fbac
CR
4039 ADVANCE_CHAR (string, slen, i);
4040 }
4041
4042 if (string[i])
4043 {
4044 /* This is expanded version of expand_string_internal as it's called by
4045 expand_string_leave_quoted */
d233b485 4046 td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */
8868edaf
CR
4047#if 0 /* TAG: bash-5.2 */
4048 if (quoted & Q_ARRAYSUB)
4049 td.flags |= W_NOCOMSUB;
4050#endif
ac50fbac
CR
4051 td.word = savestring (string);
4052 list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4053 /* This takes care of the calls from expand_string_leave_quoted and
4054 expand_string */
4055 if (list)
4056 {
4057 tlist = word_list_split (list);
4058 dispose_words (list);
4059 list = tlist;
4060 if (list)
4061 dequote_list (list);
4062 }
4063 /* This comes from expand_string_if_necessary */
4064 if (list)
4065 {
4066 ret = string_list (list);
4067 dispose_words (list);
4068 }
4069 else
4070 ret = (char *)NULL;
4071 FREE (td.word);
4072 }
a0c0a00f
CR
4073 else if (saw_quote && (quoted & Q_ARITH))
4074 ret = string_quote_removal (string, quoted);
ac50fbac
CR
4075 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4076 ret = string_quote_removal (string, quoted);
4077 else
4078 ret = savestring (string);
4079
4080 return ret;
0628567a
JA
4081}
4082
cce855bc
JA
4083#if defined (COND_COMMAND)
4084/* Just remove backslashes in STRING. Returns a new string. */
4085char *
4086remove_backslashes (string)
4087 char *string;
4088{
4089 char *r, *ret, *s;
4090
f73dda09 4091 r = ret = (char *)xmalloc (strlen (string) + 1);
cce855bc
JA
4092 for (s = string; s && *s; )
4093 {
4094 if (*s == '\\')
28ef6c31 4095 s++;
cce855bc 4096 if (*s == 0)
28ef6c31 4097 break;
cce855bc
JA
4098 *r++ = *s++;
4099 }
4100 *r = '\0';
4101 return ret;
4102}
4103
4104/* This needs better error handling. */
4105/* Expand W for use as an argument to a unary or binary operator in a
f1be666c 4106 [[...]] expression. If SPECIAL is 1, this is the rhs argument
cce855bc 4107 to the != or == operator, and should be treated as a pattern. In
f1be666c
JA
4108 this case, we quote the string specially for the globbing code. If
4109 SPECIAL is 2, this is an rhs argument for the =~ operator, and should
74091dd4
CR
4110 be quoted appropriately for regcomp/regexec. If SPECIAL is 3, this is
4111 an array subscript and should be quoted after expansion so it's only
4112 expanded once (Q_ARITH). The caller is responsible
d894cfd1
CR
4113 for removing the backslashes if the unquoted word is needed later. In
4114 any case, since we don't perform word splitting, we need to do quoted
4115 null character removal. */
cce855bc
JA
4116char *
4117cond_expand_word (w, special)
4118 WORD_DESC *w;
4119 int special;
4120{
4121 char *r, *p;
4122 WORD_LIST *l;
f1be666c 4123 int qflags;
cce855bc
JA
4124
4125 if (w->word == 0 || w->word[0] == '\0')
4126 return ((char *)NULL);
4127
3b34f6e6 4128 expand_no_split_dollar_star = 1;
0001803f 4129 w->flags |= W_NOSPLIT2;
74091dd4
CR
4130 qflags = (special == 3) ? Q_ARITH : 0;
4131 l = call_expand_word_internal (w, qflags, 0, (int *)0, (int *)0);
3b34f6e6 4132 expand_no_split_dollar_star = 0;
cce855bc
JA
4133 if (l)
4134 {
ac50fbac 4135 if (special == 0) /* LHS */
cce855bc 4136 {
d894cfd1
CR
4137 if (l->word)
4138 word_list_remove_quoted_nulls (l);
cce855bc
JA
4139 dequote_list (l);
4140 r = string_list (l);
4141 }
74091dd4
CR
4142 else if (special == 3) /* arithmetic expression, Q_ARITH */
4143 {
4144 if (l->word)
4145 word_list_remove_quoted_nulls (l); /* for now */
4146 dequote_list (l);
4147 r = string_list (l);
4148 }
cce855bc 4149 else
28ef6c31 4150 {
ac50fbac
CR
4151 /* Need to figure out whether or not we should call dequote_escapes
4152 or a new dequote_ctlnul function here, and under what
4153 circumstances. */
d233b485 4154 qflags = QGLOB_CVTNULL|QGLOB_CTLESC;
f1be666c
JA
4155 if (special == 2)
4156 qflags |= QGLOB_REGEXP;
a0c0a00f 4157 word_list_remove_quoted_nulls (l);
28ef6c31 4158 p = string_list (l);
f1be666c 4159 r = quote_string_for_globbing (p, qflags);
28ef6c31
JA
4160 free (p);
4161 }
cce855bc
JA
4162 dispose_words (l);
4163 }
74091dd4
CR
4164 else
4165 r = (char *)NULL;
4166
4167 return r;
4168}
4169#endif
4170
4171/* Expand $'...' and $"..." in a string for code paths that don't do it. The
4172 FLAGS argument is 1 if this function should treat CTLESC as a quote
4173 character (e.g., for here-documents) or not (e.g., for shell_expand_line). */
4174char *
4175expand_string_dollar_quote (string, flags)
4176 char *string;
4177 int flags;
4178{
4179 size_t slen, retind, retsize;
4180 int sindex, c, translen, peekc, news;
4181 char *ret, *trans, *send, *t;
4182 DECLARE_MBSTATE;
4183
4184 slen = strlen (string);
4185 send = string + slen;
4186 sindex = 0;
4187
4188 retsize = slen + 1;
4189 ret = xmalloc (retsize);
4190 retind = 0;
4191
4192 while (c = string[sindex])
4193 {
4194 switch (c)
4195 {
4196 default:
4197 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 1, retsize, 64);
4198 COPY_CHAR_I (ret, retind, string, send, sindex);
4199 break;
4200
4201 case '\\':
4202 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 2, retsize, 64);
4203 ret[retind++] = string[sindex++];
4204
4205 if (string[sindex])
4206 COPY_CHAR_I (ret, retind, string, send, sindex);
4207 break;
4208
4209 case '\'':
4210 case '"':
4211 if (c == '\'')
4212 news = skip_single_quoted (string, slen, ++sindex, SX_COMPLETE);
4213 else
4214 news = skip_double_quoted (string, slen, ++sindex, SX_COMPLETE);
4215 translen = news - sindex - 1;
4216 RESIZE_MALLOCED_BUFFER (ret, retind, translen + 3, retsize, 64);
4217 ret[retind++] = c;
4218 if (translen > 0)
4219 {
4220 strncpy (ret + retind, string + sindex, translen);
4221 retind += translen;
4222 }
4223 if (news > sindex && string[news - 1] == c)
4224 ret[retind++] = c;
4225 sindex = news;
4226 break;
4227
4228 case CTLESC:
4229 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 2, retsize, 64);
4230 if (flags)
4231 ret[retind++] = string[sindex++];
4232 if (string[sindex])
4233 COPY_CHAR_I (ret, retind, string, send, sindex);
4234 break;
4235
4236 case '$':
4237 peekc = string[++sindex];
4238#if defined (TRANSLATABLE_STRINGS)
4239 if (peekc != '\'' && peekc != '"')
4240#else
4241 if (peekc != '\'')
4242#endif
4243 {
4244 RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 16);
4245 ret[retind++] = c;
4246 break;
4247 }
4248 if (string[sindex + 1] == '\0') /* don't bother */
4249 {
4250 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4251 ret[retind++] = c;
4252 ret[retind++] = peekc;
4253 sindex++;
4254 break;
4255 }
4256 if (peekc == '\'')
4257 {
4258 /* SX_COMPLETE is the equivalent of ALLOWESC here */
4259 /* We overload SX_COMPLETE below */
4260 news = skip_single_quoted (string, slen, ++sindex, SX_COMPLETE);
4261 /* Check for unclosed string and don't bother if so */
4262 if (news > sindex && string[news] == '\0' && string[news-1] != peekc)
4263 {
4264 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4265 ret[retind++] = c;
4266 ret[retind++] = peekc;
4267 continue;
4268 }
4269 t = substring (string, sindex, news - 1);
4270 trans = ansiexpand (t, 0, news-sindex-1, &translen);
4271 free (t);
4272 t = sh_single_quote (trans);
4273 sindex = news;
4274 }
4275#if defined (TRANSLATABLE_STRINGS)
4276 else
4277 {
4278 news = ++sindex;
4279 t = string_extract_double_quoted (string, &news, SX_COMPLETE);
4280 /* Check for unclosed string and don't bother if so */
4281 if (news > sindex && string[news] == '\0' && string[news-1] != peekc)
4282 {
4283 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4284 ret[retind++] = c;
4285 ret[retind++] = peekc;
4286 free (t);
4287 continue;
4288 }
4289 trans = locale_expand (t, 0, news-sindex, 0, &translen);
4290 free (t);
4291 if (singlequote_translations &&
4292 ((news-sindex-1) != translen || STREQN (t, trans, translen) == 0))
4293 t = sh_single_quote (trans);
4294 else
4295 t = sh_mkdoublequoted (trans, translen, 0);
4296 sindex = news;
4297 }
4298#endif /* TRANSLATABLE_STRINGS */
4299 free (trans);
4300 trans = t;
4301 translen = strlen (trans);
4302
4303 RESIZE_MALLOCED_BUFFER (ret, retind, translen + 1, retsize, 128);
4304 strcpy (ret + retind, trans);
4305 retind += translen;
4306 FREE (trans);
4307 break;
4308 }
4309 }
cce855bc 4310
74091dd4
CR
4311 ret[retind] = 0;
4312 return ret;
cce855bc 4313}
cce855bc
JA
4314
4315/* Call expand_word_internal to expand W and handle error returns.
4316 A convenience function for functions that don't want to handle
4317 any errors or free any memory before aborting. */
4318static WORD_LIST *
b72432fd 4319call_expand_word_internal (w, q, i, c, e)
cce855bc 4320 WORD_DESC *w;
b72432fd 4321 int q, i, *c, *e;
cce855bc
JA
4322{
4323 WORD_LIST *result;
4324
b72432fd 4325 result = expand_word_internal (w, q, i, c, e);
bb70624e 4326 if (result == &expand_word_error || result == &expand_word_fatal)
cce855bc
JA
4327 {
4328 /* By convention, each time this error is returned, w->word has
bb70624e
JA
4329 already been freed (it sometimes may not be in the fatal case,
4330 but that doesn't result in a memory leak because we're going
4331 to exit in most cases). */
cce855bc 4332 w->word = (char *)NULL;
28ef6c31 4333 last_command_exit_value = EXECUTION_FAILURE;
b80f6443 4334 exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
cce855bc 4335 /* NOTREACHED */
ac50fbac 4336 return (NULL);
cce855bc 4337 }
cce855bc
JA
4338 else
4339 return (result);
4340}
4341
4342/* Perform parameter expansion, command substitution, and arithmetic
ac50fbac
CR
4343 expansion on STRING, as if it were a word. Leave the result quoted.
4344 Since this does not perform word splitting, it leaves quoted nulls
4345 in the result. */
cce855bc
JA
4346static WORD_LIST *
4347expand_string_internal (string, quoted)
4348 char *string;
4349 int quoted;
4350{
4351 WORD_DESC td;
4352 WORD_LIST *tresult;
4353
4354 if (string == 0 || *string == 0)
4355 return ((WORD_LIST *)NULL);
4356
28ef6c31
JA
4357 td.flags = 0;
4358 td.word = savestring (string);
4359
b72432fd 4360 tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
28ef6c31
JA
4361
4362 FREE (td.word);
cce855bc 4363 return (tresult);
726f6388
JA
4364}
4365
4366/* Expand STRING by performing parameter expansion, command substitution,
4367 and arithmetic expansion. Dequote the resulting WORD_LIST before
4368 returning it, but do not perform word splitting. The call to
4369 remove_quoted_nulls () is in here because word splitting normally
4370 takes care of quote removal. */
4371WORD_LIST *
4372expand_string_unsplit (string, quoted)
4373 char *string;
4374 int quoted;
4375{
4376 WORD_LIST *value;
4377
28ef6c31 4378 if (string == 0 || *string == '\0')
726f6388
JA
4379 return ((WORD_LIST *)NULL);
4380
28ef6c31 4381 expand_no_split_dollar_star = 1;
726f6388 4382 value = expand_string_internal (string, quoted);
28ef6c31
JA
4383 expand_no_split_dollar_star = 0;
4384
726f6388
JA
4385 if (value)
4386 {
4387 if (value->word)
95732b49 4388 {
8868edaf 4389 remove_quoted_nulls (value->word->word); /* XXX */
95732b49
JA
4390 value->word->flags &= ~W_HASQUOTEDNULL;
4391 }
4392 dequote_list (value);
4393 }
4394 return (value);
4395}
4396
4397/* Expand the rhs of an assignment statement */
4398WORD_LIST *
4399expand_string_assignment (string, quoted)
4400 char *string;
4401 int quoted;
4402{
4403 WORD_DESC td;
4404 WORD_LIST *value;
4405
4406 if (string == 0 || *string == '\0')
4407 return ((WORD_LIST *)NULL);
4408
4409 expand_no_split_dollar_star = 1;
4410
d233b485
CR
4411#if 0
4412 /* Other shells (ksh93) do it this way, which affects how $@ is expanded
4413 in constructs like bar=${@#0} (preserves the spaces resulting from the
4414 expansion of $@ in a context where you don't do word splitting); Posix
4415 interp 888 makes the expansion of $@ in contexts where word splitting
4416 is not performed unspecified. */
4417 td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */
4418#else
95732b49 4419 td.flags = W_ASSIGNRHS;
d233b485 4420#endif
6b9422db 4421 td.flags |= (W_NOGLOB|W_TILDEEXP);
95732b49
JA
4422 td.word = savestring (string);
4423 value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4424 FREE (td.word);
4425
4426 expand_no_split_dollar_star = 0;
4427
4428 if (value)
4429 {
4430 if (value->word)
4431 {
8868edaf 4432 remove_quoted_nulls (value->word->word); /* XXX */
95732b49
JA
4433 value->word->flags &= ~W_HASQUOTEDNULL;
4434 }
726f6388
JA
4435 dequote_list (value);
4436 }
4437 return (value);
4438}
4439
bb70624e
JA
4440/* Expand one of the PS? prompt strings. This is a sort of combination of
4441 expand_string_unsplit and expand_string_internal, but returns the
4442 passed string when an error occurs. Might want to trap other calls
4443 to jump_to_top_level here so we don't endlessly loop. */
4444WORD_LIST *
f1be666c 4445expand_prompt_string (string, quoted, wflags)
bb70624e
JA
4446 char *string;
4447 int quoted;
f1be666c 4448 int wflags;
bb70624e
JA
4449{
4450 WORD_LIST *value;
4451 WORD_DESC td;
4452
4453 if (string == 0 || *string == 0)
4454 return ((WORD_LIST *)NULL);
4455
f1be666c 4456 td.flags = wflags;
bb70624e 4457 td.word = savestring (string);
28ef6c31
JA
4458
4459 no_longjmp_on_fatal_error = 1;
bb70624e 4460 value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
28ef6c31
JA
4461 no_longjmp_on_fatal_error = 0;
4462
bb70624e
JA
4463 if (value == &expand_word_error || value == &expand_word_fatal)
4464 {
4465 value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
4466 return value;
4467 }
4468 FREE (td.word);
4469 if (value)
4470 {
4471 if (value->word)
95732b49 4472 {
8868edaf 4473 remove_quoted_nulls (value->word->word); /* XXX */
95732b49
JA
4474 value->word->flags &= ~W_HASQUOTEDNULL;
4475 }
bb70624e
JA
4476 dequote_list (value);
4477 }
4478 return (value);
4479}
4480
726f6388
JA
4481/* Expand STRING just as if you were expanding a word, but do not dequote
4482 the resultant WORD_LIST. This is called only from within this file,
4483 and is used to correctly preserve quoted characters when expanding
4484 things like ${1+"$@"}. This does parameter expansion, command
b72432fd 4485 substitution, arithmetic expansion, and word splitting. */
726f6388
JA
4486static WORD_LIST *
4487expand_string_leave_quoted (string, quoted)
4488 char *string;
4489 int quoted;
4490{
4491 WORD_LIST *tlist;
4492 WORD_LIST *tresult;
4493
ccc6cda3 4494 if (string == 0 || *string == '\0')
726f6388
JA
4495 return ((WORD_LIST *)NULL);
4496
4497 tlist = expand_string_internal (string, quoted);
4498
4499 if (tlist)
4500 {
4501 tresult = word_list_split (tlist);
4502 dispose_words (tlist);
4503 return (tresult);
4504 }
4505 return ((WORD_LIST *)NULL);
4506}
4507
ccc6cda3
JA
4508/* This does not perform word splitting or dequote the WORD_LIST
4509 it returns. */
4510static WORD_LIST *
d233b485
CR
4511expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p)
4512 char *string;
4513 int quoted, op, pflags;
4514 int *dollar_at_p, *expanded_p;
4515{
4516 WORD_DESC td;
4517 WORD_LIST *tresult;
4518 int old_nosplit;
4519
4520 if (string == 0 || *string == '\0')
4521 return (WORD_LIST *)NULL;
4522
4523 /* We want field splitting to be determined by what is going to be done with
4524 the entire ${parameterOPword} expansion, so we don't want to split the RHS
4525 we expand here. However, the expansion of $* is determined by whether we
4526 are going to eventually perform word splitting, so we want to set this
4527 depending on whether or not are are going to be splitting: if the expansion
4528 is quoted, if the OP is `=', or if IFS is set to the empty string, we
4529 are not going to be splitting, so we set expand_no_split_dollar_star to
8868edaf 4530 note this to callees.
d233b485
CR
4531 We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an
4532 assignment statement. */
4533 /* The updated treatment of $* is the result of Posix interp 888 */
4534 /* This was further clarified on the austin-group list in March, 2017 and
4535 in Posix bug 1129 */
4536 old_nosplit = expand_no_split_dollar_star;
4537 expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */
8868edaf
CR
4538 td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */
4539 td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */
d233b485
CR
4540 if (pflags & PF_ASSIGNRHS) /* pass through */
4541 td.flags |= W_ASSIGNRHS;
4542 if (op == '=')
4543#if 0
4544 td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */
4545#else
4546 td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */
4547#endif
74091dd4 4548 td.word = savestring (string);
d233b485
CR
4549 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
4550 expand_no_split_dollar_star = old_nosplit;
74091dd4 4551 free (td.word);
d233b485
CR
4552
4553 return (tresult);
4554}
4555
4556/* This does not perform word splitting or dequote the WORD_LIST
4557 it returns and it treats $* as if it were quoted. */
4558static WORD_LIST *
4559expand_string_for_pat (string, quoted, dollar_at_p, expanded_p)
ccc6cda3 4560 char *string;
a0c0a00f 4561 int quoted, *dollar_at_p, *expanded_p;
ccc6cda3
JA
4562{
4563 WORD_DESC td;
4564 WORD_LIST *tresult;
d233b485 4565 int oexp;
ccc6cda3
JA
4566
4567 if (string == 0 || *string == '\0')
4568 return (WORD_LIST *)NULL;
4569
d233b485 4570 oexp = expand_no_split_dollar_star;
a0c0a00f 4571 expand_no_split_dollar_star = 1;
aeb26a67 4572 td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */
74091dd4 4573 td.word = savestring (string);
a0c0a00f 4574 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
d233b485 4575 expand_no_split_dollar_star = oexp;
74091dd4 4576 free (td.word);
a0c0a00f 4577
ccc6cda3
JA
4578 return (tresult);
4579}
4580
726f6388
JA
4581/* Expand STRING just as if you were expanding a word. This also returns
4582 a list of words. Note that filename globbing is *NOT* done for word
4583 or string expansion, just when the shell is expanding a command. This
4584 does parameter expansion, command substitution, arithmetic expansion,
4585 and word splitting. Dequote the resultant WORD_LIST before returning. */
4586WORD_LIST *
4587expand_string (string, quoted)
4588 char *string;
4589 int quoted;
4590{
4591 WORD_LIST *result;
4592
28ef6c31 4593 if (string == 0 || *string == '\0')
726f6388
JA
4594 return ((WORD_LIST *)NULL);
4595
4596 result = expand_string_leave_quoted (string, quoted);
ccc6cda3 4597 return (result ? dequote_list (result) : result);
726f6388
JA
4598}
4599
d233b485
CR
4600/*******************************************
4601 * *
4602 * Functions to expand WORD_DESCs *
4603 * *
4604 *******************************************/
4605
4606/* Expand WORD, performing word splitting on the result. This does
4607 parameter expansion, command substitution, arithmetic expansion,
4608 word splitting, and quote removal. */
4609
4610WORD_LIST *
4611expand_word (word, quoted)
4612 WORD_DESC *word;
4613 int quoted;
4614{
4615 WORD_LIST *result, *tresult;
4616
4617 tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4618 result = word_list_split (tresult);
4619 dispose_words (tresult);
4620 return (result ? dequote_list (result) : result);
4621}
4622
4623/* Expand WORD, but do not perform word splitting on the result. This
4624 does parameter expansion, command substitution, arithmetic expansion,
4625 and quote removal. */
4626WORD_LIST *
4627expand_word_unsplit (word, quoted)
4628 WORD_DESC *word;
4629 int quoted;
4630{
4631 WORD_LIST *result;
4632
4633 result = expand_word_leave_quoted (word, quoted);
4634 return (result ? dequote_list (result) : result);
4635}
4636
4637/* Perform shell expansions on WORD, but do not perform word splitting or
4638 quote removal on the result. Virtually identical to expand_word_unsplit;
4639 could be combined if implementations don't diverge. */
4640WORD_LIST *
4641expand_word_leave_quoted (word, quoted)
4642 WORD_DESC *word;
4643 int quoted;
4644{
4645 WORD_LIST *result;
4646
4647 expand_no_split_dollar_star = 1;
4648 if (ifs_is_null)
4649 word->flags |= W_NOSPLIT;
4650 word->flags |= W_NOSPLIT2;
4651 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4652 expand_no_split_dollar_star = 0;
4653
4654 return result;
4655}
4656
726f6388
JA
4657/***************************************************
4658 * *
4659 * Functions to handle quoting chars *
4660 * *
4661 ***************************************************/
4662
cce855bc
JA
4663/* Conventions:
4664
4665 A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
4666 The parser passes CTLNUL as CTLESC CTLNUL. */
4667
cce855bc
JA
4668/* Quote escape characters in string s, but no other characters. This is
4669 used to protect CTLESC and CTLNUL in variable values from the rest of
3185942a
JA
4670 the word expansion process after the variable is expanded (word splitting
4671 and filename generation). If IFS is null, we quote spaces as well, just
4672 in case we split on spaces later (in the case of unquoted $@, we will
4673 eventually attempt to split the entire word on spaces). Corresponding
4674 code exists in dequote_escapes. Even if we don't end up splitting on
4675 spaces, quoting spaces is not a problem. This should never be called on
4676 a string that is quoted with single or double quotes or part of a here
d233b485
CR
4677 document (effectively double-quoted).
4678 FLAGS says whether or not we are going to split the result. If we are not,
4679 and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL,
4680 respectively, to prevent them from being removed as part of dequoting. */
4681static char *
4682quote_escapes_internal (string, flags)
4683 const char *string;
4684 int flags;
cce855bc 4685{
d233b485
CR
4686 const char *s, *send;
4687 char *t, *result;
7117c2d2 4688 size_t slen;
d233b485 4689 int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit;
7117c2d2 4690 DECLARE_MBSTATE;
cce855bc 4691
7117c2d2
JA
4692 slen = strlen (string);
4693 send = string + slen;
4694
f1be666c 4695 quote_spaces = (ifs_value && *ifs_value == 0);
d233b485 4696 nosplit = (flags & PF_NOSPLIT2);
3185942a
JA
4697
4698 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
d233b485
CR
4699 {
4700 skip_ctlesc |= (nosplit == 0 && *s == CTLESC);
4701 skip_ctlnul |= (nosplit == 0 && *s == CTLNUL);
4702 }
3185942a 4703
7117c2d2
JA
4704 t = result = (char *)xmalloc ((slen * 2) + 1);
4705 s = string;
4706
4707 while (*s)
cce855bc 4708 {
3185942a 4709 if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
cce855bc 4710 *t++ = CTLESC;
7117c2d2 4711 COPY_CHAR_P (t, s, send);
cce855bc
JA
4712 }
4713 *t = '\0';
ac50fbac 4714
cce855bc
JA
4715 return (result);
4716}
4717
d233b485
CR
4718char *
4719quote_escapes (string)
4720 const char *string;
4721{
4722 return (quote_escapes_internal (string, 0));
4723}
4724
4725char *
4726quote_rhs (string)
4727 const char *string;
4728{
4729 return (quote_escapes_internal (string, PF_NOSPLIT2));
4730}
4731
cce855bc
JA
4732static WORD_LIST *
4733list_quote_escapes (list)
4734 WORD_LIST *list;
4735{
4736 register WORD_LIST *w;
4737 char *t;
4738
4739 for (w = list; w; w = w->next)
4740 {
4741 t = w->word->word;
4742 w->word->word = quote_escapes (t);
4743 free (t);
4744 }
4745 return list;
4746}
4747
7117c2d2
JA
4748/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
4749
4750 The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
4751 This is necessary to make unquoted CTLESC and CTLNUL characters in the
4752 data stream pass through properly.
4753
4754 We need to remove doubled CTLESC characters inside quoted strings before
4755 quoting the entire string, so we do not double the number of CTLESC
4756 characters.
4757
4758 Also used by parts of the pattern substitution code. */
3185942a 4759char *
cce855bc 4760dequote_escapes (string)
d233b485 4761 const char *string;
cce855bc 4762{
d233b485
CR
4763 const char *s, *send;
4764 char *t, *result;
7117c2d2 4765 size_t slen;
f1be666c 4766 int quote_spaces;
7117c2d2 4767 DECLARE_MBSTATE;
cce855bc 4768
7117c2d2 4769 if (string == 0)
d233b485 4770 return (char *)0;
7117c2d2
JA
4771
4772 slen = strlen (string);
4773 send = string + slen;
4774
4775 t = result = (char *)xmalloc (slen + 1);
7117c2d2
JA
4776
4777 if (strchr (string, CTLESC) == 0)
3185942a 4778 return (strcpy (result, string));
7117c2d2 4779
f1be666c 4780 quote_spaces = (ifs_value && *ifs_value == 0);
3185942a
JA
4781
4782 s = string;
7117c2d2 4783 while (*s)
cce855bc 4784 {
f1be666c 4785 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
cce855bc
JA
4786 {
4787 s++;
4788 if (*s == '\0')
4789 break;
4790 }
7117c2d2 4791 COPY_CHAR_P (t, s, send);
cce855bc
JA
4792 }
4793 *t = '\0';
ac50fbac 4794
cce855bc
JA
4795 return result;
4796}
726f6388 4797
d233b485 4798#if defined (INCLUDE_UNUSED)
ac50fbac
CR
4799static WORD_LIST *
4800list_dequote_escapes (list)
4801 WORD_LIST *list;
4802{
4803 register WORD_LIST *w;
4804 char *t;
4805
4806 for (w = list; w; w = w->next)
4807 {
4808 t = w->word->word;
4809 w->word->word = dequote_escapes (t);
4810 free (t);
4811 }
4812 return list;
4813}
d233b485 4814#endif
ac50fbac 4815
0628567a
JA
4816/* Return a new string with the quoted representation of character C.
4817 This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
4818 set in any resultant WORD_DESC where this value is the word. */
726f6388
JA
4819static char *
4820make_quoted_char (c)
4821 int c;
4822{
4823 char *temp;
4824
f73dda09 4825 temp = (char *)xmalloc (3);
726f6388
JA
4826 if (c == 0)
4827 {
4828 temp[0] = CTLNUL;
4829 temp[1] = '\0';
4830 }
4831 else
4832 {
4833 temp[0] = CTLESC;
4834 temp[1] = c;
4835 temp[2] = '\0';
4836 }
4837 return (temp);
4838}
4839
0628567a
JA
4840/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so
4841 the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
4842 this value is the word. */
ccc6cda3 4843char *
726f6388
JA
4844quote_string (string)
4845 char *string;
4846{
ccc6cda3 4847 register char *t;
7117c2d2
JA
4848 size_t slen;
4849 char *result, *send;
726f6388 4850
ccc6cda3 4851 if (*string == 0)
726f6388 4852 {
f73dda09 4853 result = (char *)xmalloc (2);
726f6388
JA
4854 result[0] = CTLNUL;
4855 result[1] = '\0';
4856 }
4857 else
4858 {
7117c2d2 4859 DECLARE_MBSTATE;
726f6388 4860
7117c2d2
JA
4861 slen = strlen (string);
4862 send = string + slen;
4863
4864 result = (char *)xmalloc ((slen * 2) + 1);
4865
4866 for (t = result; string < send; )
726f6388
JA
4867 {
4868 *t++ = CTLESC;
7117c2d2 4869 COPY_CHAR_P (t, string, send);
726f6388
JA
4870 }
4871 *t = '\0';
4872 }
4873 return (result);
4874}
4875
0628567a 4876/* De-quote quoted characters in STRING. */
726f6388
JA
4877char *
4878dequote_string (string)
4879 char *string;
4880{
7117c2d2
JA
4881 register char *s, *t;
4882 size_t slen;
4883 char *result, *send;
4884 DECLARE_MBSTATE;
726f6388 4885
a0c0a00f 4886 if (string[0] == CTLESC && string[1] == 0)
74091dd4 4887 internal_debug ("dequote_string: string with bare CTLESC");
a0c0a00f 4888
d233b485 4889 slen = STRLEN (string);
7117c2d2
JA
4890
4891 t = result = (char *)xmalloc (slen + 1);
726f6388
JA
4892
4893 if (QUOTED_NULL (string))
4894 {
4895 result[0] = '\0';
4896 return (result);
4897 }
4898
a0c0a00f
CR
4899 /* A string consisting of only a single CTLESC should pass through unchanged */
4900 if (string[0] == CTLESC && string[1] == 0)
4901 {
4902 result[0] = CTLESC;
4903 result[1] = '\0';
4904 return (result);
4905 }
4906
726f6388
JA
4907 /* If no character in the string can be quoted, don't bother examining
4908 each character. Just return a copy of the string passed to us. */
7117c2d2
JA
4909 if (strchr (string, CTLESC) == NULL)
4910 return (strcpy (result, string));
726f6388 4911
7117c2d2
JA
4912 send = string + slen;
4913 s = string;
4914 while (*s)
726f6388 4915 {
7117c2d2 4916 if (*s == CTLESC)
726f6388 4917 {
7117c2d2
JA
4918 s++;
4919 if (*s == '\0')
726f6388
JA
4920 break;
4921 }
7117c2d2 4922 COPY_CHAR_P (t, s, send);
726f6388
JA
4923 }
4924
4925 *t = '\0';
4926 return (result);
4927}
4928
4929/* Quote the entire WORD_LIST list. */
ccc6cda3 4930static WORD_LIST *
726f6388
JA
4931quote_list (list)
4932 WORD_LIST *list;
4933{
4934 register WORD_LIST *w;
ccc6cda3 4935 char *t;
726f6388
JA
4936
4937 for (w = list; w; w = w->next)
4938 {
ccc6cda3 4939 t = w->word->word;
726f6388 4940 w->word->word = quote_string (t);
3185942a
JA
4941 if (*t == 0)
4942 w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
ccc6cda3 4943 w->word->flags |= W_QUOTED;
3185942a 4944 free (t);
726f6388 4945 }
ccc6cda3 4946 return list;
726f6388
JA
4947}
4948
d233b485
CR
4949WORD_DESC *
4950dequote_word (word)
4951 WORD_DESC *word;
4952{
4953 register char *s;
4954
4955 s = dequote_string (word->word);
4956 if (QUOTED_NULL (word->word))
4957 word->flags &= ~W_HASQUOTEDNULL;
4958 free (word->word);
4959 word->word = s;
4960
4961 return word;
4962}
4963
0628567a
JA
4964/* De-quote quoted characters in each word in LIST. */
4965WORD_LIST *
7117c2d2
JA
4966dequote_list (list)
4967 WORD_LIST *list;
4968{
4969 register char *s;
4970 register WORD_LIST *tlist;
4971
4972 for (tlist = list; tlist; tlist = tlist->next)
4973 {
4974 s = dequote_string (tlist->word->word);
3185942a
JA
4975 if (QUOTED_NULL (tlist->word->word))
4976 tlist->word->flags &= ~W_HASQUOTEDNULL;
7117c2d2
JA
4977 free (tlist->word->word);
4978 tlist->word->word = s;
4979 }
4980 return list;
4981}
4982
4983/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
4984 string. */
3185942a 4985char *
7117c2d2
JA
4986remove_quoted_escapes (string)
4987 char *string;
4988{
4989 char *t;
4990
4991 if (string)
4992 {
4993 t = dequote_escapes (string);
4994 strcpy (string, t);
4995 free (t);
4996 }
4997
4998 return (string);
4999}
5000
d233b485
CR
5001/* Remove quoted $IFS characters from STRING. Quoted IFS characters are
5002 added to protect them from word splitting, but we need to remove them
5003 if no word splitting takes place. This returns newly-allocated memory,
5004 so callers can use it to replace savestring(). */
5005char *
5006remove_quoted_ifs (string)
5007 char *string;
5008{
5009 register size_t slen;
5010 register int i, j;
5011 char *ret, *send;
5012 DECLARE_MBSTATE;
5013
5014 slen = strlen (string);
5015 send = string + slen;
5016
5017 i = j = 0;
5018 ret = (char *)xmalloc (slen + 1);
5019
5020 while (i < slen)
5021 {
5022 if (string[i] == CTLESC)
5023 {
5024 i++;
5025 if (string[i] == 0 || isifs (string[i]) == 0)
5026 ret[j++] = CTLESC;
5027 if (i == slen)
5028 break;
5029 }
5030
5031 COPY_CHAR_I (ret, j, string, send, i);
5032 }
5033 ret[j] = '\0';
5034
5035 return (ret);
5036}
5037
3185942a 5038char *
cce855bc
JA
5039remove_quoted_nulls (string)
5040 char *string;
5041{
7117c2d2
JA
5042 register size_t slen;
5043 register int i, j, prev_i;
5044 DECLARE_MBSTATE;
5045
5046 if (strchr (string, CTLNUL) == 0) /* XXX */
5047 return string; /* XXX */
5048
5049 slen = strlen (string);
5050 i = j = 0;
5051
5052 while (i < slen)
5053 {
5054 if (string[i] == CTLESC)
b80f6443
JA
5055 {
5056 /* Old code had j++, but we cannot assume that i == j at this
5057 point -- what if a CTLNUL has already been removed from the
5058 string? We don't want to drop the CTLESC or recopy characters
5059 that we've already copied down. */
d233b485
CR
5060 i++;
5061 string[j++] = CTLESC;
b80f6443
JA
5062 if (i == slen)
5063 break;
5064 }
7117c2d2 5065 else if (string[i] == CTLNUL)
a48a8ac3
CR
5066 {
5067 i++;
5068 continue;
5069 }
7117c2d2
JA
5070
5071 prev_i = i;
d233b485 5072 ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */
7117c2d2 5073 if (j < prev_i)
cce855bc 5074 {
7117c2d2 5075 do string[j++] = string[prev_i++]; while (prev_i < i);
cce855bc 5076 }
7117c2d2
JA
5077 else
5078 j = i;
cce855bc 5079 }
7117c2d2
JA
5080 string[j] = '\0';
5081
5082 return (string);
cce855bc
JA
5083}
5084
5085/* Perform quoted null character removal on each element of LIST.
5086 This modifies LIST. */
5087void
5088word_list_remove_quoted_nulls (list)
5089 WORD_LIST *list;
5090{
5091 register WORD_LIST *t;
5092
5093 for (t = list; t; t = t->next)
95732b49
JA
5094 {
5095 remove_quoted_nulls (t->word->word);
5096 t->word->flags &= ~W_HASQUOTEDNULL;
5097 }
cce855bc
JA
5098}
5099
5100/* **************************************************************** */
5101/* */
5102/* Functions for Matching and Removing Patterns */
5103/* */
5104/* **************************************************************** */
5105
b80f6443 5106#if defined (HANDLE_MULTIBYTE)
d233b485 5107# ifdef INCLUDE_UNUSED
b80f6443
JA
5108static unsigned char *
5109mb_getcharlens (string, len)
5110 char *string;
5111 int len;
5112{
5113 int i, offset, last;
5114 unsigned char *ret;
5115 char *p;
5116 DECLARE_MBSTATE;
5117
5118 i = offset = 0;
5119 last = 0;
5120 ret = (unsigned char *)xmalloc (len);
5121 memset (ret, 0, len);
5122 while (string[last])
5123 {
5124 ADVANCE_CHAR (string, len, offset);
5125 ret[last] = offset - last;
5126 last = offset;
5127 }
5128 return ret;
5129}
d233b485 5130# endif
b80f6443
JA
5131#endif
5132
cce855bc
JA
5133/* Remove the portion of PARAM matched by PATTERN according to OP, where OP
5134 can have one of 4 values:
5135 RP_LONG_LEFT remove longest matching portion at start of PARAM
726f6388
JA
5136 RP_SHORT_LEFT remove shortest matching portion at start of PARAM
5137 RP_LONG_RIGHT remove longest matching portion at end of PARAM
5138 RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
5139*/
5140
5141#define RP_LONG_LEFT 1
5142#define RP_SHORT_LEFT 2
5143#define RP_LONG_RIGHT 3
5144#define RP_SHORT_RIGHT 4
5145
495aee44 5146/* Returns its first argument if nothing matched; new memory otherwise */
726f6388 5147static char *
b80f6443 5148remove_upattern (param, pattern, op)
726f6388
JA
5149 char *param, *pattern;
5150 int op;
5151{
a0c0a00f 5152 register size_t len;
ccc6cda3 5153 register char *end;
726f6388
JA
5154 register char *p, *ret, c;
5155
ccc6cda3
JA
5156 len = STRLEN (param);
5157 end = param + len;
726f6388
JA
5158
5159 switch (op)
5160 {
5161 case RP_LONG_LEFT: /* remove longest match at start */
5162 for (p = end; p >= param; p--)
5163 {
5164 c = *p; *p = '\0';
f73dda09 5165 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
726f6388
JA
5166 {
5167 *p = c;
5168 return (savestring (p));
5169 }
5170 *p = c;
b80f6443 5171
726f6388
JA
5172 }
5173 break;
5174
5175 case RP_SHORT_LEFT: /* remove shortest match at start */
5176 for (p = param; p <= end; p++)
5177 {
5178 c = *p; *p = '\0';
f73dda09 5179 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
726f6388
JA
5180 {
5181 *p = c;
5182 return (savestring (p));
5183 }
5184 *p = c;
5185 }
5186 break;
5187
ccc6cda3
JA
5188 case RP_LONG_RIGHT: /* remove longest match at end */
5189 for (p = param; p <= end; p++)
5190 {
f73dda09 5191 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
ccc6cda3
JA
5192 {
5193 c = *p; *p = '\0';
5194 ret = savestring (param);
5195 *p = c;
5196 return (ret);
5197 }
5198 }
5199 break;
5200
5201 case RP_SHORT_RIGHT: /* remove shortest match at end */
5202 for (p = end; p >= param; p--)
5203 {
f73dda09 5204 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
ccc6cda3
JA
5205 {
5206 c = *p; *p = '\0';
5207 ret = savestring (param);
5208 *p = c;
5209 return (ret);
5210 }
5211 }
5212 break;
5213 }
b80f6443 5214
495aee44 5215 return (param); /* no match, return original string */
ccc6cda3
JA
5216}
5217
b80f6443 5218#if defined (HANDLE_MULTIBYTE)
495aee44 5219/* Returns its first argument if nothing matched; new memory otherwise */
b80f6443
JA
5220static wchar_t *
5221remove_wpattern (wparam, wstrlen, wpattern, op)
5222 wchar_t *wparam;
5223 size_t wstrlen;
5224 wchar_t *wpattern;
5225 int op;
5226{
0628567a
JA
5227 wchar_t wc, *ret;
5228 int n;
b80f6443
JA
5229
5230 switch (op)
5231 {
5232 case RP_LONG_LEFT: /* remove longest match at start */
5233 for (n = wstrlen; n >= 0; n--)
5234 {
5235 wc = wparam[n]; wparam[n] = L'\0';
5236 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5237 {
5238 wparam[n] = wc;
5239 return (wcsdup (wparam + n));
5240 }
5241 wparam[n] = wc;
5242 }
5243 break;
5244
5245 case RP_SHORT_LEFT: /* remove shortest match at start */
5246 for (n = 0; n <= wstrlen; n++)
5247 {
5248 wc = wparam[n]; wparam[n] = L'\0';
5249 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5250 {
5251 wparam[n] = wc;
5252 return (wcsdup (wparam + n));
5253 }
5254 wparam[n] = wc;
5255 }
5256 break;
5257
5258 case RP_LONG_RIGHT: /* remove longest match at end */
5259 for (n = 0; n <= wstrlen; n++)
5260 {
5261 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5262 {
5263 wc = wparam[n]; wparam[n] = L'\0';
5264 ret = wcsdup (wparam);
5265 wparam[n] = wc;
5266 return (ret);
5267 }
5268 }
5269 break;
5270
5271 case RP_SHORT_RIGHT: /* remove shortest match at end */
5272 for (n = wstrlen; n >= 0; n--)
5273 {
5274 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5275 {
5276 wc = wparam[n]; wparam[n] = L'\0';
5277 ret = wcsdup (wparam);
5278 wparam[n] = wc;
5279 return (ret);
5280 }
5281 }
5282 break;
5283 }
5284
495aee44 5285 return (wparam); /* no match, return original string */
b80f6443
JA
5286}
5287#endif /* HANDLE_MULTIBYTE */
5288
5289static char *
5290remove_pattern (param, pattern, op)
5291 char *param, *pattern;
5292 int op;
5293{
495aee44
CR
5294 char *xret;
5295
b80f6443
JA
5296 if (param == NULL)
5297 return (param);
5298 if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
5299 return (savestring (param));
5300
5301#if defined (HANDLE_MULTIBYTE)
5302 if (MB_CUR_MAX > 1)
5303 {
5304 wchar_t *ret, *oret;
5305 size_t n;
5306 wchar_t *wparam, *wpattern;
5307 mbstate_t ps;
b80f6443 5308
d233b485
CR
5309 /* XXX - could optimize here by checking param and pattern for multibyte
5310 chars with mbsmbchar and calling remove_upattern. */
5311
b80f6443
JA
5312 n = xdupmbstowcs (&wpattern, NULL, pattern);
5313 if (n == (size_t)-1)
495aee44
CR
5314 {
5315 xret = remove_upattern (param, pattern, op);
5316 return ((xret == param) ? savestring (param) : xret);
5317 }
b80f6443 5318 n = xdupmbstowcs (&wparam, NULL, param);
ac50fbac 5319
b80f6443
JA
5320 if (n == (size_t)-1)
5321 {
5322 free (wpattern);
495aee44
CR
5323 xret = remove_upattern (param, pattern, op);
5324 return ((xret == param) ? savestring (param) : xret);
b80f6443
JA
5325 }
5326 oret = ret = remove_wpattern (wparam, n, wpattern, op);
495aee44
CR
5327 /* Don't bother to convert wparam back to multibyte string if nothing
5328 matched; just return copy of original string */
5329 if (ret == wparam)
5330 {
5331 free (wparam);
5332 free (wpattern);
5333 return (savestring (param));
5334 }
b80f6443
JA
5335
5336 free (wparam);
5337 free (wpattern);
5338
5339 n = strlen (param);
0628567a 5340 xret = (char *)xmalloc (n + 1);
b80f6443
JA
5341 memset (&ps, '\0', sizeof (mbstate_t));
5342 n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
5343 xret[n] = '\0'; /* just to make sure */
5344 free (oret);
5345 return xret;
5346 }
5347 else
5348#endif
ccc6cda3 5349 {
495aee44
CR
5350 xret = remove_upattern (param, pattern, op);
5351 return ((xret == param) ? savestring (param) : xret);
ccc6cda3
JA
5352 }
5353}
5354
5355/* Match PAT anywhere in STRING and return the match boundaries.
5356 This returns 1 in case of a successful match, 0 otherwise. SP
5357 and EP are pointers into the string where the match begins and
5358 ends, respectively. MTYPE controls what kind of match is attempted.
5359 MATCH_BEG and MATCH_END anchor the match at the beginning and end
5360 of the string, respectively. The longest match is returned. */
5361static int
b80f6443 5362match_upattern (string, pat, mtype, sp, ep)
ccc6cda3
JA
5363 char *string, *pat;
5364 int mtype;
5365 char **sp, **ep;
5366{
a0c0a00f
CR
5367 int c, mlen;
5368 size_t len;
95732b49 5369 register char *p, *p1, *npat;
ccc6cda3
JA
5370 char *end;
5371
95732b49
JA
5372 /* If the pattern doesn't match anywhere in the string, go ahead and
5373 short-circuit right away. A minor optimization, saves a bunch of
5374 unnecessary calls to strmatch (up to N calls for a string of N
5375 characters) if the match is unsuccessful. To preserve the semantics
5376 of the substring matches below, we make sure that the pattern has
5377 `*' as first and last character, making a new pattern if necessary. */
5378 /* XXX - check this later if I ever implement `**' with special meaning,
5379 since this will potentially result in `**' at the beginning or end */
5380 len = STRLEN (pat);
0001803f 5381 if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
95732b49 5382 {
a0c0a00f
CR
5383 int unescaped_backslash;
5384 char *pp;
5385
0628567a 5386 p = npat = (char *)xmalloc (len + 3);
95732b49 5387 p1 = pat;
d233b485 5388 if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob)))
95732b49
JA
5389 *p++ = '*';
5390 while (*p1)
5391 *p++ = *p1++;
a0c0a00f
CR
5392#if 1
5393 /* Need to also handle a pattern that ends with an unescaped backslash.
5394 For right now, we ignore it because the pattern matching code will
5395 fail the match anyway */
5396 /* If the pattern ends with a `*' we leave it alone if it's preceded by
5397 an even number of backslashes, but if it's escaped by a backslash
5398 we need to add another `*'. */
d233b485 5399 if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\')))
a0c0a00f
CR
5400 {
5401 pp = p1 - 3;
5402 while (pp >= pat && *pp-- == '\\')
5403 unescaped_backslash = 1 - unescaped_backslash;
5404 if (unescaped_backslash)
5405 *p++ = '*';
5406 }
d233b485 5407 else if (mtype != MATCH_END && p1[-1] != '*')
95732b49 5408 *p++ = '*';
a0c0a00f
CR
5409#else
5410 if (p1[-1] != '*' || p1[-2] == '\\')
5411 *p++ = '*';
5412#endif
95732b49
JA
5413 *p = '\0';
5414 }
5415 else
5416 npat = pat;
a0c0a00f 5417 c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
95732b49
JA
5418 if (npat != pat)
5419 free (npat);
5420 if (c == FNM_NOMATCH)
5421 return (0);
5422
b80f6443
JA
5423 len = STRLEN (string);
5424 end = string + len;
ccc6cda3 5425
495aee44 5426 mlen = umatchlen (pat, len);
8868edaf
CR
5427 if (mlen > (int)len)
5428 return (0);
495aee44 5429
ccc6cda3
JA
5430 switch (mtype)
5431 {
5432 case MATCH_ANY:
5433 for (p = string; p <= end; p++)
5434 {
a0c0a00f 5435 if (match_pattern_char (pat, p, FNMATCH_IGNCASE))
ccc6cda3 5436 {
495aee44
CR
5437 p1 = (mlen == -1) ? end : p + mlen;
5438 /* p1 - p = length of portion of string to be considered
5439 p = current position in string
5440 mlen = number of characters consumed by match (-1 for entire string)
5441 end = end of string
5442 we want to break immediately if the potential match len
5443 is greater than the number of characters remaining in the
5444 string
5445 */
5446 if (p1 > end)
5447 break;
5448 for ( ; p1 >= p; p1--)
ccc6cda3
JA
5449 {
5450 c = *p1; *p1 = '\0';
a0c0a00f 5451 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
ccc6cda3
JA
5452 {
5453 *p1 = c;
5454 *sp = p;
5455 *ep = p1;
5456 return 1;
5457 }
5458 *p1 = c;
495aee44
CR
5459#if 1
5460 /* If MLEN != -1, we have a fixed length pattern. */
5461 if (mlen != -1)
5462 break;
5463#endif
ccc6cda3
JA
5464 }
5465 }
5466 }
b80f6443 5467
ccc6cda3
JA
5468 return (0);
5469
5470 case MATCH_BEG:
a0c0a00f 5471 if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0)
28ef6c31 5472 return (0);
b80f6443 5473
495aee44 5474 for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
ccc6cda3
JA
5475 {
5476 c = *p; *p = '\0';
a0c0a00f 5477 if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
ccc6cda3
JA
5478 {
5479 *p = c;
5480 *sp = string;
5481 *ep = p;
5482 return 1;
5483 }
5484 *p = c;
495aee44
CR
5485 /* If MLEN != -1, we have a fixed length pattern. */
5486 if (mlen != -1)
5487 break;
ccc6cda3 5488 }
b80f6443 5489
ccc6cda3 5490 return (0);
726f6388 5491
ccc6cda3 5492 case MATCH_END:
495aee44 5493 for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
b80f6443 5494 {
a0c0a00f 5495 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
b80f6443
JA
5496 {
5497 *sp = p;
5498 *ep = end;
5499 return 1;
5500 }
495aee44
CR
5501 /* If MLEN != -1, we have a fixed length pattern. */
5502 if (mlen != -1)
5503 break;
b80f6443
JA
5504 }
5505
5506 return (0);
5507 }
5508
5509 return (0);
5510}
5511
5512#if defined (HANDLE_MULTIBYTE)
a0c0a00f
CR
5513
5514#define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c))
5515
b80f6443
JA
5516/* Match WPAT anywhere in WSTRING and return the match boundaries.
5517 This returns 1 in case of a successful match, 0 otherwise. Wide
5518 character version. */
5519static int
5520match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
5521 wchar_t *wstring;
5522 char **indices;
5523 size_t wstrlen;
5524 wchar_t *wpat;
5525 int mtype;
5526 char **sp, **ep;
5527{
95732b49 5528 wchar_t wc, *wp, *nwpat, *wp1;
495aee44
CR
5529 size_t len;
5530 int mlen;
5531 int n, n1, n2, simple;
5532
5533 simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
5534#if defined (EXTENDED_GLOB)
5535 if (extended_glob)
91717ba3 5536 simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
b80f6443
JA
5537#endif
5538
95732b49
JA
5539 /* If the pattern doesn't match anywhere in the string, go ahead and
5540 short-circuit right away. A minor optimization, saves a bunch of
5541 unnecessary calls to strmatch (up to N calls for a string of N
5542 characters) if the match is unsuccessful. To preserve the semantics
5543 of the substring matches below, we make sure that the pattern has
5544 `*' as first and last character, making a new pattern if necessary. */
95732b49 5545 len = wcslen (wpat);
0001803f 5546 if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
95732b49 5547 {
a0c0a00f
CR
5548 int unescaped_backslash;
5549 wchar_t *wpp;
5550
0628567a 5551 wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
95732b49 5552 wp1 = wpat;
0001803f 5553 if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
95732b49
JA
5554 *wp++ = L'*';
5555 while (*wp1 != L'\0')
5556 *wp++ = *wp1++;
a0c0a00f
CR
5557#if 1
5558 /* See comments above in match_upattern. */
5559 if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\'))
5560 {
5561 wpp = wp1 - 3;
5562 while (wpp >= wpat && *wpp-- == L'\\')
5563 unescaped_backslash = 1 - unescaped_backslash;
5564 if (unescaped_backslash)
5565 *wp++ = L'*';
5566 }
5567 else if (wp1[-1] != L'*')
5568 *wp++ = L'*';
5569#else
95732b49
JA
5570 if (wp1[-1] != L'*' || wp1[-2] == L'\\')
5571 *wp++ = L'*';
a0c0a00f 5572#endif
95732b49
JA
5573 *wp = '\0';
5574 }
5575 else
5576 nwpat = wpat;
a0c0a00f 5577 len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
95732b49
JA
5578 if (nwpat != wpat)
5579 free (nwpat);
5580 if (len == FNM_NOMATCH)
5581 return (0);
5582
495aee44 5583 mlen = wmatchlen (wpat, wstrlen);
8868edaf
CR
5584 if (mlen > (int)wstrlen)
5585 return (0);
495aee44
CR
5586
5587/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
b80f6443
JA
5588 switch (mtype)
5589 {
5590 case MATCH_ANY:
5591 for (n = 0; n <= wstrlen; n++)
5592 {
a0c0a00f 5593 n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE);
495aee44 5594 if (n2)
b80f6443 5595 {
495aee44
CR
5596 n1 = (mlen == -1) ? wstrlen : n + mlen;
5597 if (n1 > wstrlen)
5598 break;
5599
5600 for ( ; n1 >= n; n1--)
b80f6443
JA
5601 {
5602 wc = wstring[n1]; wstring[n1] = L'\0';
a0c0a00f 5603 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
b80f6443
JA
5604 {
5605 wstring[n1] = wc;
5606 *sp = indices[n];
5607 *ep = indices[n1];
5608 return 1;
5609 }
5610 wstring[n1] = wc;
495aee44
CR
5611 /* If MLEN != -1, we have a fixed length pattern. */
5612 if (mlen != -1)
5613 break;
b80f6443
JA
5614 }
5615 }
5616 }
5617
5618 return (0);
5619
5620 case MATCH_BEG:
a0c0a00f 5621 if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0)
b80f6443
JA
5622 return (0);
5623
495aee44 5624 for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
b80f6443
JA
5625 {
5626 wc = wstring[n]; wstring[n] = L'\0';
a0c0a00f 5627 if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
b80f6443
JA
5628 {
5629 wstring[n] = wc;
5630 *sp = indices[0];
5631 *ep = indices[n];
5632 return 1;
5633 }
5634 wstring[n] = wc;
495aee44
CR
5635 /* If MLEN != -1, we have a fixed length pattern. */
5636 if (mlen != -1)
5637 break;
b80f6443
JA
5638 }
5639
5640 return (0);
5641
5642 case MATCH_END:
495aee44 5643 for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
b80f6443 5644 {
a0c0a00f 5645 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
b80f6443
JA
5646 {
5647 *sp = indices[n];
5648 *ep = indices[wstrlen];
5649 return 1;
5650 }
495aee44
CR
5651 /* If MLEN != -1, we have a fixed length pattern. */
5652 if (mlen != -1)
5653 break;
b80f6443
JA
5654 }
5655
ccc6cda3 5656 return (0);
726f6388 5657 }
ccc6cda3
JA
5658
5659 return (0);
726f6388 5660}
a0c0a00f 5661#undef WFOLD
b80f6443
JA
5662#endif /* HANDLE_MULTIBYTE */
5663
5664static int
5665match_pattern (string, pat, mtype, sp, ep)
5666 char *string, *pat;
5667 int mtype;
5668 char **sp, **ep;
5669{
5670#if defined (HANDLE_MULTIBYTE)
5671 int ret;
5672 size_t n;
5673 wchar_t *wstring, *wpat;
5674 char **indices;
5675#endif
5676
a0c0a00f 5677 if (string == 0 || pat == 0 || *pat == 0)
b80f6443
JA
5678 return (0);
5679
5680#if defined (HANDLE_MULTIBYTE)
5681 if (MB_CUR_MAX > 1)
5682 {
495aee44 5683 if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
495aee44
CR
5684 return (match_upattern (string, pat, mtype, sp, ep));
5685
b80f6443
JA
5686 n = xdupmbstowcs (&wpat, NULL, pat);
5687 if (n == (size_t)-1)
5688 return (match_upattern (string, pat, mtype, sp, ep));
5689 n = xdupmbstowcs (&wstring, &indices, string);
5690 if (n == (size_t)-1)
5691 {
5692 free (wpat);
5693 return (match_upattern (string, pat, mtype, sp, ep));
5694 }
5695 ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
5696
5697 free (wpat);
5698 free (wstring);
5699 free (indices);
5700
5701 return (ret);
5702 }
5703 else
5704#endif
5705 return (match_upattern (string, pat, mtype, sp, ep));
5706}
726f6388 5707
cce855bc
JA
5708static int
5709getpatspec (c, value)
5710 int c;
5711 char *value;
5712{
5713 if (c == '#')
5714 return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
5715 else /* c == '%' */
5716 return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
5717}
5718
5719/* Posix.2 says that the WORD should be run through tilde expansion,
5720 parameter expansion, command substitution and arithmetic expansion.
5721 This leaves the result quoted, so quote_string_for_globbing () has
f73dda09 5722 to be called to fix it up for strmatch (). If QUOTED is non-zero,
cce855bc
JA
5723 it means that the entire expression was enclosed in double quotes.
5724 This means that quoting characters in the pattern do not make any
5725 special pattern characters quoted. For example, the `*' in the
5726 following retains its special meaning: "${foo#'*'}". */
5727static char *
5728getpattern (value, quoted, expandpat)
5729 char *value;
5730 int quoted, expandpat;
5731{
5732 char *pat, *tword;
5733 WORD_LIST *l;
0628567a 5734#if 0
cce855bc 5735 int i;
0628567a 5736#endif
7117c2d2
JA
5737 /* There is a problem here: how to handle single or double quotes in the
5738 pattern string when the whole expression is between double quotes?
5739 POSIX.2 says that enclosing double quotes do not cause the pattern to
5740 be quoted, but does that leave us a problem with @ and array[@] and their
5741 expansions inside a pattern? */
5742#if 0
cce855bc
JA
5743 if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
5744 {
5745 i = 0;
a0c0a00f 5746 pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ);
cce855bc
JA
5747 free (tword);
5748 tword = pat;
5749 }
7117c2d2 5750#endif
cce855bc 5751
d233b485 5752 /* expand_string_for_pat () leaves WORD quoted and does not perform
7117c2d2 5753 word splitting. */
d233b485 5754 l = *value ? expand_string_for_pat (value,
7117c2d2 5755 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
cce855bc 5756 (int *)NULL, (int *)NULL)
cce855bc 5757 : (WORD_LIST *)0;
36f2c406
CR
5758 if (l)
5759 word_list_remove_quoted_nulls (l);
cce855bc
JA
5760 pat = string_list (l);
5761 dispose_words (l);
5762 if (pat)
5763 {
5764 tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
5765 free (pat);
5766 pat = tword;
5767 }
5768 return (pat);
5769}
5770
7117c2d2 5771#if 0
cce855bc
JA
5772/* Handle removing a pattern from a string as a result of ${name%[%]value}
5773 or ${name#[#]value}. */
5774static char *
7117c2d2
JA
5775variable_remove_pattern (value, pattern, patspec, quoted)
5776 char *value, *pattern;
5777 int patspec, quoted;
cce855bc 5778{
7117c2d2 5779 char *tword;
cce855bc 5780
7117c2d2 5781 tword = remove_pattern (value, pattern, patspec);
cce855bc 5782
cce855bc
JA
5783 return (tword);
5784}
a0c0a00f
CR
5785#endif
5786
5787static char *
5788list_remove_pattern (list, pattern, patspec, itype, quoted)
5789 WORD_LIST *list;
5790 char *pattern;
5791 int patspec, itype, quoted;
5792{
5793 WORD_LIST *new, *l;
5794 WORD_DESC *w;
5795 char *tword;
5796
5797 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
5798 {
5799 tword = remove_pattern (l->word->word, pattern, patspec);
5800 w = alloc_word_desc ();
5801 w->word = tword ? tword : savestring ("");
5802 new = make_word_list (w, new);
5803 }
5804
5805 l = REVERSE_LIST (new, WORD_LIST *);
8868edaf 5806 tword = string_list_pos_params (itype, l, quoted, 0);
a0c0a00f
CR
5807 dispose_words (l);
5808
5809 return (tword);
5810}
5811
5812static char *
5813parameter_list_remove_pattern (itype, pattern, patspec, quoted)
5814 int itype;
5815 char *pattern;
5816 int patspec, quoted;
5817{
5818 char *ret;
5819 WORD_LIST *list;
5820
5821 list = list_rest_of_args ();
5822 if (list == 0)
5823 return ((char *)NULL);
5824 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5825 dispose_words (list);
5826 return (ret);
5827}
5828
5829#if defined (ARRAY_VARS)
5830static char *
8868edaf 5831array_remove_pattern (var, pattern, patspec, starsub, quoted)
a0c0a00f
CR
5832 SHELL_VAR *var;
5833 char *pattern;
5834 int patspec;
8868edaf 5835 int starsub; /* so we can figure out how it's indexed */
a0c0a00f
CR
5836 int quoted;
5837{
5838 ARRAY *a;
5839 HASH_TABLE *h;
5840 int itype;
5841 char *ret;
5842 WORD_LIST *list;
5843 SHELL_VAR *v;
5844
8868edaf 5845 v = var; /* XXX - for now */
a0c0a00f 5846
8868edaf 5847 itype = starsub ? '*' : '@';
a0c0a00f
CR
5848
5849 a = (v && array_p (v)) ? array_cell (v) : 0;
5850 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
5851
5852 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
5853 if (list == 0)
5854 return ((char *)NULL);
5855 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5856 dispose_words (list);
5857
5858 return ret;
5859}
5860#endif /* ARRAY_VARS */
5861
5862static char *
74091dd4 5863parameter_brace_remove_pattern (varname, value, estatep, patstr, rtype, quoted, flags)
a0c0a00f 5864 char *varname, *value;
74091dd4 5865 array_eltstate_t *estatep;
a0c0a00f
CR
5866 char *patstr;
5867 int rtype, quoted, flags;
5868{
5869 int vtype, patspec, starsub;
d233b485 5870 char *temp1, *val, *pattern, *oname;
a0c0a00f
CR
5871 SHELL_VAR *v;
5872
5873 if (value == 0)
5874 return ((char *)NULL);
5875
d233b485 5876 oname = this_command_name;
a0c0a00f
CR
5877 this_command_name = varname;
5878
74091dd4 5879 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
a0c0a00f 5880 if (vtype == -1)
d233b485
CR
5881 {
5882 this_command_name = oname;
5883 return ((char *)NULL);
5884 }
a0c0a00f
CR
5885
5886 starsub = vtype & VT_STARSUB;
5887 vtype &= ~VT_STARSUB;
5888
5889 patspec = getpatspec (rtype, patstr);
5890 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
5891 patstr++;
5892
5893 /* Need to pass getpattern newly-allocated memory in case of expansion --
5894 the expansion code will free the passed string on an error. */
5895 temp1 = savestring (patstr);
5896 pattern = getpattern (temp1, quoted, 1);
5897 free (temp1);
5898
5899 temp1 = (char *)NULL; /* shut up gcc */
5900 switch (vtype)
5901 {
5902 case VT_VARIABLE:
5903 case VT_ARRAYMEMBER:
5904 temp1 = remove_pattern (val, pattern, patspec);
5905 if (vtype == VT_VARIABLE)
5906 FREE (val);
5907 if (temp1)
5908 {
5909 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5910 ? quote_string (temp1)
5911 : quote_escapes (temp1);
5912 free (temp1);
5913 temp1 = val;
5914 }
5915 break;
5916#if defined (ARRAY_VARS)
5917 case VT_ARRAYVAR:
8868edaf 5918 temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted);
a0c0a00f
CR
5919 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5920 {
5921 val = quote_escapes (temp1);
5922 free (temp1);
5923 temp1 = val;
5924 }
5925 break;
5926#endif
5927 case VT_POSPARMS:
5928 temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
d233b485
CR
5929 if (temp1 && quoted == 0 && ifs_is_null)
5930 {
5931 /* Posix interp 888 */
5932 }
5933 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
a0c0a00f
CR
5934 {
5935 val = quote_escapes (temp1);
5936 free (temp1);
5937 temp1 = val;
5938 }
5939 break;
5940 }
5941
d233b485
CR
5942 this_command_name = oname;
5943
a0c0a00f
CR
5944 FREE (pattern);
5945 return temp1;
5946}
5947
d233b485 5948#if defined (PROCESS_SUBSTITUTION)
a0c0a00f 5949
8868edaf
CR
5950static void reap_some_procsubs PARAMS((int));
5951
d233b485
CR
5952/*****************************************************************/
5953/* */
5954/* Hacking Process Substitution */
5955/* */
5956/*****************************************************************/
5957
5958#if !defined (HAVE_DEV_FD)
5959/* Named pipes must be removed explicitly with `unlink'. This keeps a list
5960 of FIFOs the shell has open. unlink_fifo_list will walk the list and
8868edaf
CR
5961 unlink the ones that don't have a living process on the other end.
5962 unlink_all_fifos will walk the list and unconditionally unlink them, trying
5963 to open and close the FIFO first to release any child processes sleeping on
5964 the FIFO. add_fifo_list adds the name of an open FIFO to the list.
5965 NFIFO is a count of the number of FIFOs in the list. */
d233b485
CR
5966#define FIFO_INCR 20
5967
5968/* PROC value of -1 means the process has been reaped and the FIFO needs to
5969 be removed. PROC value of 0 means the slot is unused. */
5970struct temp_fifo {
5971 char *file;
5972 pid_t proc;
5973};
5974
5975static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
5976static int nfifo;
5977static int fifo_list_size;
5978
5979void
5980clear_fifo_list ()
a0c0a00f 5981{
8868edaf
CR
5982 int i;
5983
5984 for (i = 0; i < fifo_list_size; i++)
5985 {
5986 if (fifo_list[i].file)
5987 free (fifo_list[i].file);
5988 fifo_list[i].file = NULL;
5989 fifo_list[i].proc = 0;
5990 }
5991 nfifo = 0;
d233b485 5992}
a0c0a00f 5993
9e49d343 5994void *
d233b485
CR
5995copy_fifo_list (sizep)
5996 int *sizep;
5997{
5998 if (sizep)
5999 *sizep = 0;
9e49d343 6000 return (void *)NULL;
d233b485
CR
6001}
6002
6003static void
6004add_fifo_list (pathname)
6005 char *pathname;
6006{
6007 int osize, i;
6008
6009 if (nfifo >= fifo_list_size - 1)
a0c0a00f 6010 {
d233b485
CR
6011 osize = fifo_list_size;
6012 fifo_list_size += FIFO_INCR;
6013 fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
6014 fifo_list_size * sizeof (struct temp_fifo));
6015 for (i = osize; i < fifo_list_size; i++)
6016 {
6017 fifo_list[i].file = (char *)NULL;
6018 fifo_list[i].proc = 0; /* unused */
6019 }
a0c0a00f 6020 }
d233b485
CR
6021
6022 fifo_list[nfifo].file = savestring (pathname);
6023 nfifo++;
a0c0a00f 6024}
a0c0a00f 6025
d233b485
CR
6026void
6027unlink_fifo (i)
6028 int i;
a0c0a00f 6029{
d233b485
CR
6030 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
6031 {
6032 unlink (fifo_list[i].file);
6033 free (fifo_list[i].file);
6034 fifo_list[i].file = (char *)NULL;
6035 fifo_list[i].proc = 0;
6036 }
a0c0a00f
CR
6037}
6038
d233b485
CR
6039void
6040unlink_fifo_list ()
a0c0a00f 6041{
d233b485 6042 int saved, i, j;
a0c0a00f 6043
d233b485
CR
6044 if (nfifo == 0)
6045 return;
a0c0a00f 6046
d233b485 6047 for (i = saved = 0; i < nfifo; i++)
a0c0a00f 6048 {
d233b485
CR
6049 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
6050 {
6051 unlink (fifo_list[i].file);
6052 free (fifo_list[i].file);
6053 fifo_list[i].file = (char *)NULL;
6054 fifo_list[i].proc = 0;
6055 }
6056 else
6057 saved++;
a0c0a00f 6058 }
d233b485
CR
6059
6060 /* If we didn't remove some of the FIFOs, compact the list. */
6061 if (saved)
6062 {
6063 for (i = j = 0; i < nfifo; i++)
6064 if (fifo_list[i].file)
6065 {
9e49d343
CR
6066 if (i != j)
6067 {
6068 fifo_list[j].file = fifo_list[i].file;
6069 fifo_list[j].proc = fifo_list[i].proc;
6070 fifo_list[i].file = (char *)NULL;
6071 fifo_list[i].proc = 0;
6072 }
d233b485
CR
6073 j++;
6074 }
6075 nfifo = j;
6076 }
6077 else
6078 nfifo = 0;
a0c0a00f 6079}
cce855bc 6080
8868edaf
CR
6081void
6082unlink_all_fifos ()
6083{
6084 int i, fd;
6085
6086 if (nfifo == 0)
6087 return;
6088
6089 for (i = 0; i < nfifo; i++)
6090 {
6091 fifo_list[i].proc = (pid_t)-1;
74091dd4 6092#if defined (O_NONBLOCK)
8868edaf 6093 fd = open (fifo_list[i].file, O_RDWR|O_NONBLOCK);
74091dd4
CR
6094#else
6095 fd = -1;
6096#endif
8868edaf
CR
6097 unlink_fifo (i);
6098 if (fd >= 0)
6099 close (fd);
6100 }
6101
6102 nfifo = 0;
6103}
6104
d233b485
CR
6105/* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
6106 from some point in the past, and close all open FIFOs in fifo_list
6107 that are not marked as active in LIST. If LIST is NULL, close
6108 everything in fifo_list. LSIZE is the number of elements in LIST, in
6109 case it's larger than fifo_list_size (size of fifo_list). */
6110void
6111close_new_fifos (list, lsize)
9e49d343 6112 void *list;
d233b485 6113 int lsize;
cce855bc 6114{
d233b485 6115 int i;
9e49d343 6116 char *plist;
cce855bc 6117
d233b485 6118 if (list == 0)
cce855bc 6119 {
d233b485
CR
6120 unlink_fifo_list ();
6121 return;
cce855bc
JA
6122 }
6123
9e49d343
CR
6124 for (plist = (char *)list, i = 0; i < lsize; i++)
6125 if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
d233b485 6126 unlink_fifo (i);
3185942a 6127
d233b485
CR
6128 for (i = lsize; i < fifo_list_size; i++)
6129 unlink_fifo (i);
cce855bc
JA
6130}
6131
d233b485
CR
6132int
6133find_procsub_child (pid)
6134 pid_t pid;
cce855bc 6135{
d233b485 6136 int i;
cce855bc 6137
d233b485
CR
6138 for (i = 0; i < nfifo; i++)
6139 if (fifo_list[i].proc == pid)
6140 return i;
6141 return -1;
cce855bc
JA
6142}
6143
d233b485
CR
6144void
6145set_procsub_status (ind, pid, status)
6146 int ind;
6147 pid_t pid;
6148 int status;
cce855bc 6149{
d233b485
CR
6150 if (ind >= 0 && ind < nfifo)
6151 fifo_list[ind].proc = (pid_t)-1; /* sentinel */
6152}
ac50fbac 6153
d233b485
CR
6154/* If we've marked the process for this procsub as dead, close the
6155 associated file descriptor and delete the FIFO. */
8868edaf
CR
6156static void
6157reap_some_procsubs (max)
6158 int max;
d233b485
CR
6159{
6160 int i;
7117c2d2 6161
8868edaf 6162 for (i = 0; i < max; i++)
d233b485
CR
6163 if (fifo_list[i].proc == (pid_t)-1) /* reaped */
6164 unlink_fifo (i);
6165}
a0c0a00f 6166
8868edaf
CR
6167void
6168reap_procsubs ()
6169{
6170 reap_some_procsubs (nfifo);
6171}
6172
6173#if 0
6174/* UNUSED */
d233b485
CR
6175void
6176wait_procsubs ()
6177{
6178 int i, r;
7117c2d2 6179
d233b485
CR
6180 for (i = 0; i < nfifo; i++)
6181 {
6182 if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0)
6183 {
8868edaf
CR
6184 r = wait_for (fifo_list[i].proc, 0);
6185 save_proc_status (fifo_list[i].proc, r);
d233b485
CR
6186 fifo_list[i].proc = (pid_t)-1;
6187 }
6188 }
7117c2d2 6189}
8868edaf 6190#endif
7117c2d2 6191
d233b485
CR
6192int
6193fifos_pending ()
7117c2d2 6194{
d233b485
CR
6195 return nfifo;
6196}
7117c2d2 6197
d233b485
CR
6198int
6199num_fifos ()
6200{
6201 return nfifo;
6202}
cce855bc 6203
d233b485
CR
6204static char *
6205make_named_pipe ()
6206{
6207 char *tname;
cce855bc 6208
d233b485
CR
6209 tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
6210 if (mkfifo (tname, 0600) < 0)
cce855bc 6211 {
d233b485
CR
6212 free (tname);
6213 return ((char *)NULL);
cce855bc
JA
6214 }
6215
d233b485
CR
6216 add_fifo_list (tname);
6217 return (tname);
a0c0a00f 6218}
cce855bc 6219
d233b485 6220#else /* HAVE_DEV_FD */
726f6388 6221
d233b485
CR
6222/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
6223 has open to children. NFDS is a count of the number of bits currently
6224 set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
6225 of open files. */
6226/* dev_fd_list[I] value of -1 means the process has been reaped and file
6227 descriptor I needs to be closed. Value of 0 means the slot is unused. */
726f6388 6228
d233b485
CR
6229static pid_t *dev_fd_list = (pid_t *)NULL;
6230static int nfds;
6231static int totfds; /* The highest possible number of open files. */
726f6388 6232
d233b485
CR
6233void
6234clear_fifo (i)
6235 int i;
726f6388 6236{
d233b485
CR
6237 if (dev_fd_list[i])
6238 {
6239 dev_fd_list[i] = 0;
6240 nfds--;
6241 }
726f6388
JA
6242}
6243
d233b485
CR
6244void
6245clear_fifo_list ()
726f6388 6246{
d233b485 6247 register int i;
726f6388 6248
d233b485
CR
6249 if (nfds == 0)
6250 return;
f73dda09 6251
d233b485
CR
6252 for (i = 0; nfds && i < totfds; i++)
6253 clear_fifo (i);
726f6388 6254
d233b485 6255 nfds = 0;
a0c0a00f
CR
6256}
6257
9e49d343 6258void *
495aee44
CR
6259copy_fifo_list (sizep)
6260 int *sizep;
6261{
9e49d343 6262 void *ret;
d233b485
CR
6263
6264 if (nfds == 0 || totfds == 0)
6265 {
6266 if (sizep)
6267 *sizep = 0;
9e49d343 6268 return (void *)NULL;
d233b485
CR
6269 }
6270
495aee44 6271 if (sizep)
d233b485 6272 *sizep = totfds;
9e49d343 6273 ret = xmalloc (totfds * sizeof (pid_t));
d233b485 6274 return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t)));
495aee44
CR
6275}
6276
726f6388 6277static void
d233b485
CR
6278add_fifo_list (fd)
6279 int fd;
726f6388 6280{
d233b485 6281 if (dev_fd_list == 0 || fd >= totfds)
726f6388 6282 {
d233b485
CR
6283 int ofds;
6284
6285 ofds = totfds;
6286 totfds = getdtablesize ();
6287 if (totfds < 0 || totfds > 256)
6288 totfds = 256;
6289 if (fd >= totfds)
6290 totfds = fd + 2;
6291
6292 dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0]));
6293 /* XXX - might need a loop for this */
6294 memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t));
726f6388
JA
6295 }
6296
d233b485
CR
6297 dev_fd_list[fd] = 1; /* marker; updated later */
6298 nfds++;
6299}
6300
6301int
6302fifos_pending ()
6303{
6304 return 0; /* used for cleanup; not needed with /dev/fd */
6305}
6306
6307int
6308num_fifos ()
6309{
6310 return nfds;
726f6388
JA
6311}
6312
495aee44 6313void
d233b485
CR
6314unlink_fifo (fd)
6315 int fd;
495aee44 6316{
d233b485 6317 if (dev_fd_list[fd])
495aee44 6318 {
d233b485
CR
6319 close (fd);
6320 dev_fd_list[fd] = 0;
6321 nfds--;
495aee44
CR
6322 }
6323}
6324
726f6388
JA
6325void
6326unlink_fifo_list ()
6327{
d233b485 6328 register int i;
f73dda09 6329
d233b485 6330 if (nfds == 0)
726f6388
JA
6331 return;
6332
d233b485
CR
6333 for (i = totfds-1; nfds && i >= 0; i--)
6334 unlink_fifo (i);
f73dda09 6335
d233b485 6336 nfds = 0;
726f6388
JA
6337}
6338
8868edaf
CR
6339void
6340unlink_all_fifos ()
6341{
6342 unlink_fifo_list ();
6343}
6344
d233b485
CR
6345/* Take LIST, which is a snapshot copy of dev_fd_list from some point in
6346 the past, and close all open fds in dev_fd_list that are not marked
6347 as open in LIST. If LIST is NULL, close everything in dev_fd_list.
6348 LSIZE is the number of elements in LIST, in case it's larger than
6349 totfds (size of dev_fd_list). */
495aee44
CR
6350void
6351close_new_fifos (list, lsize)
9e49d343 6352 void *list;
495aee44
CR
6353 int lsize;
6354{
6355 int i;
9e49d343 6356 pid_t *plist;
495aee44
CR
6357
6358 if (list == 0)
6359 {
6360 unlink_fifo_list ();
6361 return;
6362 }
6363
9e49d343
CR
6364 for (plist = (pid_t *)list, i = 0; i < lsize; i++)
6365 if (plist[i] == 0 && i < totfds && dev_fd_list[i])
495aee44
CR
6366 unlink_fifo (i);
6367
d233b485 6368 for (i = lsize; i < totfds; i++)
495aee44
CR
6369 unlink_fifo (i);
6370}
6371
f1be666c 6372int
d233b485
CR
6373find_procsub_child (pid)
6374 pid_t pid;
a0c0a00f 6375{
d233b485 6376 int i;
a0c0a00f
CR
6377
6378 if (nfds == 0)
d233b485 6379 return -1;
726f6388 6380
d233b485
CR
6381 for (i = 0; i < totfds; i++)
6382 if (dev_fd_list[i] == pid)
6383 return i;
f1be666c 6384
d233b485 6385 return -1;
495aee44
CR
6386}
6387
6388void
d233b485
CR
6389set_procsub_status (ind, pid, status)
6390 int ind;
6391 pid_t pid;
6392 int status;
495aee44 6393{
d233b485
CR
6394 if (ind >= 0 && ind < totfds)
6395 dev_fd_list[ind] = (pid_t)-1; /* sentinel */
495aee44
CR
6396}
6397
d233b485
CR
6398/* If we've marked the process for this procsub as dead, close the
6399 associated file descriptor. */
8868edaf
CR
6400static void
6401reap_some_procsubs (max)
6402 int max;
726f6388 6403{
d233b485 6404 int i;
726f6388 6405
8868edaf 6406 for (i = 0; nfds > 0 && i < max; i++)
d233b485
CR
6407 if (dev_fd_list[i] == (pid_t)-1)
6408 unlink_fifo (i);
726f6388
JA
6409}
6410
8868edaf
CR
6411void
6412reap_procsubs ()
6413{
6414 reap_some_procsubs (totfds);
6415}
6416
6417#if 0
6418/* UNUSED */
495aee44 6419void
d233b485 6420wait_procsubs ()
495aee44 6421{
d233b485 6422 int i, r;
495aee44 6423
d233b485 6424 for (i = 0; nfds > 0 && i < totfds; i++)
495aee44 6425 {
d233b485
CR
6426 if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0)
6427 {
8868edaf
CR
6428 r = wait_for (dev_fd_list[i], 0);
6429 save_proc_status (dev_fd_list[i], r);
d233b485
CR
6430 dev_fd_list[i] = (pid_t)-1;
6431 }
495aee44 6432 }
495aee44 6433}
8868edaf 6434#endif
495aee44 6435
726f6388
JA
6436#if defined (NOTDEF)
6437print_dev_fd_list ()
6438{
6439 register int i;
6440
f73dda09 6441 fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
726f6388
JA
6442 fflush (stderr);
6443
6444 for (i = 0; i < totfds; i++)
6445 {
6446 if (dev_fd_list[i])
6447 fprintf (stderr, " %d", i);
6448 }
6449 fprintf (stderr, "\n");
6450}
6451#endif /* NOTDEF */
6452
6453static char *
6454make_dev_fd_filename (fd)
6455 int fd;
6456{
f73dda09 6457 char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
726f6388 6458
17345e5a 6459 ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
bb70624e
JA
6460
6461 strcpy (ret, DEV_FD_PREFIX);
6462 p = inttostr (fd, intbuf, sizeof (intbuf));
6463 strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
6464
726f6388
JA
6465 add_fifo_list (fd);
6466 return (ret);
6467}
6468
6469#endif /* HAVE_DEV_FD */
6470
6471/* Return a filename that will open a connection to the process defined by
6472 executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
6473 a filename in /dev/fd corresponding to a descriptor that is one of the
6474 ends of the pipe. If not defined, we use named pipes on systems that have
6475 them. Systems without /dev/fd and named pipes are out of luck.
6476
6477 OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
6478 use the read end of the pipe and dup that file descriptor to fd 0 in
6479 the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
6480 writing or use the write end of the pipe in the child, and dup that
6481 file descriptor to fd 1 in the child. The parent does the opposite. */
6482
6483static char *
6484process_substitute (string, open_for_read_in_child)
6485 char *string;
6486 int open_for_read_in_child;
6487{
6488 char *pathname;
d233b485 6489 int fd, result, rc, function_value;
726f6388
JA
6490 pid_t old_pid, pid;
6491#if defined (HAVE_DEV_FD)
6492 int parent_pipe_fd, child_pipe_fd;
6493 int fildes[2];
6494#endif /* HAVE_DEV_FD */
6495#if defined (JOB_CONTROL)
6496 pid_t old_pipeline_pgrp;
ccc6cda3 6497#endif
726f6388 6498
cce855bc 6499 if (!string || !*string || wordexp_only)
726f6388
JA
6500 return ((char *)NULL);
6501
6502#if !defined (HAVE_DEV_FD)
6503 pathname = make_named_pipe ();
6504#else /* HAVE_DEV_FD */
6505 if (pipe (fildes) < 0)
6506 {
a0c0a00f 6507 sys_error ("%s", _("cannot make pipe for process substitution"));
726f6388
JA
6508 return ((char *)NULL);
6509 }
6510 /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
6511 the pipe in the parent, otherwise the read end. */
6512 parent_pipe_fd = fildes[open_for_read_in_child];
6513 child_pipe_fd = fildes[1 - open_for_read_in_child];
d166f048
JA
6514 /* Move the parent end of the pipe to some high file descriptor, to
6515 avoid clashes with FDs used by the script. */
6516 parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
6517
726f6388
JA
6518 pathname = make_dev_fd_filename (parent_pipe_fd);
6519#endif /* HAVE_DEV_FD */
6520
3185942a 6521 if (pathname == 0)
726f6388 6522 {
a0c0a00f 6523 sys_error ("%s", _("cannot make pipe for process substitution"));
726f6388
JA
6524 return ((char *)NULL);
6525 }
6526
6527 old_pid = last_made_pid;
6528
6529#if defined (JOB_CONTROL)
6530 old_pipeline_pgrp = pipeline_pgrp;
a0c0a00f
CR
6531 if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0)
6532 pipeline_pgrp = shell_pgrp;
ccc6cda3 6533 save_pipeline (1);
ccc6cda3
JA
6534#endif /* JOB_CONTROL */
6535
8868edaf 6536 pid = make_child ((char *)NULL, FORK_ASYNC);
726f6388
JA
6537 if (pid == 0)
6538 {
8868edaf
CR
6539#if 0
6540 int old_interactive;
6541
6542 old_interactive = interactive;
6543#endif
6544 /* The currently-executing shell is not interactive */
6545 interactive = 0;
6546
ccc6cda3 6547 reset_terminating_signals (); /* XXX */
b80f6443 6548 free_pushed_string_input ();
726f6388 6549 /* Cancel traps, in trap.c. */
495aee44 6550 restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */
15409324 6551 subshell_environment &= ~SUBSHELL_IGNTRAP;
a0c0a00f 6552 QUIT; /* catch any interrupts we got post-fork */
726f6388 6553 setup_async_signals ();
8868edaf
CR
6554#if 0
6555 if (open_for_read_in_child == 0 && old_interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))
6556 async_redirect_stdin ();
6557#endif
6558
6559 subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB|SUBSHELL_ASYNC;
a0c0a00f 6560
d233b485
CR
6561 /* We don't inherit the verbose option for command substitutions now, so
6562 let's try it for process substitutions. */
6563 change_flag ('v', FLAG_OFF);
6564
a0c0a00f
CR
6565 /* if we're expanding a redirection, we shouldn't have access to the
6566 temporary environment, but commands in the subshell should have
6567 access to their own temporary environment. */
6568 if (expanding_redir)
6569 flush_temporary_env ();
726f6388 6570 }
ccc6cda3
JA
6571
6572#if defined (JOB_CONTROL)
726f6388
JA
6573 set_sigchld_handler ();
6574 stop_making_children ();
3185942a 6575 /* XXX - should we only do this in the parent? (as in command subst) */
726f6388 6576 pipeline_pgrp = old_pipeline_pgrp;
a0c0a00f
CR
6577#else
6578 stop_making_children ();
ccc6cda3 6579#endif /* JOB_CONTROL */
726f6388
JA
6580
6581 if (pid < 0)
6582 {
a0c0a00f 6583 sys_error ("%s", _("cannot make child for process substitution"));
726f6388
JA
6584 free (pathname);
6585#if defined (HAVE_DEV_FD)
6586 close (parent_pipe_fd);
6587 close (child_pipe_fd);
6588#endif /* HAVE_DEV_FD */
d233b485
CR
6589#if defined (JOB_CONTROL)
6590 restore_pipeline (1);
6591#endif
726f6388
JA
6592 return ((char *)NULL);
6593 }
6594
6595 if (pid > 0)
6596 {
ccc6cda3 6597#if defined (JOB_CONTROL)
a0c0a00f 6598 last_procsub_child = restore_pipeline (0);
8868edaf
CR
6599 /* We assume that last_procsub_child->next == last_procsub_child because
6600 of how jobs.c:add_process() works. */
6601 last_procsub_child->next = 0;
6602 procsub_add (last_procsub_child);
ccc6cda3
JA
6603#endif
6604
d233b485
CR
6605#if defined (HAVE_DEV_FD)
6606 dev_fd_list[parent_pipe_fd] = pid;
6607#else
f73dda09
JA
6608 fifo_list[nfifo-1].proc = pid;
6609#endif
6610
726f6388
JA
6611 last_made_pid = old_pid;
6612
6613#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
6614 close_pgrp_pipe ();
6615#endif /* JOB_CONTROL && PGRP_PIPE */
6616
6617#if defined (HAVE_DEV_FD)
6618 close (child_pipe_fd);
6619#endif /* HAVE_DEV_FD */
6620
6621 return (pathname);
6622 }
6623
6624 set_sigint_handler ();
6625
6626#if defined (JOB_CONTROL)
d233b485 6627 /* make sure we don't have any job control */
726f6388 6628 set_job_control (0);
d233b485 6629
8868edaf
CR
6630 /* Clear out any existing list of process substitutions */
6631 procsub_clear ();
6632
d233b485
CR
6633 /* The idea is that we want all the jobs we start from an async process
6634 substitution to be in the same process group, but not the same pgrp
6635 as our parent shell, since we don't want to affect our parent shell's
6636 jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example.
6637 If pipeline_pgrp != shell_pgrp, we assume that there is a job control
6638 shell somewhere in our parent process chain (since make_child initializes
6639 pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this
6640 case is to set pipeline_pgrp to our PID, so all jobs started by this
6641 process have that same pgrp and we are basically the process group leader.
6642 This should not have negative effects on child processes surviving
6643 after we exit, since we wait for the children we create, but that is
6644 something to watch for. */
6645
6646 if (pipeline_pgrp != shell_pgrp)
6647 pipeline_pgrp = getpid ();
726f6388
JA
6648#endif /* JOB_CONTROL */
6649
6650#if !defined (HAVE_DEV_FD)
6651 /* Open the named pipe in the child. */
ac50fbac 6652 fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY);
726f6388
JA
6653 if (fd < 0)
6654 {
b80f6443
JA
6655 /* Two separate strings for ease of translation. */
6656 if (open_for_read_in_child)
6657 sys_error (_("cannot open named pipe %s for reading"), pathname);
6658 else
6659 sys_error (_("cannot open named pipe %s for writing"), pathname);
6660
726f6388
JA
6661 exit (127);
6662 }
bb70624e
JA
6663 if (open_for_read_in_child)
6664 {
28ef6c31 6665 if (sh_unset_nodelay_mode (fd) < 0)
bb70624e 6666 {
3185942a 6667 sys_error (_("cannot reset nodelay mode for fd %d"), fd);
bb70624e
JA
6668 exit (127);
6669 }
6670 }
726f6388
JA
6671#else /* HAVE_DEV_FD */
6672 fd = child_pipe_fd;
6673#endif /* HAVE_DEV_FD */
6674
a0c0a00f
CR
6675 /* Discard buffered stdio output before replacing the underlying file
6676 descriptor. */
6677 if (open_for_read_in_child == 0)
6678 fpurge (stdout);
6679
726f6388
JA
6680 if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
6681 {
b80f6443 6682 sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
ccc6cda3 6683 open_for_read_in_child ? 0 : 1);
726f6388
JA
6684 exit (127);
6685 }
6686
f73dda09
JA
6687 if (fd != (open_for_read_in_child ? 0 : 1))
6688 close (fd);
726f6388
JA
6689
6690 /* Need to close any files that this process has open to pipes inherited
6691 from its parent. */
6692 if (current_fds_to_close)
6693 {
6694 close_fd_bitmap (current_fds_to_close);
6695 current_fds_to_close = (struct fd_bitmap *)NULL;
6696 }
6697
6698#if defined (HAVE_DEV_FD)
6699 /* Make sure we close the parent's end of the pipe and clear the slot
6700 in the fd list so it is not closed later, if reallocated by, for
6701 instance, pipe(2). */
6702 close (parent_pipe_fd);
6703 dev_fd_list[parent_pipe_fd] = 0;
6704#endif /* HAVE_DEV_FD */
6705
8dea6e87 6706 /* subshells shouldn't have this flag, which controls using the temporary
a0c0a00f
CR
6707 environment for variable lookups. We have already flushed the temporary
6708 environment above in the case we're expanding a redirection, so processes
6709 executed by this command need to be able to set it independently of their
6710 parent. */
8dea6e87
CR
6711 expanding_redir = 0;
6712
9cce630e
CR
6713 remove_quoted_escapes (string);
6714
8868edaf
CR
6715 startup_state = 2; /* see if we can avoid a fork */
6716 parse_and_execute_level = 0;
8868edaf 6717
d233b485
CR
6718 /* Give process substitution a place to jump back to on failure,
6719 so we don't go back up to main (). */
6720 result = setjmp_nosigs (top_level);
6721
6722 /* If we're running a process substitution inside a shell function,
6723 trap `return' so we don't return from the function in the subshell
6724 and go off to never-never land. */
6725 if (result == 0 && return_catch_flag)
6726 function_value = setjmp_nosigs (return_catch);
6727 else
6728 function_value = 0;
6729
6730 if (result == ERREXIT)
6731 rc = last_command_exit_value;
74091dd4 6732 else if (result == EXITPROG || result == EXITBLTIN)
d233b485
CR
6733 rc = last_command_exit_value;
6734 else if (result)
6735 rc = EXECUTION_FAILURE;
6736 else if (function_value)
6737 rc = return_catch_value;
6738 else
6739 {
6740 subshell_level++;
6741 rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
6742 /* leave subshell level intact for any exit trap */
6743 }
726f6388
JA
6744
6745#if !defined (HAVE_DEV_FD)
6746 /* Make sure we close the named pipe in the child before we exit. */
6747 close (open_for_read_in_child ? 0 : 1);
6748#endif /* !HAVE_DEV_FD */
6749
d233b485
CR
6750 last_command_exit_value = rc;
6751 rc = run_exit_trap ();
6752 exit (rc);
726f6388
JA
6753 /*NOTREACHED*/
6754}
6755#endif /* PROCESS_SUBSTITUTION */
6756
cce855bc
JA
6757/***********************************/
6758/* */
6759/* Command Substitution */
6760/* */
6761/***********************************/
6762
74091dd4
CR
6763#define COMSUB_PIPEBUF 4096
6764
6765static char *
6766optimize_cat_file (r, quoted, flags, flagp)
6767 REDIRECT *r;
6768 int quoted, flags, *flagp;
6769{
6770 char *ret;
6771 int fd;
6772
6773 fd = open_redir_file (r, (char **)0);
6774 if (fd < 0)
6775 return &expand_param_error;
6776
6777 ret = read_comsub (fd, quoted, flags, flagp);
6778 close (fd);
6779
6780 return ret;
6781}
6782
d166f048 6783static char *
d233b485
CR
6784read_comsub (fd, quoted, flags, rflag)
6785 int fd, quoted, flags;
3185942a 6786 int *rflag;
d166f048 6787{
74091dd4
CR
6788 char *istring, buf[COMSUB_PIPEBUF], *bufp;
6789 int c, tflag, skip_ctlesc, skip_ctlnul;
8868edaf 6790 int mb_cur_max;
74091dd4 6791 size_t istring_index;
d233b485 6792 size_t istring_size;
f73dda09 6793 ssize_t bufn;
280bd77d 6794 int nullbyte;
8868edaf
CR
6795#if defined (HANDLE_MULTIBYTE)
6796 mbstate_t ps;
6797 wchar_t wc;
6798 size_t mblen;
6799 int i;
6800#endif
d166f048
JA
6801
6802 istring = (char *)NULL;
3185942a
JA
6803 istring_index = istring_size = bufn = tflag = 0;
6804
d233b485
CR
6805 skip_ctlesc = ifs_cmap[CTLESC];
6806 skip_ctlnul = ifs_cmap[CTLNUL];
d166f048 6807
8868edaf 6808 mb_cur_max = MB_CUR_MAX;
280bd77d
CR
6809 nullbyte = 0;
6810
8868edaf 6811 /* Read the output of the command through the pipe. */
d166f048
JA
6812 while (1)
6813 {
6814 if (fd < 0)
28ef6c31 6815 break;
d166f048
JA
6816 if (--bufn <= 0)
6817 {
bb70624e 6818 bufn = zread (fd, buf, sizeof (buf));
d166f048
JA
6819 if (bufn <= 0)
6820 break;
6821 bufp = buf;
6822 }
6823 c = *bufp++;
6824
28ef6c31
JA
6825 if (c == 0)
6826 {
a0c0a00f 6827#if 1
280bd77d
CR
6828 if (nullbyte == 0)
6829 {
6830 internal_warning ("%s", _("command substitution: ignored null byte in input"));
6831 nullbyte = 1;
6832 }
28ef6c31
JA
6833#endif
6834 continue;
6835 }
6836
d166f048 6837 /* Add the character to ISTRING, possibly after resizing it. */
8868edaf 6838 RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512);
d166f048 6839
f1be666c
JA
6840 /* This is essentially quote_string inline */
6841 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
6842 istring[istring_index++] = CTLESC;
d233b485
CR
6843 else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC)
6844 istring[istring_index++] = CTLESC;
f1be666c
JA
6845 /* Escape CTLESC and CTLNUL in the output to protect those characters
6846 from the rest of the word expansions (word splitting and globbing.)
6847 This is essentially quote_escapes inline. */
3185942a 6848 else if (skip_ctlesc == 0 && c == CTLESC)
d233b485 6849 istring[istring_index++] = CTLESC;
3185942a 6850 else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
d166f048
JA
6851 istring[istring_index++] = CTLESC;
6852
8868edaf
CR
6853#if defined (HANDLE_MULTIBYTE)
6854 if ((locale_utf8locale && (c & 0x80)) ||
6855 (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127))
6856 {
6857 /* read a multibyte character from buf */
6858 /* punt on the hard case for now */
6859 memset (&ps, '\0', sizeof (mbstate_t));
72912fb8 6860 mblen = mbrtowc (&wc, bufp-1, bufn, &ps);
8868edaf
CR
6861 if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1)
6862 istring[istring_index++] = c;
6863 else
6864 {
6865 istring[istring_index++] = c;
6866 for (i = 0; i < mblen-1; i++)
6867 istring[istring_index++] = *bufp++;
6868 bufn -= mblen - 1;
6869 }
6870 continue;
28ef6c31
JA
6871 }
6872#endif
8868edaf
CR
6873
6874 istring[istring_index++] = c;
d166f048
JA
6875 }
6876
6877 if (istring)
6878 istring[istring_index] = '\0';
6879
6880 /* If we read no output, just return now and save ourselves some
6881 trouble. */
6882 if (istring_index == 0)
6883 {
6884 FREE (istring);
3185942a
JA
6885 if (rflag)
6886 *rflag = tflag;
d166f048
JA
6887 return (char *)NULL;
6888 }
6889
6890 /* Strip trailing newlines from the output of the command. */
6891 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6892 {
6893 while (istring_index > 0)
6894 {
6895 if (istring[istring_index - 1] == '\n')
6896 {
6897 --istring_index;
6898
6899 /* If the newline was quoted, remove the quoting char. */
6900 if (istring[istring_index - 1] == CTLESC)
6901 --istring_index;
6902 }
6903 else
6904 break;
6905 }
6906 istring[istring_index] = '\0';
6907 }
6908 else
6909 strip_trailing (istring, istring_index - 1, 1);
6910
3185942a
JA
6911 if (rflag)
6912 *rflag = tflag;
d166f048
JA
6913 return istring;
6914}
6915
3185942a
JA
6916/* Perform command substitution on STRING. This returns a WORD_DESC * with the
6917 contained string possibly quoted. */
6918WORD_DESC *
d233b485 6919command_substitute (string, quoted, flags)
726f6388
JA
6920 char *string;
6921 int quoted;
d233b485 6922 int flags;
726f6388 6923{
95732b49 6924 pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
a0c0a00f 6925 char *istring, *s;
8868edaf 6926 int result, fildes[2], function_value, pflags, rc, tflag, fork_flags;
3185942a 6927 WORD_DESC *ret;
8868edaf 6928 sigset_t set, oset;
726f6388 6929
ccc6cda3 6930 istring = (char *)NULL;
726f6388
JA
6931
6932 /* Don't fork () if there is no need to. In the case of no command to
6933 run, just return NULL. */
a0c0a00f
CR
6934 for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++)
6935 ;
6936 if (s == 0 || *s == 0)
6937 return ((WORD_DESC *)NULL);
74091dd4
CR
6938
6939 if (*s == '<' && (s[1] != '<' && s[1] != '>' && s[1] != '&'))
6940 {
6941 COMMAND *cmd;
6942
6943 cmd = parse_string_to_command (string, 0); /* XXX - flags */
6944 if (cmd && can_optimize_cat_file (cmd))
6945 {
6946 tflag = 0;
6947 istring = optimize_cat_file (cmd->value.Simple->redirects, quoted, flags, &tflag);
6948 if (istring == &expand_param_error)
6949 {
6950 last_command_exit_value = EXECUTION_FAILURE;
6951 istring = 0;
6952 }
6953 else
6954 last_command_exit_value = EXECUTION_SUCCESS; /* compat */
6955 last_command_subst_pid = dollar_dollar_pid;
6956
6957 dispose_command (cmd);
6958 ret = alloc_word_desc ();
6959 ret->word = istring;
6960 ret->flags = tflag;
6961
6962 return ret;
6963 }
6964 dispose_command (cmd);
6965 }
726f6388 6966
cce855bc
JA
6967 if (wordexp_only && read_but_dont_execute)
6968 {
0001803f 6969 last_command_exit_value = EX_WEXPCOMSUB;
cce855bc
JA
6970 jump_to_top_level (EXITPROG);
6971 }
6972
bb70624e
JA
6973 /* We're making the assumption here that the command substitution will
6974 eventually run a command from the file system. Since we'll run
6975 maybe_make_export_env in this subshell before executing that command,
6976 the parent shell and any other shells it starts will have to remake
6977 the environment. If we make it before we fork, other shells won't
6978 have to. Don't bother if we have any temporary variable assignments,
6979 though, because the export environment will be remade after this
6980 command completes anyway, but do it if all the words to be expanded
6981 are variable assignments. */
6982 if (subst_assign_varlist == 0 || garglist == 0)
6983 maybe_make_export_env (); /* XXX */
6984
b80f6443 6985 /* Flags to pass to parse_and_execute() */
0001803f 6986 pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
b80f6443 6987
d233b485
CR
6988 old_pid = last_made_pid;
6989
726f6388
JA
6990 /* Pipe the output of executing STRING into the current shell. */
6991 if (pipe (fildes) < 0)
6992 {
a0c0a00f 6993 sys_error ("%s", _("cannot make pipe for command substitution"));
726f6388
JA
6994 goto error_exit;
6995 }
6996
726f6388 6997#if defined (JOB_CONTROL)
ccc6cda3 6998 old_pipeline_pgrp = pipeline_pgrp;
a042c731
CR
6999 /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline or
7000 we've already forked to run a disk command (and are expanding redirections,
7001 for example). */
7002 if ((subshell_environment & (SUBSHELL_FORK|SUBSHELL_PIPE)) == 0)
28ef6c31 7003 pipeline_pgrp = shell_pgrp;
ccc6cda3 7004 cleanup_the_pipeline ();
95732b49 7005#endif /* JOB_CONTROL */
726f6388 7006
95732b49 7007 old_async_pid = last_asynchronous_pid;
8868edaf
CR
7008 fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0;
7009 pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM);
95732b49
JA
7010 last_asynchronous_pid = old_async_pid;
7011
726f6388 7012 if (pid == 0)
495aee44
CR
7013 {
7014 /* Reset the signal handlers in the child, but don't free the
7015 trap strings. Set a flag noting that we have to free the
7016 trap strings if we run trap to change a signal disposition. */
7017 reset_signal_handlers ();
a0c0a00f
CR
7018 if (ISINTERRUPT)
7019 {
7020 kill (getpid (), SIGINT);
7021 CLRINTERRUPT; /* if we're ignoring SIGINT somehow */
7022 }
7023 QUIT; /* catch any interrupts we got post-fork */
495aee44 7024 subshell_environment |= SUBSHELL_RESETTRAP;
15409324 7025 subshell_environment &= ~SUBSHELL_IGNTRAP;
495aee44 7026 }
ccc6cda3
JA
7027
7028#if defined (JOB_CONTROL)
3185942a 7029 /* XXX DO THIS ONLY IN PARENT ? XXX */
ccc6cda3
JA
7030 set_sigchld_handler ();
7031 stop_making_children ();
f1be666c
JA
7032 if (pid != 0)
7033 pipeline_pgrp = old_pipeline_pgrp;
f73dda09
JA
7034#else
7035 stop_making_children ();
ccc6cda3 7036#endif /* JOB_CONTROL */
726f6388
JA
7037
7038 if (pid < 0)
7039 {
b80f6443 7040 sys_error (_("cannot make child for command substitution"));
726f6388
JA
7041 error_exit:
7042
ac50fbac
CR
7043 last_made_pid = old_pid;
7044
726f6388
JA
7045 FREE (istring);
7046 close (fildes[0]);
7047 close (fildes[1]);
3185942a 7048 return ((WORD_DESC *)NULL);
726f6388
JA
7049 }
7050
7051 if (pid == 0)
7052 {
a0c0a00f
CR
7053 /* The currently executing shell is not interactive. */
7054 interactive = 0;
7055
f3cd936b
CR
7056#if defined (JOB_CONTROL)
7057 /* Invariant: in child processes started to run command substitutions,
7058 pipeline_pgrp == shell_pgrp. Other parts of the shell assume this. */
7059 if (pipeline_pgrp > 0 && pipeline_pgrp != shell_pgrp)
7060 shell_pgrp = pipeline_pgrp;
7061#endif
7062
726f6388 7063 set_sigint_handler (); /* XXX */
28ef6c31 7064
b80f6443
JA
7065 free_pushed_string_input ();
7066
a0c0a00f
CR
7067 /* Discard buffered stdio output before replacing the underlying file
7068 descriptor. */
7069 fpurge (stdout);
7070
726f6388
JA
7071 if (dup2 (fildes[1], 1) < 0)
7072 {
a0c0a00f 7073 sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1"));
726f6388
JA
7074 exit (EXECUTION_FAILURE);
7075 }
7076
7077 /* If standard output is closed in the parent shell
7078 (such as after `exec >&-'), file descriptor 1 will be
7079 the lowest available file descriptor, and end up in
7080 fildes[0]. This can happen for stdin and stderr as well,
7081 but stdout is more important -- it will cause no output
7082 to be generated from this command. */
7083 if ((fildes[1] != fileno (stdin)) &&
7084 (fildes[1] != fileno (stdout)) &&
7085 (fildes[1] != fileno (stderr)))
7086 close (fildes[1]);
7087
7088 if ((fildes[0] != fileno (stdin)) &&
7089 (fildes[0] != fileno (stdout)) &&
7090 (fildes[0] != fileno (stderr)))
7091 close (fildes[0]);
7092
495aee44
CR
7093#ifdef __CYGWIN__
7094 /* Let stdio know the fd may have changed from text to binary mode, and
7095 make sure to preserve stdout line buffering. */
7096 freopen (NULL, "w", stdout);
7097 sh_setlinebuf (stdout);
7098#endif /* __CYGWIN__ */
7099
ccc6cda3 7100 /* This is a subshell environment. */
28ef6c31 7101 subshell_environment |= SUBSHELL_COMSUB;
ccc6cda3 7102
a0c0a00f
CR
7103 /* Many shells do not appear to inherit the -v option for command
7104 substitutions. */
7105 change_flag ('v', FLAG_OFF);
7106
7107 /* When inherit_errexit option is not enabled, command substitution does
7108 not inherit the -e flag. It is enabled when Posix mode is enabled */
7109 if (inherit_errexit == 0)
ac50fbac
CR
7110 {
7111 builtin_ignoring_errexit = 0;
7112 change_flag ('e', FLAG_OFF);
ac50fbac 7113 }
a0c0a00f
CR
7114 set_shellopts ();
7115
7116 /* If we are expanding a redirection, we can dispose of any temporary
7117 environment we received, since redirections are not supposed to have
7118 access to the temporary environment. We will have to see whether this
7119 affects temporary environments supplied to `eval', but the temporary
7120 environment gets copied to builtin_env at some point. */
7121 if (expanding_redir)
7122 {
7123 flush_temporary_env ();
7124 expanding_redir = 0;
7125 }
726f6388
JA
7126
7127 remove_quoted_escapes (string);
7128
74091dd4 7129 /* We want to expand aliases on this pass if we are not in posix mode
6ddc9cf2
CR
7130 for backwards compatibility. parse_and_execute() takes care of
7131 setting expand_aliases back to the global value when executing the
7132 parsed string. We only do this for $(...) command substitution,
7133 since that is what parse_comsub handles; `` comsubs are processed
7134 using parse.y:parse_matched_pair(). */
7135 if (expand_aliases && (flags & PF_BACKQUOTE) == 0)
74091dd4
CR
7136 expand_aliases = posixly_correct == 0;
7137
ccc6cda3 7138 startup_state = 2; /* see if we can avoid a fork */
d233b485
CR
7139 parse_and_execute_level = 0;
7140
726f6388
JA
7141 /* Give command substitution a place to jump back to on failure,
7142 so we don't go back up to main (). */
ac50fbac 7143 result = setjmp_nosigs (top_level);
726f6388 7144
bb70624e
JA
7145 /* If we're running a command substitution inside a shell function,
7146 trap `return' so we don't return from the function in the subshell
7147 and go off to never-never land. */
7148 if (result == 0 && return_catch_flag)
ac50fbac 7149 function_value = setjmp_nosigs (return_catch);
bb70624e
JA
7150 else
7151 function_value = 0;
7152
b80f6443
JA
7153 if (result == ERREXIT)
7154 rc = last_command_exit_value;
74091dd4 7155 else if (result == EXITPROG || result == EXITBLTIN)
b80f6443 7156 rc = last_command_exit_value;
726f6388 7157 else if (result)
b80f6443 7158 rc = EXECUTION_FAILURE;
bb70624e 7159 else if (function_value)
b80f6443 7160 rc = return_catch_value;
726f6388 7161 else
b80f6443
JA
7162 {
7163 subshell_level++;
7164 rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
d233b485 7165 /* leave subshell level intact for any exit trap */
b80f6443
JA
7166 }
7167
7168 last_command_exit_value = rc;
7169 rc = run_exit_trap ();
f1be666c
JA
7170#if defined (PROCESS_SUBSTITUTION)
7171 unlink_fifo_list ();
7172#endif
b80f6443 7173 exit (rc);
726f6388
JA
7174 }
7175 else
7176 {
8868edaf
CR
7177 int dummyfd;
7178
726f6388
JA
7179#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
7180 close_pgrp_pipe ();
7181#endif /* JOB_CONTROL && PGRP_PIPE */
7182
7183 close (fildes[1]);
7184
8868edaf
CR
7185 begin_unwind_frame ("read-comsub");
7186 dummyfd = fildes[0];
7187 add_unwind_protect (close, dummyfd);
7188
7189 /* Block SIGINT while we're reading from the pipe. If the child
7190 process gets a SIGINT, it will either handle it or die, and the
7191 read will return. */
7192 BLOCK_SIGNAL (SIGINT, set, oset);
3185942a 7193 tflag = 0;
d233b485 7194 istring = read_comsub (fildes[0], quoted, flags, &tflag);
ccc6cda3 7195
726f6388 7196 close (fildes[0]);
8868edaf
CR
7197 discard_unwind_frame ("read-comsub");
7198 UNBLOCK_SIGNAL (oset);
726f6388 7199
b72432fd 7200 current_command_subst_pid = pid;
8868edaf 7201 last_command_exit_value = wait_for (pid, JWAIT_NOTERM);
726f6388
JA
7202 last_command_subst_pid = pid;
7203 last_made_pid = old_pid;
7204
7205#if defined (JOB_CONTROL)
7206 /* If last_command_exit_value > 128, then the substituted command
7207 was terminated by a signal. If that signal was SIGINT, then send
7208 SIGINT to ourselves. This will break out of loops, for instance. */
b80f6443 7209 if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
726f6388 7210 kill (getpid (), SIGINT);
726f6388
JA
7211#endif /* JOB_CONTROL */
7212
3185942a
JA
7213 ret = alloc_word_desc ();
7214 ret->word = istring;
7215 ret->flags = tflag;
7216
7217 return ret;
726f6388
JA
7218 }
7219}
7220
7221/********************************************************
7222 * *
7223 * Utility functions for parameter expansion *
7224 * *
7225 ********************************************************/
7226
ccc6cda3 7227#if defined (ARRAY_VARS)
ccc6cda3 7228
f73dda09 7229static arrayind_t
ccc6cda3
JA
7230array_length_reference (s)
7231 char *s;
7232{
f73dda09
JA
7233 int len;
7234 arrayind_t ind;
3185942a 7235 char *akey;
f73dda09 7236 char *t, c;
ccc6cda3 7237 ARRAY *array;
495aee44 7238 HASH_TABLE *h;
ccc6cda3
JA
7239 SHELL_VAR *var;
7240
d233b485 7241 var = array_variable_part (s, 0, &t, &len);
726f6388 7242
ccc6cda3
JA
7243 /* If unbound variables should generate an error, report one and return
7244 failure. */
ac50fbac 7245 if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
726f6388 7246 {
f73dda09 7247 c = *--t;
ccc6cda3 7248 *t = '\0';
8868edaf 7249 set_exit_status (EXECUTION_FAILURE);
7117c2d2 7250 err_unboundvar (s);
f73dda09 7251 *t = c;
ccc6cda3 7252 return (-1);
726f6388 7253 }
ac50fbac 7254 else if (var == 0 || invisible_p (var))
ccc6cda3 7255 return 0;
726f6388 7256
28ef6c31
JA
7257 /* We support a couple of expansions for variables that are not arrays.
7258 We'll return the length of the value for v[0], and 1 for v[@] or
7259 v[*]. Return 0 for everything else. */
7260
7261 array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
495aee44 7262 h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
726f6388 7263
d233b485 7264 if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK)
ccc6cda3 7265 {
3185942a 7266 if (assoc_p (var))
495aee44 7267 return (h ? assoc_num_elements (h) : 0);
3185942a 7268 else if (array_p (var))
495aee44 7269 return (array ? array_num_elements (array) : 0);
3185942a 7270 else
495aee44 7271 return (var_isset (var) ? 1 : 0);
ccc6cda3 7272 }
ccc6cda3 7273
3185942a
JA
7274 if (assoc_p (var))
7275 {
7276 t[len - 1] = '\0';
74091dd4 7277 akey = expand_subscript_string (t, 0); /* [ */
d233b485 7278 t[len - 1] = RBRACK;
3185942a
JA
7279 if (akey == 0 || *akey == 0)
7280 {
7281 err_badarraysub (t);
ac50fbac 7282 FREE (akey);
3185942a
JA
7283 return (-1);
7284 }
7285 t = assoc_reference (assoc_cell (var), akey);
ac50fbac 7286 free (akey);
3185942a 7287 }
28ef6c31 7288 else
3185942a 7289 {
d233b485 7290 ind = array_expand_index (var, t, len, 0);
ac50fbac
CR
7291 /* negative subscripts to indexed arrays count back from end */
7292 if (var && array_p (var) && ind < 0)
7293 ind = array_max_index (array_cell (var)) + 1 + ind;
3185942a
JA
7294 if (ind < 0)
7295 {
7296 err_badarraysub (t);
7297 return (-1);
7298 }
7299 if (array_p (var))
7300 t = array_reference (array, ind);
7301 else
7302 t = (ind == 0) ? value_cell (var) : (char *)NULL;
7303 }
28ef6c31 7304
f1be666c 7305 len = MB_STRLEN (t);
ccc6cda3 7306 return (len);
726f6388 7307}
ccc6cda3 7308#endif /* ARRAY_VARS */
726f6388
JA
7309
7310static int
7311valid_brace_expansion_word (name, var_is_special)
7312 char *name;
7313 int var_is_special;
7314{
f73dda09 7315 if (DIGIT (*name) && all_digits (name))
726f6388
JA
7316 return 1;
7317 else if (var_is_special)
7318 return 1;
ccc6cda3 7319#if defined (ARRAY_VARS)
a0c0a00f 7320 else if (valid_array_reference (name, 0))
ccc6cda3
JA
7321 return 1;
7322#endif /* ARRAY_VARS */
726f6388
JA
7323 else if (legal_identifier (name))
7324 return 1;
7325 else
7326 return 0;
7327}
ccc6cda3 7328
b80f6443 7329static int
8868edaf 7330chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
b80f6443 7331 char *name;
8868edaf 7332 int quoted, pflags;
b80f6443
JA
7333 int *quoted_dollar_atp, *contains_dollar_at;
7334{
7335 char *temp1;
7336
7337 if (name == 0)
7338 {
7339 if (quoted_dollar_atp)
7340 *quoted_dollar_atp = 0;
7341 if (contains_dollar_at)
7342 *contains_dollar_at = 0;
7343 return 0;
7344 }
7345
7346 /* check for $@ and $* */
7347 if (name[0] == '@' && name[1] == 0)
7348 {
7349 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7350 *quoted_dollar_atp = 1;
7351 if (contains_dollar_at)
7352 *contains_dollar_at = 1;
7353 return 1;
7354 }
7355 else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
7356 {
8868edaf
CR
7357 /* Need more checks here that parallel what string_list_pos_params and
7358 param_expand do. Check expand_no_split_dollar_star and ??? */
7359 if (contains_dollar_at && expand_no_split_dollar_star == 0)
b80f6443
JA
7360 *contains_dollar_at = 1;
7361 return 1;
7362 }
7363
7364 /* Now check for ${array[@]} and ${array[*]} */
7365#if defined (ARRAY_VARS)
a0c0a00f 7366 else if (valid_array_reference (name, 0))
b80f6443 7367 {
d233b485
CR
7368 temp1 = mbschr (name, LBRACK);
7369 if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK)
b80f6443
JA
7370 {
7371 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7372 *quoted_dollar_atp = 1;
7373 if (contains_dollar_at)
7374 *contains_dollar_at = 1;
7375 return 1;
d233b485 7376 }
b80f6443
JA
7377 /* ${array[*]}, when unquoted, should be treated like ${array[@]},
7378 which should result in separate words even when IFS is unset. */
d233b485 7379 if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0)
b80f6443
JA
7380 {
7381 if (contains_dollar_at)
7382 *contains_dollar_at = 1;
7383 return 1;
7384 }
7385 }
7386#endif
7387 return 0;
7388}
7389
726f6388 7390/* Parameter expand NAME, and return a new string which is the expansion,
d233b485 7391 or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}.
726f6388
JA
7392 VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
7393 the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
7394 NAME was found inside of a double-quoted expression. */
95732b49 7395static WORD_DESC *
74091dd4 7396parameter_brace_expand_word (name, var_is_special, quoted, pflags, estatep)
726f6388 7397 char *name;
89a92869 7398 int var_is_special, quoted, pflags;
74091dd4 7399 array_eltstate_t *estatep;
726f6388 7400{
95732b49 7401 WORD_DESC *ret;
ccc6cda3 7402 char *temp, *tt;
7117c2d2 7403 intmax_t arg_index;
ccc6cda3 7404 SHELL_VAR *var;
74091dd4
CR
7405 int rflags;
7406 array_eltstate_t es;
726f6388 7407
95732b49
JA
7408 ret = 0;
7409 temp = 0;
f1be666c 7410 rflags = 0;
95732b49 7411
74091dd4
CR
7412#if defined (ARRAY_VARS)
7413 if (estatep)
7414 es = *estatep; /* structure copy */
7415 else
7416 {
7417 init_eltstate (&es);
7418 es.ind = INTMAX_MIN;
7419 }
7420#endif
495aee44 7421
95732b49 7422 /* Handle multiple digit arguments, as in ${11}. */
f73dda09 7423 if (legal_number (name, &arg_index))
7117c2d2
JA
7424 {
7425 tt = get_dollar_var_value (arg_index);
b80f6443
JA
7426 if (tt)
7427 temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7428 ? quote_string (tt)
7429 : quote_escapes (tt);
7430 else
7431 temp = (char *)NULL;
7117c2d2
JA
7432 FREE (tt);
7433 }
726f6388
JA
7434 else if (var_is_special) /* ${@} */
7435 {
cce855bc 7436 int sindex;
f73dda09 7437 tt = (char *)xmalloc (2 + strlen (name));
cce855bc 7438 tt[sindex = 0] = '$';
726f6388 7439 strcpy (tt + 1, name);
7117c2d2 7440
95732b49 7441 ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
89a92869 7442 (int *)NULL, (int *)NULL, pflags);
74091dd4
CR
7443
7444 /* Make sure we note that we saw a quoted null string and pass the flag back
7445 to the caller in addition to the value. */
7446 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && STR_DOLLAR_AT_STAR (name) &&
7447 ret && ret->word && QUOTED_NULL (ret->word))
7448 ret->flags |= W_HASQUOTEDNULL;
7449
cce855bc 7450 free (tt);
726f6388 7451 }
ccc6cda3 7452#if defined (ARRAY_VARS)
a0c0a00f 7453 else if (valid_array_reference (name, 0))
ccc6cda3 7454 {
ac50fbac 7455expand_arrayref:
d233b485
CR
7456 var = array_variable_part (name, 0, &tt, (int *)0);
7457 /* These are the cases where word splitting will not be performed */
ac50fbac 7458 if (pflags & PF_ASSIGNRHS)
a0c0a00f 7459 {
d233b485 7460 if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK)
a0c0a00f
CR
7461 {
7462 /* Only treat as double quoted if array variable */
7463 if (var && (array_p (var) || assoc_p (var)))
74091dd4 7464 temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &es);
a0c0a00f 7465 else
74091dd4 7466 temp = array_value (name, quoted, 0, &es);
a0c0a00f 7467 }
ac50fbac 7468 else
74091dd4 7469 temp = array_value (name, quoted, 0, &es);
a0c0a00f 7470 }
d233b485
CR
7471 /* Posix interp 888 */
7472 else if (pflags & PF_NOSPLIT2)
7473 {
7474 /* Special cases, then general case, for each of A[@], A[*], A[n] */
7475#if defined (HANDLE_MULTIBYTE)
7476 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
7477#else
7478 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
7479#endif
74091dd4 7480 temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &es);
d233b485 7481 else if (tt[0] == '@' && tt[1] == RBRACK)
74091dd4 7482 temp = array_value (name, quoted, 0, &es);
d233b485 7483 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
74091dd4 7484 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &es);
d233b485 7485 else if (tt[0] == '*' && tt[1] == RBRACK)
74091dd4 7486 temp = array_value (name, quoted, 0, &es);
d233b485 7487 else
74091dd4 7488 temp = array_value (name, quoted, 0, &es);
d233b485
CR
7489 }
7490 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
74091dd4 7491 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &es);
ac50fbac 7492 else
74091dd4
CR
7493 temp = array_value (name, quoted, 0, &es);
7494 if (es.subtype == 0 && temp)
495aee44
CR
7495 {
7496 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7497 ? quote_string (temp)
7498 : quote_escapes (temp);
7499 rflags |= W_ARRAYIND;
74091dd4
CR
7500 }
7501 /* Note that array[*] and array[@] expanded to a quoted null string by
7502 returning the W_HASQUOTEDNULL flag to the caller in addition to TEMP. */
7503 else if (es.subtype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7504 rflags |= W_HASQUOTEDNULL;
7505 else if (es.subtype == 2 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
f1be666c 7506 rflags |= W_HASQUOTEDNULL;
74091dd4 7507
52f2cda1
CR
7508 if (estatep)
7509 *estatep = es; /* structure copy */
7510 else
74091dd4 7511 flush_eltstate (&es);
ccc6cda3
JA
7512 }
7513#endif
7514 else if (var = find_variable (name))
7515 {
7117c2d2 7516 if (var_isset (var) && invisible_p (var) == 0)
28ef6c31 7517 {
ccc6cda3 7518#if defined (ARRAY_VARS)
8868edaf
CR
7519 /* We avoid a memory leak by saving TT as the memory allocated by
7520 assoc_to_string or array_to_string and leaving it 0 otherwise,
7521 then freeing TT after quoting temp. */
7522 tt = (char *)NULL;
7523 if ((pflags & PF_ALLINDS) && assoc_p (var))
7524 tt = temp = assoc_empty (assoc_cell (var)) ? (char *)NULL : assoc_to_string (assoc_cell (var), " ", quoted);
7525 else if ((pflags & PF_ALLINDS) && array_p (var))
7526 tt = temp = array_empty (array_cell (var)) ? (char *)NULL : array_to_string (array_cell (var), " ", quoted);
7527 else if (assoc_p (var))
3185942a
JA
7528 temp = assoc_reference (assoc_cell (var), "0");
7529 else if (array_p (var))
7530 temp = array_reference (array_cell (var), 0);
7531 else
7532 temp = value_cell (var);
ccc6cda3
JA
7533#else
7534 temp = value_cell (var);
7535#endif
7536
7537 if (temp)
b80f6443
JA
7538 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7539 ? quote_string (temp)
d233b485
CR
7540 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
7541 : quote_escapes (temp));
8868edaf 7542 FREE (tt);
28ef6c31 7543 }
ccc6cda3
JA
7544 else
7545 temp = (char *)NULL;
7546 }
a0c0a00f 7547 else if (var = find_variable_last_nameref (name, 0))
ac50fbac
CR
7548 {
7549 temp = nameref_cell (var);
7550#if defined (ARRAY_VARS)
7551 /* Handle expanding nameref whose value is x[n] */
a0c0a00f 7552 if (temp && *temp && valid_array_reference (temp, 0))
ac50fbac
CR
7553 {
7554 name = temp;
7555 goto expand_arrayref;
7556 }
7557 else
7558#endif
7559 /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */
7560 if (temp && *temp && legal_identifier (temp) == 0)
7561 {
8868edaf 7562 set_exit_status (EXECUTION_FAILURE);
ac50fbac
CR
7563 report_error (_("%s: invalid variable name for name reference"), temp);
7564 temp = &expand_param_error;
7565 }
7566 else
7567 temp = (char *)NULL;
7568 }
726f6388 7569 else
ccc6cda3 7570 temp = (char *)NULL;
726f6388 7571
95732b49
JA
7572 if (ret == 0)
7573 {
7574 ret = alloc_word_desc ();
7575 ret->word = temp;
f1be666c 7576 ret->flags |= rflags;
95732b49
JA
7577 }
7578 return ret;
726f6388
JA
7579}
7580
ac50fbac
CR
7581static char *
7582parameter_brace_find_indir (name, var_is_special, quoted, find_nameref)
ccc6cda3 7583 char *name;
ac50fbac 7584 int var_is_special, quoted, find_nameref;
ccc6cda3
JA
7585{
7586 char *temp, *t;
95732b49 7587 WORD_DESC *w;
ac50fbac 7588 SHELL_VAR *v;
d233b485 7589 int pflags, oldex;
ac50fbac 7590
a0c0a00f 7591 if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) &&
ac50fbac
CR
7592 nameref_p (v) && (t = nameref_cell (v)) && *t)
7593 return (savestring (t));
ccc6cda3 7594
ac50fbac
CR
7595 /* If var_is_special == 0, and name is not an array reference, this does
7596 more expansion than necessary. It should really look up the variable's
7597 value and not try to expand it. */
d233b485
CR
7598 pflags = PF_IGNUNBOUND;
7599 /* Note that we're not going to be doing word splitting here */
7600 if (var_is_special)
7601 {
7602 pflags |= PF_ASSIGNRHS; /* suppresses word splitting */
7603 oldex = expand_no_split_dollar_star;
7604 expand_no_split_dollar_star = 1;
7605 }
7606 w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0);
7607 if (var_is_special)
7608 expand_no_split_dollar_star = oldex;
7609
95732b49 7610 t = w->word;
b80f6443
JA
7611 /* Have to dequote here if necessary */
7612 if (t)
7613 {
d233b485 7614 temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special)
b80f6443
JA
7615 ? dequote_string (t)
7616 : dequote_escapes (t);
7617 free (t);
7618 t = temp;
7619 }
95732b49
JA
7620 dispose_word_desc (w);
7621
ac50fbac
CR
7622 return t;
7623}
7624
7625/* Expand an indirect reference to a variable: ${!NAME} expands to the
7626 value of the variable whose name is the value of NAME. */
7627static WORD_DESC *
8868edaf 7628parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
ac50fbac 7629 char *name;
8868edaf 7630 int var_is_special, quoted, pflags;
ac50fbac
CR
7631 int *quoted_dollar_atp, *contains_dollar_at;
7632{
d233b485 7633 char *t;
ac50fbac
CR
7634 WORD_DESC *w;
7635 SHELL_VAR *v;
7636
7637 /* See if it's a nameref first, behave in ksh93-compatible fashion.
7638 There is at least one incompatibility: given ${!foo[0]} where foo=bar,
7639 bash performs an indirect lookup on foo[0] and expands the result;
7640 ksh93 expands bar[0]. We could do that here -- there are enough usable
7641 primitives to do that -- but do not at this point. */
a0c0a00f 7642 if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0)))
ac50fbac
CR
7643 {
7644 if (nameref_p (v) && (t = nameref_cell (v)) && *t)
7645 {
7646 w = alloc_word_desc ();
7647 w->word = savestring (t);
7648 w->flags = 0;
7649 return w;
7650 }
7651 }
7652
d233b485
CR
7653 /* An indirect reference to a positional parameter or a special parameter
7654 is ok. Indirect references to array references, as explained above, are
7655 ok (currently). Only references to unset variables are errors at this
7656 point. */
7657 if (legal_identifier (name) && v == 0)
7658 {
7659 report_error (_("%s: invalid indirect expansion"), name);
7660 w = alloc_word_desc ();
7661 w->word = &expand_param_error;
7662 w->flags = 0;
7663 return (w);
7664 }
7665
ac50fbac
CR
7666 t = parameter_brace_find_indir (name, var_is_special, quoted, 0);
7667
8868edaf 7668 chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at);
d233b485
CR
7669
7670#if defined (ARRAY_VARS)
7671 /* Array references to unset variables are also an error */
7672 if (t == 0 && valid_array_reference (name, 0))
7673 {
7674 v = array_variable_part (name, 0, (char **)0, (int *)0);
7675 if (v == 0)
7676 {
7677 report_error (_("%s: invalid indirect expansion"), name);
7678 w = alloc_word_desc ();
7679 w->word = &expand_param_error;
7680 w->flags = 0;
7681 return (w);
7682 }
7683 else
7684 return (WORD_DESC *)NULL;
7685 }
7686#endif
7687
ccc6cda3 7688 if (t == 0)
95732b49
JA
7689 return (WORD_DESC *)NULL;
7690
a0c0a00f
CR
7691 if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0)
7692 {
d233b485 7693 report_error (_("%s: invalid variable name"), t);
a0c0a00f
CR
7694 free (t);
7695 w = alloc_word_desc ();
7696 w->word = &expand_param_error;
7697 w->flags = 0;
7698 return (w);
7699 }
7700
8868edaf 7701 w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0);
ccc6cda3 7702 free (t);
95732b49
JA
7703
7704 return w;
ccc6cda3
JA
7705}
7706
726f6388
JA
7707/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
7708 depending on the value of C, the separating character. C can be one of
ccc6cda3
JA
7709 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
7710 between double quotes. */
95732b49 7711static WORD_DESC *
d233b485 7712parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat)
726f6388 7713 char *name, *value;
d233b485 7714 int op, quoted, pflags, *qdollaratp, *hasdollarat;
726f6388 7715{
95732b49 7716 WORD_DESC *w;
8868edaf 7717 WORD_LIST *l, *tl;
74091dd4
CR
7718 char *t, *t1, *temp, *vname, *newval;
7719 int l_hasdollat, sindex, arrayref;
d233b485 7720 SHELL_VAR *v;
74091dd4 7721 array_eltstate_t es;
726f6388 7722
a0c0a00f 7723/*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/
ccc6cda3
JA
7724 /* If the entire expression is between double quotes, we want to treat
7725 the value as a double-quoted string, with the exception that we strip
3185942a 7726 embedded unescaped double quotes (for sh backwards compatibility). */
95732b49 7727 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
726f6388 7728 {
a0c0a00f
CR
7729 sindex = 0;
7730 temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ);
726f6388 7731 }
95732b49
JA
7732 else
7733 temp = value;
ccc6cda3 7734
95732b49 7735 w = alloc_word_desc ();
a0c0a00f 7736 l_hasdollat = 0;
d233b485 7737 l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL)
ccc6cda3
JA
7738 : (WORD_LIST *)0;
7739 if (hasdollarat)
a0c0a00f 7740 *hasdollarat = l_hasdollat || (l && l->next);
95732b49
JA
7741 if (temp != value)
7742 free (temp);
8868edaf
CR
7743
7744 /* list_string takes multiple CTLNULs and turns them into an empty word
7745 with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the
7746 rest of this function and the caller. */
7747 for (tl = l; tl; tl = tl->next)
7748 {
7749 if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) &&
7750 (tl->word->flags | W_SAWQUOTEDNULL))
7751 {
7752 t = make_quoted_char ('\0');
7753 FREE (tl->word->word);
7754 tl->word->word = t;
7755 tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL;
7756 tl->word->flags &= ~W_SAWQUOTEDNULL;
7757 }
7758 }
7759
726f6388
JA
7760 if (l)
7761 {
a0c0a00f
CR
7762 /* If l->next is not null, we know that TEMP contained "$@", since that
7763 is the only expansion that creates more than one word. */
7764 if (qdollaratp && ((l_hasdollat && quoted) || l->next))
7765 {
7766/*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/
7767 *qdollaratp = 1;
7768 }
7769
ccc6cda3 7770 /* The expansion of TEMP returned something. We need to treat things
a0c0a00f
CR
7771 slightly differently if L_HASDOLLAT is non-zero. If we have "$@",
7772 the individual words have already been quoted. We need to turn them
b80f6443
JA
7773 into a string with the words separated by the first character of
7774 $IFS without any additional quoting, so string_list_dollar_at won't
a0c0a00f
CR
7775 do the right thing. If IFS is null, we want "$@" to split into
7776 separate arguments, not be concatenated, so we use string_list_internal
7777 and mark the word to be split on spaces later. We use
7778 string_list_dollar_star for "$@" otherwise. */
7779 if (l->next && ifs_is_null)
7780 {
7781 temp = string_list_internal (l, " ");
7782 w->flags |= W_SPLITSPACE;
7783 }
d233b485
CR
7784 else if (l_hasdollat || l->next)
7785 temp = string_list_dollar_star (l, quoted, 0);
a0c0a00f 7786 else
d233b485
CR
7787 {
7788 temp = string_list (l);
7789 if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL))
7790 w->flags |= W_SAWQUOTEDNULL; /* XXX */
7791 }
b80f6443 7792
cd110fdf
CR
7793 /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
7794 a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
7795 flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
7796 expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7797 (which is more paranoia than anything else), we need to return the
7798 quoted null string and set the flags to indicate it. */
ac50fbac 7799 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
7800 {
7801 w->flags |= W_HASQUOTEDNULL;
a0c0a00f
CR
7802/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/
7803 /* If we return a quoted null with L_HASDOLLARAT, we either have a
7804 construct like "${@-$@}" or "${@-${@-$@}}" with no positional
7805 parameters or a quoted expansion of "$@" with $1 == ''. In either
7806 case, we don't want to enable special handling of $@. */
7807 if (qdollaratp && l_hasdollat)
7808 *qdollaratp = 0;
cd110fdf 7809 }
726f6388
JA
7810 dispose_words (l);
7811 }
a0c0a00f 7812 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat)
726f6388 7813 {
a0c0a00f
CR
7814 /* Posix interp 221 changed the rules on this. The idea is that
7815 something like "$xxx$@" should expand the same as "${foo-$xxx$@}"
7816 when foo and xxx are unset. The problem is that it's not in any
7817 way backwards compatible and few other shells do it. We're eventually
7818 going to try and split the difference (heh) a little bit here. */
7819 /* l_hasdollat == 1 means we saw a quoted dollar at. */
7820
ccc6cda3
JA
7821 /* The brace expansion occurred between double quotes and there was
7822 a $@ in TEMP. It does not matter if the $@ is quoted, as long as
7117c2d2 7823 it does not expand to anything. In this case, we want to return
a0c0a00f 7824 a quoted empty string. Posix interp 888 */
0628567a 7825 temp = make_quoted_char ('\0');
95732b49 7826 w->flags |= W_HASQUOTEDNULL;
a0c0a00f 7827/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/
726f6388
JA
7828 }
7829 else
7830 temp = (char *)NULL;
7831
d233b485 7832 if (op == '-' || op == '+')
95732b49
JA
7833 {
7834 w->word = temp;
7835 return w;
7836 }
726f6388 7837
d233b485
CR
7838 /* op == '=' */
7839 t1 = temp ? dequote_string (temp) : savestring ("");
7840 free (temp);
a0c0a00f
CR
7841
7842 /* bash-4.4/5.0 */
7843 vname = name;
7844 if (*name == '!' &&
7845 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1])))
7846 {
7847 vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1);
7848 if (vname == 0 || *vname == 0)
7849 {
7850 report_error (_("%s: invalid indirect expansion"), name);
7851 free (vname);
d233b485 7852 free (t1);
a0c0a00f
CR
7853 dispose_word (w);
7854 return &expand_wdesc_error;
7855 }
7856 if (legal_identifier (vname) == 0)
7857 {
7858 report_error (_("%s: invalid variable name"), vname);
7859 free (vname);
d233b485 7860 free (t1);
a0c0a00f
CR
7861 dispose_word (w);
7862 return &expand_wdesc_error;
7863 }
7864 }
7865
74091dd4 7866 arrayref = 0;
b80f6443 7867#if defined (ARRAY_VARS)
a0c0a00f 7868 if (valid_array_reference (vname, 0))
74091dd4
CR
7869 {
7870 init_eltstate (&es);
7871 v = assign_array_element (vname, t1, ASS_ALLOWALLSUB, &es);
7872 arrayref = 1;
7873 newval = es.value;
7874 }
b80f6443
JA
7875 else
7876#endif /* ARRAY_VARS */
d233b485
CR
7877 v = bind_variable (vname, t1, 0);
7878
7879 if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */
7880 {
7881 if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct)
7882 {
7883 last_command_exit_value = EXECUTION_FAILURE;
7884 exp_jump_to_top_level (FORCE_EOF);
7885 }
7886 else
7887 {
7888 if (vname != name)
7889 free (vname);
7890 last_command_exit_value = EX_BADUSAGE;
7891 exp_jump_to_top_level (DISCARD);
7892 }
7893 }
a0c0a00f
CR
7894
7895 stupidly_hack_special_variables (vname);
7896
74091dd4
CR
7897 /* "In all cases, the final value of parameter shall be substituted." */
7898 if (shell_compatibility_level > 51)
7899 {
7900 FREE (t1);
7901#if defined (ARRAY_VARS)
7902 if (arrayref)
7903 {
7904 t1 = newval;
7905 flush_eltstate (&es);
7906 }
7907 else
7908 t1 = get_variable_value (v);
7909#else
7910 t1 = value_cell (v);
7911#endif
7912 }
7913
a0c0a00f
CR
7914 if (vname != name)
7915 free (vname);
95732b49 7916
495aee44 7917 /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
495aee44 7918
d233b485
CR
7919 /* If we are double-quoted or if we are not going to be performing word
7920 splitting, we want to quote the value we return appropriately, like
7921 the other expansions this function handles. */
7922 w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1);
74091dd4 7923 /* If we have something that's non-null, but not a quoted null string,
8868edaf
CR
7924 and we're not going to be performing word splitting (we know we're not
7925 because the operator is `='), we can forget we saw a quoted null. */
7926 if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0)
7927 w->flags &= ~W_SAWQUOTEDNULL;
d233b485 7928
8868edaf
CR
7929 /* If we convert a null string into a quoted null, make sure the caller
7930 knows it. */
7931 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word))
7932 w->flags |= W_HASQUOTEDNULL;
7933
95732b49 7934 return w;
726f6388
JA
7935}
7936
7937/* Deal with the right hand side of a ${name:?value} expansion in the case
7938 that NAME is null or not set. If VALUE is non-null it is expanded and
7939 used as the error message to print, otherwise a standard message is
7940 printed. */
7941static void
d233b485 7942parameter_brace_expand_error (name, value, check_null)
726f6388 7943 char *name, *value;
d233b485 7944 int check_null;
726f6388 7945{
ccc6cda3
JA
7946 WORD_LIST *l;
7947 char *temp;
7948
8868edaf 7949 set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */
726f6388
JA
7950 if (value && *value)
7951 {
95732b49 7952 l = expand_string (value, 0);
ccc6cda3
JA
7953 temp = string_list (l);
7954 report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
7955 FREE (temp);
726f6388
JA
7956 dispose_words (l);
7957 }
d233b485
CR
7958 else if (check_null == 0)
7959 report_error (_("%s: parameter not set"), name);
726f6388 7960 else
b80f6443 7961 report_error (_("%s: parameter null or not set"), name);
726f6388
JA
7962
7963 /* Free the data we have allocated during this expansion, since we
7964 are about to longjmp out. */
7965 free (name);
7966 FREE (value);
7967}
7968
7969/* Return 1 if NAME is something for which parameter_brace_expand_length is
7970 OK to do. */
7971static int
7972valid_length_expression (name)
7973 char *name;
7974{
28ef6c31 7975 return (name[1] == '\0' || /* ${#} */
f73dda09
JA
7976 ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */
7977 (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
ccc6cda3 7978#if defined (ARRAY_VARS)
a0c0a00f 7979 valid_array_reference (name + 1, 0) || /* ${#a[7]} */
ccc6cda3 7980#endif
726f6388
JA
7981 legal_identifier (name + 1)); /* ${#PS1} */
7982}
7983
7984/* Handle the parameter brace expansion that requires us to return the
7985 length of a parameter. */
7117c2d2 7986static intmax_t
726f6388
JA
7987parameter_brace_expand_length (name)
7988 char *name;
7989{
ccc6cda3 7990 char *t, *newname;
7117c2d2 7991 intmax_t number, arg_index;
ccc6cda3 7992 WORD_LIST *list;
ccc6cda3 7993 SHELL_VAR *var;
8868edaf
CR
7994
7995 var = (SHELL_VAR *)NULL;
ccc6cda3
JA
7996
7997 if (name[1] == '\0') /* ${#} */
7998 number = number_of_args ();
a0c0a00f 7999 else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */
cce855bc 8000 number = number_of_args ();
f73dda09 8001 else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
cce855bc
JA
8002 {
8003 /* Take the lengths of some of the shell's special parameters. */
8004 switch (name[1])
8005 {
8006 case '-':
8007 t = which_set_flags ();
8008 break;
8009 case '?':
8010 t = itos (last_command_exit_value);
8011 break;
8012 case '$':
8013 t = itos (dollar_dollar_pid);
8014 break;
8015 case '!':
8016 if (last_asynchronous_pid == NO_PID)
495aee44 8017 t = (char *)NULL; /* XXX - error if set -u set? */
cce855bc 8018 else
f73dda09 8019 t = itos (last_asynchronous_pid);
cce855bc
JA
8020 break;
8021 case '#':
8022 t = itos (number_of_args ());
8023 break;
8024 }
8025 number = STRLEN (t);
8026 FREE (t);
8027 }
ccc6cda3 8028#if defined (ARRAY_VARS)
a0c0a00f 8029 else if (valid_array_reference (name + 1, 0))
ccc6cda3
JA
8030 number = array_length_reference (name + 1);
8031#endif /* ARRAY_VARS */
cce855bc 8032 else
ccc6cda3
JA
8033 {
8034 number = 0;
8035
f73dda09 8036 if (legal_number (name + 1, &arg_index)) /* ${#1} */
ccc6cda3 8037 {
f73dda09 8038 t = get_dollar_var_value (arg_index);
495aee44
CR
8039 if (t == 0 && unbound_vars_is_error)
8040 return INTMAX_MIN;
eb873671 8041 number = MB_STRLEN (t);
ccc6cda3
JA
8042 FREE (t);
8043 }
8044#if defined (ARRAY_VARS)
3185942a 8045 else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
ccc6cda3 8046 {
3185942a
JA
8047 if (assoc_p (var))
8048 t = assoc_reference (assoc_cell (var), "0");
8049 else
8050 t = array_reference (array_cell (var), 0);
495aee44
CR
8051 if (t == 0 && unbound_vars_is_error)
8052 return INTMAX_MIN;
eb873671 8053 number = MB_STRLEN (t);
ccc6cda3
JA
8054 }
8055#endif
8868edaf
CR
8056 /* Fast path for the common case of taking the length of a non-dynamic
8057 scalar variable value. */
8058 else if ((var || (var = find_variable (name + 1))) &&
8059 invisible_p (var) == 0 &&
8060 array_p (var) == 0 && assoc_p (var) == 0 &&
8061 var->dynamic_value == 0)
8062 number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0;
8063 else if (var == 0 && unbound_vars_is_error == 0)
8064 number = 0;
ccc6cda3
JA
8065 else /* ${#PS1} */
8066 {
8067 newname = savestring (name);
8068 newname[0] = '$';
8069 list = expand_string (newname, Q_DOUBLE_QUOTES);
8070 t = list ? string_list (list) : (char *)NULL;
8071 free (newname);
8072 if (list)
8073 dispose_words (list);
8074
495aee44 8075 number = t ? MB_STRLEN (t) : 0;
ccc6cda3
JA
8076 FREE (t);
8077 }
8078 }
ccc6cda3
JA
8079
8080 return (number);
8081}
8082
28ef6c31
JA
8083/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression,
8084 so we do some ad-hoc parsing of an arithmetic expression to find
8085 the first DELIM, instead of using strchr(3). Two rules:
8086 1. If the substring contains a `(', read until closing `)'.
8087 2. If the substring contains a `?', read past one `:' for each `?'.
a0c0a00f 8088 The SD_ARITHEXP flag to skip_to_delim takes care of doing this.
28ef6c31
JA
8089*/
8090
8091static char *
8092skiparith (substr, delim)
8093 char *substr;
8094 int delim;
8095{
a0c0a00f
CR
8096 int i;
8097 char delims[2];
28ef6c31 8098
a0c0a00f
CR
8099 delims[0] = delim;
8100 delims[1] = '\0';
7117c2d2 8101
a0c0a00f 8102 i = skip_to_delim (substr, 0, delims, SD_ARITHEXP);
7117c2d2 8103 return (substr + i);
28ef6c31
JA
8104}
8105
ccc6cda3
JA
8106/* Verify and limit the start and end of the desired substring. If
8107 VTYPE == 0, a regular shell variable is being used; if it is 1,
cce855bc 8108 then the positional parameters are being used; if it is 2, then
e8ce775d
JA
8109 VALUE is really a pointer to an array variable that should be used.
8110 Return value is 1 if both values were OK, 0 if there was a problem
8111 with an invalid expression, or -1 if the values were out of range. */
ccc6cda3 8112static int
3185942a
JA
8113verify_substring_values (v, value, substr, vtype, e1p, e2p)
8114 SHELL_VAR *v;
ccc6cda3 8115 char *value, *substr;
f73dda09 8116 int vtype;
7117c2d2 8117 intmax_t *e1p, *e2p;
ccc6cda3 8118{
bb70624e 8119 char *t, *temp1, *temp2;
f73dda09 8120 arrayind_t len;
74091dd4 8121 int expok, eflag;
ccc6cda3
JA
8122#if defined (ARRAY_VARS)
8123 ARRAY *a;
3185942a 8124 HASH_TABLE *h;
ccc6cda3
JA
8125#endif
8126
28ef6c31
JA
8127 /* duplicate behavior of strchr(3) */
8128 t = skiparith (substr, ':');
8129 if (*t && *t == ':')
7117c2d2 8130 *t = '\0';
28ef6c31
JA
8131 else
8132 t = (char *)0;
f73dda09 8133
74091dd4
CR
8134 temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES|Q_ARITH);
8135 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
8136
8137 *e1p = evalexp (temp1, eflag, &expok);
ccc6cda3 8138 free (temp1);
d166f048
JA
8139 if (expok == 0)
8140 return (0);
ccc6cda3 8141
f73dda09 8142 len = -1; /* paranoia */
ccc6cda3
JA
8143 switch (vtype)
8144 {
8145 case VT_VARIABLE:
d166f048 8146 case VT_ARRAYMEMBER:
eb873671 8147 len = MB_STRLEN (value);
ccc6cda3
JA
8148 break;
8149 case VT_POSPARMS:
8150 len = number_of_args () + 1;
3185942a
JA
8151 if (*e1p == 0)
8152 len++; /* add one arg if counting from $0 */
ccc6cda3
JA
8153 break;
8154#if defined (ARRAY_VARS)
8155 case VT_ARRAYVAR:
eb873671 8156 /* For arrays, the first value deals with array indices. Negative
3185942a
JA
8157 offsets count from one past the array's maximum index. Associative
8158 arrays treat the number of elements as the maximum index. */
8159 if (assoc_p (v))
8160 {
8161 h = assoc_cell (v);
8162 len = assoc_num_elements (h) + (*e1p < 0);
8163 }
8164 else
8165 {
8166 a = (ARRAY *)value;
8167 len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
8168 }
ccc6cda3
JA
8169 break;
8170#endif
8171 }
8172
f73dda09
JA
8173 if (len == -1) /* paranoia */
8174 return -1;
8175
ccc6cda3
JA
8176 if (*e1p < 0) /* negative offsets count from end */
8177 *e1p += len;
8178
eb873671 8179 if (*e1p > len || *e1p < 0)
e8ce775d 8180 return (-1);
d166f048 8181
b80f6443
JA
8182#if defined (ARRAY_VARS)
8183 /* For arrays, the second offset deals with the number of elements. */
8184 if (vtype == VT_ARRAYVAR)
3185942a 8185 len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
b80f6443
JA
8186#endif
8187
ccc6cda3
JA
8188 if (t)
8189 {
8190 t++;
bb70624e 8191 temp2 = savestring (t);
74091dd4 8192 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
bb70624e 8193 free (temp2);
ccc6cda3 8194 t[-1] = ':';
74091dd4 8195 *e2p = evalexp (temp1, eflag, &expok);
ccc6cda3 8196 free (temp1);
d166f048 8197 if (expok == 0)
28ef6c31 8198 return (0);
d233b485
CR
8199
8200 /* Should we allow positional parameter length < 0 to count backwards
8201 from end of positional parameters? */
ac50fbac 8202#if 1
495aee44 8203 if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
74091dd4 8204#else /* XXX - postponed; this isn't really a valuable feature */
ac50fbac
CR
8205 if (vtype == VT_ARRAYVAR && *e2p < 0)
8206#endif
28ef6c31 8207 {
b80f6443 8208 internal_error (_("%s: substring expression < 0"), t);
ccc6cda3 8209 return (0);
28ef6c31 8210 }
b80f6443
JA
8211#if defined (ARRAY_VARS)
8212 /* In order to deal with sparse arrays, push the intelligence about how
8213 to deal with the number of elements desired down to the array-
8214 specific functions. */
8215 if (vtype != VT_ARRAYVAR)
8216#endif
8217 {
495aee44
CR
8218 if (*e2p < 0)
8219 {
8220 *e2p += len;
8221 if (*e2p < 0 || *e2p < *e1p)
8222 {
8223 internal_error (_("%s: substring expression < 0"), t);
8224 return (0);
8225 }
8226 }
8227 else
8228 *e2p += *e1p; /* want E2 chars starting at E1 */
b80f6443
JA
8229 if (*e2p > len)
8230 *e2p = len;
8231 }
ccc6cda3
JA
8232 }
8233 else
8234 *e2p = len;
8235
8236 return (1);
8237}
8238
ccc6cda3 8239/* Return the type of variable specified by VARNAME (simple variable,
cce855bc 8240 positional param, or array variable). Also return the value specified
7117c2d2 8241 by VARNAME (value of a variable or a reference to an array element).
495aee44
CR
8242 QUOTED is the standard description of quoting state, using Q_* defines.
8243 FLAGS is currently a set of flags to pass to array_value. If IND is
74091dd4 8244 not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
495aee44 8245 passed to array_value so the array index is not computed again.
7117c2d2
JA
8246 If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
8247 characters in the value are quoted with CTLESC and takes appropriate
8248 steps. For convenience, *VALP is set to the dequoted VALUE. */
ccc6cda3 8249static int
74091dd4 8250get_var_and_type (varname, value, estatep, quoted, flags, varp, valp)
ccc6cda3 8251 char *varname, *value;
74091dd4 8252 array_eltstate_t *estatep;
495aee44 8253 int quoted, flags;
ccc6cda3
JA
8254 SHELL_VAR **varp;
8255 char **valp;
8256{
ac50fbac
CR
8257 int vtype, want_indir;
8258 char *temp, *vname;
ccc6cda3 8259 SHELL_VAR *v;
ccc6cda3 8260
ac50fbac
CR
8261 want_indir = *varname == '!' &&
8262 (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1])
8263 || VALID_INDIR_PARAM (varname[1]));
8264 if (want_indir)
8265 vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1);
a0c0a00f 8266 /* XXX - what if vname == 0 || *vname == 0 ? */
ac50fbac
CR
8267 else
8268 vname = varname;
a0c0a00f
CR
8269
8270 if (vname == 0)
8271 {
8272 vtype = VT_VARIABLE;
8273 *varp = (SHELL_VAR *)NULL;
8274 *valp = (char *)NULL;
8275 return (vtype);
8276 }
8277
7117c2d2 8278 /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
a0c0a00f 8279 vtype = STR_DOLLAR_AT_STAR (vname);
ac50fbac 8280 if (vtype == VT_POSPARMS && vname[0] == '*')
b80f6443 8281 vtype |= VT_STARSUB;
ccc6cda3
JA
8282 *varp = (SHELL_VAR *)NULL;
8283
8284#if defined (ARRAY_VARS)
a0c0a00f 8285 if (valid_array_reference (vname, 0))
ccc6cda3 8286 {
d233b485 8287 v = array_variable_part (vname, 0, &temp, (int *)0);
495aee44 8288 /* If we want to signal array_value to use an already-computed index,
74091dd4
CR
8289 the caller will set ESTATEP->IND to that index and pass AV_USEIND in
8290 FLAGS. */
8291 if (estatep && (flags & AV_USEIND) == 0)
8292 estatep->ind = INTMAX_MIN;
8293
ac50fbac
CR
8294 if (v && invisible_p (v))
8295 {
8296 vtype = VT_ARRAYMEMBER;
8297 *varp = (SHELL_VAR *)NULL;
8298 *valp = (char *)NULL;
8299 }
3185942a 8300 if (v && (array_p (v) || assoc_p (v)))
d233b485
CR
8301 {
8302 if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)
ccc6cda3 8303 {
ac50fbac 8304 /* Callers have to differentiate between indexed and associative */
ccc6cda3 8305 vtype = VT_ARRAYVAR;
b80f6443
JA
8306 if (temp[0] == '*')
8307 vtype |= VT_STARSUB;
3185942a 8308 *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
ccc6cda3
JA
8309 }
8310 else
8311 {
d166f048 8312 vtype = VT_ARRAYMEMBER;
74091dd4 8313 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
ccc6cda3
JA
8314 }
8315 *varp = v;
8316 }
d233b485
CR
8317 else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK))
8318 {
8319 vtype = VT_VARIABLE;
8320 *varp = v;
8321 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8868edaf 8322 *valp = value ? dequote_string (value) : (char *)NULL;
d233b485
CR
8323 else
8324 *valp = value ? dequote_escapes (value) : (char *)NULL;
8325 }
8326 else
8327 {
8328 vtype = VT_ARRAYMEMBER;
8329 *varp = v;
74091dd4 8330 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
d233b485
CR
8331 }
8332 }
8333 else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
8334 {
8335 vtype = VT_ARRAYMEMBER;
8336 *varp = v;
8337 *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
8338 }
8339 else
8340#endif
8341 {
8342 if (value && vtype == VT_VARIABLE)
8343 {
8344 *varp = find_variable (vname);
8345 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8346 *valp = dequote_string (value);
8347 else
8348 *valp = dequote_escapes (value);
8349 }
8350 else
8351 *valp = value;
8352 }
8353
8354 if (want_indir)
8355 free (vname);
8356
8357 return vtype;
8358}
8359
8360/***********************************************************/
8361/* */
8362/* Functions to perform transformations on variable values */
8363/* */
8364/***********************************************************/
8365
8366static char *
8367string_var_assignment (v, s)
8368 SHELL_VAR *v;
8369 char *s;
8370{
8371 char flags[MAX_ATTRIBUTES], *ret, *val;
8372 int i;
8373
8868edaf 8374 val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0);
d233b485 8375 i = var_attribute_string (v, 0, flags);
8868edaf
CR
8376 if (i == 0 && val == 0)
8377 return (char *)NULL;
8378
8379 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES);
8380 if (i > 0 && val == 0)
8381 sprintf (ret, "declare -%s %s", flags, v->name);
8382 else if (i > 0)
d233b485
CR
8383 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
8384 else
8385 sprintf (ret, "%s=%s", v->name, val);
8386 free (val);
8387 return ret;
8388}
8389
8390#if defined (ARRAY_VARS)
8391static char *
8868edaf 8392array_var_assignment (v, itype, quoted, atype)
d233b485 8393 SHELL_VAR *v;
8868edaf 8394 int itype, quoted, atype;
d233b485
CR
8395{
8396 char *ret, *val, flags[MAX_ATTRIBUTES];
8397 int i;
8398
8399 if (v == 0)
8400 return (char *)NULL;
8868edaf
CR
8401 if (atype == 2)
8402 val = array_p (v) ? array_to_kvpair (array_cell (v), 0)
8403 : assoc_to_kvpair (assoc_cell (v), 0);
8404 else
8405 val = array_p (v) ? array_to_assign (array_cell (v), 0)
8406 : assoc_to_assign (assoc_cell (v), 0);
8407
8408 if (val == 0 && (invisible_p (v) || var_isset (v) == 0))
8409 ; /* placeholder */
8410 else if (val == 0)
d233b485
CR
8411 {
8412 val = (char *)xmalloc (3);
8413 val[0] = LPAREN;
8414 val[1] = RPAREN;
8415 val[2] = 0;
8416 }
8417 else
8418 {
8419 ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val);
8420 free (val);
8421 val = ret;
8422 }
8868edaf
CR
8423
8424 if (atype == 2)
8425 return val;
8426
d233b485 8427 i = var_attribute_string (v, 0, flags);
8868edaf
CR
8428 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16);
8429 if (val)
8430 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
8431 else
8432 sprintf (ret, "declare -%s %s", flags, v->name);
d233b485
CR
8433 free (val);
8434 return ret;
8435}
8436#endif
8437
8438static char *
8439pos_params_assignment (list, itype, quoted)
8440 WORD_LIST *list;
8441 int itype;
8442 int quoted;
8443{
8444 char *temp, *ret;
8445
8446 /* first, we transform the list to quote each word. */
8447 temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted);
8448 ret = (char *)xmalloc (strlen (temp) + 8);
8449 strcpy (ret, "set -- ");
8450 strcpy (ret + 7, temp);
8451 free (temp);
8452 return ret;
8453}
8454
8455static char *
8456string_transform (xc, v, s)
8457 int xc;
8458 SHELL_VAR *v;
8459 char *s;
8460{
8461 char *ret, flags[MAX_ATTRIBUTES], *t;
8462 int i;
8463
8868edaf
CR
8464 if (((xc == 'A' || xc == 'a') && v == 0))
8465 return (char *)NULL;
8466 else if (xc != 'a' && xc != 'A' && s == 0)
d233b485
CR
8467 return (char *)NULL;
8468
8469 switch (xc)
8470 {
8471 /* Transformations that interrogate the variable */
8472 case 'a':
8473 i = var_attribute_string (v, 0, flags);
8474 ret = (i > 0) ? savestring (flags) : (char *)NULL;
8475 break;
8476 case 'A':
8477 ret = string_var_assignment (v, s);
8478 break;
8868edaf 8479 case 'K':
74091dd4 8480 case 'k':
8868edaf
CR
8481 ret = sh_quote_reusable (s, 0);
8482 break;
d233b485
CR
8483 /* Transformations that modify the variable's value */
8484 case 'E':
8485 t = ansiexpand (s, 0, strlen (s), (int *)0);
8486 ret = dequote_escapes (t);
8487 free (t);
8488 break;
8489 case 'P':
8490 ret = decode_prompt_string (s);
8491 break;
8492 case 'Q':
8493 ret = sh_quote_reusable (s, 0);
8494 break;
8868edaf
CR
8495 case 'U':
8496 ret = sh_modcase (s, 0, CASE_UPPER);
8497 break;
8498 case 'u':
8499 ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */
8500 break;
8501 case 'L':
8502 ret = sh_modcase (s, 0, CASE_LOWER);
8503 break;
d233b485
CR
8504 default:
8505 ret = (char *)NULL;
8506 break;
8507 }
8508 return ret;
8509}
8510
8511static char *
8512list_transform (xc, v, list, itype, quoted)
8513 int xc;
8514 SHELL_VAR *v;
8515 WORD_LIST *list;
8516 int itype, quoted;
8517{
8518 WORD_LIST *new, *l;
8519 WORD_DESC *w;
8520 char *tword;
8521 int qflags;
8522
8523 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
8524 {
8525 tword = string_transform (xc, v, l->word->word);
8526 w = alloc_word_desc ();
8527 w->word = tword ? tword : savestring (""); /* XXX */
8528 new = make_word_list (w, new);
8529 }
8530 l = REVERSE_LIST (new, WORD_LIST *);
8531
8532 qflags = quoted;
8533 /* If we are expanding in a context where word splitting will not be
8534 performed, treat as quoted. This changes how $* will be expanded. */
8535 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
8536 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8537
8868edaf 8538 tword = string_list_pos_params (itype, l, qflags, 0);
d233b485
CR
8539 dispose_words (l);
8540
8541 return (tword);
8542}
8543
8544static char *
8545parameter_list_transform (xc, itype, quoted)
8546 int xc;
8547 int itype;
8548 int quoted;
8549{
8550 char *ret;
8551 WORD_LIST *list;
8552
8553 list = list_rest_of_args ();
8554 if (list == 0)
8555 return ((char *)NULL);
8556 if (xc == 'A')
8557 ret = pos_params_assignment (list, itype, quoted);
8558 else
8559 ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted);
8560 dispose_words (list);
8561 return (ret);
8562}
8563
8564#if defined (ARRAY_VARS)
8565static char *
8868edaf 8566array_transform (xc, var, starsub, quoted)
d233b485
CR
8567 int xc;
8568 SHELL_VAR *var;
8868edaf 8569 int starsub; /* so we can figure out how it's indexed */
d233b485
CR
8570 int quoted;
8571{
8572 ARRAY *a;
8573 HASH_TABLE *h;
74091dd4 8574 int itype, qflags;
d233b485
CR
8575 char *ret;
8576 WORD_LIST *list;
8577 SHELL_VAR *v;
8578
8868edaf 8579 v = var; /* XXX - for now */
d233b485 8580
8868edaf 8581 itype = starsub ? '*' : '@';
d233b485
CR
8582
8583 if (xc == 'A')
8868edaf
CR
8584 return (array_var_assignment (v, itype, quoted, 1));
8585 else if (xc == 'K')
8586 return (array_var_assignment (v, itype, quoted, 2));
8587
8588 /* special case for unset arrays and attributes */
8589 if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0))
8590 {
8591 char flags[MAX_ATTRIBUTES];
8592 int i;
8593
8594 i = var_attribute_string (v, 0, flags);
8595 return ((i > 0) ? savestring (flags) : (char *)NULL);
8596 }
d233b485
CR
8597
8598 a = (v && array_p (v)) ? array_cell (v) : 0;
8599 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
8868edaf 8600
74091dd4
CR
8601 /* XXX - for now */
8602 if (xc == 'k')
8603 {
8604 if (v == 0)
8605 return ((char *)NULL);
8606 list = array_p (v) ? array_to_kvpair_list (a) : assoc_to_kvpair_list (h);
8607 qflags = quoted;
8608 /* If we are expanding in a context where word splitting will not be
8609 performed, treat as quoted. This changes how $* will be expanded. */
8610 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
8611 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8612
8613 ret = string_list_pos_params (itype, list, qflags, 0);
8614 dispose_words (list);
8615 return ret;
8616 }
8617
d233b485
CR
8618 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
8619 if (list == 0)
8620 return ((char *)NULL);
8621 ret = list_transform (xc, v, list, itype, quoted);
8622 dispose_words (list);
8623
8624 return ret;
8625}
8626#endif /* ARRAY_VARS */
8627
8868edaf
CR
8628static int
8629valid_parameter_transform (xform)
8630 char *xform;
8631{
8632 if (xform[1])
8633 return 0;
8634
8635 /* check for valid values of xform[0] */
8636 switch (xform[0])
8637 {
8638 case 'a': /* expand to a string with just attributes */
8639 case 'A': /* expand as an assignment statement with attributes */
8640 case 'K': /* expand assoc array to list of key/value pairs */
74091dd4 8641 case 'k': /* XXX - for now */
8868edaf
CR
8642 case 'E': /* expand like $'...' */
8643 case 'P': /* expand like prompt string */
8644 case 'Q': /* quote reusably */
8645 case 'U': /* transform to uppercase */
74091dd4 8646 case 'u': /* transform by capitalizing */
8868edaf
CR
8647 case 'L': /* transform to lowercase */
8648 return 1;
8649 default:
8650 return 0;
8651 }
8652}
8653
d233b485 8654static char *
74091dd4 8655parameter_brace_transform (varname, value, estatep, xform, rtype, quoted, pflags, flags)
d233b485 8656 char *varname, *value;
74091dd4 8657 array_eltstate_t *estatep;
d233b485
CR
8658 char *xform;
8659 int rtype, quoted, pflags, flags;
8660{
8868edaf 8661 int vtype, xc, starsub;
d233b485
CR
8662 char *temp1, *val, *oname;
8663 SHELL_VAR *v;
8664
8665 xc = xform[0];
8666 if (value == 0 && xc != 'A' && xc != 'a')
8667 return ((char *)NULL);
8668
8669 oname = this_command_name;
8670 this_command_name = varname;
8671
74091dd4 8672 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
d233b485
CR
8673 if (vtype == -1)
8674 {
8675 this_command_name = oname;
8676 return ((char *)NULL);
8677 }
8678
74091dd4 8679 if (xform[0] == 0 || valid_parameter_transform (xform) == 0)
d233b485 8680 {
d233b485 8681 this_command_name = oname;
74091dd4
CR
8682 if (vtype == VT_VARIABLE)
8683 FREE (val);
8868edaf 8684 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
d233b485
CR
8685 }
8686
8868edaf
CR
8687 starsub = vtype & VT_STARSUB;
8688 vtype &= ~VT_STARSUB;
8689
d233b485
CR
8690 /* If we are asked to display the attributes of an unset variable, V will
8691 be NULL after the call to get_var_and_type. Double-check here. */
8868edaf 8692 if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0)
d233b485
CR
8693 v = find_variable (varname);
8694
8695 temp1 = (char *)NULL; /* shut up gcc */
8868edaf 8696 switch (vtype)
d233b485
CR
8697 {
8698 case VT_VARIABLE:
8699 case VT_ARRAYMEMBER:
8700 temp1 = string_transform (xc, v, val);
8701 if (vtype == VT_VARIABLE)
8702 FREE (val);
8703 if (temp1)
8704 {
8705 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8706 ? quote_string (temp1)
8707 : quote_escapes (temp1);
8708 free (temp1);
8709 temp1 = val;
8710 }
8711 break;
8712#if defined (ARRAY_VARS)
8713 case VT_ARRAYVAR:
8868edaf 8714 temp1 = array_transform (xc, v, starsub, quoted);
d233b485 8715 if (temp1 && quoted == 0 && ifs_is_null)
95732b49 8716 {
d233b485 8717 /* Posix interp 888 */
95732b49 8718 }
d233b485 8719 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3185942a 8720 {
d233b485
CR
8721 val = quote_escapes (temp1);
8722 free (temp1);
8723 temp1 = val;
3185942a 8724 }
d233b485 8725 break;
ccc6cda3 8726#endif
d233b485
CR
8727 case VT_POSPARMS:
8728 temp1 = parameter_list_transform (xc, varname[0], quoted);
8729 if (temp1 && quoted == 0 && ifs_is_null)
b80f6443 8730 {
d233b485 8731 /* Posix interp 888 */
b80f6443 8732 }
d233b485
CR
8733 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
8734 {
8735 val = quote_escapes (temp1);
8736 free (temp1);
8737 temp1 = val;
8738 }
8739 break;
b80f6443 8740 }
ccc6cda3 8741
d233b485
CR
8742 this_command_name = oname;
8743 return temp1;
ccc6cda3
JA
8744}
8745
cce855bc
JA
8746/******************************************************/
8747/* */
8748/* Functions to extract substrings of variable values */
8749/* */
8750/******************************************************/
8751
b80f6443
JA
8752#if defined (HANDLE_MULTIBYTE)
8753/* Character-oriented rather than strictly byte-oriented substrings. S and
8754 E, rather being strict indices into STRING, indicate character (possibly
8755 multibyte character) positions that require calculation.
8756 Used by the ${param:offset[:length]} expansion. */
8757static char *
8758mb_substring (string, s, e)
8759 char *string;
8760 int s, e;
8761{
8762 char *tt;
a0c0a00f
CR
8763 int start, stop, i;
8764 size_t slen;
b80f6443
JA
8765 DECLARE_MBSTATE;
8766
8767 start = 0;
95732b49
JA
8768 /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
8769 slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
b80f6443
JA
8770
8771 i = s;
8772 while (string[start] && i--)
8773 ADVANCE_CHAR (string, slen, start);
8774 stop = start;
8775 i = e - s;
8776 while (string[stop] && i--)
8777 ADVANCE_CHAR (string, slen, stop);
8778 tt = substring (string, start, stop);
8779 return tt;
8780}
8781#endif
8782
ccc6cda3
JA
8783/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
8784 is `@', use the positional parameters; otherwise, use the value of
8785 VARNAME. If VARNAME is an array variable, use the array elements. */
8786
8787static char *
74091dd4 8788parameter_brace_substring (varname, value, estatep, substr, quoted, pflags, flags)
495aee44 8789 char *varname, *value;
74091dd4 8790 array_eltstate_t *estatep;
495aee44 8791 char *substr;
d233b485 8792 int quoted, pflags, flags;
ccc6cda3 8793{
7117c2d2 8794 intmax_t e1, e2;
b80f6443 8795 int vtype, r, starsub;
0628567a 8796 char *temp, *val, *tt, *oname;
ccc6cda3
JA
8797 SHELL_VAR *v;
8798
a0c0a00f 8799 if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1]))
ccc6cda3
JA
8800 return ((char *)NULL);
8801
0628567a 8802 oname = this_command_name;
ccc6cda3
JA
8803 this_command_name = varname;
8804
74091dd4 8805 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
ccc6cda3 8806 if (vtype == -1)
0628567a
JA
8807 {
8808 this_command_name = oname;
8809 return ((char *)NULL);
8810 }
ccc6cda3 8811
b80f6443
JA
8812 starsub = vtype & VT_STARSUB;
8813 vtype &= ~VT_STARSUB;
8814
3185942a 8815 r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
0628567a 8816 this_command_name = oname;
e8ce775d 8817 if (r <= 0)
ac50fbac
CR
8818 {
8819 if (vtype == VT_VARIABLE)
8820 FREE (val);
8821 return ((r == 0) ? &expand_param_error : (char *)NULL);
8822 }
ccc6cda3
JA
8823
8824 switch (vtype)
8825 {
8826 case VT_VARIABLE:
d166f048 8827 case VT_ARRAYMEMBER:
b80f6443
JA
8828#if defined (HANDLE_MULTIBYTE)
8829 if (MB_CUR_MAX > 1)
8830 tt = mb_substring (val, e1, e2);
8831 else
8832#endif
7117c2d2 8833 tt = substring (val, e1, e2);
b80f6443 8834
7117c2d2
JA
8835 if (vtype == VT_VARIABLE)
8836 FREE (val);
8837 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8838 temp = quote_string (tt);
8839 else
8840 temp = tt ? quote_escapes (tt) : (char *)NULL;
8841 FREE (tt);
ccc6cda3
JA
8842 break;
8843 case VT_POSPARMS:
d233b485
CR
8844 case VT_ARRAYVAR:
8845 if (vtype == VT_POSPARMS)
8868edaf 8846 tt = pos_params (varname, e1, e2, quoted, pflags);
d233b485
CR
8847#if defined (ARRAY_VARS)
8848 /* assoc_subrange and array_subrange both call string_list_pos_params,
8849 so we can treat this case just like VT_POSPARAMS. */
8850 else if (assoc_p (v))
8851 /* we convert to list and take first e2 elements starting at e1th
8852 element -- officially undefined for now */
8868edaf 8853 tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags);
d233b485
CR
8854 else
8855 /* We want E2 to be the number of elements desired (arrays can be
8856 sparse, so verify_substring_values just returns the numbers
8857 specified and we rely on array_subrange to understand how to
8858 deal with them). */
8868edaf 8859 tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags);
d233b485
CR
8860#endif
8861 /* We want to leave this alone in every case where pos_params/
8862 string_list_pos_params quotes the list members */
8863 if (tt && quoted == 0 && ifs_is_null)
8864 {
8865 temp = tt; /* Posix interp 888 */
8866 }
8868edaf
CR
8867 else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS))
8868 {
8869 temp = tt; /* Posix interp 888 */
8870 }
d233b485 8871 else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
7117c2d2
JA
8872 {
8873 temp = tt ? quote_escapes (tt) : (char *)NULL;
8874 FREE (tt);
8875 }
8876 else
8877 temp = tt;
ccc6cda3 8878 break;
d233b485 8879
f73dda09
JA
8880 default:
8881 temp = (char *)NULL;
ccc6cda3
JA
8882 }
8883
8884 return temp;
8885}
8886
cce855bc
JA
8887/****************************************************************/
8888/* */
8889/* Functions to perform pattern substitution on variable values */
8890/* */
8891/****************************************************************/
8892
495aee44
CR
8893static int
8894shouldexp_replacement (s)
8895 char *s;
8896{
74091dd4
CR
8897 size_t slen;
8898 int sindex, c;
8899 DECLARE_MBSTATE;
495aee44 8900
74091dd4
CR
8901 sindex = 0;
8902 slen = STRLEN (s);
8903 while (c = s[sindex])
495aee44 8904 {
74091dd4
CR
8905 if (c == '\\')
8906 {
8907 sindex++;
8908 if (s[sindex] == 0)
8909 return 0;
8910 /* We want to remove this backslash because we treat it as special
8911 in this context. THIS ASSUMES THE STRING IS PROCESSED BY
8912 strcreplace() OR EQUIVALENT that handles removing backslashes
8913 preceding the special character. */
8914 if (s[sindex] == '&')
8915 return 1;
8916 if (s[sindex] == '\\')
8917 return 1;
8918 }
8919 else if (c == '&')
495aee44 8920 return 1;
74091dd4 8921 ADVANCE_CHAR (s, slen, sindex);
495aee44
CR
8922 }
8923 return 0;
8924}
8925
ccc6cda3
JA
8926char *
8927pat_subst (string, pat, rep, mflags)
8928 char *string, *pat, *rep;
8929 int mflags;
8930{
8868edaf 8931 char *ret, *s, *e, *str, *rstr, *mstr, *send;
a0c0a00f
CR
8932 int rptr, mtype, rxpand, mlen;
8933 size_t rsize, l, replen, rslen;
8868edaf 8934 DECLARE_MBSTATE;
495aee44 8935
d233b485 8936 if (string == 0)
495aee44 8937 return (savestring (""));
ccc6cda3 8938
b72432fd 8939 mtype = mflags & MATCH_TYPEMASK;
74091dd4 8940 rxpand = mflags & MATCH_EXPREP;
495aee44 8941
b72432fd
JA
8942 /* Special cases:
8943 * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
8944 * with REP and return the result.
8945 * 2. A null pattern with mtype == MATCH_END means to append REP to
8946 * STRING and return the result.
a0c0a00f
CR
8947 * 3. A null STRING with a matching pattern means to append REP to
8948 * STRING and return the result.
74091dd4
CR
8949 *
8950 * These process `&' in the replacement string, like `sed' does when
8951 * presented with a BRE of `^' or `$'.
b72432fd
JA
8952 */
8953 if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
8954 {
74091dd4
CR
8955 rstr = (mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2) : rep;
8956 rslen = STRLEN (rstr);
495aee44 8957 l = STRLEN (string);
74091dd4
CR
8958 ret = (char *)xmalloc (rslen + l + 2);
8959 if (rslen == 0)
bb70624e
JA
8960 strcpy (ret, string);
8961 else if (mtype == MATCH_BEG)
b72432fd 8962 {
74091dd4
CR
8963 strcpy (ret, rstr);
8964 strcpy (ret + rslen, string);
b72432fd
JA
8965 }
8966 else
8967 {
8968 strcpy (ret, string);
74091dd4 8969 strcpy (ret + l, rstr);
b72432fd 8970 }
74091dd4
CR
8971 if (rstr != rep)
8972 free (rstr);
b72432fd
JA
8973 return (ret);
8974 }
a0c0a00f 8975 else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
7b9954e6
CR
8976 return (mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2)
8977 : (rep ? savestring (rep) : savestring (""));
b72432fd 8978
f73dda09 8979 ret = (char *)xmalloc (rsize = 64);
ccc6cda3 8980 ret[0] = '\0';
8868edaf 8981 send = string + strlen (string);
ccc6cda3 8982
a0c0a00f 8983 for (replen = STRLEN (rep), rptr = 0, str = string; *str;)
ccc6cda3
JA
8984 {
8985 if (match_pattern (str, pat, mtype, &s, &e) == 0)
8986 break;
8987 l = s - str;
495aee44 8988
a0c0a00f 8989 if (rep && rxpand)
495aee44 8990 {
a0c0a00f
CR
8991 int x;
8992 mlen = e - s;
8993 mstr = xmalloc (mlen + 1);
495aee44
CR
8994 for (x = 0; x < mlen; x++)
8995 mstr[x] = s[x];
a0c0a00f 8996 mstr[mlen] = '\0';
74091dd4 8997 rstr = strcreplace (rep, '&', mstr, 2);
a0c0a00f
CR
8998 free (mstr);
8999 rslen = strlen (rstr);
495aee44
CR
9000 }
9001 else
a0c0a00f
CR
9002 {
9003 rstr = rep;
9004 rslen = replen;
9005 }
495aee44
CR
9006
9007 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
ccc6cda3
JA
9008
9009 /* OK, now copy the leading unmatched portion of the string (from
9010 str to s) to ret starting at rptr (the current offset). Then copy
28ef6c31
JA
9011 the replacement string at ret + rptr + (s - str). Increment
9012 rptr (if necessary) and str and go on. */
ccc6cda3
JA
9013 if (l)
9014 {
9015 strncpy (ret + rptr, str, l);
9016 rptr += l;
9017 }
9018 if (replen)
9019 {
495aee44
CR
9020 strncpy (ret + rptr, rstr, rslen);
9021 rptr += rslen;
ccc6cda3
JA
9022 }
9023 str = e; /* e == end of match */
b80f6443 9024
495aee44
CR
9025 if (rstr != rep)
9026 free (rstr);
9027
ccc6cda3 9028 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
28ef6c31 9029 break;
b80f6443
JA
9030
9031 if (s == e)
0001803f
CR
9032 {
9033 /* On a zero-length match, make sure we copy one character, since
9034 we increment one character to avoid infinite recursion. */
8868edaf
CR
9035 char *p, *origp, *origs;
9036 size_t clen;
9037
9038 RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64);
9039#if defined (HANDLE_MULTIBYTE)
9040 p = origp = ret + rptr;
9041 origs = str;
9042 COPY_CHAR_P (p, str, send);
9043 rptr += p - origp;
9044 e += str - origs;
9045#else
0001803f
CR
9046 ret[rptr++] = *str++;
9047 e++; /* avoid infinite recursion on zero-length match */
8868edaf 9048#endif
0001803f 9049 }
ccc6cda3
JA
9050 }
9051
9052 /* Now copy the unmatched portion of the input string */
495aee44 9053 if (str && *str)
d166f048 9054 {
74091dd4
CR
9055 l = send - str + 1;
9056 RESIZE_MALLOCED_BUFFER (ret, rptr, l, rsize, 64);
d166f048
JA
9057 strcpy (ret + rptr, str);
9058 }
ccc6cda3
JA
9059 else
9060 ret[rptr] = '\0';
9061
9062 return ret;
9063}
9064
9065/* Do pattern match and replacement on the positional parameters. */
9066static char *
9067pos_params_pat_subst (string, pat, rep, mflags)
9068 char *string, *pat, *rep;
9069 int mflags;
9070{
9071 WORD_LIST *save, *params;
9072 WORD_DESC *w;
0628567a 9073 char *ret;
8868edaf 9074 int pchar, qflags, pflags;
ccc6cda3
JA
9075
9076 save = params = list_rest_of_args ();
9077 if (save == 0)
9078 return ((char *)NULL);
9079
9080 for ( ; params; params = params->next)
9081 {
9082 ret = pat_subst (params->word->word, pat, rep, mflags);
95732b49
JA
9083 w = alloc_word_desc ();
9084 w->word = ret ? ret : savestring ("");
ccc6cda3
JA
9085 dispose_word (params->word);
9086 params->word = w;
ccc6cda3
JA
9087 }
9088
3185942a
JA
9089 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
9090 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
8868edaf 9091 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
3185942a 9092
d233b485
CR
9093 /* If we are expanding in a context where word splitting will not be
9094 performed, treat as quoted. This changes how $* will be expanded. */
9095 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null)
9096 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
3185942a 9097
8868edaf 9098 ret = string_list_pos_params (pchar, save, qflags, pflags);
ccc6cda3
JA
9099 dispose_words (save);
9100
9101 return (ret);
9102}
9103
cce855bc
JA
9104/* Perform pattern substitution on VALUE, which is the expansion of
9105 VARNAME. PATSUB is an expression supplying the pattern to match
9106 and the string to substitute. QUOTED is a flags word containing
9107 the type of quoting currently in effect. */
ccc6cda3 9108static char *
74091dd4 9109parameter_brace_patsub (varname, value, estatep, patsub, quoted, pflags, flags)
495aee44 9110 char *varname, *value;
74091dd4 9111 array_eltstate_t *estatep;
495aee44 9112 char *patsub;
a0c0a00f 9113 int quoted, pflags, flags;
ccc6cda3 9114{
3185942a 9115 int vtype, mflags, starsub, delim;
d233b485 9116 char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname;
ccc6cda3
JA
9117 SHELL_VAR *v;
9118
9119 if (value == 0)
9120 return ((char *)NULL);
9121
d233b485
CR
9122 oname = this_command_name;
9123 this_command_name = varname; /* error messages */
ccc6cda3 9124
74091dd4 9125 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
ccc6cda3 9126 if (vtype == -1)
d233b485
CR
9127 {
9128 this_command_name = oname;
9129 return ((char *)NULL);
9130 }
ccc6cda3 9131
b80f6443
JA
9132 starsub = vtype & VT_STARSUB;
9133 vtype &= ~VT_STARSUB;
9134
ccc6cda3 9135 mflags = 0;
ac50fbac
CR
9136 /* PATSUB is never NULL when this is called. */
9137 if (*patsub == '/')
f1be666c
JA
9138 {
9139 mflags |= MATCH_GLOBREP;
9140 patsub++;
9141 }
7117c2d2
JA
9142
9143 /* Malloc this because expand_string_if_necessary or one of the expansion
9144 functions in its call chain may free it on a substitution error. */
bb70624e 9145 lpatsub = savestring (patsub);
ccc6cda3
JA
9146
9147 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9148 mflags |= MATCH_QUOTED;
9149
b80f6443
JA
9150 if (starsub)
9151 mflags |= MATCH_STARSUB;
9152
a0c0a00f
CR
9153 if (pflags & PF_ASSIGNRHS)
9154 mflags |= MATCH_ASSIGNRHS;
9155
0628567a
JA
9156 /* If the pattern starts with a `/', make sure we skip over it when looking
9157 for the replacement delimiter. */
3185942a
JA
9158 delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
9159 if (lpatsub[delim] == '/')
9160 {
9161 lpatsub[delim] = 0;
9162 rep = lpatsub + delim + 1;
9163 }
9164 else
9165 rep = (char *)NULL;
ccc6cda3
JA
9166
9167 if (rep && *rep == '\0')
9168 rep = (char *)NULL;
9169
b80f6443
JA
9170 /* Perform the same expansions on the pattern as performed by the
9171 pattern removal expansions. */
9172 pat = getpattern (lpatsub, quoted, 1);
bb70624e 9173
ccc6cda3 9174 if (rep)
d166f048 9175 {
ac50fbac
CR
9176 /* We want to perform quote removal on the expanded replacement even if
9177 the entire expansion is double-quoted because the parser and string
9178 extraction functions treated quotes in the replacement string as
9179 special. THIS IS NOT BACKWARDS COMPATIBLE WITH BASH-4.2. */
74091dd4 9180 if (shell_compatibility_level > 42 && patsub_replacement == 0)
ac50fbac 9181 rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
74091dd4
CR
9182 else if (shell_compatibility_level > 42 && patsub_replacement)
9183 rep = expand_string_for_patsub (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT));
ac50fbac
CR
9184 /* This is the bash-4.2 code. */
9185 else if ((mflags & MATCH_QUOTED) == 0)
f73dda09 9186 rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
d166f048 9187 else
f73dda09 9188 rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
74091dd4
CR
9189
9190 /* Check whether or not to replace `&' in the replacement string after
9191 expanding it, since we want to treat backslashes quoting the `&'
9192 consistently. */
9193 if (patsub_replacement && rep && *rep && shouldexp_replacement (rep))
9194 mflags |= MATCH_EXPREP;
9195
d166f048 9196 }
ccc6cda3 9197
0628567a 9198 /* ksh93 doesn't allow the match specifier to be a part of the expanded
f1be666c
JA
9199 pattern. This is an extension. Make sure we don't anchor the pattern
9200 at the beginning or end of the string if we're doing global replacement,
9201 though. */
ccc6cda3 9202 p = pat;
f1be666c
JA
9203 if (mflags & MATCH_GLOBREP)
9204 mflags |= MATCH_ANY;
0628567a 9205 else if (pat && pat[0] == '#')
ccc6cda3
JA
9206 {
9207 mflags |= MATCH_BEG;
9208 p++;
9209 }
d166f048 9210 else if (pat && pat[0] == '%')
ccc6cda3
JA
9211 {
9212 mflags |= MATCH_END;
9213 p++;
9214 }
9215 else
9216 mflags |= MATCH_ANY;
9217
cce855bc
JA
9218 /* OK, we now want to substitute REP for PAT in VAL. If
9219 flags & MATCH_GLOBREP is non-zero, the substitution is done
9220 everywhere, otherwise only the first occurrence of PAT is
7117c2d2
JA
9221 replaced. The pattern matching code doesn't understand
9222 CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
9223 values passed in (VT_VARIABLE) so the pattern substitution
9224 code works right. We need to requote special chars after
9225 we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
9226 other cases if QUOTED == 0, since the posparams and arrays
9227 indexed by * or @ do special things when QUOTED != 0. */
9228
ccc6cda3
JA
9229 switch (vtype)
9230 {
9231 case VT_VARIABLE:
d166f048 9232 case VT_ARRAYMEMBER:
ccc6cda3 9233 temp = pat_subst (val, p, rep, mflags);
7117c2d2
JA
9234 if (vtype == VT_VARIABLE)
9235 FREE (val);
9236 if (temp)
9237 {
3185942a 9238 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
7117c2d2
JA
9239 free (temp);
9240 temp = tt;
9241 }
ccc6cda3
JA
9242 break;
9243 case VT_POSPARMS:
d233b485
CR
9244 /* This does the right thing for the case where we are not performing
9245 word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and
9246 pos_params_pat_subst/string_list_pos_params will do the right thing
9247 in turn for the case where ifs_is_null. Posix interp 888 */
9248 if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB))
9249 mflags |= MATCH_ASSIGNRHS;
ccc6cda3 9250 temp = pos_params_pat_subst (val, p, rep, mflags);
d233b485
CR
9251 if (temp && quoted == 0 && ifs_is_null)
9252 {
9253 /* Posix interp 888 */
9254 }
8868edaf
CR
9255 else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS))
9256 {
9257 /* Posix interp 888 */
9258 }
d233b485 9259 else if (temp && (mflags & MATCH_QUOTED) == 0)
7117c2d2
JA
9260 {
9261 tt = quote_escapes (temp);
9262 free (temp);
9263 temp = tt;
9264 }
ccc6cda3
JA
9265 break;
9266#if defined (ARRAY_VARS)
9267 case VT_ARRAYVAR:
d233b485
CR
9268 /* If we are expanding in a context where word splitting will not be
9269 performed, treat as quoted. This changes how ${A[*]} will be
9270 expanded to make it identical to $*. */
9271 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9272 mflags |= MATCH_QUOTED; /* Posix interp 888 */
9273
9274 /* these eventually call string_list_pos_params */
9275 if (assoc_p (v))
9276 temp = assoc_patsub (assoc_cell (v), p, rep, mflags);
9277 else
9278 temp = array_patsub (array_cell (v), p, rep, mflags);
9279
9280 if (temp && quoted == 0 && ifs_is_null)
9281 {
9282 /* Posix interp 888 */
9283 }
9284 else if (temp && (mflags & MATCH_QUOTED) == 0)
9285 {
9286 tt = quote_escapes (temp);
9287 free (temp);
9288 temp = tt;
9289 }
3185942a
JA
9290 break;
9291#endif
9292 }
9293
9294 FREE (pat);
9295 FREE (rep);
9296 free (lpatsub);
9297
d233b485
CR
9298 this_command_name = oname;
9299
3185942a
JA
9300 return temp;
9301}
9302
9303/****************************************************************/
9304/* */
9305/* Functions to perform case modification on variable values */
9306/* */
9307/****************************************************************/
9308
9309/* Do case modification on the positional parameters. */
9310
9311static char *
9312pos_params_modcase (string, pat, modop, mflags)
9313 char *string, *pat;
9314 int modop;
9315 int mflags;
9316{
9317 WORD_LIST *save, *params;
9318 WORD_DESC *w;
9319 char *ret;
8868edaf 9320 int pchar, qflags, pflags;
3185942a
JA
9321
9322 save = params = list_rest_of_args ();
9323 if (save == 0)
9324 return ((char *)NULL);
9325
9326 for ( ; params; params = params->next)
9327 {
9328 ret = sh_modcase (params->word->word, pat, modop);
9329 w = alloc_word_desc ();
9330 w->word = ret ? ret : savestring ("");
9331 dispose_word (params->word);
9332 params->word = w;
9333 }
9334
9335 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
9336 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
8868edaf 9337 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
3185942a 9338
d233b485
CR
9339 /* If we are expanding in a context where word splitting will not be
9340 performed, treat as quoted. This changes how $* will be expanded. */
9341 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9342 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
9343
8868edaf 9344 ret = string_list_pos_params (pchar, save, qflags, pflags);
3185942a
JA
9345 dispose_words (save);
9346
9347 return (ret);
9348}
9349
9350/* Perform case modification on VALUE, which is the expansion of
9351 VARNAME. MODSPEC is an expression supplying the type of modification
9352 to perform. QUOTED is a flags word containing the type of quoting
9353 currently in effect. */
9354static char *
74091dd4 9355parameter_brace_casemod (varname, value, estatep, modspec, patspec, quoted, pflags, flags)
3185942a 9356 char *varname, *value;
74091dd4
CR
9357 array_eltstate_t *estatep;
9358 int modspec;
3185942a 9359 char *patspec;
d233b485 9360 int quoted, pflags, flags;
3185942a
JA
9361{
9362 int vtype, starsub, modop, mflags, x;
d233b485 9363 char *val, *temp, *pat, *p, *lpat, *tt, *oname;
3185942a
JA
9364 SHELL_VAR *v;
9365
9366 if (value == 0)
9367 return ((char *)NULL);
9368
d233b485 9369 oname = this_command_name;
3185942a
JA
9370 this_command_name = varname;
9371
74091dd4 9372 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
3185942a 9373 if (vtype == -1)
d233b485
CR
9374 {
9375 this_command_name = oname;
9376 return ((char *)NULL);
9377 }
3185942a
JA
9378
9379 starsub = vtype & VT_STARSUB;
9380 vtype &= ~VT_STARSUB;
9381
9382 modop = 0;
9383 mflags = 0;
9384 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9385 mflags |= MATCH_QUOTED;
9386 if (starsub)
9387 mflags |= MATCH_STARSUB;
d233b485
CR
9388 if (pflags & PF_ASSIGNRHS)
9389 mflags |= MATCH_ASSIGNRHS;
3185942a
JA
9390
9391 p = patspec;
9392 if (modspec == '^')
9393 {
9394 x = p && p[0] == modspec;
17345e5a 9395 modop = x ? CASE_UPPER : CASE_UPFIRST;
3185942a
JA
9396 p += x;
9397 }
9398 else if (modspec == ',')
9399 {
9400 x = p && p[0] == modspec;
17345e5a 9401 modop = x ? CASE_LOWER : CASE_LOWFIRST;
3185942a
JA
9402 p += x;
9403 }
9404 else if (modspec == '~')
9405 {
9406 x = p && p[0] == modspec;
9407 modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
9408 p += x;
9409 }
9410
9411 lpat = p ? savestring (p) : 0;
9412 /* Perform the same expansions on the pattern as performed by the
d233b485 9413 pattern removal expansions. */
3185942a
JA
9414 pat = lpat ? getpattern (lpat, quoted, 1) : 0;
9415
9416 /* OK, now we do the case modification. */
9417 switch (vtype)
9418 {
9419 case VT_VARIABLE:
9420 case VT_ARRAYMEMBER:
9421 temp = sh_modcase (val, pat, modop);
9422 if (vtype == VT_VARIABLE)
9423 FREE (val);
9424 if (temp)
9425 {
9426 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
9427 free (temp);
9428 temp = tt;
9429 }
9430 break;
9431
9432 case VT_POSPARMS:
9433 temp = pos_params_modcase (val, pat, modop, mflags);
d233b485
CR
9434 if (temp && quoted == 0 && ifs_is_null)
9435 {
9436 /* Posix interp 888 */
9437 }
9438 else if (temp && (mflags & MATCH_QUOTED) == 0)
7117c2d2
JA
9439 {
9440 tt = quote_escapes (temp);
9441 free (temp);
9442 temp = tt;
9443 }
3185942a
JA
9444 break;
9445
9446#if defined (ARRAY_VARS)
9447 case VT_ARRAYVAR:
d233b485
CR
9448 /* If we are expanding in a context where word splitting will not be
9449 performed, treat as quoted. This changes how ${A[*]} will be
9450 expanded to make it identical to $*. */
9451 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9452 mflags |= MATCH_QUOTED; /* Posix interp 888 */
9453
3185942a
JA
9454 temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
9455 : array_modcase (array_cell (v), pat, modop, mflags);
d233b485
CR
9456
9457 if (temp && quoted == 0 && ifs_is_null)
9458 {
9459 /* Posix interp 888 */
9460 }
9461 else if (temp && (mflags & MATCH_QUOTED) == 0)
9462 {
9463 tt = quote_escapes (temp);
9464 free (temp);
9465 temp = tt;
9466 }
9467
ccc6cda3
JA
9468 break;
9469#endif
9470 }
9471
9472 FREE (pat);
3185942a 9473 free (lpat);
ccc6cda3 9474
d233b485
CR
9475 this_command_name = oname;
9476
ccc6cda3
JA
9477 return temp;
9478}
9479
0628567a
JA
9480/* Check for unbalanced parens in S, which is the contents of $(( ... )). If
9481 any occur, this must be a nested command substitution, so return 0.
9482 Otherwise, return 1. A valid arithmetic expression must always have a
9483 ( before a matching ), so any cases where there are more right parens
9484 means that this must not be an arithmetic expression, though the parser
9485 will not accept it without a balanced total number of parens. */
9486static int
9487chk_arithsub (s, len)
9488 const char *s;
9489 int len;
9490{
9491 int i, count;
9492 DECLARE_MBSTATE;
9493
9494 i = count = 0;
9495 while (i < len)
9496 {
0001803f 9497 if (s[i] == LPAREN)
0628567a 9498 count++;
0001803f 9499 else if (s[i] == RPAREN)
0628567a
JA
9500 {
9501 count--;
9502 if (count < 0)
9503 return 0;
9504 }
9505
9506 switch (s[i])
9507 {
9508 default:
9509 ADVANCE_CHAR (s, len, i);
9510 break;
9511
9512 case '\\':
9513 i++;
9514 if (s[i])
9515 ADVANCE_CHAR (s, len, i);
9516 break;
9517
9518 case '\'':
a0c0a00f 9519 i = skip_single_quoted (s, len, ++i, 0);
0628567a
JA
9520 break;
9521
9522 case '"':
a0c0a00f 9523 i = skip_double_quoted ((char *)s, len, ++i, 0);
0628567a
JA
9524 break;
9525 }
9526 }
9527
9528 return (count == 0);
9529}
9530
cce855bc
JA
9531/****************************************************************/
9532/* */
9533/* Functions to perform parameter expansion on a string */
9534/* */
9535/****************************************************************/
9536
3185942a 9537/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
95732b49 9538static WORD_DESC *
0001803f 9539parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
ccc6cda3 9540 char *string;
a0c0a00f 9541 int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at;
ccc6cda3
JA
9542{
9543 int check_nullness, var_is_set, var_is_null, var_is_special;
8868edaf 9544 int want_substring, want_indir, want_patsub, want_casemod, want_attributes;
ccc6cda3 9545 char *name, *value, *temp, *temp1;
95732b49 9546 WORD_DESC *tdesc, *ret;
8868edaf 9547 int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref;
7117c2d2 9548 intmax_t number;
74091dd4 9549 array_eltstate_t es;
ccc6cda3 9550
3185942a 9551 temp = temp1 = value = (char *)NULL;
ccc6cda3 9552 var_is_set = var_is_null = var_is_special = check_nullness = 0;
8868edaf 9553 want_substring = want_indir = want_patsub = want_casemod = want_attributes = 0;
ccc6cda3 9554
8868edaf 9555 local_pflags = 0;
a0c0a00f
CR
9556 all_element_arrayref = 0;
9557
cce855bc
JA
9558 sindex = *indexp;
9559 t_index = ++sindex;
0628567a
JA
9560 /* ${#var} doesn't have any of the other parameter expansions on it. */
9561 if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
3185942a 9562 name = string_extract (string, &t_index, "}", SX_VARNAME);
0628567a 9563 else
3185942a
JA
9564#if defined (CASEMOD_EXPANSIONS)
9565 /* To enable case-toggling expansions using the `~' operator character
8868edaf
CR
9566 define CASEMOD_TOGGLECASE in config-top.h */
9567# if defined (CASEMOD_TOGGLECASE)
a0c0a00f 9568 name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME);
3185942a 9569# else
a0c0a00f 9570 name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME);
8868edaf 9571# endif /* CASEMOD_TOGGLECASE */
3185942a 9572#else
a0c0a00f 9573 name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME);
3185942a 9574#endif /* CASEMOD_EXPANSIONS */
cce855bc 9575
a0c0a00f
CR
9576 /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly
9577 the cleanest code ever. */
9578 if (*name == 0 && sindex == t_index && string[sindex] == '@')
9579 {
9580 name = (char *)xrealloc (name, 2);
9581 name[0] = '@';
9582 name[1] = '\0';
9583 t_index++;
9584 }
d233b485 9585 else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE)
a0c0a00f
CR
9586 {
9587 name = (char *)xrealloc (name, t_index - sindex + 2);
9588 name[t_index - sindex] = '@';
9589 name[t_index - sindex + 1] = '\0';
9590 t_index++;
9591 }
9592
95732b49
JA
9593 ret = 0;
9594 tflag = 0;
9595
74091dd4
CR
9596#if defined (ARRAY_VARS)
9597 init_eltstate (&es);
9598#endif
9599 es.ind = INTMAX_MIN; /* XXX */
495aee44 9600
cce855bc
JA
9601 /* If the name really consists of a special variable, then make sure
9602 that we have the entire name. We don't allow indirect references
a0c0a00f
CR
9603 to special variables except `#', `?', `@' and `*'. This clause is
9604 designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more
9605 general. */
495aee44 9606 if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
a0c0a00f 9607 (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) ||
495aee44 9608 (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
ccc6cda3
JA
9609 {
9610 t_index++;
a0c0a00f 9611 temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0);
ac50fbac 9612 name = (char *)xrealloc (name, 3 + (strlen (temp1)));
ccc6cda3
JA
9613 *name = string[sindex];
9614 if (string[sindex] == '!')
9615 {
28ef6c31
JA
9616 /* indirect reference of $#, $?, $@, or $* */
9617 name[1] = string[sindex + 1];
9618 strcpy (name + 2, temp1);
ccc6cda3 9619 }
cce855bc 9620 else
ccc6cda3
JA
9621 strcpy (name + 1, temp1);
9622 free (temp1);
9623 }
9624 sindex = t_index;
9625
9626 /* Find out what character ended the variable name. Then
9627 do the appropriate thing. */
9628 if (c = string[sindex])
9629 sindex++;
9630
9631 /* If c is followed by one of the valid parameter expansion
9632 characters, move past it as normal. If not, assume that
9633 a substring specification is being given, and do not move
9634 past it. */
28ef6c31 9635 if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
ccc6cda3
JA
9636 {
9637 check_nullness++;
9638 if (c = string[sindex])
9639 sindex++;
9640 }
cce855bc 9641 else if (c == ':' && string[sindex] != RBRACE)
ccc6cda3 9642 want_substring = 1;
ac50fbac 9643 else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */
ccc6cda3 9644 want_patsub = 1;
3185942a
JA
9645#if defined (CASEMOD_EXPANSIONS)
9646 else if (c == '^' || c == ',' || c == '~')
9647 {
9648 modspec = c;
9649 want_casemod = 1;
9650 }
9651#endif
8868edaf
CR
9652 else if (c == '@' && (string[sindex] == 'a' || string[sindex] == 'A') && string[sindex+1] == RBRACE)
9653 {
9654 /* special case because we do not want to shortcut foo as foo[0] here */
9655 want_attributes = 1;
9656 local_pflags |= PF_ALLINDS;
9657 }
ccc6cda3 9658
cce855bc
JA
9659 /* Catch the valid and invalid brace expressions that made it through the
9660 tests above. */
9661 /* ${#-} is a valid expansion and means to take the length of $-.
9662 Similarly for ${#?} and ${##}... */
9663 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
28ef6c31 9664 VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
cce855bc 9665 {
f73dda09 9666 name = (char *)xrealloc (name, 3);
cce855bc
JA
9667 name[1] = c;
9668 name[2] = '\0';
9669 c = string[sindex++];
9670 }
9671
9672 /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
9673 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
9674 member (c, "%:=+/") && string[sindex] == RBRACE)
9675 {
9676 temp = (char *)NULL;
a0c0a00f 9677 goto bad_substitution; /* XXX - substitution error */
cce855bc
JA
9678 }
9679
9680 /* Indirect expansion begins with a `!'. A valid indirect expansion is
9681 either a variable name, one of the positional parameters or a special
9682 variable that expands to one of the positional parameters. */
9683 want_indir = *name == '!' &&
f73dda09 9684 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
7117c2d2 9685 || VALID_INDIR_PARAM (name[1]));
ccc6cda3 9686
d233b485 9687 /* Determine the value of this variable whose name is NAME. */
ccc6cda3 9688
cce855bc 9689 /* Check for special variables, directly referenced. */
bb70624e 9690 if (SPECIAL_VAR (name, want_indir))
ccc6cda3
JA
9691 var_is_special++;
9692
cce855bc
JA
9693 /* Check for special expansion things, like the length of a parameter */
9694 if (*name == '#' && name[1])
ccc6cda3 9695 {
cce855bc 9696 /* If we are not pointing at the character just after the
28ef6c31
JA
9697 closing brace, then we haven't gotten all of the name.
9698 Since it begins with a special character, this is a bad
9699 substitution. Also check NAME for validity before trying
9700 to go on. */
cce855bc 9701 if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
ccc6cda3
JA
9702 {
9703 temp = (char *)NULL;
a0c0a00f 9704 goto bad_substitution; /* substitution error */
ccc6cda3
JA
9705 }
9706
9707 number = parameter_brace_expand_length (name);
495aee44
CR
9708 if (number == INTMAX_MIN && unbound_vars_is_error)
9709 {
8868edaf 9710 set_exit_status (EXECUTION_FAILURE);
495aee44
CR
9711 err_unboundvar (name+1);
9712 free (name);
9713 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9714 }
ccc6cda3
JA
9715 free (name);
9716
9717 *indexp = sindex;
95732b49
JA
9718 if (number < 0)
9719 return (&expand_wdesc_error);
9720 else
9721 {
9722 ret = alloc_word_desc ();
9723 ret->word = itos (number);
9724 return ret;
9725 }
ccc6cda3
JA
9726 }
9727
9728 /* ${@} is identical to $@. */
9729 if (name[0] == '@' && name[1] == '\0')
9730 {
9731 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9732 *quoted_dollar_atp = 1;
9733
9734 if (contains_dollar_at)
9735 *contains_dollar_at = 1;
ac50fbac
CR
9736
9737 tflag |= W_DOLLARAT;
ccc6cda3
JA
9738 }
9739
b80f6443 9740 /* Process ${!PREFIX*} expansion. */
bb70624e
JA
9741 if (want_indir && string[sindex - 1] == RBRACE &&
9742 (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
f73dda09 9743 legal_variable_starter ((unsigned char) name[1]))
bb70624e
JA
9744 {
9745 char **x;
9746 WORD_LIST *xlist;
9747
9748 temp1 = savestring (name + 1);
9749 number = strlen (temp1);
9750 temp1[number - 1] = '\0';
9751 x = all_variables_matching_prefix (temp1);
7117c2d2 9752 xlist = strvec_to_word_list (x, 0, 0);
28ef6c31 9753 if (string[sindex - 2] == '*')
d233b485 9754 temp = string_list_dollar_star (xlist, quoted, 0);
28ef6c31
JA
9755 else
9756 {
a0c0a00f 9757 temp = string_list_dollar_at (xlist, quoted, 0);
28ef6c31
JA
9758 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9759 *quoted_dollar_atp = 1;
9760 if (contains_dollar_at)
9761 *contains_dollar_at = 1;
ac50fbac
CR
9762
9763 tflag |= W_DOLLARAT;
28ef6c31 9764 }
bb70624e 9765 free (x);
89a92869 9766 dispose_words (xlist);
bb70624e
JA
9767 free (temp1);
9768 *indexp = sindex;
95732b49 9769
ac50fbac
CR
9770 free (name);
9771
95732b49
JA
9772 ret = alloc_word_desc ();
9773 ret->word = temp;
ac50fbac 9774 ret->flags = tflag; /* XXX */
95732b49 9775 return ret;
bb70624e 9776 }
b80f6443
JA
9777
9778#if defined (ARRAY_VARS)
d233b485 9779 /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */
b80f6443 9780 if (want_indir && string[sindex - 1] == RBRACE &&
d233b485 9781 string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0))
b80f6443
JA
9782 {
9783 char *x, *x1;
9784
9785 temp1 = savestring (name + 1);
d233b485 9786 x = array_variable_name (temp1, 0, &x1, (int *)0);
b80f6443 9787 FREE (x);
d233b485 9788 if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK)
b80f6443 9789 {
8868edaf 9790 temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */
b80f6443
JA
9791 if (x1[0] == '@')
9792 {
9793 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9794 *quoted_dollar_atp = 1;
9795 if (contains_dollar_at)
9796 *contains_dollar_at = 1;
ac50fbac
CR
9797
9798 tflag |= W_DOLLARAT;
b80f6443
JA
9799 }
9800
a0c0a00f 9801 free (name);
b80f6443
JA
9802 free (temp1);
9803 *indexp = sindex;
95732b49
JA
9804
9805 ret = alloc_word_desc ();
9806 ret->word = temp;
ac50fbac 9807 ret->flags = tflag; /* XXX */
95732b49 9808 return ret;
b80f6443
JA
9809 }
9810
9811 free (temp1);
9812 }
9813#endif /* ARRAY_VARS */
bb70624e 9814
ccc6cda3
JA
9815 /* Make sure that NAME is valid before trying to go on. */
9816 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
9817 var_is_special) == 0)
9818 {
9819 temp = (char *)NULL;
a0c0a00f 9820 goto bad_substitution; /* substitution error */
ccc6cda3
JA
9821 }
9822
9823 if (want_indir)
1a1f8b54 9824 {
8868edaf 9825 tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags|local_pflags, quoted_dollar_atp, contains_dollar_at);
a0c0a00f
CR
9826 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9827 {
9828 temp = (char *)NULL;
9829 goto bad_substitution;
9830 }
d233b485 9831
1a1f8b54
CR
9832 /* Turn off the W_ARRAYIND flag because there is no way for this function
9833 to return the index we're supposed to be using. */
9834 if (tdesc && tdesc->flags)
9835 tdesc->flags &= ~W_ARRAYIND;
74091dd4
CR
9836
9837 /* If the indir expansion contains $@/$*, extend the special treatment
9838 of the case of no positional parameters and `set -u' to it. */
9839 if (contains_dollar_at && *contains_dollar_at)
9840 all_element_arrayref = 1;
1a1f8b54 9841 }
95732b49 9842 else
8868edaf
CR
9843 {
9844 local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS));
74091dd4 9845 tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &es);
8868edaf 9846 }
95732b49 9847
d233b485
CR
9848 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9849 {
9850 tflag = 0;
9851 tdesc = 0;
9852 }
9853
95732b49
JA
9854 if (tdesc)
9855 {
9856 temp = tdesc->word;
9857 tflag = tdesc->flags;
9858 dispose_word_desc (tdesc);
9859 }
ccc6cda3 9860 else
74091dd4 9861 temp = (char *)0;
ccc6cda3 9862
ac50fbac
CR
9863 if (temp == &expand_param_error || temp == &expand_param_fatal)
9864 {
9865 FREE (name);
9866 FREE (value);
9867 return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9868 }
9869
ccc6cda3 9870#if defined (ARRAY_VARS)
a0c0a00f
CR
9871 if (valid_array_reference (name, 0))
9872 {
9873 int qflags;
9874 char *t;
9875
9876 qflags = quoted;
9877 /* If in a context where word splitting will not take place, treat as
9878 if double-quoted. Has effects with $* and ${array[*]} */
d233b485 9879
a0c0a00f
CR
9880 if (pflags & PF_ASSIGNRHS)
9881 qflags |= Q_DOUBLE_QUOTES;
a0c0a00f 9882 /* We duplicate a little code here */
d233b485
CR
9883 t = mbschr (name, LBRACK);
9884 if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK)
9885 {
9886 all_element_arrayref = 1;
9887 if (expand_no_split_dollar_star && t[1] == '*') /* XXX */
9888 qflags |= Q_DOUBLE_QUOTES;
9889 }
8868edaf 9890 chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at);
a0c0a00f 9891 }
ccc6cda3
JA
9892#endif
9893
9894 var_is_set = temp != (char *)0;
9895 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
ac50fbac
CR
9896 /* XXX - this may not need to be restricted to special variables */
9897 if (check_nullness)
9898 var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp);
d233b485
CR
9899#if defined (ARRAY_VARS)
9900 if (check_nullness)
9901 var_is_null |= var_is_set &&
9902 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) &&
9903 QUOTED_NULL (temp) &&
9904 valid_array_reference (name, 0) &&
8868edaf 9905 chk_atstar (name, 0, 0, (int *)0, (int *)0);
d233b485 9906#endif
ccc6cda3
JA
9907
9908 /* Get the rest of the stuff inside the braces. */
cce855bc 9909 if (c && c != RBRACE)
ccc6cda3
JA
9910 {
9911 /* Extract the contents of the ${ ... } expansion
28ef6c31 9912 according to the Posix.2 rules. */
49ed961b 9913 value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
cce855bc 9914 if (string[sindex] == RBRACE)
28ef6c31 9915 sindex++;
ccc6cda3 9916 else
a0c0a00f 9917 goto bad_substitution; /* substitution error */
ccc6cda3
JA
9918 }
9919 else
9920 value = (char *)NULL;
726f6388 9921
ccc6cda3
JA
9922 *indexp = sindex;
9923
495aee44
CR
9924 /* All the cases where an expansion can possibly generate an unbound
9925 variable error. */
8868edaf 9926 if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE)
495aee44 9927 {
a0c0a00f 9928 if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0)
495aee44 9929 {
8868edaf 9930 set_exit_status (EXECUTION_FAILURE);
495aee44
CR
9931 err_unboundvar (name);
9932 FREE (value);
9933 FREE (temp);
9934 free (name);
9935 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9936 }
9937 }
9938
ccc6cda3
JA
9939 /* If this is a substring spec, process it and add the result. */
9940 if (want_substring)
726f6388 9941 {
74091dd4 9942 temp1 = parameter_brace_substring (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
ccc6cda3
JA
9943 FREE (value);
9944 FREE (temp);
74091dd4
CR
9945#if defined (ARRAY_VARS)
9946 flush_eltstate (&es);
9947#endif
95732b49 9948
d233b485
CR
9949 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9950 {
9951 FREE (name);
9952 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9953 }
95732b49
JA
9954
9955 ret = alloc_word_desc ();
9956 ret->word = temp1;
ac50fbac
CR
9957 /* We test quoted_dollar_atp because we want variants with double-quoted
9958 "$@" to take a different code path. In fact, we make sure at the end
9959 of expand_word_internal that we're only looking at these flags if
9960 quoted_dollar_at == 0. */
8868edaf 9961 if (temp1 &&
ac50fbac
CR
9962 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9963 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
0628567a 9964 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
8868edaf
CR
9965 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 &&
9966 (pflags & PF_ASSIGNRHS))
9967 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
d233b485
CR
9968 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9969 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9970 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9971
9972 FREE (name);
95732b49 9973 return ret;
726f6388 9974 }
ccc6cda3 9975 else if (want_patsub)
726f6388 9976 {
74091dd4 9977 temp1 = parameter_brace_patsub (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
ccc6cda3
JA
9978 FREE (value);
9979 FREE (temp);
74091dd4
CR
9980#if defined (ARRAY_VARS)
9981 flush_eltstate (&es);
9982#endif
95732b49 9983
d233b485
CR
9984 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9985 {
9986 FREE (name);
9987 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9988 }
95732b49
JA
9989
9990 ret = alloc_word_desc ();
9991 ret->word = temp1;
ac50fbac
CR
9992 if (temp1 &&
9993 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9994 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
3185942a 9995 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
d233b485
CR
9996 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9997 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9998 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9999
10000 FREE (name);
95732b49 10001 return ret;
ccc6cda3 10002 }
3185942a
JA
10003#if defined (CASEMOD_EXPANSIONS)
10004 else if (want_casemod)
10005 {
74091dd4 10006 temp1 = parameter_brace_casemod (name, temp, &es, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
3185942a
JA
10007 FREE (value);
10008 FREE (temp);
74091dd4
CR
10009#if defined (ARRAY_VARS)
10010 flush_eltstate (&es);
10011#endif
3185942a 10012
d233b485
CR
10013 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
10014 {
10015 FREE (name);
10016 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
10017 }
3185942a
JA
10018
10019 ret = alloc_word_desc ();
10020 ret->word = temp1;
ac50fbac
CR
10021 if (temp1 &&
10022 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
10023 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
3185942a 10024 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
d233b485
CR
10025 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10026 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10027 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10028
10029 FREE (name);
3185942a
JA
10030 return ret;
10031 }
10032#endif
726f6388 10033
ccc6cda3
JA
10034 /* Do the right thing based on which character ended the variable name. */
10035 switch (c)
10036 {
10037 default:
10038 case '\0':
a0c0a00f 10039bad_substitution:
8868edaf 10040 set_exit_status (EXECUTION_FAILURE);
b80f6443 10041 report_error (_("%s: bad substitution"), string ? string : "??");
ccc6cda3
JA
10042 FREE (value);
10043 FREE (temp);
10044 free (name);
74091dd4
CR
10045#if defined (ARRAY_VARS)
10046 flush_eltstate (&es);
10047#endif
a0c0a00f
CR
10048 if (shell_compatibility_level <= 43)
10049 return &expand_wdesc_error;
10050 else
10051 return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error);
ccc6cda3 10052
cce855bc 10053 case RBRACE:
ccc6cda3 10054 break;
726f6388 10055
a0c0a00f 10056 case '@':
74091dd4 10057 temp1 = parameter_brace_transform (name, temp, &es, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
a0c0a00f
CR
10058 free (temp);
10059 free (value);
74091dd4
CR
10060#if defined (ARRAY_VARS)
10061 flush_eltstate (&es);
10062#endif
d233b485 10063
a0c0a00f
CR
10064 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
10065 {
d233b485 10066 free (name);
8868edaf 10067 set_exit_status (EXECUTION_FAILURE);
a0c0a00f
CR
10068 report_error (_("%s: bad substitution"), string ? string : "??");
10069 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
10070 }
10071
10072 ret = alloc_word_desc ();
10073 ret->word = temp1;
10074 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10075 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
d233b485
CR
10076 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10077 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10078 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10079
10080 free (name);
a0c0a00f
CR
10081 return ret;
10082
ccc6cda3
JA
10083 case '#': /* ${param#[#]pattern} */
10084 case '%': /* ${param%[%]pattern} */
10085 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
28ef6c31
JA
10086 {
10087 FREE (value);
ccc6cda3 10088 break;
28ef6c31 10089 }
74091dd4 10090 temp1 = parameter_brace_remove_pattern (name, temp, &es, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
ccc6cda3
JA
10091 free (temp);
10092 free (value);
74091dd4
CR
10093#if defined (ARRAY_VARS)
10094 flush_eltstate (&es);
10095#endif
3185942a
JA
10096
10097 ret = alloc_word_desc ();
10098 ret->word = temp1;
10099 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10100 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
d233b485
CR
10101 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10102 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10103 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10104
10105 free (name);
3185942a 10106 return ret;
ccc6cda3
JA
10107
10108 case '-':
10109 case '=':
10110 case '?':
10111 case '+':
10112 if (var_is_set && var_is_null == 0)
28ef6c31
JA
10113 {
10114 /* If the operator is `+', we don't want the value of the named
10115 variable for anything, just the value of the right hand side. */
ccc6cda3
JA
10116 if (c == '+')
10117 {
28ef6c31
JA
10118 /* XXX -- if we're double-quoted and the named variable is "$@",
10119 we want to turn off any special handling of "$@" --
10120 we're not using it, so whatever is on the rhs applies. */
10121 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
10122 *quoted_dollar_atp = 0;
10123 if (contains_dollar_at)
10124 *contains_dollar_at = 0;
10125
ccc6cda3
JA
10126 FREE (temp);
10127 if (value)
28ef6c31 10128 {
495aee44
CR
10129 /* From Posix discussion on austin-group list. Issue 221
10130 requires that backslashes escaping `}' inside
10131 double-quoted ${...} be removed. */
10132 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10133 quoted |= Q_DOLBRACE;
95732b49
JA
10134 ret = parameter_brace_expand_rhs (name, value, c,
10135 quoted,
a0c0a00f 10136 pflags,
95732b49
JA
10137 quoted_dollar_atp,
10138 contains_dollar_at);
10139 /* XXX - fix up later, esp. noting presence of
10140 W_HASQUOTEDNULL in ret->flags */
ccc6cda3
JA
10141 free (value);
10142 }
10143 else
28ef6c31 10144 temp = (char *)NULL;
ccc6cda3
JA
10145 }
10146 else
10147 {
10148 FREE (value);
10149 }
10150 /* Otherwise do nothing; just use the value in TEMP. */
726f6388 10151 }
ccc6cda3 10152 else /* VAR not set or VAR is NULL. */
28ef6c31 10153 {
74091dd4
CR
10154 /* If we're freeing a quoted null here, we need to remember we saw
10155 it so we can restore it later if needed, or the caller can note it.
10156 The check against `+' doesn't really matter, since the other cases
10157 don't use or return TFLAG, but it's good for clarity. */
10158 if (c == '+' && temp && QUOTED_NULL (temp) &&
10159 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
10160 tflag |= W_HASQUOTEDNULL;
10161
ccc6cda3
JA
10162 FREE (temp);
10163 temp = (char *)NULL;
10164 if (c == '=' && var_is_special)
10165 {
8868edaf 10166 set_exit_status (EXECUTION_FAILURE);
b80f6443 10167 report_error (_("$%s: cannot assign in this way"), name);
ccc6cda3
JA
10168 free (name);
10169 free (value);
74091dd4
CR
10170#if defined (ARRAY_VARS)
10171 flush_eltstate (&es);
10172#endif
95732b49 10173 return &expand_wdesc_error;
ccc6cda3
JA
10174 }
10175 else if (c == '?')
10176 {
d233b485 10177 parameter_brace_expand_error (name, value, check_nullness);
74091dd4
CR
10178#if defined (ARRAY_VARS)
10179 flush_eltstate (&es);
10180#endif
95732b49 10181 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
ccc6cda3
JA
10182 }
10183 else if (c != '+')
28ef6c31
JA
10184 {
10185 /* XXX -- if we're double-quoted and the named variable is "$@",
10186 we want to turn off any special handling of "$@" --
10187 we're not using it, so whatever is on the rhs applies. */
10188 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
10189 *quoted_dollar_atp = 0;
10190 if (contains_dollar_at)
10191 *contains_dollar_at = 0;
10192
495aee44
CR
10193 /* From Posix discussion on austin-group list. Issue 221 requires
10194 that backslashes escaping `}' inside double-quoted ${...} be
10195 removed. */
10196 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10197 quoted |= Q_DOLBRACE;
a0c0a00f 10198 ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags,
95732b49
JA
10199 quoted_dollar_atp,
10200 contains_dollar_at);
10201 /* XXX - fix up later, esp. noting presence of
10202 W_HASQUOTEDNULL in tdesc->flags */
28ef6c31 10203 }
ccc6cda3 10204 free (value);
726f6388 10205 }
28ef6c31 10206
ccc6cda3 10207 break;
726f6388 10208 }
ccc6cda3 10209 free (name);
74091dd4
CR
10210#if defined (ARRAY_VARS)
10211 flush_eltstate (&es);
10212#endif
95732b49
JA
10213
10214 if (ret == 0)
10215 {
10216 ret = alloc_word_desc ();
10217 ret->flags = tflag;
10218 ret->word = temp;
10219 }
10220 return (ret);
726f6388
JA
10221}
10222
cce855bc
JA
10223/* Expand a single ${xxx} expansion. The braces are optional. When
10224 the braces are used, parameter_brace_expand() does the work,
10225 possibly calling param_expand recursively. */
95732b49 10226static WORD_DESC *
cce855bc
JA
10227param_expand (string, sindex, quoted, expanded_something,
10228 contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
10229 pflags)
10230 char *string;
10231 int *sindex, quoted, *expanded_something, *contains_dollar_at;
10232 int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
10233{
a0c0a00f 10234 char *temp, *temp1, uerror[3], *savecmd;
74091dd4 10235 int zindex, t_index, expok, eflag;
f73dda09 10236 unsigned char c;
7117c2d2 10237 intmax_t number;
cce855bc 10238 SHELL_VAR *var;
8868edaf 10239 WORD_LIST *list, *l;
95732b49 10240 WORD_DESC *tdesc, *ret;
8868edaf 10241 int tflag, nullarg;
cce855bc 10242
a0c0a00f 10243/*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/
cce855bc
JA
10244 zindex = *sindex;
10245 c = string[++zindex];
10246
10247 temp = (char *)NULL;
95732b49
JA
10248 ret = tdesc = (WORD_DESC *)NULL;
10249 tflag = 0;
cce855bc
JA
10250
10251 /* Do simple cases first. Switch on what follows '$'. */
10252 switch (c)
10253 {
10254 /* $0 .. $9? */
10255 case '0':
10256 case '1':
10257 case '2':
10258 case '3':
10259 case '4':
10260 case '5':
10261 case '6':
10262 case '7':
10263 case '8':
10264 case '9':
f73dda09 10265 temp1 = dollar_vars[TODIGIT (c)];
d233b485 10266 /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */
cce855bc
JA
10267 if (unbound_vars_is_error && temp1 == (char *)NULL)
10268 {
7117c2d2
JA
10269 uerror[0] = '$';
10270 uerror[1] = c;
10271 uerror[2] = '\0';
8868edaf 10272 set_exit_status (EXECUTION_FAILURE);
0001803f 10273 err_unboundvar (uerror);
95732b49 10274 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
cce855bc 10275 }
b80f6443
JA
10276 if (temp1)
10277 temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10278 ? quote_string (temp1)
10279 : quote_escapes (temp1);
10280 else
10281 temp = (char *)NULL;
95732b49 10282
cce855bc
JA
10283 break;
10284
10285 /* $$ -- pid of the invoking shell. */
10286 case '$':
10287 temp = itos (dollar_dollar_pid);
10288 break;
10289
10290 /* $# -- number of positional parameters. */
10291 case '#':
10292 temp = itos (number_of_args ());
10293 break;
10294
10295 /* $? -- return value of the last synchronous command. */
10296 case '?':
10297 temp = itos (last_command_exit_value);
10298 break;
10299
10300 /* $- -- flags supplied to the shell on invocation or by `set'. */
10301 case '-':
10302 temp = which_set_flags ();
10303 break;
10304
10305 /* $! -- Pid of the last asynchronous command. */
10306 case '!':
10307 /* If no asynchronous pids have been created, expand to nothing.
10308 If `set -u' has been executed, and no async processes have
10309 been created, this is an expansion error. */
10310 if (last_asynchronous_pid == NO_PID)
10311 {
10312 if (expanded_something)
10313 *expanded_something = 0;
10314 temp = (char *)NULL;
d233b485 10315 if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
cce855bc 10316 {
7117c2d2
JA
10317 uerror[0] = '$';
10318 uerror[1] = c;
10319 uerror[2] = '\0';
8868edaf 10320 set_exit_status (EXECUTION_FAILURE);
0001803f 10321 err_unboundvar (uerror);
95732b49 10322 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
cce855bc
JA
10323 }
10324 }
10325 else
f73dda09 10326 temp = itos (last_asynchronous_pid);
cce855bc
JA
10327 break;
10328
10329 /* The only difference between this and $@ is when the arg is quoted. */
10330 case '*': /* `$*' */
10331 list = list_rest_of_args ();
10332
89a92869
CR
10333#if 0
10334 /* According to austin-group posix proposal by Geoff Clare in
10335 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
10336
10337 "The shell shall write a message to standard error and
10338 immediately exit when it tries to expand an unset parameter
10339 other than the '@' and '*' special parameters."
10340 */
10341
10342 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
3185942a
JA
10343 {
10344 uerror[0] = '$';
10345 uerror[1] = '*';
10346 uerror[2] = '\0';
8868edaf 10347 set_exit_status (EXECUTION_FAILURE);
89a92869 10348 err_unboundvar (uerror);
3185942a
JA
10349 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10350 }
89a92869 10351#endif
3185942a 10352
cce855bc
JA
10353 /* If there are no command-line arguments, this should just
10354 disappear if there are other characters in the expansion,
10355 even if it's quoted. */
10356 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
10357 temp = (char *)NULL;
0001803f 10358 else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
cce855bc
JA
10359 {
10360 /* If we have "$*" we want to make a string of the positional
10361 parameters, separated by the first character of $IFS, and
10362 quote the whole string, including the separators. If IFS
10363 is unset, the parameters are separated by ' '; if $IFS is
10364 null, the parameters are concatenated. */
d233b485 10365 temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list);
495aee44
CR
10366 if (temp)
10367 {
a0c0a00f 10368 temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp;
495aee44
CR
10369 if (*temp == 0)
10370 tflag |= W_HASQUOTEDNULL;
a0c0a00f
CR
10371 if (temp != temp1)
10372 free (temp);
495aee44
CR
10373 temp = temp1;
10374 }
cce855bc
JA
10375 }
10376 else
28ef6c31 10377 {
95732b49
JA
10378 /* We check whether or not we're eventually going to split $* here,
10379 for example when IFS is empty and we are processing the rhs of
10380 an assignment statement. In that case, we don't separate the
10381 arguments at all. Otherwise, if the $* is not quoted it is
10382 identical to $@ */
d233b485
CR
10383 if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS))
10384 {
8868edaf
CR
10385 /* Posix interp 888: RHS of assignment, IFS unset: no splitting,
10386 separate with space */
10387 temp1 = string_list_dollar_star (list, quoted, pflags);
10388 temp = temp1 ? quote_string (temp1) : temp1;
10389 /* XXX - tentative - note that we saw a quoted null here */
10390 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
10391 tflag |= W_SAWQUOTEDNULL;
10392 FREE (temp1);
d233b485
CR
10393 }
10394 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS))
10395 {
10396 /* Posix interp 888: RHS of assignment, IFS set to '' */
10397 temp1 = string_list_dollar_star (list, quoted, pflags);
10398 temp = temp1 ? quote_escapes (temp1) : temp1;
10399 FREE (temp1);
10400 }
10401 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS))
10402 {
10403 /* Posix interp 888: RHS of assignment, IFS set to non-null value */
10404 temp1 = string_list_dollar_star (list, quoted, pflags);
10405 temp = temp1 ? quote_string (temp1) : temp1;
8868edaf
CR
10406
10407 /* XXX - tentative - note that we saw a quoted null here */
10408 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
10409 tflag |= W_SAWQUOTEDNULL;
d233b485
CR
10410 FREE (temp1);
10411 }
10412 /* XXX - should we check ifs_is_set here as well? */
95732b49 10413# if defined (HANDLE_MULTIBYTE)
d233b485 10414 else if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
95732b49 10415# else
d233b485 10416 else if (expand_no_split_dollar_star && ifs_firstc == 0)
95732b49 10417# endif
d233b485
CR
10418 /* Posix interp 888: not RHS, no splitting, IFS set to '' */
10419 temp = string_list_dollar_star (list, quoted, 0);
95732b49 10420 else
ac50fbac 10421 {
a0c0a00f 10422 temp = string_list_dollar_at (list, quoted, 0);
d233b485
CR
10423 /* Set W_SPLITSPACE to make sure the individual positional
10424 parameters are split into separate arguments */
10425#if 0
ac50fbac 10426 if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null))
d233b485
CR
10427#else /* change with bash-5.0 */
10428 if (quoted == 0 && ifs_is_null)
10429#endif
ac50fbac 10430 tflag |= W_SPLITSPACE;
a0c0a00f
CR
10431 /* If we're not quoted but we still don't want word splitting, make
10432 we quote the IFS characters to protect them from splitting (e.g.,
10433 when $@ is in the string as well). */
10434 else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS))
10435 {
10436 temp1 = quote_string (temp);
10437 free (temp);
10438 temp = temp1;
10439 }
ac50fbac
CR
10440 }
10441
28ef6c31
JA
10442 if (expand_no_split_dollar_star == 0 && contains_dollar_at)
10443 *contains_dollar_at = 1;
10444 }
cce855bc
JA
10445
10446 dispose_words (list);
10447 break;
10448
10449 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
10450 means that we have to turn quoting off after we split into
10451 the individually quoted arguments so that the final split
10452 on the first character of $IFS is still done. */
10453 case '@': /* `$@' */
10454 list = list_rest_of_args ();
10455
89a92869
CR
10456#if 0
10457 /* According to austin-group posix proposal by Geoff Clare in
10458 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
10459
10460 "The shell shall write a message to standard error and
10461 immediately exit when it tries to expand an unset parameter
10462 other than the '@' and '*' special parameters."
10463 */
10464
10465 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
3185942a
JA
10466 {
10467 uerror[0] = '$';
10468 uerror[1] = '@';
10469 uerror[2] = '\0';
8868edaf 10470 set_exit_status (EXECUTION_FAILURE);
89a92869 10471 err_unboundvar (uerror);
3185942a
JA
10472 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10473 }
89a92869 10474#endif
3185942a 10475
8868edaf
CR
10476 for (nullarg = 0, l = list; l; l = l->next)
10477 {
10478 if (l->word && (l->word->word == 0 || l->word->word[0] == 0))
10479 nullarg = 1;
10480 }
10481
cce855bc
JA
10482 /* We want to flag the fact that we saw this. We can't turn
10483 off quoting entirely, because other characters in the
10484 string might need it (consider "\"$@\""), but we need some
10485 way to signal that the final split on the first character
10486 of $IFS should be done, even though QUOTED is 1. */
0001803f 10487 /* XXX - should this test include Q_PATQUOTE? */
cce855bc
JA
10488 if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10489 *quoted_dollar_at_p = 1;
10490 if (contains_dollar_at)
10491 *contains_dollar_at = 1;
10492
10493 /* We want to separate the positional parameters with the first
10494 character of $IFS in case $IFS is something other than a space.
10495 We also want to make sure that splitting is done no matter what --
10496 according to POSIX.2, this expands to a list of the positional
10497 parameters no matter what IFS is set to. */
3b34f6e6
CR
10498 /* XXX - what to do when in a context where word splitting is not
10499 performed? Even when IFS is not the default, posix seems to imply
8868edaf
CR
10500 that we have to expand $@ to all the positional parameters and
10501 separate them with spaces, which are preserved because word splitting
10502 doesn't take place. See below for how we use PF_NOSPLIT2 here. */
d233b485
CR
10503
10504 /* These are the cases where word splitting will not be performed. */
10505 if (pflags & PF_ASSIGNRHS)
8868edaf
CR
10506 {
10507 temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags);
10508 if (nullarg)
10509 tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */
10510 }
10511
d233b485
CR
10512 /* This needs to match what expand_word_internal does with non-quoted $@
10513 does with separating with spaces. Passing Q_DOUBLE_QUOTES means that
10514 the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that
10515 they will separated by spaces. After doing this, we need the special
10516 handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC
10517 quotes. */
10518 else if (pflags & PF_NOSPLIT2)
10519 {
10520#if defined (HANDLE_MULTIBYTE)
10521 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
10522#else
10523 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
10524#endif
10525 /* Posix interp 888 */
10526 temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags);
10527 else
10528 temp = string_list_dollar_at (list, quoted, pflags);
10529 }
10530 else
10531 temp = string_list_dollar_at (list, quoted, pflags);
cce855bc 10532
ac50fbac 10533 tflag |= W_DOLLARAT;
cce855bc
JA
10534 dispose_words (list);
10535 break;
10536
10537 case LBRACE:
0001803f 10538 tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
95732b49
JA
10539 quoted_dollar_at_p,
10540 contains_dollar_at);
10541
95732b49
JA
10542 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
10543 return (tdesc);
10544 temp = tdesc ? tdesc->word : (char *)0;
cce855bc
JA
10545
10546 /* XXX */
bb70624e 10547 /* Quoted nulls should be removed if there is anything else
cce855bc
JA
10548 in the string. */
10549 /* Note that we saw the quoted null so we can add one back at
10550 the end of this function if there are no other characters
28ef6c31
JA
10551 in the string, discard TEMP, and go on. The exception to
10552 this is when we have "${@}" and $1 is '', since $@ needs
10553 special handling. */
95732b49 10554 if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
cce855bc
JA
10555 {
10556 if (had_quoted_null_p)
10557 *had_quoted_null_p = 1;
28ef6c31
JA
10558 if (*quoted_dollar_at_p == 0)
10559 {
10560 free (temp);
95732b49 10561 tdesc->word = temp = (char *)NULL;
28ef6c31
JA
10562 }
10563
cce855bc
JA
10564 }
10565
95732b49 10566 ret = tdesc;
cce855bc
JA
10567 goto return0;
10568
10569 /* Do command or arithmetic substitution. */
10570 case LPAREN:
10571 /* We have to extract the contents of this paren substitution. */
10572 t_index = zindex + 1;
a0c0a00f
CR
10573 /* XXX - might want to check for string[t_index+2] == LPAREN and parse
10574 as arithmetic substitution immediately. */
10575 temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0);
cce855bc
JA
10576 zindex = t_index;
10577
10578 /* For Posix.2-style `$(( ))' arithmetic substitution,
28ef6c31 10579 extract the expression and pass it to the evaluator. */
cce855bc
JA
10580 if (temp && *temp == LPAREN)
10581 {
10582 char *temp2;
10583 temp1 = temp + 1;
10584 temp2 = savestring (temp1);
10585 t_index = strlen (temp2) - 1;
10586
10587 if (temp2[t_index] != RPAREN)
10588 {
10589 free (temp2);
10590 goto comsub;
10591 }
10592
10593 /* Cut off ending `)' */
10594 temp2[t_index] = '\0';
10595
0628567a
JA
10596 if (chk_arithsub (temp2, t_index) == 0)
10597 {
10598 free (temp2);
0001803f
CR
10599#if 0
10600 internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
10601#endif
0628567a
JA
10602 goto comsub;
10603 }
10604
cce855bc 10605 /* Expand variables found inside the expression. */
a0c0a00f 10606 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
cce855bc
JA
10607 free (temp2);
10608
10609arithsub:
10610 /* No error messages. */
a0c0a00f 10611 savecmd = this_command_name;
cce855bc 10612 this_command_name = (char *)NULL;
74091dd4
CR
10613
10614 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
10615 number = evalexp (temp1, eflag, &expok);
a0c0a00f 10616 this_command_name = savecmd;
cce855bc
JA
10617 free (temp);
10618 free (temp1);
10619 if (expok == 0)
10620 {
10621 if (interactive_shell == 0 && posixly_correct)
10622 {
8868edaf 10623 set_exit_status (EXECUTION_FAILURE);
95732b49 10624 return (&expand_wdesc_fatal);
cce855bc
JA
10625 }
10626 else
95732b49 10627 return (&expand_wdesc_error);
cce855bc
JA
10628 }
10629 temp = itos (number);
10630 break;
10631 }
10632
10633comsub:
b80f6443
JA
10634 if (pflags & PF_NOCOMSUB)
10635 /* we need zindex+1 because string[zindex] == RPAREN */
10636 temp1 = substring (string, *sindex, zindex+1);
10637 else
3185942a 10638 {
d233b485 10639 tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS);
3185942a
JA
10640 temp1 = tdesc ? tdesc->word : (char *)NULL;
10641 if (tdesc)
10642 dispose_word_desc (tdesc);
10643 }
cce855bc
JA
10644 FREE (temp);
10645 temp = temp1;
10646 break;
10647
10648 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
10649 away in a future bash release. */
d233b485 10650 case '[': /*]*/
bb70624e 10651 /* Extract the contents of this arithmetic substitution. */
cce855bc
JA
10652 t_index = zindex + 1;
10653 temp = extract_arithmetic_subst (string, &t_index);
10654 zindex = t_index;
3185942a
JA
10655 if (temp == 0)
10656 {
10657 temp = savestring (string);
10658 if (expanded_something)
10659 *expanded_something = 0;
10660 goto return0;
10661 }
cce855bc
JA
10662
10663 /* Do initial variable expansion. */
a0c0a00f 10664 temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH);
cce855bc
JA
10665
10666 goto arithsub;
10667
10668 default:
10669 /* Find the variable in VARIABLE_LIST. */
10670 temp = (char *)NULL;
10671
10672 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
10673 ;
10674 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
10675
10676 /* If this isn't a variable name, then just output the `$'. */
10677 if (temp1 == 0 || *temp1 == '\0')
10678 {
10679 FREE (temp1);
f73dda09 10680 temp = (char *)xmalloc (2);
cce855bc
JA
10681 temp[0] = '$';
10682 temp[1] = '\0';
10683 if (expanded_something)
10684 *expanded_something = 0;
10685 goto return0;
10686 }
10687
10688 /* If the variable exists, return its value cell. */
10689 var = find_variable (temp1);
10690
7117c2d2 10691 if (var && invisible_p (var) == 0 && var_isset (var))
cce855bc
JA
10692 {
10693#if defined (ARRAY_VARS)
3185942a 10694 if (assoc_p (var) || array_p (var))
cce855bc 10695 {
3185942a
JA
10696 temp = array_p (var) ? array_reference (array_cell (var), 0)
10697 : assoc_reference (assoc_cell (var), "0");
cce855bc 10698 if (temp)
b80f6443
JA
10699 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10700 ? quote_string (temp)
10701 : quote_escapes (temp);
10702 else if (unbound_vars_is_error)
10703 goto unbound_variable;
cce855bc
JA
10704 }
10705 else
10706#endif
b80f6443
JA
10707 {
10708 temp = value_cell (var);
10709
10710 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10711 ? quote_string (temp)
d233b485
CR
10712 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
10713 : quote_escapes (temp));
b80f6443
JA
10714 }
10715
cce855bc 10716 free (temp1);
7117c2d2 10717
cce855bc
JA
10718 goto return0;
10719 }
b64a0e1d
CR
10720 else if (var && (invisible_p (var) || var_isset (var) == 0))
10721 temp = (char *)NULL;
a0c0a00f 10722 else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0)
ac50fbac
CR
10723 {
10724 temp = nameref_cell (var);
10725#if defined (ARRAY_VARS)
a0c0a00f 10726 if (temp && *temp && valid_array_reference (temp, 0))
ac50fbac 10727 {
74091dd4
CR
10728 chk_atstar (temp, quoted, pflags, quoted_dollar_at_p, contains_dollar_at);
10729 tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, 0);
ac50fbac
CR
10730 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
10731 return (tdesc);
10732 ret = tdesc;
10733 goto return0;
10734 }
10735 else
10736#endif
10737 /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */
10738 if (temp && *temp && legal_identifier (temp) == 0)
10739 {
8868edaf 10740 set_exit_status (EXECUTION_FAILURE);
ac50fbac
CR
10741 report_error (_("%s: invalid variable name for name reference"), temp);
10742 return (&expand_wdesc_error); /* XXX */
10743 }
10744 else
10745 temp = (char *)NULL;
10746 }
cce855bc
JA
10747
10748 temp = (char *)NULL;
10749
b80f6443 10750unbound_variable:
cce855bc 10751 if (unbound_vars_is_error)
0001803f 10752 {
8868edaf 10753 set_exit_status (EXECUTION_FAILURE);
0001803f
CR
10754 err_unboundvar (temp1);
10755 }
cce855bc
JA
10756 else
10757 {
10758 free (temp1);
10759 goto return0;
10760 }
10761
10762 free (temp1);
8868edaf 10763 set_exit_status (EXECUTION_FAILURE);
cce855bc 10764 return ((unbound_vars_is_error && interactive_shell == 0)
95732b49
JA
10765 ? &expand_wdesc_fatal
10766 : &expand_wdesc_error);
cce855bc
JA
10767 }
10768
10769 if (string[zindex])
10770 zindex++;
10771
10772return0:
10773 *sindex = zindex;
95732b49
JA
10774
10775 if (ret == 0)
10776 {
10777 ret = alloc_word_desc ();
10778 ret->flags = tflag; /* XXX */
10779 ret->word = temp;
10780 }
10781 return ret;
cce855bc
JA
10782}
10783
74091dd4
CR
10784#if defined (ARRAY_VARS)
10785/* Characters that need to be backslash-quoted after expanding array subscripts */
10786static char abstab[256] = { '\1' };
10787
10788/* Run an array subscript through the appropriate word expansions. */
10789char *
10790expand_subscript_string (string, quoted)
10791 char *string;
10792 int quoted;
10793{
10794 WORD_DESC td;
10795 WORD_LIST *tlist;
10796 int oe;
10797 char *ret;
10798
10799 if (string == 0 || *string == 0)
10800 return (char *)NULL;
10801
10802 oe = expand_no_split_dollar_star;
10803 ret = (char *)NULL;
10804
d1cf6ad9 10805#if 0
74091dd4 10806 td.flags = W_NOPROCSUB|W_NOTILDE|W_NOSPLIT2; /* XXX - W_NOCOMSUB? */
d1cf6ad9
CR
10807#else
10808 td.flags = W_NOPROCSUB|W_NOSPLIT2; /* XXX - W_NOCOMSUB? */
10809#endif
74091dd4
CR
10810 td.word = savestring (string); /* in case it's freed on error */
10811
10812 expand_no_split_dollar_star = 1;
10813 tlist = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
10814 expand_no_split_dollar_star = oe;
10815
10816 if (tlist)
10817 {
10818 if (tlist->word)
10819 {
10820 remove_quoted_nulls (tlist->word->word);
10821 tlist->word->flags &= ~W_HASQUOTEDNULL;
10822 }
10823 dequote_list (tlist);
10824 ret = string_list (tlist);
10825 dispose_words (tlist);
10826 }
10827
10828 free (td.word);
10829 return (ret);
10830}
10831
10832/* Expand the subscript in STRING, which is an array reference. To ensure we
10833 only expand it once, we quote the characters that would start another
10834 expansion and the bracket characters that are special to array subscripts. */
10835static char *
10836expand_array_subscript (string, sindex, quoted, flags)
10837 char *string;
10838 int *sindex;
10839 int quoted, flags;
10840{
10841 char *ret, *exp, *t;
10842 size_t slen;
10843 int si, ni;
10844
10845 si = *sindex;
10846 slen = STRLEN (string);
10847
10848 if (abstab[0] == '\1')
10849 {
10850 /* These are basically the characters that start shell expansions plus
10851 the characters that delimit subscripts. */
10852 memset (abstab, '\0', sizeof (abstab));
10853 abstab[LBRACK] = abstab[RBRACK] = 1;
10854 abstab['$'] = abstab['`'] = abstab['~'] = 1;
10855 abstab['\\'] = abstab['\''] = 1;
10856 abstab['"'] = 1; /* XXX */
10857 /* We don't quote `@' or `*' in the subscript at all. */
10858 }
10859
10860 /* string[si] == LBRACK */
10861 ni = skipsubscript (string, si, 0);
10862 /* These checks mirror the ones in valid_array_reference. The check for
10863 (ni - si) == 1 checks for empty subscripts. We don't check that the
10864 subscript is a separate word if we're parsing an arithmetic expression. */
10865 if (ni >= slen || string[ni] != RBRACK || (ni - si) == 1 ||
10866 (string[ni+1] != '\0' && (quoted & Q_ARITH) == 0))
10867 {
10868 /* let's check and see what fails this check */
10869 INTERNAL_DEBUG (("expand_array_subscript: bad subscript string: `%s'", string+si));
10870 ret = (char *)xmalloc (2); /* badly-formed subscript */
10871 ret[0] = string[si];
10872 ret[1] = '\0';
10873 *sindex = si + 1;
10874 return ret;
10875 }
10876
10877 /* STRING[ni] == RBRACK */
10878 exp = substring (string, si+1, ni);
10879 t = expand_subscript_string (exp, quoted & ~(Q_ARITH|Q_DOUBLE_QUOTES));
10880 free (exp);
a1e58b8c 10881 exp = t ? sh_backslash_quote (t, abstab, 0) : savestring ("");
74091dd4
CR
10882 free (t);
10883
10884 slen = STRLEN (exp);
10885 ret = xmalloc (slen + 2 + 1);
10886 ret[0] ='[';
10887 strcpy (ret + 1, exp);
10888 ret[slen + 1] = ']';
10889 ret[slen + 2] = '\0';
10890
10891 free (exp);
10892 *sindex = ni + 1;
10893
10894 return ret;
10895}
10896#endif
10897
a0c0a00f
CR
10898void
10899invalidate_cached_quoted_dollar_at ()
10900{
10901 dispose_words (cached_quoted_dollar_at);
10902 cached_quoted_dollar_at = 0;
10903}
10904
cce855bc
JA
10905/* Make a word list which is the result of parameter and variable
10906 expansion, command substitution, arithmetic substitution, and
10907 quote removal of WORD. Return a pointer to a WORD_LIST which is
10908 the result of the expansion. If WORD contains a null word, the
10909 word list returned is also null.
726f6388 10910
ccc6cda3
JA
10911 QUOTED contains flag values defined in shell.h.
10912
b72432fd
JA
10913 ISEXP is used to tell expand_word_internal that the word should be
10914 treated as the result of an expansion. This has implications for
10915 how IFS characters in the word are treated.
10916
726f6388
JA
10917 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
10918 they point to an integer value which receives information about expansion.
10919 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
10920 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
10921 else zero.
10922
10923 This only does word splitting in the case of $@ expansion. In that
10924 case, we split on ' '. */
10925
10926/* Values for the local variable quoted_state. */
10927#define UNQUOTED 0
10928#define PARTIALLY_QUOTED 1
10929#define WHOLLY_QUOTED 2
10930
10931static WORD_LIST *
b72432fd 10932expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
726f6388 10933 WORD_DESC *word;
b72432fd 10934 int quoted, isexp;
726f6388
JA
10935 int *contains_dollar_at;
10936 int *expanded_something;
10937{
ccc6cda3
JA
10938 WORD_LIST *list;
10939 WORD_DESC *tword;
726f6388
JA
10940
10941 /* The intermediate string that we build while expanding. */
ccc6cda3 10942 char *istring;
726f6388
JA
10943
10944 /* The current size of the above object. */
a0c0a00f 10945 size_t istring_size;
726f6388
JA
10946
10947 /* Index into ISTRING. */
74091dd4 10948 size_t istring_index;
726f6388
JA
10949
10950 /* Temporary string storage. */
ccc6cda3 10951 char *temp, *temp1;
726f6388
JA
10952
10953 /* The text of WORD. */
ccc6cda3 10954 register char *string;
726f6388 10955
7117c2d2
JA
10956 /* The size of STRING. */
10957 size_t string_size;
10958
726f6388 10959 /* The index into STRING. */
ccc6cda3 10960 int sindex;
726f6388
JA
10961
10962 /* This gets 1 if we see a $@ while quoted. */
ccc6cda3 10963 int quoted_dollar_at;
726f6388
JA
10964
10965 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
10966 whether WORD contains no quoting characters, a partially quoted
10967 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
ccc6cda3
JA
10968 int quoted_state;
10969
95732b49 10970 /* State flags */
ccc6cda3 10971 int had_quoted_null;
d233b485 10972 int has_quoted_ifs; /* did we add a quoted $IFS character here? */
0b913689 10973 int has_dollar_at, temp_has_dollar_at;
74091dd4 10974 int internal_tilde;
ac50fbac 10975 int split_on_spaces;
d233b485 10976 int local_expanded;
28ef6c31 10977 int tflag;
0001803f 10978 int pflags; /* flags passed to param_expand */
a0c0a00f 10979 int mb_cur_max;
726f6388 10980
95732b49
JA
10981 int assignoff; /* If assignment, offset of `=' */
10982
f73dda09 10983 register unsigned char c; /* Current character. */
726f6388 10984 int t_index; /* For calls to string_extract_xxx. */
726f6388 10985
bb70624e 10986 char twochars[2];
b72432fd 10987
7117c2d2
JA
10988 DECLARE_MBSTATE;
10989
74091dd4
CR
10990 /* OK, let's see if we can optimize a common idiom: "$@". This needs to make sure
10991 that all of the flags callers care about (e.g., W_HASQUOTEDNULL) are set in
10992 list->flags. */
a0c0a00f
CR
10993 if (STREQ (word->word, "\"$@\"") &&
10994 (word->flags == (W_HASDOLLAR|W_QUOTED)) &&
10995 dollar_vars[1]) /* XXX - check IFS here as well? */
10996 {
10997 if (contains_dollar_at)
10998 *contains_dollar_at = 1;
10999 if (expanded_something)
11000 *expanded_something = 1;
11001 if (cached_quoted_dollar_at)
11002 return (copy_word_list (cached_quoted_dollar_at));
11003 list = list_rest_of_args ();
11004 list = quote_list (list);
11005 cached_quoted_dollar_at = copy_word_list (list);
11006 return (list);
11007 }
11008
f73dda09 11009 istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
ccc6cda3 11010 istring[istring_index = 0] = '\0';
cce855bc 11011 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
d233b485 11012 has_quoted_ifs = 0;
ac50fbac 11013 split_on_spaces = 0;
74091dd4 11014 internal_tilde = 0; /* expanding =~ or :~ */
ccc6cda3
JA
11015 quoted_state = UNQUOTED;
11016
11017 string = word->word;
11018 if (string == 0)
11019 goto finished_with_string;
a0c0a00f
CR
11020 mb_cur_max = MB_CUR_MAX;
11021
95732b49 11022 /* Don't need the string length for the SADD... and COPY_ macros unless
d233b485 11023 multibyte characters are possible, but do need it for bounds checking. */
a0c0a00f 11024 string_size = (mb_cur_max > 1) ? strlen (string) : 1;
726f6388
JA
11025
11026 if (contains_dollar_at)
11027 *contains_dollar_at = 0;
11028
95732b49
JA
11029 assignoff = -1;
11030
726f6388
JA
11031 /* Begin the expansion. */
11032
ccc6cda3 11033 for (sindex = 0; ;)
726f6388
JA
11034 {
11035 c = string[sindex];
11036
ac50fbac 11037 /* Case on top-level character. */
726f6388
JA
11038 switch (c)
11039 {
11040 case '\0':
11041 goto finished_with_string;
11042
11043 case CTLESC:
7117c2d2
JA
11044 sindex++;
11045#if HANDLE_MULTIBYTE
a0c0a00f 11046 if (mb_cur_max > 1 && string[sindex])
7117c2d2 11047 {
b80f6443 11048 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7117c2d2
JA
11049 }
11050 else
11051#endif
11052 {
11053 temp = (char *)xmalloc (3);
11054 temp[0] = CTLESC;
11055 temp[1] = c = string[sindex];
11056 temp[2] = '\0';
11057 }
726f6388 11058
cce855bc 11059dollar_add_string:
726f6388
JA
11060 if (string[sindex])
11061 sindex++;
11062
cce855bc
JA
11063add_string:
11064 if (temp)
11065 {
11066 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
11067 temp = (char *)0;
11068 }
11069
11070 break;
726f6388
JA
11071
11072#if defined (PROCESS_SUBSTITUTION)
11073 /* Process substitution. */
11074 case '<':
11075 case '>':
11076 {
d233b485 11077 /* XXX - technically this should only be expanded at the start
a0c0a00f 11078 of a word */
74091dd4 11079 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & W_NOPROCSUB))
726f6388 11080 {
bb70624e 11081 sindex--; /* add_character: label increments sindex */
726f6388
JA
11082 goto add_character;
11083 }
11084 else
cce855bc 11085 t_index = sindex + 1; /* skip past both '<' and LPAREN */
726f6388 11086
85b94814 11087 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/
ccc6cda3 11088 sindex = t_index;
726f6388
JA
11089
11090 /* If the process substitution specification is `<()', we want to
11091 open the pipe for writing in the child and produce output; if
11092 it is `>()', we want to open the pipe for reading in the child
11093 and consume input. */
ccc6cda3 11094 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
726f6388
JA
11095
11096 FREE (temp1);
11097
11098 goto dollar_add_string;
11099 }
11100#endif /* PROCESS_SUBSTITUTION */
11101
74091dd4
CR
11102#if defined (ARRAY_VARS)
11103 case '[': /*]*/
11104 if ((quoted & Q_ARITH) == 0 || shell_compatibility_level <= 51)
11105 {
11106 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
11107 goto add_ifs_character;
11108 else
11109 goto add_character;
11110 }
11111 else
11112 {
11113 temp = expand_array_subscript (string, &sindex, quoted, word->flags);
11114 goto add_string;
11115 }
11116#endif
11117
95732b49
JA
11118 case '=':
11119 /* Posix.2 section 3.6.1 says that tildes following `=' in words
11120 which are not assignment statements are not expanded. If the
11121 shell isn't in posix mode, though, we perform tilde expansion
11122 on `likely candidate' unquoted assignment statements (flags
11123 include W_ASSIGNMENT but not W_QUOTED). A likely candidate
11124 contains an unquoted :~ or =~. Something to think about: we
11125 now have a flag that says to perform tilde expansion on arguments
11126 to `assignment builtins' like declare and export that look like
11127 assignment statements. We now do tilde expansion on such words
11128 even in POSIX mode. */
11129 if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
17345e5a 11130 {
0001803f 11131 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
17345e5a
JA
11132 goto add_ifs_character;
11133 else
11134 goto add_character;
11135 }
95732b49 11136 /* If we're not in posix mode or forcing assignment-statement tilde
8868edaf
CR
11137 expansion, note where the first `=' appears in the word and prepare
11138 to do tilde expansion following the first `='. We have to keep
11139 track of the first `=' (using assignoff) to avoid being confused
11140 by an `=' in the rhs of the assignment statement. */
95732b49
JA
11141 if ((word->flags & W_ASSIGNMENT) &&
11142 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
11143 assignoff == -1 && sindex > 0)
11144 assignoff = sindex;
11145 if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
74091dd4 11146 internal_tilde = 1;
a0c0a00f 11147
a0c0a00f
CR
11148 if (word->flags & W_ASSIGNARG)
11149 word->flags |= W_ASSIGNRHS; /* affects $@ */
11150
0001803f 11151 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
d233b485
CR
11152 {
11153 has_quoted_ifs++;
11154 goto add_ifs_character;
11155 }
17345e5a
JA
11156 else
11157 goto add_character;
95732b49
JA
11158
11159 case ':':
d233b485 11160 if (word->flags & (W_NOTILDE|W_NOASSNTILDE))
17345e5a 11161 {
0001803f 11162 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
17345e5a
JA
11163 goto add_ifs_character;
11164 else
11165 goto add_character;
11166 }
95732b49 11167
8868edaf
CR
11168 if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) &&
11169 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
95732b49 11170 string[sindex+1] == '~')
74091dd4 11171 internal_tilde = 1;
17345e5a 11172
0001803f 11173 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
17345e5a
JA
11174 goto add_ifs_character;
11175 else
11176 goto add_character;
95732b49
JA
11177
11178 case '~':
11179 /* If the word isn't supposed to be tilde expanded, or we're not
11180 at the start of a word or after an unquoted : or = in an
d233b485
CR
11181 assignment statement, we don't do tilde expansion. We don't
11182 do tilde expansion if quoted or in an arithmetic context. */
11183
74091dd4
CR
11184 if ((word->flags & W_NOTILDE) ||
11185 (sindex > 0 && (internal_tilde == 0)) ||
d233b485 11186 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
95732b49 11187 {
74091dd4 11188 internal_tilde = 0;
0001803f 11189 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
17345e5a
JA
11190 goto add_ifs_character;
11191 else
11192 goto add_character;
95732b49
JA
11193 }
11194
11195 if (word->flags & W_ASSIGNRHS)
11196 tflag = 2;
11197 else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
11198 tflag = 1;
11199 else
11200 tflag = 0;
11201
11202 temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
11203
74091dd4 11204 internal_tilde = 0;
95732b49
JA
11205
11206 if (temp && *temp && t_index > 0)
11207 {
11208 temp1 = bash_tilde_expand (temp, tflag);
0628567a
JA
11209 if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
11210 {
11211 FREE (temp);
11212 FREE (temp1);
11213 goto add_character; /* tilde expansion failed */
11214 }
95732b49
JA
11215 free (temp);
11216 temp = temp1;
11217 sindex += t_index;
3185942a 11218 goto add_quoted_string; /* XXX was add_string */
95732b49
JA
11219 }
11220 else
11221 {
11222 FREE (temp);
11223 goto add_character;
11224 }
11225
726f6388 11226 case '$':
726f6388
JA
11227 if (expanded_something)
11228 *expanded_something = 1;
d233b485 11229 local_expanded = 1;
726f6388 11230
0b913689 11231 temp_has_dollar_at = 0;
0001803f
CR
11232 pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
11233 if (word->flags & W_NOSPLIT2)
11234 pflags |= PF_NOSPLIT2;
ac50fbac
CR
11235 if (word->flags & W_ASSIGNRHS)
11236 pflags |= PF_ASSIGNRHS;
a0c0a00f
CR
11237 if (word->flags & W_COMPLETE)
11238 pflags |= PF_COMPLETE;
8868edaf 11239
95732b49 11240 tword = param_expand (string, &sindex, quoted, expanded_something,
0b913689 11241 &temp_has_dollar_at, &quoted_dollar_at,
0001803f 11242 &had_quoted_null, pflags);
0b913689 11243 has_dollar_at += temp_has_dollar_at;
ac50fbac 11244 split_on_spaces += (tword->flags & W_SPLITSPACE);
726f6388 11245
95732b49 11246 if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
726f6388 11247 {
cce855bc
JA
11248 free (string);
11249 free (istring);
95732b49
JA
11250 return ((tword == &expand_wdesc_error) ? &expand_word_error
11251 : &expand_word_fatal);
cce855bc
JA
11252 }
11253 if (contains_dollar_at && has_dollar_at)
11254 *contains_dollar_at = 1;
95732b49
JA
11255
11256 if (tword && (tword->flags & W_HASQUOTEDNULL))
d233b485
CR
11257 had_quoted_null = 1; /* note for later */
11258 if (tword && (tword->flags & W_SAWQUOTEDNULL))
11259 had_quoted_null = 1; /* XXX */
95732b49 11260
ac50fbac 11261 temp = tword ? tword->word : (char *)NULL;
95732b49
JA
11262 dispose_word_desc (tword);
11263
a601c749
CR
11264 /* Kill quoted nulls; we will add them back at the end of
11265 expand_word_internal if nothing else in the string */
11266 if (had_quoted_null && temp && QUOTED_NULL (temp))
11267 {
11268 FREE (temp);
11269 temp = (char *)NULL;
11270 }
11271
cce855bc
JA
11272 goto add_string;
11273 break;
726f6388 11274
cce855bc
JA
11275 case '`': /* Backquoted command substitution. */
11276 {
b80f6443 11277 t_index = sindex++;
726f6388 11278
74091dd4 11279 temp = string_extract (string, &sindex, "`", (word->flags & W_COMPLETE) ? SX_COMPLETE : SX_REQMATCH);
95732b49
JA
11280 /* The test of sindex against t_index is to allow bare instances of
11281 ` to pass through, for backwards compatibility. */
11282 if (temp == &extract_string_error || temp == &extract_string_fatal)
11283 {
11284 if (sindex - 1 == t_index)
11285 {
11286 sindex = t_index;
11287 goto add_character;
11288 }
8868edaf 11289 set_exit_status (EXECUTION_FAILURE);
3185942a 11290 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
95732b49
JA
11291 free (string);
11292 free (istring);
11293 return ((temp == &extract_string_error) ? &expand_word_error
11294 : &expand_word_fatal);
11295 }
11296
cce855bc
JA
11297 if (expanded_something)
11298 *expanded_something = 1;
d233b485 11299 local_expanded = 1;
726f6388 11300
b80f6443
JA
11301 if (word->flags & W_NOCOMSUB)
11302 /* sindex + 1 because string[sindex] == '`' */
11303 temp1 = substring (string, t_index, sindex + 1);
11304 else
11305 {
11306 de_backslash (temp);
6ddc9cf2 11307 tword = command_substitute (temp, quoted, PF_BACKQUOTE);
3185942a
JA
11308 temp1 = tword ? tword->word : (char *)NULL;
11309 if (tword)
11310 dispose_word_desc (tword);
b80f6443 11311 }
cce855bc
JA
11312 FREE (temp);
11313 temp = temp1;
11314 goto dollar_add_string;
11315 }
ccc6cda3 11316
cce855bc
JA
11317 case '\\':
11318 if (string[sindex + 1] == '\n')
11319 {
11320 sindex += 2;
11321 continue;
11322 }
726f6388 11323
cce855bc 11324 c = string[++sindex];
726f6388 11325
8868edaf
CR
11326 /* "However, the double-quote character ( '"' ) shall not be treated
11327 specially within a here-document, except when the double-quote
11328 appears within "$()", "``", or "${}"." */
11329 if ((quoted & Q_HERE_DOCUMENT) && (quoted & Q_DOLBRACE) && c == '"')
11330 tflag = CBSDQUOTE; /* special case */
11331 else if (quoted & Q_HERE_DOCUMENT)
28ef6c31 11332 tflag = CBSHDOC;
cce855bc 11333 else if (quoted & Q_DOUBLE_QUOTES)
28ef6c31 11334 tflag = CBSDQUOTE;
cce855bc 11335 else
28ef6c31
JA
11336 tflag = 0;
11337
495aee44
CR
11338 /* From Posix discussion on austin-group list: Backslash escaping
11339 a } in ${...} is removed. Issue 0000221 */
11340 if ((quoted & Q_DOLBRACE) && c == RBRACE)
11341 {
ac50fbac
CR
11342 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11343 }
11344 /* This is the fix for " $@\ " */
11345 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c))
11346 {
11347 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11348 DEFAULT_ARRAY_SIZE);
11349 istring[istring_index++] = CTLESC;
11350 istring[istring_index++] = '\\';
11351 istring[istring_index] = '\0';
11352
495aee44
CR
11353 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11354 }
d233b485
CR
11355 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0)
11356 {
11357 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11358 DEFAULT_ARRAY_SIZE);
11359 istring[istring_index++] = CTLESC;
11360 istring[istring_index++] = '\\';
11361 istring[istring_index] = '\0';
11362 break;
11363 }
495aee44 11364 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
cce855bc 11365 {
7117c2d2 11366 SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
bb70624e
JA
11367 }
11368 else if (c == 0)
11369 {
11370 c = CTLNUL;
11371 sindex--; /* add_character: label increments sindex */
11372 goto add_character;
cce855bc
JA
11373 }
11374 else
bb70624e 11375 {
7117c2d2 11376 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
bb70624e 11377 }
726f6388 11378
bb70624e
JA
11379 sindex++;
11380add_twochars:
11381 /* BEFORE jumping here, we need to increment sindex if appropriate */
11382 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11383 DEFAULT_ARRAY_SIZE);
11384 istring[istring_index++] = twochars[0];
11385 istring[istring_index++] = twochars[1];
11386 istring[istring_index] = '\0';
11387
11388 break;
726f6388 11389
cce855bc 11390 case '"':
74091dd4 11391 /* XXX - revisit this */
a0c0a00f 11392 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0))
cce855bc 11393 goto add_character;
ccc6cda3
JA
11394
11395 t_index = ++sindex;
a0c0a00f 11396 temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0);
ccc6cda3
JA
11397
11398 /* If the quotes surrounded the entire string, then the
11399 whole word was quoted. */
11400 quoted_state = (t_index == 1 && string[sindex] == '\0')
11401 ? WHOLLY_QUOTED
7117c2d2 11402 : PARTIALLY_QUOTED;
ccc6cda3
JA
11403
11404 if (temp && *temp)
726f6388 11405 {
95732b49
JA
11406 tword = alloc_word_desc ();
11407 tword->word = temp;
11408
a0c0a00f 11409 if (word->flags & W_ASSIGNARG)
d233b485 11410 tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */
a0c0a00f
CR
11411 if (word->flags & W_COMPLETE)
11412 tword->flags |= W_COMPLETE; /* for command substitutions */
4f747edc
CR
11413 if (word->flags & W_NOCOMSUB)
11414 tword->flags |= W_NOCOMSUB;
11415 if (word->flags & W_NOPROCSUB)
11416 tword->flags |= W_NOPROCSUB;
a0c0a00f 11417
8868edaf
CR
11418 if (word->flags & W_ASSIGNRHS)
11419 tword->flags |= W_ASSIGNRHS;
11420
ccc6cda3
JA
11421 temp = (char *)NULL;
11422
d233b485 11423 temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */
95732b49 11424 /* Need to get W_HASQUOTEDNULL flag through this function. */
74091dd4
CR
11425 /* XXX - preserve Q_ARITH here? */
11426 list = expand_word_internal (tword, Q_DOUBLE_QUOTES|(quoted&Q_ARITH), 0, &temp_has_dollar_at, (int *)NULL);
0b913689 11427 has_dollar_at += temp_has_dollar_at;
726f6388 11428
ccc6cda3
JA
11429 if (list == &expand_word_error || list == &expand_word_fatal)
11430 {
11431 free (istring);
11432 free (string);
11433 /* expand_word_internal has already freed temp_word->word
11434 for us because of the way it prints error messages. */
11435 tword->word = (char *)NULL;
11436 dispose_word (tword);
11437 return list;
11438 }
726f6388 11439
ccc6cda3 11440 dispose_word (tword);
726f6388 11441
ccc6cda3
JA
11442 /* "$@" (a double-quoted dollar-at) expands into nothing,
11443 not even a NULL word, when there are no positional
d233b485
CR
11444 parameters. Posix interp 888 says that other parts of the
11445 word that expand to quoted nulls result in quoted nulls, so
11446 we can't just throw the entire word away if we have "$@"
11447 anywhere in it. We use had_quoted_null to keep track */
a0c0a00f 11448 if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */
726f6388 11449 {
ccc6cda3
JA
11450 quoted_dollar_at++;
11451 break;
11452 }
11453
d233b485
CR
11454 /* If this list comes back with a quoted null from expansion,
11455 we have either "$x" or "$@" with $1 == ''. In either case,
11456 we need to make sure we add a quoted null argument and
11457 disable the special handling that "$@" gets. */
11458 if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL))
11459 {
d233b485 11460 if (had_quoted_null && temp_has_dollar_at)
8868edaf 11461 quoted_dollar_at++;
d233b485
CR
11462 had_quoted_null = 1; /* XXX */
11463 }
11464
ccc6cda3
JA
11465 /* If we get "$@", we know we have expanded something, so we
11466 need to remember it for the final split on $IFS. This is
11467 a special case; it's the only case where a quoted string
11468 can expand into more than one word. It's going to come back
11469 from the above call to expand_word_internal as a list with
8868edaf 11470 multiple words. */
ccc6cda3
JA
11471 if (list)
11472 dequote_list (list);
11473
a0c0a00f 11474 if (temp_has_dollar_at) /* XXX - was has_dollar_at */
ccc6cda3
JA
11475 {
11476 quoted_dollar_at++;
11477 if (contains_dollar_at)
11478 *contains_dollar_at = 1;
11479 if (expanded_something)
11480 *expanded_something = 1;
d233b485 11481 local_expanded = 1;
ccc6cda3
JA
11482 }
11483 }
11484 else
11485 {
11486 /* What we have is "". This is a minor optimization. */
f73dda09 11487 FREE (temp);
ccc6cda3 11488 list = (WORD_LIST *)NULL;
d233b485 11489 had_quoted_null = 1; /* note for later */
ccc6cda3
JA
11490 }
11491
11492 /* The code above *might* return a list (consider the case of "$@",
11493 where it returns "$1", "$2", etc.). We can't throw away the
11494 rest of the list, and we have to make sure each word gets added
11495 as quoted. We test on tresult->next: if it is non-NULL, we
11496 quote the whole list, save it to a string with string_list, and
11497 add that string. We don't need to quote the results of this
11498 (and it would be wrong, since that would quote the separators
11499 as well), so we go directly to add_string. */
11500 if (list)
11501 {
11502 if (list->next)
11503 {
bc4cd23c
JA
11504 /* Testing quoted_dollar_at makes sure that "$@" is
11505 split correctly when $IFS does not contain a space. */
11506 temp = quoted_dollar_at
a0c0a00f 11507 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0)
bc4cd23c 11508 : string_list (quote_list (list));
ccc6cda3 11509 dispose_words (list);
726f6388
JA
11510 goto add_string;
11511 }
11512 else
11513 {
ccc6cda3 11514 temp = savestring (list->word->word);
95732b49 11515 tflag = list->word->flags;
ccc6cda3 11516 dispose_words (list);
95732b49 11517
cce855bc
JA
11518 /* If the string is not a quoted null string, we want
11519 to remove any embedded unquoted CTLNUL characters.
11520 We do not want to turn quoted null strings back into
11521 the empty string, though. We do this because we
11522 want to remove any quoted nulls from expansions that
11523 contain other characters. For example, if we have
11524 x"$*"y or "x$*y" and there are no positional parameters,
7117c2d2 11525 the $* should expand into nothing. */
95732b49
JA
11526 /* We use the W_HASQUOTEDNULL flag to differentiate the
11527 cases: a quoted null character as above and when
11528 CTLNUL is contained in the (non-null) expansion
11529 of some variable. We use the had_quoted_null flag to
11530 pass the value through this function to its caller. */
11531 if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
cce855bc 11532 remove_quoted_nulls (temp); /* XXX */
726f6388
JA
11533 }
11534 }
ccc6cda3
JA
11535 else
11536 temp = (char *)NULL;
726f6388 11537
d233b485
CR
11538 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
11539 had_quoted_null = 1; /* note for later */
11540
ccc6cda3 11541 /* We do not want to add quoted nulls to strings that are only
ac50fbac
CR
11542 partially quoted; we can throw them away. The exception to
11543 this is when we are going to be performing word splitting,
11544 since we have to preserve a null argument if the next character
11545 will cause word splitting. */
8868edaf
CR
11546 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
11547 {
11548 c = CTLNUL;
11549 sindex--;
11550 had_quoted_null = 1;
11551 goto add_character;
11552 }
495aee44 11553 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
cce855bc 11554 continue;
726f6388 11555
ccc6cda3 11556 add_quoted_string:
726f6388 11557
ccc6cda3
JA
11558 if (temp)
11559 {
11560 temp1 = temp;
11561 temp = quote_string (temp);
11562 free (temp1);
bb70624e 11563 goto add_string;
ccc6cda3
JA
11564 }
11565 else
11566 {
11567 /* Add NULL arg. */
bb70624e
JA
11568 c = CTLNUL;
11569 sindex--; /* add_character: label increments sindex */
d233b485 11570 had_quoted_null = 1; /* note for later */
bb70624e 11571 goto add_character;
ccc6cda3 11572 }
bb70624e 11573
ccc6cda3 11574 /* break; */
726f6388 11575
ccc6cda3 11576 case '\'':
95732b49 11577 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
ccc6cda3 11578 goto add_character;
726f6388 11579
ccc6cda3 11580 t_index = ++sindex;
74091dd4 11581 temp = string_extract_single_quoted (string, &sindex, 0);
726f6388 11582
ccc6cda3
JA
11583 /* If the entire STRING was surrounded by single quotes,
11584 then the string is wholly quoted. */
11585 quoted_state = (t_index == 1 && string[sindex] == '\0')
11586 ? WHOLLY_QUOTED
7117c2d2 11587 : PARTIALLY_QUOTED;
726f6388 11588
ccc6cda3
JA
11589 /* If all we had was '', it is a null expansion. */
11590 if (*temp == '\0')
11591 {
11592 free (temp);
11593 temp = (char *)NULL;
11594 }
11595 else
7117c2d2 11596 remove_quoted_escapes (temp); /* ??? */
726f6388 11597
d233b485
CR
11598 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
11599 had_quoted_null = 1; /* note for later */
11600
ccc6cda3 11601 /* We do not want to add quoted nulls to strings that are only
a0c0a00f 11602 partially quoted; such nulls are discarded. See above for the
d233b485 11603 exception, which is when the string is going to be split.
8868edaf
CR
11604 Posix interp 888/1129 */
11605 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
11606 {
11607 c = CTLNUL;
11608 sindex--;
11609 goto add_character;
11610 }
11611
a0c0a00f 11612 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
ccc6cda3 11613 continue;
726f6388 11614
bb70624e
JA
11615 /* If we have a quoted null expansion, add a quoted NULL to istring. */
11616 if (temp == 0)
11617 {
11618 c = CTLNUL;
11619 sindex--; /* add_character: label increments sindex */
11620 goto add_character;
11621 }
11622 else
11623 goto add_quoted_string;
11624
ccc6cda3 11625 /* break; */
726f6388 11626
8868edaf
CR
11627 case ' ':
11628 /* If we are in a context where the word is not going to be split, but
11629 we need to account for $@ and $* producing one word for each
11630 positional parameter, add quoted spaces so the spaces in the
11631 expansion of "$@", if any, behave correctly. We still may need to
11632 split if we are expanding the rhs of a word expansion. */
11633 if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0))
11634 {
11635 if (string[sindex])
11636 sindex++;
11637 twochars[0] = CTLESC;
11638 twochars[1] = c;
11639 goto add_twochars;
11640 }
11641 /* FALLTHROUGH */
11642
726f6388 11643 default:
726f6388 11644 /* This is the fix for " $@ " */
8868edaf 11645add_ifs_character:
a0c0a00f 11646 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0))
726f6388 11647 {
d233b485
CR
11648 if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)
11649 has_quoted_ifs++;
8868edaf 11650add_quoted_character:
bb70624e
JA
11651 if (string[sindex]) /* from old goto dollar_add_string */
11652 sindex++;
11653 if (c == 0)
11654 {
11655 c = CTLNUL;
11656 goto add_character;
11657 }
11658 else
11659 {
7117c2d2 11660#if HANDLE_MULTIBYTE
d233b485
CR
11661 /* XXX - should make sure that c is actually multibyte,
11662 otherwise we can use the twochars branch */
a0c0a00f 11663 if (mb_cur_max > 1)
b80f6443
JA
11664 sindex--;
11665
a0c0a00f 11666 if (mb_cur_max > 1)
7117c2d2 11667 {
b80f6443 11668 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7117c2d2
JA
11669 }
11670 else
11671#endif
11672 {
11673 twochars[0] = CTLESC;
11674 twochars[1] = c;
11675 goto add_twochars;
11676 }
bb70624e 11677 }
726f6388
JA
11678 }
11679
7117c2d2
JA
11680 SADD_MBCHAR (temp, string, sindex, string_size);
11681
8868edaf 11682add_character:
ccc6cda3
JA
11683 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
11684 DEFAULT_ARRAY_SIZE);
726f6388
JA
11685 istring[istring_index++] = c;
11686 istring[istring_index] = '\0';
11687
11688 /* Next character. */
11689 sindex++;
11690 }
11691 }
11692
11693finished_with_string:
726f6388
JA
11694 /* OK, we're ready to return. If we have a quoted string, and
11695 quoted_dollar_at is not set, we do no splitting at all; otherwise
11696 we split on ' '. The routines that call this will handle what to
11697 do if nothing has been expanded. */
ccc6cda3
JA
11698
11699 /* Partially and wholly quoted strings which expand to the empty
11700 string are retained as an empty arguments. Unquoted strings
11701 which expand to the empty string are discarded. The single
11702 exception is the case of expanding "$@" when there are no
11703 positional parameters. In that case, we discard the expansion. */
11704
11705 /* Because of how the code that handles "" and '' in partially
11706 quoted strings works, we need to make ISTRING into a QUOTED_NULL
11707 if we saw quoting characters, but the expansion was empty.
11708 "" and '' are tossed away before we get to this point when
11709 processing partially quoted strings. This makes "" and $xxx""
11710 equivalent when xxx is unset. We also look to see whether we
11711 saw a quoted null from a ${} expansion and add one back if we
11712 need to. */
11713
11714 /* If we expand to nothing and there were no single or double quotes
11715 in the word, we throw it away. Otherwise, we return a NULL word.
11716 The single exception is for $@ surrounded by double quotes when
11717 there are no positional parameters. In that case, we also throw
11718 the word away. */
11719
11720 if (*istring == '\0')
11721 {
74091dd4 11722#if 0
ccc6cda3 11723 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
74091dd4
CR
11724#else
11725 if (had_quoted_null || (quoted_dollar_at == 0 && quoted_state == PARTIALLY_QUOTED))
11726#endif
726f6388 11727 {
726f6388
JA
11728 istring[0] = CTLNUL;
11729 istring[1] = '\0';
d233b485
CR
11730 tword = alloc_word_desc ();
11731 tword->word = istring;
11732 istring = 0; /* avoid later free() */
95732b49 11733 tword->flags |= W_HASQUOTEDNULL; /* XXX */
ccc6cda3
JA
11734 list = make_word_list (tword, (WORD_LIST *)NULL);
11735 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
11736 tword->flags |= W_QUOTED;
726f6388 11737 }
ccc6cda3
JA
11738 /* According to sh, ksh, and Posix.2, if a word expands into nothing
11739 and a double-quoted "$@" appears anywhere in it, then the entire
11740 word is removed. */
a0c0a00f
CR
11741 /* XXX - exception appears to be that quoted null strings result in
11742 null arguments */
ccc6cda3
JA
11743 else if (quoted_state == UNQUOTED || quoted_dollar_at)
11744 list = (WORD_LIST *)NULL;
f73dda09
JA
11745 else
11746 list = (WORD_LIST *)NULL;
ccc6cda3
JA
11747 }
11748 else if (word->flags & W_NOSPLIT)
11749 {
d233b485
CR
11750 tword = alloc_word_desc ();
11751 tword->word = istring;
11752 if (had_quoted_null && QUOTED_NULL (istring))
11753 tword->flags |= W_HASQUOTEDNULL;
11754 istring = 0; /* avoid later free() */
ccc6cda3
JA
11755 if (word->flags & W_ASSIGNMENT)
11756 tword->flags |= W_ASSIGNMENT; /* XXX */
95732b49
JA
11757 if (word->flags & W_COMPASSIGN)
11758 tword->flags |= W_COMPASSIGN; /* XXX */
b72432fd
JA
11759 if (word->flags & W_NOGLOB)
11760 tword->flags |= W_NOGLOB; /* XXX */
ac50fbac
CR
11761 if (word->flags & W_NOBRACE)
11762 tword->flags |= W_NOBRACE; /* XXX */
74091dd4
CR
11763 if (word->flags & W_ARRAYREF)
11764 tword->flags |= W_ARRAYREF;
ccc6cda3 11765 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
28ef6c31 11766 tword->flags |= W_QUOTED;
95732b49 11767 list = make_word_list (tword, (WORD_LIST *)NULL);
ccc6cda3 11768 }
8868edaf
CR
11769 else if (word->flags & W_ASSIGNRHS)
11770 {
11771 list = list_string (istring, "", quoted);
11772 tword = list->word;
11773 if (had_quoted_null && QUOTED_NULL (istring))
11774 tword->flags |= W_HASQUOTEDNULL;
11775 free (list);
11776 free (istring);
11777 istring = 0; /* avoid later free() */
11778 goto set_word_flags;
11779 }
ccc6cda3
JA
11780 else
11781 {
11782 char *ifs_chars;
11783
7117c2d2 11784 ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
726f6388 11785
cce855bc
JA
11786 /* If we have $@, we need to split the results no matter what. If
11787 IFS is unset or NULL, string_list_dollar_at has separated the
11788 positional parameters with a space, so we split on space (we have
11789 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
11790 string_list_dollar_at has separated the positional parameters
ac50fbac
CR
11791 with the first character of $IFS, so we split on $IFS. If
11792 SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
11793 unset or null, and we want to make sure that we split on spaces
a0c0a00f
CR
11794 regardless of what else has happened to IFS since the expansion,
11795 or we expanded "$@" with IFS null and we need to split the positional
11796 parameters into separate words. */
ac50fbac 11797 if (split_on_spaces)
d233b485
CR
11798 {
11799 /* If IFS is not set, and the word is not quoted, we want to split
11800 the individual words on $' \t\n'. We rely on previous steps to
11801 quote the portions of the word that should not be split */
11802 if (ifs_is_set == 0)
11803 list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */
11804 else
11805 list = list_string (istring, " ", 1); /* XXX quoted == 1? */
11806 }
11807
3b34f6e6
CR
11808 /* If we have $@ (has_dollar_at != 0) and we are in a context where we
11809 don't want to split the result (W_NOSPLIT2), and we are not quoted,
11810 we have already separated the arguments with the first character of
11811 $IFS. In this case, we want to return a list with a single word
11812 with the separator possibly replaced with a space (it's what other
11813 shells seem to do).
11814 quoted_dollar_at is internal to this function and is set if we are
11815 passed an argument that is unquoted (quoted == 0) but we encounter a
11816 double-quoted $@ while expanding it. */
11817 else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2))
11818 {
d233b485 11819 tword = alloc_word_desc ();
3b34f6e6
CR
11820 /* Only split and rejoin if we have to */
11821 if (*ifs_chars && *ifs_chars != ' ')
11822 {
d233b485
CR
11823 /* list_string dequotes CTLESCs in the string it's passed, so we
11824 need it to get the space separation right if space isn't the
11825 first character in IFS (but is present) and to remove the
11826 quoting we added back in param_expand(). */
3b34f6e6 11827 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
d233b485
CR
11828 /* This isn't exactly right in the case where we're expanding
11829 the RHS of an expansion like ${var-$@} where IFS=: (for
11830 example). The W_NOSPLIT2 means we do the separation with :;
11831 the list_string removes the quotes and breaks the string into
11832 a list, and the string_list rejoins it on spaces. When we
11833 return, we expect to be able to split the results, but the
11834 space separation means the right split doesn't happen. */
11835 tword->word = string_list (list);
3b34f6e6
CR
11836 }
11837 else
d233b485
CR
11838 tword->word = istring;
11839 if (had_quoted_null && QUOTED_NULL (istring))
11840 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11841 if (tword->word != istring)
11842 free (istring);
11843 istring = 0; /* avoid later free() */
a0c0a00f
CR
11844 goto set_word_flags;
11845 }
ac50fbac 11846 else if (has_dollar_at && ifs_chars)
cce855bc 11847 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
ccc6cda3
JA
11848 else
11849 {
d233b485
CR
11850 tword = alloc_word_desc ();
11851 if (expanded_something && *expanded_something == 0 && has_quoted_ifs)
11852 tword->word = remove_quoted_ifs (istring);
11853 else
11854 tword->word = istring;
8868edaf 11855 if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */
d233b485
CR
11856 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11857 else if (had_quoted_null)
11858 tword->flags |= W_SAWQUOTEDNULL; /* XXX */
11859 if (tword->word != istring)
11860 free (istring);
11861 istring = 0; /* avoid later free() */
3b34f6e6 11862set_word_flags:
ccc6cda3
JA
11863 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
11864 tword->flags |= W_QUOTED;
11865 if (word->flags & W_ASSIGNMENT)
11866 tword->flags |= W_ASSIGNMENT;
95732b49
JA
11867 if (word->flags & W_COMPASSIGN)
11868 tword->flags |= W_COMPASSIGN;
b72432fd
JA
11869 if (word->flags & W_NOGLOB)
11870 tword->flags |= W_NOGLOB;
ac50fbac
CR
11871 if (word->flags & W_NOBRACE)
11872 tword->flags |= W_NOBRACE;
74091dd4
CR
11873 if (word->flags & W_ARRAYREF)
11874 tword->flags |= W_ARRAYREF;
95732b49 11875 list = make_word_list (tword, (WORD_LIST *)NULL);
726f6388 11876 }
726f6388 11877 }
726f6388 11878
ccc6cda3
JA
11879 free (istring);
11880 return (list);
726f6388
JA
11881}
11882
11883/* **************************************************************** */
11884/* */
11885/* Functions for Quote Removal */
11886/* */
11887/* **************************************************************** */
11888
11889/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
7117c2d2 11890 backslash quoting rules for within double quotes or a here document. */
726f6388
JA
11891char *
11892string_quote_removal (string, quoted)
11893 char *string;
11894 int quoted;
11895{
7117c2d2
JA
11896 size_t slen;
11897 char *r, *result_string, *temp, *send;
f73dda09
JA
11898 int sindex, tindex, dquote;
11899 unsigned char c;
7117c2d2 11900 DECLARE_MBSTATE;
726f6388
JA
11901
11902 /* The result can be no longer than the original string. */
7117c2d2
JA
11903 slen = strlen (string);
11904 send = string + slen;
11905
11906 r = result_string = (char *)xmalloc (slen + 1);
726f6388 11907
ccc6cda3 11908 for (dquote = sindex = 0; c = string[sindex];)
726f6388
JA
11909 {
11910 switch (c)
11911 {
11912 case '\\':
11913 c = string[++sindex];
3185942a
JA
11914 if (c == 0)
11915 {
11916 *r++ = '\\';
11917 break;
11918 }
28ef6c31 11919 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
726f6388 11920 *r++ = '\\';
ccc6cda3 11921 /* FALLTHROUGH */
726f6388
JA
11922
11923 default:
7117c2d2 11924 SCOPY_CHAR_M (r, string, send, sindex);
726f6388
JA
11925 break;
11926
11927 case '\'':
ccc6cda3 11928 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
726f6388
JA
11929 {
11930 *r++ = c;
11931 sindex++;
ccc6cda3 11932 break;
726f6388 11933 }
ccc6cda3 11934 tindex = sindex + 1;
74091dd4 11935 temp = string_extract_single_quoted (string, &tindex, 0);
ccc6cda3 11936 if (temp)
726f6388 11937 {
ccc6cda3
JA
11938 strcpy (r, temp);
11939 r += strlen (r);
11940 free (temp);
726f6388 11941 }
ccc6cda3 11942 sindex = tindex;
726f6388
JA
11943 break;
11944
11945 case '"':
11946 dquote = 1 - dquote;
11947 sindex++;
11948 break;
11949 }
11950 }
11951 *r = '\0';
11952 return (result_string);
11953}
11954
ccc6cda3
JA
11955#if 0
11956/* UNUSED */
726f6388
JA
11957/* Perform quote removal on word WORD. This allocates and returns a new
11958 WORD_DESC *. */
11959WORD_DESC *
11960word_quote_removal (word, quoted)
11961 WORD_DESC *word;
11962 int quoted;
11963{
11964 WORD_DESC *w;
11965 char *t;
11966
11967 t = string_quote_removal (word->word, quoted);
95732b49
JA
11968 w = alloc_word_desc ();
11969 w->word = t ? t : savestring ("");
726f6388
JA
11970 return (w);
11971}
11972
11973/* Perform quote removal on all words in LIST. If QUOTED is non-zero,
11974 the members of the list are treated as if they are surrounded by
11975 double quotes. Return a new list, or NULL if LIST is NULL. */
11976WORD_LIST *
11977word_list_quote_removal (list, quoted)
11978 WORD_LIST *list;
11979 int quoted;
11980{
95732b49 11981 WORD_LIST *result, *t, *tresult, *e;
726f6388 11982
ccc6cda3 11983 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
726f6388 11984 {
7117c2d2 11985 tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
95732b49 11986#if 0
726f6388 11987 result = (WORD_LIST *) list_append (result, tresult);
95732b49
JA
11988#else
11989 if (result == 0)
11990 result = e = tresult;
11991 else
11992 {
11993 e->next = tresult;
11994 while (e->next)
11995 e = e->next;
11996 }
11997#endif
726f6388
JA
11998 }
11999 return (result);
12000}
ccc6cda3 12001#endif
726f6388 12002
726f6388
JA
12003/*******************************************
12004 * *
12005 * Functions to perform word splitting *
12006 * *
12007 *******************************************/
12008
7117c2d2
JA
12009void
12010setifs (v)
12011 SHELL_VAR *v;
b72432fd 12012{
7117c2d2
JA
12013 char *t;
12014 unsigned char uc;
12015
12016 ifs_var = v;
95732b49 12017 ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
b72432fd 12018
ac50fbac
CR
12019 ifs_is_set = ifs_var != 0;
12020 ifs_is_null = ifs_is_set && (*ifs_value == 0);
12021
95732b49
JA
12022 /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
12023 handle multibyte chars in IFS */
7117c2d2
JA
12024 memset (ifs_cmap, '\0', sizeof (ifs_cmap));
12025 for (t = ifs_value ; t && *t; t++)
12026 {
12027 uc = *t;
12028 ifs_cmap[uc] = 1;
12029 }
12030
95732b49
JA
12031#if defined (HANDLE_MULTIBYTE)
12032 if (ifs_value == 0)
12033 {
d233b485 12034 ifs_firstc[0] = '\0'; /* XXX - ? */
95732b49
JA
12035 ifs_firstc_len = 1;
12036 }
12037 else
12038 {
d233b485
CR
12039 if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value))
12040 ifs_firstc_len = (*ifs_value != 0) ? 1 : 0;
12041 else
12042 {
12043 size_t ifs_len;
12044 ifs_len = strnlen (ifs_value, MB_CUR_MAX);
12045 ifs_firstc_len = MBLEN (ifs_value, ifs_len);
12046 }
95732b49
JA
12047 if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
12048 {
12049 ifs_firstc[0] = ifs_value[0];
12050 ifs_firstc[1] = '\0';
12051 ifs_firstc_len = 1;
12052 }
12053 else
12054 memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
12055 }
12056#else
7117c2d2 12057 ifs_firstc = ifs_value ? *ifs_value : 0;
95732b49 12058#endif
7117c2d2
JA
12059}
12060
12061char *
12062getifs ()
12063{
12064 return ifs_value;
b72432fd
JA
12065}
12066
726f6388
JA
12067/* This splits a single word into a WORD LIST on $IFS, but only if the word
12068 is not quoted. list_string () performs quote removal for us, even if we
12069 don't do any splitting. */
12070WORD_LIST *
7117c2d2 12071word_split (w, ifs_chars)
726f6388 12072 WORD_DESC *w;
7117c2d2 12073 char *ifs_chars;
726f6388
JA
12074{
12075 WORD_LIST *result;
12076
12077 if (w)
12078 {
7117c2d2 12079 char *xifs;
726f6388 12080
7117c2d2
JA
12081 xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
12082 result = list_string (w->word, xifs, w->flags & W_QUOTED);
726f6388
JA
12083 }
12084 else
12085 result = (WORD_LIST *)NULL;
ccc6cda3 12086
726f6388
JA
12087 return (result);
12088}
12089
12090/* Perform word splitting on LIST and return the RESULT. It is possible
12091 to return (WORD_LIST *)NULL. */
12092static WORD_LIST *
12093word_list_split (list)
12094 WORD_LIST *list;
12095{
95732b49 12096 WORD_LIST *result, *t, *tresult, *e;
d233b485 12097 WORD_DESC *w;
726f6388 12098
ccc6cda3 12099 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
726f6388 12100 {
7117c2d2 12101 tresult = word_split (t->word, ifs_value);
d233b485
CR
12102 /* POSIX 2.6: "If the complete expansion appropriate for a word results
12103 in an empty field, that empty field shall be deleted from the list
12104 of fields that form the completely expanded command, unless the
12105 original word contained single-quote or double-quote characters."
12106 This is where we handle these words that contain quoted null strings
12107 and other characters that expand to nothing after word splitting. */
12108 if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */
12109 {
12110 w = alloc_word_desc ();
12111 w->word = (char *)xmalloc (1);
12112 w->word[0] = '\0';
12113 tresult = make_word_list (w, (WORD_LIST *)NULL);
12114 }
74091dd4
CR
12115#if defined (ARRAY_VARS)
12116 /* pass W_ARRAYREF through for words that are not split and are
12117 identical to the original word. */
12118 if (tresult && tresult->next == 0 && t->next == 0 && (t->word->flags & W_ARRAYREF) && STREQ (t->word->word, tresult->word->word))
12119 tresult->word->flags |= W_ARRAYREF;
12120#endif
95732b49
JA
12121 if (result == 0)
12122 result = e = tresult;
12123 else
12124 {
12125 e->next = tresult;
12126 while (e->next)
12127 e = e->next;
12128 }
726f6388
JA
12129 }
12130 return (result);
12131}
12132
12133/**************************************************
12134 * *
cce855bc 12135 * Functions to expand an entire WORD_LIST *
726f6388
JA
12136 * *
12137 **************************************************/
12138
b80f6443
JA
12139/* Do any word-expansion-specific cleanup and jump to top_level */
12140static void
12141exp_jump_to_top_level (v)
12142 int v;
12143{
3185942a
JA
12144 set_pipestatus_from_exit (last_command_exit_value);
12145
b80f6443
JA
12146 /* Cleanup code goes here. */
12147 expand_no_split_dollar_star = 0; /* XXX */
d233b485
CR
12148 if (expanding_redir)
12149 undo_partial_redirects ();
b80f6443 12150 expanding_redir = 0;
3185942a 12151 assigning_in_environment = 0;
b80f6443 12152
f1be666c
JA
12153 if (parse_and_execute_level == 0)
12154 top_level_cleanup (); /* from sig.c */
12155
b80f6443
JA
12156 jump_to_top_level (v);
12157}
12158
cce855bc
JA
12159/* Put NLIST (which is a WORD_LIST * of only one element) at the front of
12160 ELIST, and set ELIST to the new list. */
12161#define PREPEND_LIST(nlist, elist) \
12162 do { nlist->next = elist; elist = nlist; } while (0)
12163
726f6388
JA
12164/* Separate out any initial variable assignments from TLIST. If set -k has
12165 been executed, remove all assignment statements from TLIST. Initial
12166 variable assignments and other environment assignments are placed
bb70624e 12167 on SUBST_ASSIGN_VARLIST. */
726f6388
JA
12168static WORD_LIST *
12169separate_out_assignments (tlist)
12170 WORD_LIST *tlist;
12171{
12172 register WORD_LIST *vp, *lp;
12173
0001803f 12174 if (tlist == 0)
726f6388
JA
12175 return ((WORD_LIST *)NULL);
12176
bb70624e
JA
12177 if (subst_assign_varlist)
12178 dispose_words (subst_assign_varlist); /* Clean up after previous error */
b72432fd 12179
bb70624e 12180 subst_assign_varlist = (WORD_LIST *)NULL;
726f6388
JA
12181 vp = lp = tlist;
12182
12183 /* Separate out variable assignments at the start of the command.
12184 Loop invariant: vp->next == lp
12185 Loop postcondition:
7117c2d2
JA
12186 lp = list of words left after assignment statements skipped
12187 tlist = original list of words
726f6388 12188 */
ccc6cda3 12189 while (lp && (lp->word->flags & W_ASSIGNMENT))
726f6388
JA
12190 {
12191 vp = lp;
12192 lp = lp->next;
12193 }
12194
bb70624e
JA
12195 /* If lp != tlist, we have some initial assignment statements.
12196 We make SUBST_ASSIGN_VARLIST point to the list of assignment
12197 words and TLIST point to the remaining words. */
726f6388
JA
12198 if (lp != tlist)
12199 {
bb70624e 12200 subst_assign_varlist = tlist;
726f6388
JA
12201 /* ASSERT(vp->next == lp); */
12202 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
12203 tlist = lp; /* remainder of word list */
12204 }
12205
12206 /* vp == end of variable list */
12207 /* tlist == remainder of original word list without variable assignments */
12208 if (!tlist)
12209 /* All the words in tlist were assignment statements */
12210 return ((WORD_LIST *)NULL);
12211
12212 /* ASSERT(tlist != NULL); */
ccc6cda3 12213 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
726f6388
JA
12214
12215 /* If the -k option is in effect, we need to go through the remaining
bb70624e
JA
12216 words, separate out the assignment words, and place them on
12217 SUBST_ASSIGN_VARLIST. */
726f6388
JA
12218 if (place_keywords_in_env)
12219 {
12220 WORD_LIST *tp; /* tp == running pointer into tlist */
12221
12222 tp = tlist;
12223 lp = tlist->next;
12224
12225 /* Loop Invariant: tp->next == lp */
12226 /* Loop postcondition: tlist == word list without assignment statements */
12227 while (lp)
12228 {
ccc6cda3 12229 if (lp->word->flags & W_ASSIGNMENT)
726f6388
JA
12230 {
12231 /* Found an assignment statement, add this word to end of
bb70624e
JA
12232 subst_assign_varlist (vp). */
12233 if (!subst_assign_varlist)
12234 subst_assign_varlist = vp = lp;
726f6388
JA
12235 else
12236 {
12237 vp->next = lp;
12238 vp = lp;
12239 }
12240
12241 /* Remove the word pointed to by LP from TLIST. */
12242 tp->next = lp->next;
12243 /* ASSERT(vp == lp); */
12244 lp->next = (WORD_LIST *)NULL;
12245 lp = tp->next;
12246 }
12247 else
12248 {
12249 tp = lp;
12250 lp = lp->next;
12251 }
12252 }
12253 }
12254 return (tlist);
12255}
12256
cce855bc
JA
12257#define WEXP_VARASSIGN 0x001
12258#define WEXP_BRACEEXP 0x002
12259#define WEXP_TILDEEXP 0x004
12260#define WEXP_PARAMEXP 0x008
12261#define WEXP_PATHEXP 0x010
12262
12263/* All of the expansions, including variable assignments at the start of
12264 the list. */
12265#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
12266
12267/* All of the expansions except variable assignments at the start of
12268 the list. */
12269#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
12270
12271/* All of the `shell expansions': brace expansion, tilde expansion, parameter
12272 expansion, command substitution, arithmetic expansion, word splitting, and
12273 quote removal. */
12274#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
12275
726f6388
JA
12276/* Take the list of words in LIST and do the various substitutions. Return
12277 a new list of words which is the expanded list, and without things like
12278 variable assignments. */
12279
12280WORD_LIST *
12281expand_words (list)
12282 WORD_LIST *list;
12283{
cce855bc 12284 return (expand_word_list_internal (list, WEXP_ALL));
726f6388
JA
12285}
12286
12287/* Same as expand_words (), but doesn't hack variable or environment
12288 variables. */
12289WORD_LIST *
12290expand_words_no_vars (list)
12291 WORD_LIST *list;
12292{
cce855bc 12293 return (expand_word_list_internal (list, WEXP_NOVARS));
726f6388
JA
12294}
12295
cce855bc
JA
12296WORD_LIST *
12297expand_words_shellexp (list)
726f6388 12298 WORD_LIST *list;
726f6388 12299{
cce855bc
JA
12300 return (expand_word_list_internal (list, WEXP_SHELLEXP));
12301}
726f6388 12302
cce855bc
JA
12303static WORD_LIST *
12304glob_expand_word_list (tlist, eflags)
12305 WORD_LIST *tlist;
12306 int eflags;
12307{
12308 char **glob_array, *temp_string;
12309 register int glob_index;
12310 WORD_LIST *glob_list, *output_list, *disposables, *next;
12311 WORD_DESC *tword;
8868edaf 12312 int x;
726f6388 12313
cce855bc
JA
12314 output_list = disposables = (WORD_LIST *)NULL;
12315 glob_array = (char **)NULL;
12316 while (tlist)
12317 {
12318 /* For each word, either globbing is attempted or the word is
12319 added to orig_list. If globbing succeeds, the results are
12320 added to orig_list and the word (tlist) is added to the list
12321 of disposable words. If globbing fails and failed glob
12322 expansions are left unchanged (the shell default), the
12323 original word is added to orig_list. If globbing fails and
12324 failed glob expansions are removed, the original word is
12325 added to the list of disposable words. orig_list ends up
7117c2d2 12326 in reverse order and requires a call to REVERSE_LIST to
cce855bc
JA
12327 be set right. After all words are examined, the disposable
12328 words are freed. */
12329 next = tlist->next;
726f6388 12330
cce855bc 12331 /* If the word isn't an assignment and contains an unquoted
28ef6c31 12332 pattern matching character, then glob it. */
b72432fd 12333 if ((tlist->word->flags & W_NOGLOB) == 0 &&
cce855bc 12334 unquoted_glob_pattern_p (tlist->word->word))
726f6388 12335 {
8868edaf 12336 glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */
cce855bc
JA
12337
12338 /* Handle error cases.
12339 I don't think we should report errors like "No such file
12340 or directory". However, I would like to report errors
12341 like "Read failed". */
12342
b80f6443 12343 if (glob_array == 0 || GLOB_FAILED (glob_array))
726f6388 12344 {
bb70624e 12345 glob_array = (char **)xmalloc (sizeof (char *));
cce855bc
JA
12346 glob_array[0] = (char *)NULL;
12347 }
12348
12349 /* Dequote the current word in case we have to use it. */
12350 if (glob_array[0] == NULL)
12351 {
12352 temp_string = dequote_string (tlist->word->word);
12353 free (tlist->word->word);
12354 tlist->word->word = temp_string;
12355 }
12356
12357 /* Make the array into a word list. */
12358 glob_list = (WORD_LIST *)NULL;
12359 for (glob_index = 0; glob_array[glob_index]; glob_index++)
12360 {
12361 tword = make_bare_word (glob_array[glob_index]);
cce855bc
JA
12362 glob_list = make_word_list (tword, glob_list);
12363 }
12364
12365 if (glob_list)
12366 {
12367 output_list = (WORD_LIST *)list_append (glob_list, output_list);
12368 PREPEND_LIST (tlist, disposables);
12369 }
b80f6443
JA
12370 else if (fail_glob_expansion != 0)
12371 {
ac50fbac 12372 last_command_exit_value = EXECUTION_FAILURE;
b80f6443 12373 report_error (_("no match: %s"), tlist->word->word);
f1be666c 12374 exp_jump_to_top_level (DISCARD);
b80f6443 12375 }
cce855bc
JA
12376 else if (allow_null_glob_expansion == 0)
12377 {
12378 /* Failed glob expressions are left unchanged. */
12379 PREPEND_LIST (tlist, output_list);
12380 }
12381 else
12382 {
12383 /* Failed glob expressions are removed. */
12384 PREPEND_LIST (tlist, disposables);
726f6388 12385 }
726f6388 12386 }
cce855bc
JA
12387 else
12388 {
12389 /* Dequote the string. */
12390 temp_string = dequote_string (tlist->word->word);
12391 free (tlist->word->word);
12392 tlist->word->word = temp_string;
12393 PREPEND_LIST (tlist, output_list);
12394 }
12395
7117c2d2 12396 strvec_dispose (glob_array);
cce855bc
JA
12397 glob_array = (char **)NULL;
12398
12399 tlist = next;
726f6388
JA
12400 }
12401
cce855bc
JA
12402 if (disposables)
12403 dispose_words (disposables);
12404
12405 if (output_list)
12406 output_list = REVERSE_LIST (output_list, WORD_LIST *);
12407
12408 return (output_list);
12409}
726f6388
JA
12410
12411#if defined (BRACE_EXPANSION)
cce855bc
JA
12412static WORD_LIST *
12413brace_expand_word_list (tlist, eflags)
12414 WORD_LIST *tlist;
12415 int eflags;
12416{
12417 register char **expansions;
12418 char *temp_string;
12419 WORD_LIST *disposables, *output_list, *next;
12420 WORD_DESC *w;
12421 int eindex;
12422
12423 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
726f6388 12424 {
cce855bc 12425 next = tlist->next;
726f6388 12426
ac50fbac
CR
12427 if (tlist->word->flags & W_NOBRACE)
12428 {
12429/*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/
12430 PREPEND_LIST (tlist, output_list);
12431 continue;
12432 }
12433
0001803f
CR
12434 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
12435 {
12436/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
12437 PREPEND_LIST (tlist, output_list);
12438 continue;
12439 }
ac50fbac 12440
cce855bc
JA
12441 /* Only do brace expansion if the word has a brace character. If
12442 not, just add the word list element to BRACES and continue. In
12443 the common case, at least when running shell scripts, this will
0001803f 12444 degenerate to a bunch of calls to `mbschr', and then what is
cce855bc 12445 basically a reversal of TLIST into BRACES, which is corrected
7117c2d2 12446 by a call to REVERSE_LIST () on BRACES when the end of TLIST
cce855bc 12447 is reached. */
0001803f 12448 if (mbschr (tlist->word->word, LBRACE))
726f6388 12449 {
cce855bc 12450 expansions = brace_expand (tlist->word->word);
726f6388 12451
cce855bc 12452 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
726f6388 12453 {
ac50fbac
CR
12454 w = alloc_word_desc ();
12455 w->word = temp_string;
12456
cce855bc
JA
12457 /* If brace expansion didn't change the word, preserve
12458 the flags. We may want to preserve the flags
12459 unconditionally someday -- XXX */
12460 if (STREQ (temp_string, tlist->word->word))
12461 w->flags = tlist->word->flags;
ac50fbac
CR
12462 else
12463 w = make_word_flags (w, temp_string);
12464
cce855bc 12465 output_list = make_word_list (w, output_list);
726f6388 12466 }
cce855bc 12467 free (expansions);
726f6388 12468
cce855bc
JA
12469 /* Add TLIST to the list of words to be freed after brace
12470 expansion has been performed. */
12471 PREPEND_LIST (tlist, disposables);
12472 }
12473 else
12474 PREPEND_LIST (tlist, output_list);
726f6388 12475 }
cce855bc
JA
12476
12477 if (disposables)
12478 dispose_words (disposables);
12479
12480 if (output_list)
12481 output_list = REVERSE_LIST (output_list, WORD_LIST *);
12482
12483 return (output_list);
12484}
12485#endif
12486
3185942a 12487#if defined (ARRAY_VARS)
8868edaf
CR
12488/* Take WORD, a compound array assignment, and internally run (for example),
12489 'declare -A w', where W is the variable name portion of WORD. OPTION is
12490 the list of options to supply to `declare'. CMD is the declaration command
12491 we are expanding right now; it's unused currently. */
3185942a 12492static int
a0c0a00f 12493make_internal_declare (word, option, cmd)
3185942a
JA
12494 char *word;
12495 char *option;
a0c0a00f 12496 char *cmd;
3185942a 12497{
a0c0a00f 12498 int t, r;
3185942a
JA
12499 WORD_LIST *wl;
12500 WORD_DESC *w;
12501
12502 w = make_word (word);
12503
12504 t = assignment (w->word, 0);
a0c0a00f
CR
12505 if (w->word[t] == '=')
12506 {
12507 w->word[t] = '\0';
12508 if (w->word[t - 1] == '+') /* cut off any append op */
12509 w->word[t - 1] = '\0';
12510 }
3185942a
JA
12511
12512 wl = make_word_list (w, (WORD_LIST *)NULL);
12513 wl = make_word_list (make_word (option), wl);
12514
a0c0a00f
CR
12515 r = declare_builtin (wl);
12516
12517 dispose_words (wl);
12518 return r;
3185942a 12519}
8868edaf
CR
12520
12521/* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME
12522 is an associative array.
12523
12524 If we are processing an indexed array, expand_compound_array_assignment
12525 will expand all the individual words and quote_compound_array_list will
12526 single-quote them. If we are processing an associative array, we use
12527 parse_string_to_word_list to split VALUE into a list of words instead of
12528 faking up a shell variable and calling expand_compound_array_assignment.
12529 expand_and_quote_assoc_word expands and single-quotes each word in VALUE
12530 together so we don't have problems finding the end of the subscript when
12531 quoting it.
12532
12533 Words in VALUE can be individual words, which are expanded and single-quoted,
12534 or words of the form [IND]=VALUE, which end up as explained below, as
12535 ['expanded-ind']='expanded-value'. */
12536
12537static WORD_LIST *
12538expand_oneword (value, flags)
12539 char *value;
12540 int flags;
12541{
12542 WORD_LIST *l, *nl;
12543 char *t;
76404c85 12544 int kvpair;
8868edaf
CR
12545
12546 if (flags == 0)
12547 {
12548 /* Indexed array */
12549 l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags);
12550 /* Now we quote the results of the expansion above to prevent double
12551 expansion. */
12552 quote_compound_array_list (l, flags);
12553 return l;
12554 }
12555 else
12556 {
12557 /* Associative array */
12558 l = parse_string_to_word_list (value, 1, "array assign");
76404c85
CR
12559#if ASSOC_KVPAIR_ASSIGNMENT
12560 kvpair = kvpair_assignment_p (l);
12561#endif
12562
8868edaf
CR
12563 /* For associative arrays, with their arbitrary subscripts, we have to
12564 expand and quote in one step so we don't have to search for the
12565 closing right bracket more than once. */
12566 for (nl = l; nl; nl = nl->next)
12567 {
76404c85
CR
12568#if ASSOC_KVPAIR_ASSIGNMENT
12569 if (kvpair)
12570 /* keys and values undergo the same set of expansions */
12571 t = expand_and_quote_kvpair_word (nl->word->word);
12572 else
12573#endif
8868edaf
CR
12574 if ((nl->word->flags & W_ASSIGNMENT) == 0)
12575 t = sh_single_quote (nl->word->word ? nl->word->word : "");
12576 else
12577 t = expand_and_quote_assoc_word (nl->word->word, flags);
12578 free (nl->word->word);
12579 nl->word->word = t;
12580 }
12581 return l;
12582 }
12583}
12584
12585/* Expand a single compound assignment argument to a declaration builtin.
12586 This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through
12587 unchanged. The VALUE is expanded and each word in the result is single-
12588 quoted. Words of the form [key]=value end up as
12589 ['expanded-key']='expanded-value'. Associative arrays have special
12590 handling, see expand_oneword() above. The return value is
12591 NAME[+]=( expanded-and-quoted-VALUE ). */
12592static void
12593expand_compound_assignment_word (tlist, flags)
12594 WORD_LIST *tlist;
12595 int flags;
12596{
12597 WORD_LIST *l;
12598 int wlen, oind, t;
12599 char *value, *temp;
12600
12601/*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/
12602 t = assignment (tlist->word->word, 0);
12603
12604 /* value doesn't have the open and close parens */
12605 oind = 1;
12606 value = extract_array_assignment_list (tlist->word->word + t + 1, &oind);
12607 /* This performs one round of expansion on the index/key and value and
12608 single-quotes each word in the result. */
12609 l = expand_oneword (value, flags);
12610 free (value);
12611
12612 value = string_list (l);
cc978a67
CR
12613 dispose_words (l);
12614
8868edaf
CR
12615 wlen = STRLEN (value);
12616
12617 /* Now, let's rebuild the string */
12618 temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */
12619 memcpy (temp, tlist->word->word, ++t);
12620 temp[t++] = '(';
12621 if (value)
12622 memcpy (temp + t, value, wlen);
12623 t += wlen;
12624 temp[t++] = ')';
12625 temp[t] = '\0';
12626/*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/
12627
12628 free (tlist->word->word);
12629 tlist->word->word = temp;
12630
12631 free (value);
12632}
12633
12634/* Expand and process an argument to a declaration command. We have already
12635 set flags in TLIST->word->flags depending on the declaration command
12636 (declare, local, etc.) and the options supplied to it (-a, -A, etc.).
12637 TLIST->word->word is of the form NAME[+]=( VALUE ).
12638
12639 This does several things, all using pieces of other functions to get the
12640 evaluation sequence right. It's called for compound array assignments with
12641 the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs).
12642 It parses out which flags need to be set for declare to create the variable
12643 correctly, then calls declare internally (make_internal_declare) to make
12644 sure the variable exists with the correct attributes. Before the variable
12645 is created, it calls expand_compound_assignment_word to expand VALUE to a
12646 list of words, appropriately quoted for further evaluation. This preserves
12647 the semantics of word-expansion-before-calling-builtins. Finally, it calls
12648 do_word_assignment to perform the expansion and assignment with the same
12649 expansion semantics as a standalone assignment statement (no word splitting,
12650 etc.) even though the word is single-quoted so all that needs to happen is
12651 quote removal. */
12652static WORD_LIST *
12653expand_declaration_argument (tlist, wcmd)
12654 WORD_LIST *tlist, *wcmd;
12655{
12656 char opts[16], omap[128];
12657 int t, opti, oind, skip, inheriting;
12658 WORD_LIST *l;
12659
12660 inheriting = localvar_inherit;
12661 opti = 0;
12662 if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY))
12663 opts[opti++] = '-';
12664
12665 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
12666 {
12667 opts[opti++] = 'g';
12668 opts[opti++] = 'A';
12669 }
12670 else if (tlist->word->flags & W_ASSIGNASSOC)
12671 {
12672 opts[opti++] = 'A';
12673 }
12674 else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
12675 {
12676 opts[opti++] = 'g';
12677 opts[opti++] = 'a';
12678 }
12679 else if (tlist->word->flags & W_ASSIGNARRAY)
12680 {
12681 opts[opti++] = 'a';
12682 }
12683 else if (tlist->word->flags & W_ASSNGLOBAL)
12684 opts[opti++] = 'g';
12685
12686 if (tlist->word->flags & W_CHKLOCAL)
12687 opts[opti++] = 'G';
12688
12689 /* If we have special handling note the integer attribute and others
12690 that transform the value upon assignment. What we do is take all
12691 of the option arguments and scan through them looking for options
12692 that cause such transformations, and add them to the `opts' array. */
12693
12694 memset (omap, '\0', sizeof (omap));
12695 for (l = wcmd->next; l != tlist; l = l->next)
12696 {
74091dd4
CR
12697 int optchar;
12698
12699 if (l->word->word[0] != '-' && l->word->word[0] != '+')
8868edaf
CR
12700 break; /* non-option argument */
12701 if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0)
12702 break; /* -- signals end of options */
74091dd4 12703 optchar = l->word->word[0];
8868edaf
CR
12704 for (oind = 1; l->word->word[oind]; oind++)
12705 switch (l->word->word[oind])
12706 {
12707 case 'I':
12708 inheriting = 1;
12709 case 'i':
12710 case 'l':
12711 case 'u':
12712 case 'c':
12713 omap[l->word->word[oind]] = 1;
12714 if (opti == 0)
74091dd4 12715 opts[opti++] = optchar;
8868edaf
CR
12716 break;
12717 default:
12718 break;
12719 }
12720 }
12721
12722 for (oind = 0; oind < sizeof (omap); oind++)
12723 if (omap[oind])
12724 opts[opti++] = oind;
12725
12726 /* If there are no -a/-A options, but we have a compound assignment,
12727 we have a choice: we can set opts[0]='-', opts[1]='a', since the
12728 default is to create an indexed array, and call
12729 make_internal_declare with that, or we can just skip the -a and let
12730 declare_builtin deal with it. Once we're here, we're better set
12731 up for the latter, since we don't want to deal with looking up
12732 any existing variable here -- better to let declare_builtin do it.
12733 We need the variable created, though, especially if it's local, so
12734 we get the scoping right before we call do_word_assignment.
12735 To ensure that make_local_declare gets called, we add `--' if there
12736 aren't any options. */
12737 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0)
12738 {
12739 if (opti == 0)
12740 {
12741 opts[opti++] = '-';
12742 opts[opti++] = '-';
12743 }
12744 }
12745 opts[opti] = '\0';
12746
12747 /* This isn't perfect, but it's a start. Improvements later. We expand
12748 tlist->word->word and single-quote the results to avoid multiple
12749 expansions by, say, do_assignment_internal(). We have to weigh the
12750 cost of reconstructing the compound assignment string with its single
12751 quoting and letting the declare builtin handle it. The single quotes
12752 will prevent any unwanted additional expansion or word splitting. */
12753 expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0);
12754
12755 skip = 0;
12756 if (opti > 0)
12757 {
12758 t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0);
12759 if (t != EXECUTION_SUCCESS)
12760 {
12761 last_command_exit_value = t;
12762 if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */
12763 skip = 1;
12764 else
12765 exp_jump_to_top_level (DISCARD);
12766 }
12767 }
12768
12769 if (skip == 0)
12770 {
12771 t = do_word_assignment (tlist->word, 0);
12772 if (t == 0)
12773 {
12774 last_command_exit_value = EXECUTION_FAILURE;
12775 exp_jump_to_top_level (DISCARD);
12776 }
12777 }
12778
12779 /* Now transform the word as ksh93 appears to do and go on */
12780 t = assignment (tlist->word->word, 0);
12781 tlist->word->word[t] = '\0';
12782 if (tlist->word->word[t - 1] == '+')
12783 tlist->word->word[t - 1] = '\0'; /* cut off append op */
12784 tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
12785
12786 return (tlist);
12787}
12788#endif /* ARRAY_VARS */
3185942a 12789
cce855bc
JA
12790static WORD_LIST *
12791shell_expand_word_list (tlist, eflags)
12792 WORD_LIST *tlist;
12793 int eflags;
12794{
a0c0a00f 12795 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd;
cce855bc 12796 int expanded_something, has_dollar_at;
726f6388 12797
726f6388 12798 /* We do tilde expansion all the time. This is what 1003.2 says. */
8868edaf 12799 wcmd = new_list = (WORD_LIST *)NULL;
a0c0a00f 12800
cce855bc 12801 for (orig_list = tlist; tlist; tlist = next)
726f6388 12802 {
8868edaf
CR
12803 if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN))
12804 wcmd = tlist;
12805
726f6388
JA
12806 next = tlist->next;
12807
95732b49
JA
12808#if defined (ARRAY_VARS)
12809 /* If this is a compound array assignment to a builtin that accepts
12810 such assignments (e.g., `declare'), take the assignment and perform
12811 it separately, handling the semantics of declarations inside shell
12812 functions. This avoids the double-evaluation of such arguments,
12813 because `declare' does some evaluation of compound assignments on
12814 its own. */
12815 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
8868edaf 12816 expand_declaration_argument (tlist, wcmd);
95732b49 12817#endif
726f6388 12818
ccc6cda3 12819 expanded_something = 0;
726f6388 12820 expanded = expand_word_internal
b72432fd 12821 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
726f6388
JA
12822
12823 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
12824 {
12825 /* By convention, each time this error is returned,
12826 tlist->word->word has already been freed. */
12827 tlist->word->word = (char *)NULL;
ccc6cda3 12828
726f6388
JA
12829 /* Dispose our copy of the original list. */
12830 dispose_words (orig_list);
d166f048 12831 /* Dispose the new list we're building. */
726f6388
JA
12832 dispose_words (new_list);
12833
28ef6c31 12834 last_command_exit_value = EXECUTION_FAILURE;
726f6388 12835 if (expanded == &expand_word_error)
b80f6443 12836 exp_jump_to_top_level (DISCARD);
726f6388 12837 else
b80f6443 12838 exp_jump_to_top_level (FORCE_EOF);
726f6388
JA
12839 }
12840
ccc6cda3
JA
12841 /* Don't split words marked W_NOSPLIT. */
12842 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
726f6388 12843 {
ccc6cda3 12844 temp_list = word_list_split (expanded);
726f6388
JA
12845 dispose_words (expanded);
12846 }
12847 else
12848 {
12849 /* If no parameter expansion, command substitution, process
12850 substitution, or arithmetic substitution took place, then
12851 do not do word splitting. We still have to remove quoted
12852 null characters from the result. */
12853 word_list_remove_quoted_nulls (expanded);
ccc6cda3 12854 temp_list = expanded;
726f6388
JA
12855 }
12856
ccc6cda3
JA
12857 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
12858 new_list = (WORD_LIST *)list_append (expanded, new_list);
726f6388
JA
12859 }
12860
cce855bc
JA
12861 if (orig_list)
12862 dispose_words (orig_list);
726f6388 12863
726f6388 12864 if (new_list)
cce855bc 12865 new_list = REVERSE_LIST (new_list, WORD_LIST *);
726f6388 12866
cce855bc
JA
12867 return (new_list);
12868}
726f6388 12869
74091dd4
CR
12870/* Perform assignment statements optionally preceding a command name COMMAND.
12871 If COMMAND == NULL, is_nullcmd usually == 1. Follow the POSIX rules for
12872 variable assignment errors. */
12873static int
12874do_assignment_statements (varlist, command, is_nullcmd)
12875 WORD_LIST *varlist;
12876 char *command;
12877 int is_nullcmd;
12878{
12879 WORD_LIST *temp_list;
12880 char *savecmd;
12881 sh_wassign_func_t *assign_func;
12882 int is_special_builtin, is_builtin_or_func, tint;
12883
12884 /* If the remainder of the words expand to nothing, Posix.2 requires
12885 that the variable and environment assignments affect the shell's
12886 environment (do_word_assignment). */
12887 assign_func = is_nullcmd ? do_word_assignment : assign_in_env;
12888 tempenv_assign_error = 0;
12889
12890 is_builtin_or_func = command && (find_shell_builtin (command) || find_function (command));
12891 /* Posix says that special builtins exit if a variable assignment error
12892 occurs in an assignment preceding it. (XXX - this is old -- current Posix
12893 says that any variable assignment error causes a non-interactive shell
12894 to exit. See the STRICT_POSIX checks below. */
12895 is_special_builtin = posixly_correct && command && find_special_builtin (command);
12896
12897 savecmd = this_command_name;
12898 for (temp_list = varlist; temp_list; temp_list = temp_list->next)
12899 {
12900 this_command_name = (char *)NULL;
12901 assigning_in_environment = is_nullcmd == 0;
12902 tint = (*assign_func) (temp_list->word, is_builtin_or_func);
12903 assigning_in_environment = 0;
12904 this_command_name = savecmd;
12905
12906 /* Variable assignment errors in non-interactive shells running
12907 in posix mode cause the shell to exit. */
12908 if (tint == 0)
12909 {
12910 if (is_nullcmd) /* assignment statement */
12911 {
12912 last_command_exit_value = EXECUTION_FAILURE;
12913#if defined (STRICT_POSIX)
12914 if (posixly_correct && interactive_shell == 0)
12915#else
12916 if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
12917#endif
12918 exp_jump_to_top_level (FORCE_EOF);
12919 else
12920 exp_jump_to_top_level (DISCARD);
12921 }
12922 /* In posix mode, assignment errors in the temporary environment
12923 cause a non-interactive shell executing a special builtin to
12924 exit and a non-interactive shell to otherwise jump back to the
12925 top level. This is what POSIX says to do for variable assignment
12926 errors, and POSIX says errors in assigning to the temporary
12927 environment are treated as variable assignment errors.
12928 (XXX - this is not what current POSIX says - look at the
12929 STRICT_POSIX defines. */
12930 else if (posixly_correct)
12931 {
12932 last_command_exit_value = EXECUTION_FAILURE;
12933#if defined (STRICT_POSIX)
12934 exp_jump_to_top_level ((interactive_shell == 0) ? FORCE_EOF : DISCARD);
12935#else
12936 if (interactive_shell == 0 && is_special_builtin)
12937 exp_jump_to_top_level (FORCE_EOF);
12938 else if (interactive_shell == 0)
12939 exp_jump_to_top_level (DISCARD); /* XXX - maybe change later */
12940 else
12941 exp_jump_to_top_level (DISCARD);
12942#endif
12943 }
12944 else
12945 tempenv_assign_error++;
12946 }
12947 }
12948 return (tempenv_assign_error);
12949}
12950
cce855bc
JA
12951/* The workhorse for expand_words () and expand_words_no_vars ().
12952 First arg is LIST, a WORD_LIST of words.
b72432fd
JA
12953 Second arg EFLAGS is a flags word controlling which expansions are
12954 performed.
726f6388 12955
cce855bc
JA
12956 This does all of the substitutions: brace expansion, tilde expansion,
12957 parameter expansion, command substitution, arithmetic expansion,
12958 process substitution, word splitting, and pathname expansion, according
12959 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
12960 set, or for which no expansion is done, do not undergo word splitting.
ac50fbac
CR
12961 Words with the W_NOGLOB bit set do not undergo pathname expansion; words
12962 with W_NOBRACE set do not undergo brace expansion (see
12963 brace_expand_word_list above). */
cce855bc
JA
12964static WORD_LIST *
12965expand_word_list_internal (list, eflags)
12966 WORD_LIST *list;
12967 int eflags;
12968{
12969 WORD_LIST *new_list, *temp_list;
726f6388 12970
ac50fbac 12971 tempenv_assign_error = 0;
cce855bc
JA
12972 if (list == 0)
12973 return ((WORD_LIST *)NULL);
726f6388 12974
bb70624e 12975 garglist = new_list = copy_word_list (list);
cce855bc
JA
12976 if (eflags & WEXP_VARASSIGN)
12977 {
bb70624e 12978 garglist = new_list = separate_out_assignments (new_list);
cce855bc
JA
12979 if (new_list == 0)
12980 {
bb70624e 12981 if (subst_assign_varlist)
74091dd4
CR
12982 do_assignment_statements (subst_assign_varlist, (char *)NULL, 1);
12983
12984 dispose_words (subst_assign_varlist);
12985 subst_assign_varlist = (WORD_LIST *)NULL;
12986
cce855bc
JA
12987 return ((WORD_LIST *)NULL);
12988 }
12989 }
726f6388 12990
cce855bc
JA
12991 /* Begin expanding the words that remain. The expansions take place on
12992 things that aren't really variable assignments. */
726f6388 12993
cce855bc
JA
12994#if defined (BRACE_EXPANSION)
12995 /* Do brace expansion on this word if there are any brace characters
12996 in the string. */
12997 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
12998 new_list = brace_expand_word_list (new_list, eflags);
12999#endif /* BRACE_EXPANSION */
726f6388 13000
cce855bc
JA
13001 /* Perform the `normal' shell expansions: tilde expansion, parameter and
13002 variable substitution, command substitution, arithmetic expansion,
13003 and word splitting. */
13004 new_list = shell_expand_word_list (new_list, eflags);
726f6388 13005
cce855bc
JA
13006 /* Okay, we're almost done. Now let's just do some filename
13007 globbing. */
13008 if (new_list)
13009 {
13010 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
13011 /* Glob expand the word list unless globbing has been disabled. */
13012 new_list = glob_expand_word_list (new_list, eflags);
726f6388 13013 else
cce855bc
JA
13014 /* Dequote the words, because we're not performing globbing. */
13015 new_list = dequote_list (new_list);
726f6388
JA
13016 }
13017
bb70624e 13018 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
726f6388 13019 {
74091dd4 13020 do_assignment_statements (subst_assign_varlist, (new_list && new_list->word) ? new_list->word->word : (char *)NULL, new_list == 0);
726f6388 13021
bb70624e
JA
13022 dispose_words (subst_assign_varlist);
13023 subst_assign_varlist = (WORD_LIST *)NULL;
726f6388
JA
13024 }
13025
cce855bc 13026 return (new_list);
ccc6cda3 13027}