]> git.ipfire.org Git - thirdparty/bash.git/blame - subst.c
Bash-5.2 patch 7: fixes for alias expansion inside command substitution in POSIX...
[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
1696 tlen = si - i - 1;
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
1716 tlen = si - i - 1;
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
3822/* If there are any characters in STRING that require full expansion,
3823 then call FUNC to expand STRING; otherwise just perform quote
3824 removal if necessary. This returns a new string. */
3825static char *
f73dda09 3826expand_string_if_necessary (string, quoted, func)
cce855bc
JA
3827 char *string;
3828 int quoted;
f73dda09 3829 EXPFUNC *func;
cce855bc
JA
3830{
3831 WORD_LIST *list;
7117c2d2 3832 size_t slen;
cce855bc
JA
3833 int i, saw_quote;
3834 char *ret;
7117c2d2 3835 DECLARE_MBSTATE;
cce855bc 3836
95732b49
JA
3837 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3838 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
7117c2d2
JA
3839 i = saw_quote = 0;
3840 while (string[i])
cce855bc
JA
3841 {
3842 if (EXP_CHAR (string[i]))
3843 break;
3844 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3845 saw_quote = 1;
7117c2d2 3846 ADVANCE_CHAR (string, slen, i);
cce855bc
JA
3847 }
3848
3849 if (string[i])
3850 {
3851 list = (*func) (string, quoted);
3852 if (list)
3853 {
3854 ret = string_list (list);
3855 dispose_words (list);
3856 }
3857 else
3858 ret = (char *)NULL;
3859 }
3860 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3861 ret = string_quote_removal (string, quoted);
3862 else
3863 ret = savestring (string);
7117c2d2 3864
cce855bc
JA
3865 return ret;
3866}
3867
3868static inline char *
f73dda09 3869expand_string_to_string_internal (string, quoted, func)
cce855bc
JA
3870 char *string;
3871 int quoted;
f73dda09 3872 EXPFUNC *func;
cce855bc
JA
3873{
3874 WORD_LIST *list;
3875 char *ret;
3876
3877 if (string == 0 || *string == '\0')
3878 return ((char *)NULL);
3879
3880 list = (*func) (string, quoted);
3881 if (list)
3882 {
3883 ret = string_list (list);
3884 dispose_words (list);
3885 }
3886 else
3887 ret = (char *)NULL;
3888
3889 return (ret);
3890}
3891
f73dda09
JA
3892char *
3893expand_string_to_string (string, quoted)
3894 char *string;
3895 int quoted;
3896{
3897 return (expand_string_to_string_internal (string, quoted, expand_string));
3898}
3899
3900char *
3901expand_string_unsplit_to_string (string, quoted)
3902 char *string;
3903 int quoted;
3904{
3905 return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
3906}
3907
95732b49
JA
3908char *
3909expand_assignment_string_to_string (string, quoted)
3910 char *string;
3911 int quoted;
3912{
3913 return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
3914}
3915
74091dd4
CR
3916/* Kind of like a combination of dequote_string and quote_string_for_globbing;
3917 try to remove CTLESC quoting characters and convert CTLESC escaping a `&'
3918 or a backslash into a backslash. The output of this function must eventually
3919 be processed by strcreplace(). */
3920static char *
3921quote_string_for_repl (string, flags)
3922 char *string;
3923 int flags;
3924{
3925 size_t slen;
3926 char *result, *t;
3927 const char *s, *send;
3928 DECLARE_MBSTATE;
3929
3930 slen = strlen (string);
3931 send = string + slen;
3932
3933 result = (char *)xmalloc (slen * 2 + 1);
3934
3935 if (string[0] == CTLESC && string[1] == 0)
3936 {
3937 result[0] = CTLESC;
3938 result[1] = '\0';
3939 return (result);
3940 }
3941
3942 /* This is awkward. We want to translate CTLESC-\ to \\ if we will
3943 eventually send this string through strcreplace(), which we will do
3944 only if shouldexp_replacement() determines that there is something
3945 to replace. We can either make sure to escape backslashes here and
3946 have shouldexp_replacement() signal that we should send the string to
3947 strcreplace() if it sees an escaped backslash, or we can scan the
3948 string before copying it and turn CTLESC-\ into \\ only if we encounter
3949 a CTLESC-& or a &. This does the former and changes shouldexp_replacement().
3950 If we double the backslashes here, we'll get doubled backslashes in any
3951 result that doesn't get passed to strcreplace(). */
3952
3953 for (s = string, t = result; *s; )
3954 {
3955 /* This function's result has to be processed by strcreplace() */
3956 if (*s == CTLESC && (s[1] == '&' || s[1] == '\\'))
3957 {
3958 *t++ = '\\';
3959 s++;
3960 *t++ = *s++;
3961 continue;
3962 }
3963 /* Dequote it */
3964 if (*s == CTLESC)
3965 {
3966 s++;
3967 if (*s == '\0')
3968 break;
3969 }
3970 COPY_CHAR_P (t, s, send);
3971 }
3972
3973 *t = '\0';
3974 return (result);
3975}
3976
3977/* This does not perform word splitting on the WORD_LIST it returns and
3978 it treats $* as if it were quoted. It dequotes the WORD_LIST, adds
3979 backslash escapes before CTLESC-quoted backslash and `& if
3980 patsub_replacement is enabled. */
3981static char *
3982expand_string_for_patsub (string, quoted)
3983 char *string;
3984 int quoted;
3985{
3986 WORD_LIST *value;
3987 char *ret, *t;
3988
3989 if (string == 0 || *string == '\0')
3990 return (char *)NULL;
3991
3992 value = expand_string_for_pat (string, quoted, (int *)0, (int *)0);
3993
3994 if (value && value->word)
3995 {
3996 remove_quoted_nulls (value->word->word); /* XXX */
3997 value->word->flags &= ~W_HASQUOTEDNULL;
3998 }
3999
4000 if (value)
4001 {
4002 t = (value->next) ? string_list (value) : value->word->word;
4003 ret = quote_string_for_repl (t, quoted);
4004 if (t != value->word->word)
4005 free (t);
4006 dispose_words (value);
4007 }
4008 else
4009 ret = (char *)NULL;
4010
4011 return (ret);
4012}
4013
0628567a
JA
4014char *
4015expand_arith_string (string, quoted)
4016 char *string;
3185942a 4017 int quoted;
0628567a 4018{
ac50fbac
CR
4019 WORD_DESC td;
4020 WORD_LIST *list, *tlist;
4021 size_t slen;
4022 int i, saw_quote;
4023 char *ret;
4024 DECLARE_MBSTATE;
4025
4026 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
4027 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
4028 i = saw_quote = 0;
4029 while (string[i])
4030 {
4031 if (EXP_CHAR (string[i]))
4032 break;
4033 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
74091dd4 4034 saw_quote = string[i];
ac50fbac
CR
4035 ADVANCE_CHAR (string, slen, i);
4036 }
4037
4038 if (string[i])
4039 {
4040 /* This is expanded version of expand_string_internal as it's called by
4041 expand_string_leave_quoted */
d233b485 4042 td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */
8868edaf
CR
4043#if 0 /* TAG: bash-5.2 */
4044 if (quoted & Q_ARRAYSUB)
4045 td.flags |= W_NOCOMSUB;
4046#endif
ac50fbac
CR
4047 td.word = savestring (string);
4048 list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4049 /* This takes care of the calls from expand_string_leave_quoted and
4050 expand_string */
4051 if (list)
4052 {
4053 tlist = word_list_split (list);
4054 dispose_words (list);
4055 list = tlist;
4056 if (list)
4057 dequote_list (list);
4058 }
4059 /* This comes from expand_string_if_necessary */
4060 if (list)
4061 {
4062 ret = string_list (list);
4063 dispose_words (list);
4064 }
4065 else
4066 ret = (char *)NULL;
4067 FREE (td.word);
4068 }
a0c0a00f
CR
4069 else if (saw_quote && (quoted & Q_ARITH))
4070 ret = string_quote_removal (string, quoted);
ac50fbac
CR
4071 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4072 ret = string_quote_removal (string, quoted);
4073 else
4074 ret = savestring (string);
4075
4076 return ret;
0628567a
JA
4077}
4078
cce855bc
JA
4079#if defined (COND_COMMAND)
4080/* Just remove backslashes in STRING. Returns a new string. */
4081char *
4082remove_backslashes (string)
4083 char *string;
4084{
4085 char *r, *ret, *s;
4086
f73dda09 4087 r = ret = (char *)xmalloc (strlen (string) + 1);
cce855bc
JA
4088 for (s = string; s && *s; )
4089 {
4090 if (*s == '\\')
28ef6c31 4091 s++;
cce855bc 4092 if (*s == 0)
28ef6c31 4093 break;
cce855bc
JA
4094 *r++ = *s++;
4095 }
4096 *r = '\0';
4097 return ret;
4098}
4099
4100/* This needs better error handling. */
4101/* Expand W for use as an argument to a unary or binary operator in a
f1be666c 4102 [[...]] expression. If SPECIAL is 1, this is the rhs argument
cce855bc 4103 to the != or == operator, and should be treated as a pattern. In
f1be666c
JA
4104 this case, we quote the string specially for the globbing code. If
4105 SPECIAL is 2, this is an rhs argument for the =~ operator, and should
74091dd4
CR
4106 be quoted appropriately for regcomp/regexec. If SPECIAL is 3, this is
4107 an array subscript and should be quoted after expansion so it's only
4108 expanded once (Q_ARITH). The caller is responsible
d894cfd1
CR
4109 for removing the backslashes if the unquoted word is needed later. In
4110 any case, since we don't perform word splitting, we need to do quoted
4111 null character removal. */
cce855bc
JA
4112char *
4113cond_expand_word (w, special)
4114 WORD_DESC *w;
4115 int special;
4116{
4117 char *r, *p;
4118 WORD_LIST *l;
f1be666c 4119 int qflags;
cce855bc
JA
4120
4121 if (w->word == 0 || w->word[0] == '\0')
4122 return ((char *)NULL);
4123
3b34f6e6 4124 expand_no_split_dollar_star = 1;
0001803f 4125 w->flags |= W_NOSPLIT2;
74091dd4
CR
4126 qflags = (special == 3) ? Q_ARITH : 0;
4127 l = call_expand_word_internal (w, qflags, 0, (int *)0, (int *)0);
3b34f6e6 4128 expand_no_split_dollar_star = 0;
cce855bc
JA
4129 if (l)
4130 {
ac50fbac 4131 if (special == 0) /* LHS */
cce855bc 4132 {
d894cfd1
CR
4133 if (l->word)
4134 word_list_remove_quoted_nulls (l);
cce855bc
JA
4135 dequote_list (l);
4136 r = string_list (l);
4137 }
74091dd4
CR
4138 else if (special == 3) /* arithmetic expression, Q_ARITH */
4139 {
4140 if (l->word)
4141 word_list_remove_quoted_nulls (l); /* for now */
4142 dequote_list (l);
4143 r = string_list (l);
4144 }
cce855bc 4145 else
28ef6c31 4146 {
ac50fbac
CR
4147 /* Need to figure out whether or not we should call dequote_escapes
4148 or a new dequote_ctlnul function here, and under what
4149 circumstances. */
d233b485 4150 qflags = QGLOB_CVTNULL|QGLOB_CTLESC;
f1be666c
JA
4151 if (special == 2)
4152 qflags |= QGLOB_REGEXP;
a0c0a00f 4153 word_list_remove_quoted_nulls (l);
28ef6c31 4154 p = string_list (l);
f1be666c 4155 r = quote_string_for_globbing (p, qflags);
28ef6c31
JA
4156 free (p);
4157 }
cce855bc
JA
4158 dispose_words (l);
4159 }
74091dd4
CR
4160 else
4161 r = (char *)NULL;
4162
4163 return r;
4164}
4165#endif
4166
4167/* Expand $'...' and $"..." in a string for code paths that don't do it. The
4168 FLAGS argument is 1 if this function should treat CTLESC as a quote
4169 character (e.g., for here-documents) or not (e.g., for shell_expand_line). */
4170char *
4171expand_string_dollar_quote (string, flags)
4172 char *string;
4173 int flags;
4174{
4175 size_t slen, retind, retsize;
4176 int sindex, c, translen, peekc, news;
4177 char *ret, *trans, *send, *t;
4178 DECLARE_MBSTATE;
4179
4180 slen = strlen (string);
4181 send = string + slen;
4182 sindex = 0;
4183
4184 retsize = slen + 1;
4185 ret = xmalloc (retsize);
4186 retind = 0;
4187
4188 while (c = string[sindex])
4189 {
4190 switch (c)
4191 {
4192 default:
4193 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 1, retsize, 64);
4194 COPY_CHAR_I (ret, retind, string, send, sindex);
4195 break;
4196
4197 case '\\':
4198 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 2, retsize, 64);
4199 ret[retind++] = string[sindex++];
4200
4201 if (string[sindex])
4202 COPY_CHAR_I (ret, retind, string, send, sindex);
4203 break;
4204
4205 case '\'':
4206 case '"':
4207 if (c == '\'')
4208 news = skip_single_quoted (string, slen, ++sindex, SX_COMPLETE);
4209 else
4210 news = skip_double_quoted (string, slen, ++sindex, SX_COMPLETE);
4211 translen = news - sindex - 1;
4212 RESIZE_MALLOCED_BUFFER (ret, retind, translen + 3, retsize, 64);
4213 ret[retind++] = c;
4214 if (translen > 0)
4215 {
4216 strncpy (ret + retind, string + sindex, translen);
4217 retind += translen;
4218 }
4219 if (news > sindex && string[news - 1] == c)
4220 ret[retind++] = c;
4221 sindex = news;
4222 break;
4223
4224 case CTLESC:
4225 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 2, retsize, 64);
4226 if (flags)
4227 ret[retind++] = string[sindex++];
4228 if (string[sindex])
4229 COPY_CHAR_I (ret, retind, string, send, sindex);
4230 break;
4231
4232 case '$':
4233 peekc = string[++sindex];
4234#if defined (TRANSLATABLE_STRINGS)
4235 if (peekc != '\'' && peekc != '"')
4236#else
4237 if (peekc != '\'')
4238#endif
4239 {
4240 RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 16);
4241 ret[retind++] = c;
4242 break;
4243 }
4244 if (string[sindex + 1] == '\0') /* don't bother */
4245 {
4246 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4247 ret[retind++] = c;
4248 ret[retind++] = peekc;
4249 sindex++;
4250 break;
4251 }
4252 if (peekc == '\'')
4253 {
4254 /* SX_COMPLETE is the equivalent of ALLOWESC here */
4255 /* We overload SX_COMPLETE below */
4256 news = skip_single_quoted (string, slen, ++sindex, SX_COMPLETE);
4257 /* Check for unclosed string and don't bother if so */
4258 if (news > sindex && string[news] == '\0' && string[news-1] != peekc)
4259 {
4260 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4261 ret[retind++] = c;
4262 ret[retind++] = peekc;
4263 continue;
4264 }
4265 t = substring (string, sindex, news - 1);
4266 trans = ansiexpand (t, 0, news-sindex-1, &translen);
4267 free (t);
4268 t = sh_single_quote (trans);
4269 sindex = news;
4270 }
4271#if defined (TRANSLATABLE_STRINGS)
4272 else
4273 {
4274 news = ++sindex;
4275 t = string_extract_double_quoted (string, &news, SX_COMPLETE);
4276 /* Check for unclosed string and don't bother if so */
4277 if (news > sindex && string[news] == '\0' && string[news-1] != peekc)
4278 {
4279 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4280 ret[retind++] = c;
4281 ret[retind++] = peekc;
4282 free (t);
4283 continue;
4284 }
4285 trans = locale_expand (t, 0, news-sindex, 0, &translen);
4286 free (t);
4287 if (singlequote_translations &&
4288 ((news-sindex-1) != translen || STREQN (t, trans, translen) == 0))
4289 t = sh_single_quote (trans);
4290 else
4291 t = sh_mkdoublequoted (trans, translen, 0);
4292 sindex = news;
4293 }
4294#endif /* TRANSLATABLE_STRINGS */
4295 free (trans);
4296 trans = t;
4297 translen = strlen (trans);
4298
4299 RESIZE_MALLOCED_BUFFER (ret, retind, translen + 1, retsize, 128);
4300 strcpy (ret + retind, trans);
4301 retind += translen;
4302 FREE (trans);
4303 break;
4304 }
4305 }
cce855bc 4306
74091dd4
CR
4307 ret[retind] = 0;
4308 return ret;
cce855bc 4309}
cce855bc
JA
4310
4311/* Call expand_word_internal to expand W and handle error returns.
4312 A convenience function for functions that don't want to handle
4313 any errors or free any memory before aborting. */
4314static WORD_LIST *
b72432fd 4315call_expand_word_internal (w, q, i, c, e)
cce855bc 4316 WORD_DESC *w;
b72432fd 4317 int q, i, *c, *e;
cce855bc
JA
4318{
4319 WORD_LIST *result;
4320
b72432fd 4321 result = expand_word_internal (w, q, i, c, e);
bb70624e 4322 if (result == &expand_word_error || result == &expand_word_fatal)
cce855bc
JA
4323 {
4324 /* By convention, each time this error is returned, w->word has
bb70624e
JA
4325 already been freed (it sometimes may not be in the fatal case,
4326 but that doesn't result in a memory leak because we're going
4327 to exit in most cases). */
cce855bc 4328 w->word = (char *)NULL;
28ef6c31 4329 last_command_exit_value = EXECUTION_FAILURE;
b80f6443 4330 exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
cce855bc 4331 /* NOTREACHED */
ac50fbac 4332 return (NULL);
cce855bc 4333 }
cce855bc
JA
4334 else
4335 return (result);
4336}
4337
4338/* Perform parameter expansion, command substitution, and arithmetic
ac50fbac
CR
4339 expansion on STRING, as if it were a word. Leave the result quoted.
4340 Since this does not perform word splitting, it leaves quoted nulls
4341 in the result. */
cce855bc
JA
4342static WORD_LIST *
4343expand_string_internal (string, quoted)
4344 char *string;
4345 int quoted;
4346{
4347 WORD_DESC td;
4348 WORD_LIST *tresult;
4349
4350 if (string == 0 || *string == 0)
4351 return ((WORD_LIST *)NULL);
4352
28ef6c31
JA
4353 td.flags = 0;
4354 td.word = savestring (string);
4355
b72432fd 4356 tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
28ef6c31
JA
4357
4358 FREE (td.word);
cce855bc 4359 return (tresult);
726f6388
JA
4360}
4361
4362/* Expand STRING by performing parameter expansion, command substitution,
4363 and arithmetic expansion. Dequote the resulting WORD_LIST before
4364 returning it, but do not perform word splitting. The call to
4365 remove_quoted_nulls () is in here because word splitting normally
4366 takes care of quote removal. */
4367WORD_LIST *
4368expand_string_unsplit (string, quoted)
4369 char *string;
4370 int quoted;
4371{
4372 WORD_LIST *value;
4373
28ef6c31 4374 if (string == 0 || *string == '\0')
726f6388
JA
4375 return ((WORD_LIST *)NULL);
4376
28ef6c31 4377 expand_no_split_dollar_star = 1;
726f6388 4378 value = expand_string_internal (string, quoted);
28ef6c31
JA
4379 expand_no_split_dollar_star = 0;
4380
726f6388
JA
4381 if (value)
4382 {
4383 if (value->word)
95732b49 4384 {
8868edaf 4385 remove_quoted_nulls (value->word->word); /* XXX */
95732b49
JA
4386 value->word->flags &= ~W_HASQUOTEDNULL;
4387 }
4388 dequote_list (value);
4389 }
4390 return (value);
4391}
4392
4393/* Expand the rhs of an assignment statement */
4394WORD_LIST *
4395expand_string_assignment (string, quoted)
4396 char *string;
4397 int quoted;
4398{
4399 WORD_DESC td;
4400 WORD_LIST *value;
4401
4402 if (string == 0 || *string == '\0')
4403 return ((WORD_LIST *)NULL);
4404
4405 expand_no_split_dollar_star = 1;
4406
d233b485
CR
4407#if 0
4408 /* Other shells (ksh93) do it this way, which affects how $@ is expanded
4409 in constructs like bar=${@#0} (preserves the spaces resulting from the
4410 expansion of $@ in a context where you don't do word splitting); Posix
4411 interp 888 makes the expansion of $@ in contexts where word splitting
4412 is not performed unspecified. */
4413 td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */
4414#else
95732b49 4415 td.flags = W_ASSIGNRHS;
d233b485 4416#endif
6b9422db 4417 td.flags |= (W_NOGLOB|W_TILDEEXP);
95732b49
JA
4418 td.word = savestring (string);
4419 value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4420 FREE (td.word);
4421
4422 expand_no_split_dollar_star = 0;
4423
4424 if (value)
4425 {
4426 if (value->word)
4427 {
8868edaf 4428 remove_quoted_nulls (value->word->word); /* XXX */
95732b49
JA
4429 value->word->flags &= ~W_HASQUOTEDNULL;
4430 }
726f6388
JA
4431 dequote_list (value);
4432 }
4433 return (value);
4434}
4435
bb70624e
JA
4436/* Expand one of the PS? prompt strings. This is a sort of combination of
4437 expand_string_unsplit and expand_string_internal, but returns the
4438 passed string when an error occurs. Might want to trap other calls
4439 to jump_to_top_level here so we don't endlessly loop. */
4440WORD_LIST *
f1be666c 4441expand_prompt_string (string, quoted, wflags)
bb70624e
JA
4442 char *string;
4443 int quoted;
f1be666c 4444 int wflags;
bb70624e
JA
4445{
4446 WORD_LIST *value;
4447 WORD_DESC td;
4448
4449 if (string == 0 || *string == 0)
4450 return ((WORD_LIST *)NULL);
4451
f1be666c 4452 td.flags = wflags;
bb70624e 4453 td.word = savestring (string);
28ef6c31
JA
4454
4455 no_longjmp_on_fatal_error = 1;
bb70624e 4456 value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
28ef6c31
JA
4457 no_longjmp_on_fatal_error = 0;
4458
bb70624e
JA
4459 if (value == &expand_word_error || value == &expand_word_fatal)
4460 {
4461 value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
4462 return value;
4463 }
4464 FREE (td.word);
4465 if (value)
4466 {
4467 if (value->word)
95732b49 4468 {
8868edaf 4469 remove_quoted_nulls (value->word->word); /* XXX */
95732b49
JA
4470 value->word->flags &= ~W_HASQUOTEDNULL;
4471 }
bb70624e
JA
4472 dequote_list (value);
4473 }
4474 return (value);
4475}
4476
726f6388
JA
4477/* Expand STRING just as if you were expanding a word, but do not dequote
4478 the resultant WORD_LIST. This is called only from within this file,
4479 and is used to correctly preserve quoted characters when expanding
4480 things like ${1+"$@"}. This does parameter expansion, command
b72432fd 4481 substitution, arithmetic expansion, and word splitting. */
726f6388
JA
4482static WORD_LIST *
4483expand_string_leave_quoted (string, quoted)
4484 char *string;
4485 int quoted;
4486{
4487 WORD_LIST *tlist;
4488 WORD_LIST *tresult;
4489
ccc6cda3 4490 if (string == 0 || *string == '\0')
726f6388
JA
4491 return ((WORD_LIST *)NULL);
4492
4493 tlist = expand_string_internal (string, quoted);
4494
4495 if (tlist)
4496 {
4497 tresult = word_list_split (tlist);
4498 dispose_words (tlist);
4499 return (tresult);
4500 }
4501 return ((WORD_LIST *)NULL);
4502}
4503
ccc6cda3
JA
4504/* This does not perform word splitting or dequote the WORD_LIST
4505 it returns. */
4506static WORD_LIST *
d233b485
CR
4507expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p)
4508 char *string;
4509 int quoted, op, pflags;
4510 int *dollar_at_p, *expanded_p;
4511{
4512 WORD_DESC td;
4513 WORD_LIST *tresult;
4514 int old_nosplit;
4515
4516 if (string == 0 || *string == '\0')
4517 return (WORD_LIST *)NULL;
4518
4519 /* We want field splitting to be determined by what is going to be done with
4520 the entire ${parameterOPword} expansion, so we don't want to split the RHS
4521 we expand here. However, the expansion of $* is determined by whether we
4522 are going to eventually perform word splitting, so we want to set this
4523 depending on whether or not are are going to be splitting: if the expansion
4524 is quoted, if the OP is `=', or if IFS is set to the empty string, we
4525 are not going to be splitting, so we set expand_no_split_dollar_star to
8868edaf 4526 note this to callees.
d233b485
CR
4527 We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an
4528 assignment statement. */
4529 /* The updated treatment of $* is the result of Posix interp 888 */
4530 /* This was further clarified on the austin-group list in March, 2017 and
4531 in Posix bug 1129 */
4532 old_nosplit = expand_no_split_dollar_star;
4533 expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */
8868edaf
CR
4534 td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */
4535 td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */
d233b485
CR
4536 if (pflags & PF_ASSIGNRHS) /* pass through */
4537 td.flags |= W_ASSIGNRHS;
4538 if (op == '=')
4539#if 0
4540 td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */
4541#else
4542 td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */
4543#endif
74091dd4 4544 td.word = savestring (string);
d233b485
CR
4545 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
4546 expand_no_split_dollar_star = old_nosplit;
74091dd4 4547 free (td.word);
d233b485
CR
4548
4549 return (tresult);
4550}
4551
4552/* This does not perform word splitting or dequote the WORD_LIST
4553 it returns and it treats $* as if it were quoted. */
4554static WORD_LIST *
4555expand_string_for_pat (string, quoted, dollar_at_p, expanded_p)
ccc6cda3 4556 char *string;
a0c0a00f 4557 int quoted, *dollar_at_p, *expanded_p;
ccc6cda3
JA
4558{
4559 WORD_DESC td;
4560 WORD_LIST *tresult;
d233b485 4561 int oexp;
ccc6cda3
JA
4562
4563 if (string == 0 || *string == '\0')
4564 return (WORD_LIST *)NULL;
4565
d233b485 4566 oexp = expand_no_split_dollar_star;
a0c0a00f 4567 expand_no_split_dollar_star = 1;
aeb26a67 4568 td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */
74091dd4 4569 td.word = savestring (string);
a0c0a00f 4570 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
d233b485 4571 expand_no_split_dollar_star = oexp;
74091dd4 4572 free (td.word);
a0c0a00f 4573
ccc6cda3
JA
4574 return (tresult);
4575}
4576
726f6388
JA
4577/* Expand STRING just as if you were expanding a word. This also returns
4578 a list of words. Note that filename globbing is *NOT* done for word
4579 or string expansion, just when the shell is expanding a command. This
4580 does parameter expansion, command substitution, arithmetic expansion,
4581 and word splitting. Dequote the resultant WORD_LIST before returning. */
4582WORD_LIST *
4583expand_string (string, quoted)
4584 char *string;
4585 int quoted;
4586{
4587 WORD_LIST *result;
4588
28ef6c31 4589 if (string == 0 || *string == '\0')
726f6388
JA
4590 return ((WORD_LIST *)NULL);
4591
4592 result = expand_string_leave_quoted (string, quoted);
ccc6cda3 4593 return (result ? dequote_list (result) : result);
726f6388
JA
4594}
4595
d233b485
CR
4596/*******************************************
4597 * *
4598 * Functions to expand WORD_DESCs *
4599 * *
4600 *******************************************/
4601
4602/* Expand WORD, performing word splitting on the result. This does
4603 parameter expansion, command substitution, arithmetic expansion,
4604 word splitting, and quote removal. */
4605
4606WORD_LIST *
4607expand_word (word, quoted)
4608 WORD_DESC *word;
4609 int quoted;
4610{
4611 WORD_LIST *result, *tresult;
4612
4613 tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4614 result = word_list_split (tresult);
4615 dispose_words (tresult);
4616 return (result ? dequote_list (result) : result);
4617}
4618
4619/* Expand WORD, but do not perform word splitting on the result. This
4620 does parameter expansion, command substitution, arithmetic expansion,
4621 and quote removal. */
4622WORD_LIST *
4623expand_word_unsplit (word, quoted)
4624 WORD_DESC *word;
4625 int quoted;
4626{
4627 WORD_LIST *result;
4628
4629 result = expand_word_leave_quoted (word, quoted);
4630 return (result ? dequote_list (result) : result);
4631}
4632
4633/* Perform shell expansions on WORD, but do not perform word splitting or
4634 quote removal on the result. Virtually identical to expand_word_unsplit;
4635 could be combined if implementations don't diverge. */
4636WORD_LIST *
4637expand_word_leave_quoted (word, quoted)
4638 WORD_DESC *word;
4639 int quoted;
4640{
4641 WORD_LIST *result;
4642
4643 expand_no_split_dollar_star = 1;
4644 if (ifs_is_null)
4645 word->flags |= W_NOSPLIT;
4646 word->flags |= W_NOSPLIT2;
4647 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4648 expand_no_split_dollar_star = 0;
4649
4650 return result;
4651}
4652
726f6388
JA
4653/***************************************************
4654 * *
4655 * Functions to handle quoting chars *
4656 * *
4657 ***************************************************/
4658
cce855bc
JA
4659/* Conventions:
4660
4661 A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
4662 The parser passes CTLNUL as CTLESC CTLNUL. */
4663
cce855bc
JA
4664/* Quote escape characters in string s, but no other characters. This is
4665 used to protect CTLESC and CTLNUL in variable values from the rest of
3185942a
JA
4666 the word expansion process after the variable is expanded (word splitting
4667 and filename generation). If IFS is null, we quote spaces as well, just
4668 in case we split on spaces later (in the case of unquoted $@, we will
4669 eventually attempt to split the entire word on spaces). Corresponding
4670 code exists in dequote_escapes. Even if we don't end up splitting on
4671 spaces, quoting spaces is not a problem. This should never be called on
4672 a string that is quoted with single or double quotes or part of a here
d233b485
CR
4673 document (effectively double-quoted).
4674 FLAGS says whether or not we are going to split the result. If we are not,
4675 and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL,
4676 respectively, to prevent them from being removed as part of dequoting. */
4677static char *
4678quote_escapes_internal (string, flags)
4679 const char *string;
4680 int flags;
cce855bc 4681{
d233b485
CR
4682 const char *s, *send;
4683 char *t, *result;
7117c2d2 4684 size_t slen;
d233b485 4685 int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit;
7117c2d2 4686 DECLARE_MBSTATE;
cce855bc 4687
7117c2d2
JA
4688 slen = strlen (string);
4689 send = string + slen;
4690
f1be666c 4691 quote_spaces = (ifs_value && *ifs_value == 0);
d233b485 4692 nosplit = (flags & PF_NOSPLIT2);
3185942a
JA
4693
4694 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
d233b485
CR
4695 {
4696 skip_ctlesc |= (nosplit == 0 && *s == CTLESC);
4697 skip_ctlnul |= (nosplit == 0 && *s == CTLNUL);
4698 }
3185942a 4699
7117c2d2
JA
4700 t = result = (char *)xmalloc ((slen * 2) + 1);
4701 s = string;
4702
4703 while (*s)
cce855bc 4704 {
3185942a 4705 if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
cce855bc 4706 *t++ = CTLESC;
7117c2d2 4707 COPY_CHAR_P (t, s, send);
cce855bc
JA
4708 }
4709 *t = '\0';
ac50fbac 4710
cce855bc
JA
4711 return (result);
4712}
4713
d233b485
CR
4714char *
4715quote_escapes (string)
4716 const char *string;
4717{
4718 return (quote_escapes_internal (string, 0));
4719}
4720
4721char *
4722quote_rhs (string)
4723 const char *string;
4724{
4725 return (quote_escapes_internal (string, PF_NOSPLIT2));
4726}
4727
cce855bc
JA
4728static WORD_LIST *
4729list_quote_escapes (list)
4730 WORD_LIST *list;
4731{
4732 register WORD_LIST *w;
4733 char *t;
4734
4735 for (w = list; w; w = w->next)
4736 {
4737 t = w->word->word;
4738 w->word->word = quote_escapes (t);
4739 free (t);
4740 }
4741 return list;
4742}
4743
7117c2d2
JA
4744/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
4745
4746 The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
4747 This is necessary to make unquoted CTLESC and CTLNUL characters in the
4748 data stream pass through properly.
4749
4750 We need to remove doubled CTLESC characters inside quoted strings before
4751 quoting the entire string, so we do not double the number of CTLESC
4752 characters.
4753
4754 Also used by parts of the pattern substitution code. */
3185942a 4755char *
cce855bc 4756dequote_escapes (string)
d233b485 4757 const char *string;
cce855bc 4758{
d233b485
CR
4759 const char *s, *send;
4760 char *t, *result;
7117c2d2 4761 size_t slen;
f1be666c 4762 int quote_spaces;
7117c2d2 4763 DECLARE_MBSTATE;
cce855bc 4764
7117c2d2 4765 if (string == 0)
d233b485 4766 return (char *)0;
7117c2d2
JA
4767
4768 slen = strlen (string);
4769 send = string + slen;
4770
4771 t = result = (char *)xmalloc (slen + 1);
7117c2d2
JA
4772
4773 if (strchr (string, CTLESC) == 0)
3185942a 4774 return (strcpy (result, string));
7117c2d2 4775
f1be666c 4776 quote_spaces = (ifs_value && *ifs_value == 0);
3185942a
JA
4777
4778 s = string;
7117c2d2 4779 while (*s)
cce855bc 4780 {
f1be666c 4781 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
cce855bc
JA
4782 {
4783 s++;
4784 if (*s == '\0')
4785 break;
4786 }
7117c2d2 4787 COPY_CHAR_P (t, s, send);
cce855bc
JA
4788 }
4789 *t = '\0';
ac50fbac 4790
cce855bc
JA
4791 return result;
4792}
726f6388 4793
d233b485 4794#if defined (INCLUDE_UNUSED)
ac50fbac
CR
4795static WORD_LIST *
4796list_dequote_escapes (list)
4797 WORD_LIST *list;
4798{
4799 register WORD_LIST *w;
4800 char *t;
4801
4802 for (w = list; w; w = w->next)
4803 {
4804 t = w->word->word;
4805 w->word->word = dequote_escapes (t);
4806 free (t);
4807 }
4808 return list;
4809}
d233b485 4810#endif
ac50fbac 4811
0628567a
JA
4812/* Return a new string with the quoted representation of character C.
4813 This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
4814 set in any resultant WORD_DESC where this value is the word. */
726f6388
JA
4815static char *
4816make_quoted_char (c)
4817 int c;
4818{
4819 char *temp;
4820
f73dda09 4821 temp = (char *)xmalloc (3);
726f6388
JA
4822 if (c == 0)
4823 {
4824 temp[0] = CTLNUL;
4825 temp[1] = '\0';
4826 }
4827 else
4828 {
4829 temp[0] = CTLESC;
4830 temp[1] = c;
4831 temp[2] = '\0';
4832 }
4833 return (temp);
4834}
4835
0628567a
JA
4836/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so
4837 the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
4838 this value is the word. */
ccc6cda3 4839char *
726f6388
JA
4840quote_string (string)
4841 char *string;
4842{
ccc6cda3 4843 register char *t;
7117c2d2
JA
4844 size_t slen;
4845 char *result, *send;
726f6388 4846
ccc6cda3 4847 if (*string == 0)
726f6388 4848 {
f73dda09 4849 result = (char *)xmalloc (2);
726f6388
JA
4850 result[0] = CTLNUL;
4851 result[1] = '\0';
4852 }
4853 else
4854 {
7117c2d2 4855 DECLARE_MBSTATE;
726f6388 4856
7117c2d2
JA
4857 slen = strlen (string);
4858 send = string + slen;
4859
4860 result = (char *)xmalloc ((slen * 2) + 1);
4861
4862 for (t = result; string < send; )
726f6388
JA
4863 {
4864 *t++ = CTLESC;
7117c2d2 4865 COPY_CHAR_P (t, string, send);
726f6388
JA
4866 }
4867 *t = '\0';
4868 }
4869 return (result);
4870}
4871
0628567a 4872/* De-quote quoted characters in STRING. */
726f6388
JA
4873char *
4874dequote_string (string)
4875 char *string;
4876{
7117c2d2
JA
4877 register char *s, *t;
4878 size_t slen;
4879 char *result, *send;
4880 DECLARE_MBSTATE;
726f6388 4881
a0c0a00f 4882 if (string[0] == CTLESC && string[1] == 0)
74091dd4 4883 internal_debug ("dequote_string: string with bare CTLESC");
a0c0a00f 4884
d233b485 4885 slen = STRLEN (string);
7117c2d2
JA
4886
4887 t = result = (char *)xmalloc (slen + 1);
726f6388
JA
4888
4889 if (QUOTED_NULL (string))
4890 {
4891 result[0] = '\0';
4892 return (result);
4893 }
4894
a0c0a00f
CR
4895 /* A string consisting of only a single CTLESC should pass through unchanged */
4896 if (string[0] == CTLESC && string[1] == 0)
4897 {
4898 result[0] = CTLESC;
4899 result[1] = '\0';
4900 return (result);
4901 }
4902
726f6388
JA
4903 /* If no character in the string can be quoted, don't bother examining
4904 each character. Just return a copy of the string passed to us. */
7117c2d2
JA
4905 if (strchr (string, CTLESC) == NULL)
4906 return (strcpy (result, string));
726f6388 4907
7117c2d2
JA
4908 send = string + slen;
4909 s = string;
4910 while (*s)
726f6388 4911 {
7117c2d2 4912 if (*s == CTLESC)
726f6388 4913 {
7117c2d2
JA
4914 s++;
4915 if (*s == '\0')
726f6388
JA
4916 break;
4917 }
7117c2d2 4918 COPY_CHAR_P (t, s, send);
726f6388
JA
4919 }
4920
4921 *t = '\0';
4922 return (result);
4923}
4924
4925/* Quote the entire WORD_LIST list. */
ccc6cda3 4926static WORD_LIST *
726f6388
JA
4927quote_list (list)
4928 WORD_LIST *list;
4929{
4930 register WORD_LIST *w;
ccc6cda3 4931 char *t;
726f6388
JA
4932
4933 for (w = list; w; w = w->next)
4934 {
ccc6cda3 4935 t = w->word->word;
726f6388 4936 w->word->word = quote_string (t);
3185942a
JA
4937 if (*t == 0)
4938 w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
ccc6cda3 4939 w->word->flags |= W_QUOTED;
3185942a 4940 free (t);
726f6388 4941 }
ccc6cda3 4942 return list;
726f6388
JA
4943}
4944
d233b485
CR
4945WORD_DESC *
4946dequote_word (word)
4947 WORD_DESC *word;
4948{
4949 register char *s;
4950
4951 s = dequote_string (word->word);
4952 if (QUOTED_NULL (word->word))
4953 word->flags &= ~W_HASQUOTEDNULL;
4954 free (word->word);
4955 word->word = s;
4956
4957 return word;
4958}
4959
0628567a
JA
4960/* De-quote quoted characters in each word in LIST. */
4961WORD_LIST *
7117c2d2
JA
4962dequote_list (list)
4963 WORD_LIST *list;
4964{
4965 register char *s;
4966 register WORD_LIST *tlist;
4967
4968 for (tlist = list; tlist; tlist = tlist->next)
4969 {
4970 s = dequote_string (tlist->word->word);
3185942a
JA
4971 if (QUOTED_NULL (tlist->word->word))
4972 tlist->word->flags &= ~W_HASQUOTEDNULL;
7117c2d2
JA
4973 free (tlist->word->word);
4974 tlist->word->word = s;
4975 }
4976 return list;
4977}
4978
4979/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
4980 string. */
3185942a 4981char *
7117c2d2
JA
4982remove_quoted_escapes (string)
4983 char *string;
4984{
4985 char *t;
4986
4987 if (string)
4988 {
4989 t = dequote_escapes (string);
4990 strcpy (string, t);
4991 free (t);
4992 }
4993
4994 return (string);
4995}
4996
d233b485
CR
4997/* Remove quoted $IFS characters from STRING. Quoted IFS characters are
4998 added to protect them from word splitting, but we need to remove them
4999 if no word splitting takes place. This returns newly-allocated memory,
5000 so callers can use it to replace savestring(). */
5001char *
5002remove_quoted_ifs (string)
5003 char *string;
5004{
5005 register size_t slen;
5006 register int i, j;
5007 char *ret, *send;
5008 DECLARE_MBSTATE;
5009
5010 slen = strlen (string);
5011 send = string + slen;
5012
5013 i = j = 0;
5014 ret = (char *)xmalloc (slen + 1);
5015
5016 while (i < slen)
5017 {
5018 if (string[i] == CTLESC)
5019 {
5020 i++;
5021 if (string[i] == 0 || isifs (string[i]) == 0)
5022 ret[j++] = CTLESC;
5023 if (i == slen)
5024 break;
5025 }
5026
5027 COPY_CHAR_I (ret, j, string, send, i);
5028 }
5029 ret[j] = '\0';
5030
5031 return (ret);
5032}
5033
3185942a 5034char *
cce855bc
JA
5035remove_quoted_nulls (string)
5036 char *string;
5037{
7117c2d2
JA
5038 register size_t slen;
5039 register int i, j, prev_i;
5040 DECLARE_MBSTATE;
5041
5042 if (strchr (string, CTLNUL) == 0) /* XXX */
5043 return string; /* XXX */
5044
5045 slen = strlen (string);
5046 i = j = 0;
5047
5048 while (i < slen)
5049 {
5050 if (string[i] == CTLESC)
b80f6443
JA
5051 {
5052 /* Old code had j++, but we cannot assume that i == j at this
5053 point -- what if a CTLNUL has already been removed from the
5054 string? We don't want to drop the CTLESC or recopy characters
5055 that we've already copied down. */
d233b485
CR
5056 i++;
5057 string[j++] = CTLESC;
b80f6443
JA
5058 if (i == slen)
5059 break;
5060 }
7117c2d2 5061 else if (string[i] == CTLNUL)
a48a8ac3
CR
5062 {
5063 i++;
5064 continue;
5065 }
7117c2d2
JA
5066
5067 prev_i = i;
d233b485 5068 ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */
7117c2d2 5069 if (j < prev_i)
cce855bc 5070 {
7117c2d2 5071 do string[j++] = string[prev_i++]; while (prev_i < i);
cce855bc 5072 }
7117c2d2
JA
5073 else
5074 j = i;
cce855bc 5075 }
7117c2d2
JA
5076 string[j] = '\0';
5077
5078 return (string);
cce855bc
JA
5079}
5080
5081/* Perform quoted null character removal on each element of LIST.
5082 This modifies LIST. */
5083void
5084word_list_remove_quoted_nulls (list)
5085 WORD_LIST *list;
5086{
5087 register WORD_LIST *t;
5088
5089 for (t = list; t; t = t->next)
95732b49
JA
5090 {
5091 remove_quoted_nulls (t->word->word);
5092 t->word->flags &= ~W_HASQUOTEDNULL;
5093 }
cce855bc
JA
5094}
5095
5096/* **************************************************************** */
5097/* */
5098/* Functions for Matching and Removing Patterns */
5099/* */
5100/* **************************************************************** */
5101
b80f6443 5102#if defined (HANDLE_MULTIBYTE)
d233b485 5103# ifdef INCLUDE_UNUSED
b80f6443
JA
5104static unsigned char *
5105mb_getcharlens (string, len)
5106 char *string;
5107 int len;
5108{
5109 int i, offset, last;
5110 unsigned char *ret;
5111 char *p;
5112 DECLARE_MBSTATE;
5113
5114 i = offset = 0;
5115 last = 0;
5116 ret = (unsigned char *)xmalloc (len);
5117 memset (ret, 0, len);
5118 while (string[last])
5119 {
5120 ADVANCE_CHAR (string, len, offset);
5121 ret[last] = offset - last;
5122 last = offset;
5123 }
5124 return ret;
5125}
d233b485 5126# endif
b80f6443
JA
5127#endif
5128
cce855bc
JA
5129/* Remove the portion of PARAM matched by PATTERN according to OP, where OP
5130 can have one of 4 values:
5131 RP_LONG_LEFT remove longest matching portion at start of PARAM
726f6388
JA
5132 RP_SHORT_LEFT remove shortest matching portion at start of PARAM
5133 RP_LONG_RIGHT remove longest matching portion at end of PARAM
5134 RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
5135*/
5136
5137#define RP_LONG_LEFT 1
5138#define RP_SHORT_LEFT 2
5139#define RP_LONG_RIGHT 3
5140#define RP_SHORT_RIGHT 4
5141
495aee44 5142/* Returns its first argument if nothing matched; new memory otherwise */
726f6388 5143static char *
b80f6443 5144remove_upattern (param, pattern, op)
726f6388
JA
5145 char *param, *pattern;
5146 int op;
5147{
a0c0a00f 5148 register size_t len;
ccc6cda3 5149 register char *end;
726f6388
JA
5150 register char *p, *ret, c;
5151
ccc6cda3
JA
5152 len = STRLEN (param);
5153 end = param + len;
726f6388
JA
5154
5155 switch (op)
5156 {
5157 case RP_LONG_LEFT: /* remove longest match at start */
5158 for (p = end; p >= param; p--)
5159 {
5160 c = *p; *p = '\0';
f73dda09 5161 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
726f6388
JA
5162 {
5163 *p = c;
5164 return (savestring (p));
5165 }
5166 *p = c;
b80f6443 5167
726f6388
JA
5168 }
5169 break;
5170
5171 case RP_SHORT_LEFT: /* remove shortest match at start */
5172 for (p = param; p <= end; p++)
5173 {
5174 c = *p; *p = '\0';
f73dda09 5175 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
726f6388
JA
5176 {
5177 *p = c;
5178 return (savestring (p));
5179 }
5180 *p = c;
5181 }
5182 break;
5183
ccc6cda3
JA
5184 case RP_LONG_RIGHT: /* remove longest match at end */
5185 for (p = param; p <= end; p++)
5186 {
f73dda09 5187 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
ccc6cda3
JA
5188 {
5189 c = *p; *p = '\0';
5190 ret = savestring (param);
5191 *p = c;
5192 return (ret);
5193 }
5194 }
5195 break;
5196
5197 case RP_SHORT_RIGHT: /* remove shortest match at end */
5198 for (p = end; p >= param; p--)
5199 {
f73dda09 5200 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
ccc6cda3
JA
5201 {
5202 c = *p; *p = '\0';
5203 ret = savestring (param);
5204 *p = c;
5205 return (ret);
5206 }
5207 }
5208 break;
5209 }
b80f6443 5210
495aee44 5211 return (param); /* no match, return original string */
ccc6cda3
JA
5212}
5213
b80f6443 5214#if defined (HANDLE_MULTIBYTE)
495aee44 5215/* Returns its first argument if nothing matched; new memory otherwise */
b80f6443
JA
5216static wchar_t *
5217remove_wpattern (wparam, wstrlen, wpattern, op)
5218 wchar_t *wparam;
5219 size_t wstrlen;
5220 wchar_t *wpattern;
5221 int op;
5222{
0628567a
JA
5223 wchar_t wc, *ret;
5224 int n;
b80f6443
JA
5225
5226 switch (op)
5227 {
5228 case RP_LONG_LEFT: /* remove longest match at start */
5229 for (n = wstrlen; n >= 0; n--)
5230 {
5231 wc = wparam[n]; wparam[n] = L'\0';
5232 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5233 {
5234 wparam[n] = wc;
5235 return (wcsdup (wparam + n));
5236 }
5237 wparam[n] = wc;
5238 }
5239 break;
5240
5241 case RP_SHORT_LEFT: /* remove shortest match at start */
5242 for (n = 0; n <= wstrlen; n++)
5243 {
5244 wc = wparam[n]; wparam[n] = L'\0';
5245 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5246 {
5247 wparam[n] = wc;
5248 return (wcsdup (wparam + n));
5249 }
5250 wparam[n] = wc;
5251 }
5252 break;
5253
5254 case RP_LONG_RIGHT: /* remove longest match at end */
5255 for (n = 0; n <= wstrlen; n++)
5256 {
5257 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5258 {
5259 wc = wparam[n]; wparam[n] = L'\0';
5260 ret = wcsdup (wparam);
5261 wparam[n] = wc;
5262 return (ret);
5263 }
5264 }
5265 break;
5266
5267 case RP_SHORT_RIGHT: /* remove shortest match at end */
5268 for (n = wstrlen; n >= 0; n--)
5269 {
5270 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5271 {
5272 wc = wparam[n]; wparam[n] = L'\0';
5273 ret = wcsdup (wparam);
5274 wparam[n] = wc;
5275 return (ret);
5276 }
5277 }
5278 break;
5279 }
5280
495aee44 5281 return (wparam); /* no match, return original string */
b80f6443
JA
5282}
5283#endif /* HANDLE_MULTIBYTE */
5284
5285static char *
5286remove_pattern (param, pattern, op)
5287 char *param, *pattern;
5288 int op;
5289{
495aee44
CR
5290 char *xret;
5291
b80f6443
JA
5292 if (param == NULL)
5293 return (param);
5294 if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
5295 return (savestring (param));
5296
5297#if defined (HANDLE_MULTIBYTE)
5298 if (MB_CUR_MAX > 1)
5299 {
5300 wchar_t *ret, *oret;
5301 size_t n;
5302 wchar_t *wparam, *wpattern;
5303 mbstate_t ps;
b80f6443 5304
d233b485
CR
5305 /* XXX - could optimize here by checking param and pattern for multibyte
5306 chars with mbsmbchar and calling remove_upattern. */
5307
b80f6443
JA
5308 n = xdupmbstowcs (&wpattern, NULL, pattern);
5309 if (n == (size_t)-1)
495aee44
CR
5310 {
5311 xret = remove_upattern (param, pattern, op);
5312 return ((xret == param) ? savestring (param) : xret);
5313 }
b80f6443 5314 n = xdupmbstowcs (&wparam, NULL, param);
ac50fbac 5315
b80f6443
JA
5316 if (n == (size_t)-1)
5317 {
5318 free (wpattern);
495aee44
CR
5319 xret = remove_upattern (param, pattern, op);
5320 return ((xret == param) ? savestring (param) : xret);
b80f6443
JA
5321 }
5322 oret = ret = remove_wpattern (wparam, n, wpattern, op);
495aee44
CR
5323 /* Don't bother to convert wparam back to multibyte string if nothing
5324 matched; just return copy of original string */
5325 if (ret == wparam)
5326 {
5327 free (wparam);
5328 free (wpattern);
5329 return (savestring (param));
5330 }
b80f6443
JA
5331
5332 free (wparam);
5333 free (wpattern);
5334
5335 n = strlen (param);
0628567a 5336 xret = (char *)xmalloc (n + 1);
b80f6443
JA
5337 memset (&ps, '\0', sizeof (mbstate_t));
5338 n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
5339 xret[n] = '\0'; /* just to make sure */
5340 free (oret);
5341 return xret;
5342 }
5343 else
5344#endif
ccc6cda3 5345 {
495aee44
CR
5346 xret = remove_upattern (param, pattern, op);
5347 return ((xret == param) ? savestring (param) : xret);
ccc6cda3
JA
5348 }
5349}
5350
5351/* Match PAT anywhere in STRING and return the match boundaries.
5352 This returns 1 in case of a successful match, 0 otherwise. SP
5353 and EP are pointers into the string where the match begins and
5354 ends, respectively. MTYPE controls what kind of match is attempted.
5355 MATCH_BEG and MATCH_END anchor the match at the beginning and end
5356 of the string, respectively. The longest match is returned. */
5357static int
b80f6443 5358match_upattern (string, pat, mtype, sp, ep)
ccc6cda3
JA
5359 char *string, *pat;
5360 int mtype;
5361 char **sp, **ep;
5362{
a0c0a00f
CR
5363 int c, mlen;
5364 size_t len;
95732b49 5365 register char *p, *p1, *npat;
ccc6cda3
JA
5366 char *end;
5367
95732b49
JA
5368 /* If the pattern doesn't match anywhere in the string, go ahead and
5369 short-circuit right away. A minor optimization, saves a bunch of
5370 unnecessary calls to strmatch (up to N calls for a string of N
5371 characters) if the match is unsuccessful. To preserve the semantics
5372 of the substring matches below, we make sure that the pattern has
5373 `*' as first and last character, making a new pattern if necessary. */
5374 /* XXX - check this later if I ever implement `**' with special meaning,
5375 since this will potentially result in `**' at the beginning or end */
5376 len = STRLEN (pat);
0001803f 5377 if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
95732b49 5378 {
a0c0a00f
CR
5379 int unescaped_backslash;
5380 char *pp;
5381
0628567a 5382 p = npat = (char *)xmalloc (len + 3);
95732b49 5383 p1 = pat;
d233b485 5384 if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob)))
95732b49
JA
5385 *p++ = '*';
5386 while (*p1)
5387 *p++ = *p1++;
a0c0a00f
CR
5388#if 1
5389 /* Need to also handle a pattern that ends with an unescaped backslash.
5390 For right now, we ignore it because the pattern matching code will
5391 fail the match anyway */
5392 /* If the pattern ends with a `*' we leave it alone if it's preceded by
5393 an even number of backslashes, but if it's escaped by a backslash
5394 we need to add another `*'. */
d233b485 5395 if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\')))
a0c0a00f
CR
5396 {
5397 pp = p1 - 3;
5398 while (pp >= pat && *pp-- == '\\')
5399 unescaped_backslash = 1 - unescaped_backslash;
5400 if (unescaped_backslash)
5401 *p++ = '*';
5402 }
d233b485 5403 else if (mtype != MATCH_END && p1[-1] != '*')
95732b49 5404 *p++ = '*';
a0c0a00f
CR
5405#else
5406 if (p1[-1] != '*' || p1[-2] == '\\')
5407 *p++ = '*';
5408#endif
95732b49
JA
5409 *p = '\0';
5410 }
5411 else
5412 npat = pat;
a0c0a00f 5413 c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
95732b49
JA
5414 if (npat != pat)
5415 free (npat);
5416 if (c == FNM_NOMATCH)
5417 return (0);
5418
b80f6443
JA
5419 len = STRLEN (string);
5420 end = string + len;
ccc6cda3 5421
495aee44 5422 mlen = umatchlen (pat, len);
8868edaf
CR
5423 if (mlen > (int)len)
5424 return (0);
495aee44 5425
ccc6cda3
JA
5426 switch (mtype)
5427 {
5428 case MATCH_ANY:
5429 for (p = string; p <= end; p++)
5430 {
a0c0a00f 5431 if (match_pattern_char (pat, p, FNMATCH_IGNCASE))
ccc6cda3 5432 {
495aee44
CR
5433 p1 = (mlen == -1) ? end : p + mlen;
5434 /* p1 - p = length of portion of string to be considered
5435 p = current position in string
5436 mlen = number of characters consumed by match (-1 for entire string)
5437 end = end of string
5438 we want to break immediately if the potential match len
5439 is greater than the number of characters remaining in the
5440 string
5441 */
5442 if (p1 > end)
5443 break;
5444 for ( ; p1 >= p; p1--)
ccc6cda3
JA
5445 {
5446 c = *p1; *p1 = '\0';
a0c0a00f 5447 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
ccc6cda3
JA
5448 {
5449 *p1 = c;
5450 *sp = p;
5451 *ep = p1;
5452 return 1;
5453 }
5454 *p1 = c;
495aee44
CR
5455#if 1
5456 /* If MLEN != -1, we have a fixed length pattern. */
5457 if (mlen != -1)
5458 break;
5459#endif
ccc6cda3
JA
5460 }
5461 }
5462 }
b80f6443 5463
ccc6cda3
JA
5464 return (0);
5465
5466 case MATCH_BEG:
a0c0a00f 5467 if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0)
28ef6c31 5468 return (0);
b80f6443 5469
495aee44 5470 for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
ccc6cda3
JA
5471 {
5472 c = *p; *p = '\0';
a0c0a00f 5473 if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
ccc6cda3
JA
5474 {
5475 *p = c;
5476 *sp = string;
5477 *ep = p;
5478 return 1;
5479 }
5480 *p = c;
495aee44
CR
5481 /* If MLEN != -1, we have a fixed length pattern. */
5482 if (mlen != -1)
5483 break;
ccc6cda3 5484 }
b80f6443 5485
ccc6cda3 5486 return (0);
726f6388 5487
ccc6cda3 5488 case MATCH_END:
495aee44 5489 for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
b80f6443 5490 {
a0c0a00f 5491 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
b80f6443
JA
5492 {
5493 *sp = p;
5494 *ep = end;
5495 return 1;
5496 }
495aee44
CR
5497 /* If MLEN != -1, we have a fixed length pattern. */
5498 if (mlen != -1)
5499 break;
b80f6443
JA
5500 }
5501
5502 return (0);
5503 }
5504
5505 return (0);
5506}
5507
5508#if defined (HANDLE_MULTIBYTE)
a0c0a00f
CR
5509
5510#define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c))
5511
b80f6443
JA
5512/* Match WPAT anywhere in WSTRING and return the match boundaries.
5513 This returns 1 in case of a successful match, 0 otherwise. Wide
5514 character version. */
5515static int
5516match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
5517 wchar_t *wstring;
5518 char **indices;
5519 size_t wstrlen;
5520 wchar_t *wpat;
5521 int mtype;
5522 char **sp, **ep;
5523{
95732b49 5524 wchar_t wc, *wp, *nwpat, *wp1;
495aee44
CR
5525 size_t len;
5526 int mlen;
5527 int n, n1, n2, simple;
5528
5529 simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
5530#if defined (EXTENDED_GLOB)
5531 if (extended_glob)
91717ba3 5532 simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
b80f6443
JA
5533#endif
5534
95732b49
JA
5535 /* If the pattern doesn't match anywhere in the string, go ahead and
5536 short-circuit right away. A minor optimization, saves a bunch of
5537 unnecessary calls to strmatch (up to N calls for a string of N
5538 characters) if the match is unsuccessful. To preserve the semantics
5539 of the substring matches below, we make sure that the pattern has
5540 `*' as first and last character, making a new pattern if necessary. */
95732b49 5541 len = wcslen (wpat);
0001803f 5542 if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
95732b49 5543 {
a0c0a00f
CR
5544 int unescaped_backslash;
5545 wchar_t *wpp;
5546
0628567a 5547 wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
95732b49 5548 wp1 = wpat;
0001803f 5549 if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
95732b49
JA
5550 *wp++ = L'*';
5551 while (*wp1 != L'\0')
5552 *wp++ = *wp1++;
a0c0a00f
CR
5553#if 1
5554 /* See comments above in match_upattern. */
5555 if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\'))
5556 {
5557 wpp = wp1 - 3;
5558 while (wpp >= wpat && *wpp-- == L'\\')
5559 unescaped_backslash = 1 - unescaped_backslash;
5560 if (unescaped_backslash)
5561 *wp++ = L'*';
5562 }
5563 else if (wp1[-1] != L'*')
5564 *wp++ = L'*';
5565#else
95732b49
JA
5566 if (wp1[-1] != L'*' || wp1[-2] == L'\\')
5567 *wp++ = L'*';
a0c0a00f 5568#endif
95732b49
JA
5569 *wp = '\0';
5570 }
5571 else
5572 nwpat = wpat;
a0c0a00f 5573 len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
95732b49
JA
5574 if (nwpat != wpat)
5575 free (nwpat);
5576 if (len == FNM_NOMATCH)
5577 return (0);
5578
495aee44 5579 mlen = wmatchlen (wpat, wstrlen);
8868edaf
CR
5580 if (mlen > (int)wstrlen)
5581 return (0);
495aee44
CR
5582
5583/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
b80f6443
JA
5584 switch (mtype)
5585 {
5586 case MATCH_ANY:
5587 for (n = 0; n <= wstrlen; n++)
5588 {
a0c0a00f 5589 n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE);
495aee44 5590 if (n2)
b80f6443 5591 {
495aee44
CR
5592 n1 = (mlen == -1) ? wstrlen : n + mlen;
5593 if (n1 > wstrlen)
5594 break;
5595
5596 for ( ; n1 >= n; n1--)
b80f6443
JA
5597 {
5598 wc = wstring[n1]; wstring[n1] = L'\0';
a0c0a00f 5599 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
b80f6443
JA
5600 {
5601 wstring[n1] = wc;
5602 *sp = indices[n];
5603 *ep = indices[n1];
5604 return 1;
5605 }
5606 wstring[n1] = wc;
495aee44
CR
5607 /* If MLEN != -1, we have a fixed length pattern. */
5608 if (mlen != -1)
5609 break;
b80f6443
JA
5610 }
5611 }
5612 }
5613
5614 return (0);
5615
5616 case MATCH_BEG:
a0c0a00f 5617 if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0)
b80f6443
JA
5618 return (0);
5619
495aee44 5620 for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
b80f6443
JA
5621 {
5622 wc = wstring[n]; wstring[n] = L'\0';
a0c0a00f 5623 if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
b80f6443
JA
5624 {
5625 wstring[n] = wc;
5626 *sp = indices[0];
5627 *ep = indices[n];
5628 return 1;
5629 }
5630 wstring[n] = wc;
495aee44
CR
5631 /* If MLEN != -1, we have a fixed length pattern. */
5632 if (mlen != -1)
5633 break;
b80f6443
JA
5634 }
5635
5636 return (0);
5637
5638 case MATCH_END:
495aee44 5639 for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
b80f6443 5640 {
a0c0a00f 5641 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
b80f6443
JA
5642 {
5643 *sp = indices[n];
5644 *ep = indices[wstrlen];
5645 return 1;
5646 }
495aee44
CR
5647 /* If MLEN != -1, we have a fixed length pattern. */
5648 if (mlen != -1)
5649 break;
b80f6443
JA
5650 }
5651
ccc6cda3 5652 return (0);
726f6388 5653 }
ccc6cda3
JA
5654
5655 return (0);
726f6388 5656}
a0c0a00f 5657#undef WFOLD
b80f6443
JA
5658#endif /* HANDLE_MULTIBYTE */
5659
5660static int
5661match_pattern (string, pat, mtype, sp, ep)
5662 char *string, *pat;
5663 int mtype;
5664 char **sp, **ep;
5665{
5666#if defined (HANDLE_MULTIBYTE)
5667 int ret;
5668 size_t n;
5669 wchar_t *wstring, *wpat;
5670 char **indices;
5671#endif
5672
a0c0a00f 5673 if (string == 0 || pat == 0 || *pat == 0)
b80f6443
JA
5674 return (0);
5675
5676#if defined (HANDLE_MULTIBYTE)
5677 if (MB_CUR_MAX > 1)
5678 {
495aee44 5679 if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
495aee44
CR
5680 return (match_upattern (string, pat, mtype, sp, ep));
5681
b80f6443
JA
5682 n = xdupmbstowcs (&wpat, NULL, pat);
5683 if (n == (size_t)-1)
5684 return (match_upattern (string, pat, mtype, sp, ep));
5685 n = xdupmbstowcs (&wstring, &indices, string);
5686 if (n == (size_t)-1)
5687 {
5688 free (wpat);
5689 return (match_upattern (string, pat, mtype, sp, ep));
5690 }
5691 ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
5692
5693 free (wpat);
5694 free (wstring);
5695 free (indices);
5696
5697 return (ret);
5698 }
5699 else
5700#endif
5701 return (match_upattern (string, pat, mtype, sp, ep));
5702}
726f6388 5703
cce855bc
JA
5704static int
5705getpatspec (c, value)
5706 int c;
5707 char *value;
5708{
5709 if (c == '#')
5710 return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
5711 else /* c == '%' */
5712 return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
5713}
5714
5715/* Posix.2 says that the WORD should be run through tilde expansion,
5716 parameter expansion, command substitution and arithmetic expansion.
5717 This leaves the result quoted, so quote_string_for_globbing () has
f73dda09 5718 to be called to fix it up for strmatch (). If QUOTED is non-zero,
cce855bc
JA
5719 it means that the entire expression was enclosed in double quotes.
5720 This means that quoting characters in the pattern do not make any
5721 special pattern characters quoted. For example, the `*' in the
5722 following retains its special meaning: "${foo#'*'}". */
5723static char *
5724getpattern (value, quoted, expandpat)
5725 char *value;
5726 int quoted, expandpat;
5727{
5728 char *pat, *tword;
5729 WORD_LIST *l;
0628567a 5730#if 0
cce855bc 5731 int i;
0628567a 5732#endif
7117c2d2
JA
5733 /* There is a problem here: how to handle single or double quotes in the
5734 pattern string when the whole expression is between double quotes?
5735 POSIX.2 says that enclosing double quotes do not cause the pattern to
5736 be quoted, but does that leave us a problem with @ and array[@] and their
5737 expansions inside a pattern? */
5738#if 0
cce855bc
JA
5739 if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
5740 {
5741 i = 0;
a0c0a00f 5742 pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ);
cce855bc
JA
5743 free (tword);
5744 tword = pat;
5745 }
7117c2d2 5746#endif
cce855bc 5747
d233b485 5748 /* expand_string_for_pat () leaves WORD quoted and does not perform
7117c2d2 5749 word splitting. */
d233b485 5750 l = *value ? expand_string_for_pat (value,
7117c2d2 5751 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
cce855bc 5752 (int *)NULL, (int *)NULL)
cce855bc 5753 : (WORD_LIST *)0;
36f2c406
CR
5754 if (l)
5755 word_list_remove_quoted_nulls (l);
cce855bc
JA
5756 pat = string_list (l);
5757 dispose_words (l);
5758 if (pat)
5759 {
5760 tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
5761 free (pat);
5762 pat = tword;
5763 }
5764 return (pat);
5765}
5766
7117c2d2 5767#if 0
cce855bc
JA
5768/* Handle removing a pattern from a string as a result of ${name%[%]value}
5769 or ${name#[#]value}. */
5770static char *
7117c2d2
JA
5771variable_remove_pattern (value, pattern, patspec, quoted)
5772 char *value, *pattern;
5773 int patspec, quoted;
cce855bc 5774{
7117c2d2 5775 char *tword;
cce855bc 5776
7117c2d2 5777 tword = remove_pattern (value, pattern, patspec);
cce855bc 5778
cce855bc
JA
5779 return (tword);
5780}
a0c0a00f
CR
5781#endif
5782
5783static char *
5784list_remove_pattern (list, pattern, patspec, itype, quoted)
5785 WORD_LIST *list;
5786 char *pattern;
5787 int patspec, itype, quoted;
5788{
5789 WORD_LIST *new, *l;
5790 WORD_DESC *w;
5791 char *tword;
5792
5793 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
5794 {
5795 tword = remove_pattern (l->word->word, pattern, patspec);
5796 w = alloc_word_desc ();
5797 w->word = tword ? tword : savestring ("");
5798 new = make_word_list (w, new);
5799 }
5800
5801 l = REVERSE_LIST (new, WORD_LIST *);
8868edaf 5802 tword = string_list_pos_params (itype, l, quoted, 0);
a0c0a00f
CR
5803 dispose_words (l);
5804
5805 return (tword);
5806}
5807
5808static char *
5809parameter_list_remove_pattern (itype, pattern, patspec, quoted)
5810 int itype;
5811 char *pattern;
5812 int patspec, quoted;
5813{
5814 char *ret;
5815 WORD_LIST *list;
5816
5817 list = list_rest_of_args ();
5818 if (list == 0)
5819 return ((char *)NULL);
5820 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5821 dispose_words (list);
5822 return (ret);
5823}
5824
5825#if defined (ARRAY_VARS)
5826static char *
8868edaf 5827array_remove_pattern (var, pattern, patspec, starsub, quoted)
a0c0a00f
CR
5828 SHELL_VAR *var;
5829 char *pattern;
5830 int patspec;
8868edaf 5831 int starsub; /* so we can figure out how it's indexed */
a0c0a00f
CR
5832 int quoted;
5833{
5834 ARRAY *a;
5835 HASH_TABLE *h;
5836 int itype;
5837 char *ret;
5838 WORD_LIST *list;
5839 SHELL_VAR *v;
5840
8868edaf 5841 v = var; /* XXX - for now */
a0c0a00f 5842
8868edaf 5843 itype = starsub ? '*' : '@';
a0c0a00f
CR
5844
5845 a = (v && array_p (v)) ? array_cell (v) : 0;
5846 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
5847
5848 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
5849 if (list == 0)
5850 return ((char *)NULL);
5851 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5852 dispose_words (list);
5853
5854 return ret;
5855}
5856#endif /* ARRAY_VARS */
5857
5858static char *
74091dd4 5859parameter_brace_remove_pattern (varname, value, estatep, patstr, rtype, quoted, flags)
a0c0a00f 5860 char *varname, *value;
74091dd4 5861 array_eltstate_t *estatep;
a0c0a00f
CR
5862 char *patstr;
5863 int rtype, quoted, flags;
5864{
5865 int vtype, patspec, starsub;
d233b485 5866 char *temp1, *val, *pattern, *oname;
a0c0a00f
CR
5867 SHELL_VAR *v;
5868
5869 if (value == 0)
5870 return ((char *)NULL);
5871
d233b485 5872 oname = this_command_name;
a0c0a00f
CR
5873 this_command_name = varname;
5874
74091dd4 5875 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
a0c0a00f 5876 if (vtype == -1)
d233b485
CR
5877 {
5878 this_command_name = oname;
5879 return ((char *)NULL);
5880 }
a0c0a00f
CR
5881
5882 starsub = vtype & VT_STARSUB;
5883 vtype &= ~VT_STARSUB;
5884
5885 patspec = getpatspec (rtype, patstr);
5886 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
5887 patstr++;
5888
5889 /* Need to pass getpattern newly-allocated memory in case of expansion --
5890 the expansion code will free the passed string on an error. */
5891 temp1 = savestring (patstr);
5892 pattern = getpattern (temp1, quoted, 1);
5893 free (temp1);
5894
5895 temp1 = (char *)NULL; /* shut up gcc */
5896 switch (vtype)
5897 {
5898 case VT_VARIABLE:
5899 case VT_ARRAYMEMBER:
5900 temp1 = remove_pattern (val, pattern, patspec);
5901 if (vtype == VT_VARIABLE)
5902 FREE (val);
5903 if (temp1)
5904 {
5905 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5906 ? quote_string (temp1)
5907 : quote_escapes (temp1);
5908 free (temp1);
5909 temp1 = val;
5910 }
5911 break;
5912#if defined (ARRAY_VARS)
5913 case VT_ARRAYVAR:
8868edaf 5914 temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted);
a0c0a00f
CR
5915 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5916 {
5917 val = quote_escapes (temp1);
5918 free (temp1);
5919 temp1 = val;
5920 }
5921 break;
5922#endif
5923 case VT_POSPARMS:
5924 temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
d233b485
CR
5925 if (temp1 && quoted == 0 && ifs_is_null)
5926 {
5927 /* Posix interp 888 */
5928 }
5929 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
a0c0a00f
CR
5930 {
5931 val = quote_escapes (temp1);
5932 free (temp1);
5933 temp1 = val;
5934 }
5935 break;
5936 }
5937
d233b485
CR
5938 this_command_name = oname;
5939
a0c0a00f
CR
5940 FREE (pattern);
5941 return temp1;
5942}
5943
d233b485 5944#if defined (PROCESS_SUBSTITUTION)
a0c0a00f 5945
8868edaf
CR
5946static void reap_some_procsubs PARAMS((int));
5947
d233b485
CR
5948/*****************************************************************/
5949/* */
5950/* Hacking Process Substitution */
5951/* */
5952/*****************************************************************/
5953
5954#if !defined (HAVE_DEV_FD)
5955/* Named pipes must be removed explicitly with `unlink'. This keeps a list
5956 of FIFOs the shell has open. unlink_fifo_list will walk the list and
8868edaf
CR
5957 unlink the ones that don't have a living process on the other end.
5958 unlink_all_fifos will walk the list and unconditionally unlink them, trying
5959 to open and close the FIFO first to release any child processes sleeping on
5960 the FIFO. add_fifo_list adds the name of an open FIFO to the list.
5961 NFIFO is a count of the number of FIFOs in the list. */
d233b485
CR
5962#define FIFO_INCR 20
5963
5964/* PROC value of -1 means the process has been reaped and the FIFO needs to
5965 be removed. PROC value of 0 means the slot is unused. */
5966struct temp_fifo {
5967 char *file;
5968 pid_t proc;
5969};
5970
5971static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
5972static int nfifo;
5973static int fifo_list_size;
5974
5975void
5976clear_fifo_list ()
a0c0a00f 5977{
8868edaf
CR
5978 int i;
5979
5980 for (i = 0; i < fifo_list_size; i++)
5981 {
5982 if (fifo_list[i].file)
5983 free (fifo_list[i].file);
5984 fifo_list[i].file = NULL;
5985 fifo_list[i].proc = 0;
5986 }
5987 nfifo = 0;
d233b485 5988}
a0c0a00f 5989
9e49d343 5990void *
d233b485
CR
5991copy_fifo_list (sizep)
5992 int *sizep;
5993{
5994 if (sizep)
5995 *sizep = 0;
9e49d343 5996 return (void *)NULL;
d233b485
CR
5997}
5998
5999static void
6000add_fifo_list (pathname)
6001 char *pathname;
6002{
6003 int osize, i;
6004
6005 if (nfifo >= fifo_list_size - 1)
a0c0a00f 6006 {
d233b485
CR
6007 osize = fifo_list_size;
6008 fifo_list_size += FIFO_INCR;
6009 fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
6010 fifo_list_size * sizeof (struct temp_fifo));
6011 for (i = osize; i < fifo_list_size; i++)
6012 {
6013 fifo_list[i].file = (char *)NULL;
6014 fifo_list[i].proc = 0; /* unused */
6015 }
a0c0a00f 6016 }
d233b485
CR
6017
6018 fifo_list[nfifo].file = savestring (pathname);
6019 nfifo++;
a0c0a00f 6020}
a0c0a00f 6021
d233b485
CR
6022void
6023unlink_fifo (i)
6024 int i;
a0c0a00f 6025{
d233b485
CR
6026 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
6027 {
6028 unlink (fifo_list[i].file);
6029 free (fifo_list[i].file);
6030 fifo_list[i].file = (char *)NULL;
6031 fifo_list[i].proc = 0;
6032 }
a0c0a00f
CR
6033}
6034
d233b485
CR
6035void
6036unlink_fifo_list ()
a0c0a00f 6037{
d233b485 6038 int saved, i, j;
a0c0a00f 6039
d233b485
CR
6040 if (nfifo == 0)
6041 return;
a0c0a00f 6042
d233b485 6043 for (i = saved = 0; i < nfifo; i++)
a0c0a00f 6044 {
d233b485
CR
6045 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
6046 {
6047 unlink (fifo_list[i].file);
6048 free (fifo_list[i].file);
6049 fifo_list[i].file = (char *)NULL;
6050 fifo_list[i].proc = 0;
6051 }
6052 else
6053 saved++;
a0c0a00f 6054 }
d233b485
CR
6055
6056 /* If we didn't remove some of the FIFOs, compact the list. */
6057 if (saved)
6058 {
6059 for (i = j = 0; i < nfifo; i++)
6060 if (fifo_list[i].file)
6061 {
9e49d343
CR
6062 if (i != j)
6063 {
6064 fifo_list[j].file = fifo_list[i].file;
6065 fifo_list[j].proc = fifo_list[i].proc;
6066 fifo_list[i].file = (char *)NULL;
6067 fifo_list[i].proc = 0;
6068 }
d233b485
CR
6069 j++;
6070 }
6071 nfifo = j;
6072 }
6073 else
6074 nfifo = 0;
a0c0a00f 6075}
cce855bc 6076
8868edaf
CR
6077void
6078unlink_all_fifos ()
6079{
6080 int i, fd;
6081
6082 if (nfifo == 0)
6083 return;
6084
6085 for (i = 0; i < nfifo; i++)
6086 {
6087 fifo_list[i].proc = (pid_t)-1;
74091dd4 6088#if defined (O_NONBLOCK)
8868edaf 6089 fd = open (fifo_list[i].file, O_RDWR|O_NONBLOCK);
74091dd4
CR
6090#else
6091 fd = -1;
6092#endif
8868edaf
CR
6093 unlink_fifo (i);
6094 if (fd >= 0)
6095 close (fd);
6096 }
6097
6098 nfifo = 0;
6099}
6100
d233b485
CR
6101/* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
6102 from some point in the past, and close all open FIFOs in fifo_list
6103 that are not marked as active in LIST. If LIST is NULL, close
6104 everything in fifo_list. LSIZE is the number of elements in LIST, in
6105 case it's larger than fifo_list_size (size of fifo_list). */
6106void
6107close_new_fifos (list, lsize)
9e49d343 6108 void *list;
d233b485 6109 int lsize;
cce855bc 6110{
d233b485 6111 int i;
9e49d343 6112 char *plist;
cce855bc 6113
d233b485 6114 if (list == 0)
cce855bc 6115 {
d233b485
CR
6116 unlink_fifo_list ();
6117 return;
cce855bc
JA
6118 }
6119
9e49d343
CR
6120 for (plist = (char *)list, i = 0; i < lsize; i++)
6121 if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
d233b485 6122 unlink_fifo (i);
3185942a 6123
d233b485
CR
6124 for (i = lsize; i < fifo_list_size; i++)
6125 unlink_fifo (i);
cce855bc
JA
6126}
6127
d233b485
CR
6128int
6129find_procsub_child (pid)
6130 pid_t pid;
cce855bc 6131{
d233b485 6132 int i;
cce855bc 6133
d233b485
CR
6134 for (i = 0; i < nfifo; i++)
6135 if (fifo_list[i].proc == pid)
6136 return i;
6137 return -1;
cce855bc
JA
6138}
6139
d233b485
CR
6140void
6141set_procsub_status (ind, pid, status)
6142 int ind;
6143 pid_t pid;
6144 int status;
cce855bc 6145{
d233b485
CR
6146 if (ind >= 0 && ind < nfifo)
6147 fifo_list[ind].proc = (pid_t)-1; /* sentinel */
6148}
ac50fbac 6149
d233b485
CR
6150/* If we've marked the process for this procsub as dead, close the
6151 associated file descriptor and delete the FIFO. */
8868edaf
CR
6152static void
6153reap_some_procsubs (max)
6154 int max;
d233b485
CR
6155{
6156 int i;
7117c2d2 6157
8868edaf 6158 for (i = 0; i < max; i++)
d233b485
CR
6159 if (fifo_list[i].proc == (pid_t)-1) /* reaped */
6160 unlink_fifo (i);
6161}
a0c0a00f 6162
8868edaf
CR
6163void
6164reap_procsubs ()
6165{
6166 reap_some_procsubs (nfifo);
6167}
6168
6169#if 0
6170/* UNUSED */
d233b485
CR
6171void
6172wait_procsubs ()
6173{
6174 int i, r;
7117c2d2 6175
d233b485
CR
6176 for (i = 0; i < nfifo; i++)
6177 {
6178 if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0)
6179 {
8868edaf
CR
6180 r = wait_for (fifo_list[i].proc, 0);
6181 save_proc_status (fifo_list[i].proc, r);
d233b485
CR
6182 fifo_list[i].proc = (pid_t)-1;
6183 }
6184 }
7117c2d2 6185}
8868edaf 6186#endif
7117c2d2 6187
d233b485
CR
6188int
6189fifos_pending ()
7117c2d2 6190{
d233b485
CR
6191 return nfifo;
6192}
7117c2d2 6193
d233b485
CR
6194int
6195num_fifos ()
6196{
6197 return nfifo;
6198}
cce855bc 6199
d233b485
CR
6200static char *
6201make_named_pipe ()
6202{
6203 char *tname;
cce855bc 6204
d233b485
CR
6205 tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
6206 if (mkfifo (tname, 0600) < 0)
cce855bc 6207 {
d233b485
CR
6208 free (tname);
6209 return ((char *)NULL);
cce855bc
JA
6210 }
6211
d233b485
CR
6212 add_fifo_list (tname);
6213 return (tname);
a0c0a00f 6214}
cce855bc 6215
d233b485 6216#else /* HAVE_DEV_FD */
726f6388 6217
d233b485
CR
6218/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
6219 has open to children. NFDS is a count of the number of bits currently
6220 set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
6221 of open files. */
6222/* dev_fd_list[I] value of -1 means the process has been reaped and file
6223 descriptor I needs to be closed. Value of 0 means the slot is unused. */
726f6388 6224
d233b485
CR
6225static pid_t *dev_fd_list = (pid_t *)NULL;
6226static int nfds;
6227static int totfds; /* The highest possible number of open files. */
726f6388 6228
d233b485
CR
6229void
6230clear_fifo (i)
6231 int i;
726f6388 6232{
d233b485
CR
6233 if (dev_fd_list[i])
6234 {
6235 dev_fd_list[i] = 0;
6236 nfds--;
6237 }
726f6388
JA
6238}
6239
d233b485
CR
6240void
6241clear_fifo_list ()
726f6388 6242{
d233b485 6243 register int i;
726f6388 6244
d233b485
CR
6245 if (nfds == 0)
6246 return;
f73dda09 6247
d233b485
CR
6248 for (i = 0; nfds && i < totfds; i++)
6249 clear_fifo (i);
726f6388 6250
d233b485 6251 nfds = 0;
a0c0a00f
CR
6252}
6253
9e49d343 6254void *
495aee44
CR
6255copy_fifo_list (sizep)
6256 int *sizep;
6257{
9e49d343 6258 void *ret;
d233b485
CR
6259
6260 if (nfds == 0 || totfds == 0)
6261 {
6262 if (sizep)
6263 *sizep = 0;
9e49d343 6264 return (void *)NULL;
d233b485
CR
6265 }
6266
495aee44 6267 if (sizep)
d233b485 6268 *sizep = totfds;
9e49d343 6269 ret = xmalloc (totfds * sizeof (pid_t));
d233b485 6270 return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t)));
495aee44
CR
6271}
6272
726f6388 6273static void
d233b485
CR
6274add_fifo_list (fd)
6275 int fd;
726f6388 6276{
d233b485 6277 if (dev_fd_list == 0 || fd >= totfds)
726f6388 6278 {
d233b485
CR
6279 int ofds;
6280
6281 ofds = totfds;
6282 totfds = getdtablesize ();
6283 if (totfds < 0 || totfds > 256)
6284 totfds = 256;
6285 if (fd >= totfds)
6286 totfds = fd + 2;
6287
6288 dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0]));
6289 /* XXX - might need a loop for this */
6290 memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t));
726f6388
JA
6291 }
6292
d233b485
CR
6293 dev_fd_list[fd] = 1; /* marker; updated later */
6294 nfds++;
6295}
6296
6297int
6298fifos_pending ()
6299{
6300 return 0; /* used for cleanup; not needed with /dev/fd */
6301}
6302
6303int
6304num_fifos ()
6305{
6306 return nfds;
726f6388
JA
6307}
6308
495aee44 6309void
d233b485
CR
6310unlink_fifo (fd)
6311 int fd;
495aee44 6312{
d233b485 6313 if (dev_fd_list[fd])
495aee44 6314 {
d233b485
CR
6315 close (fd);
6316 dev_fd_list[fd] = 0;
6317 nfds--;
495aee44
CR
6318 }
6319}
6320
726f6388
JA
6321void
6322unlink_fifo_list ()
6323{
d233b485 6324 register int i;
f73dda09 6325
d233b485 6326 if (nfds == 0)
726f6388
JA
6327 return;
6328
d233b485
CR
6329 for (i = totfds-1; nfds && i >= 0; i--)
6330 unlink_fifo (i);
f73dda09 6331
d233b485 6332 nfds = 0;
726f6388
JA
6333}
6334
8868edaf
CR
6335void
6336unlink_all_fifos ()
6337{
6338 unlink_fifo_list ();
6339}
6340
d233b485
CR
6341/* Take LIST, which is a snapshot copy of dev_fd_list from some point in
6342 the past, and close all open fds in dev_fd_list that are not marked
6343 as open in LIST. If LIST is NULL, close everything in dev_fd_list.
6344 LSIZE is the number of elements in LIST, in case it's larger than
6345 totfds (size of dev_fd_list). */
495aee44
CR
6346void
6347close_new_fifos (list, lsize)
9e49d343 6348 void *list;
495aee44
CR
6349 int lsize;
6350{
6351 int i;
9e49d343 6352 pid_t *plist;
495aee44
CR
6353
6354 if (list == 0)
6355 {
6356 unlink_fifo_list ();
6357 return;
6358 }
6359
9e49d343
CR
6360 for (plist = (pid_t *)list, i = 0; i < lsize; i++)
6361 if (plist[i] == 0 && i < totfds && dev_fd_list[i])
495aee44
CR
6362 unlink_fifo (i);
6363
d233b485 6364 for (i = lsize; i < totfds; i++)
495aee44
CR
6365 unlink_fifo (i);
6366}
6367
f1be666c 6368int
d233b485
CR
6369find_procsub_child (pid)
6370 pid_t pid;
a0c0a00f 6371{
d233b485 6372 int i;
a0c0a00f
CR
6373
6374 if (nfds == 0)
d233b485 6375 return -1;
726f6388 6376
d233b485
CR
6377 for (i = 0; i < totfds; i++)
6378 if (dev_fd_list[i] == pid)
6379 return i;
f1be666c 6380
d233b485 6381 return -1;
495aee44
CR
6382}
6383
6384void
d233b485
CR
6385set_procsub_status (ind, pid, status)
6386 int ind;
6387 pid_t pid;
6388 int status;
495aee44 6389{
d233b485
CR
6390 if (ind >= 0 && ind < totfds)
6391 dev_fd_list[ind] = (pid_t)-1; /* sentinel */
495aee44
CR
6392}
6393
d233b485
CR
6394/* If we've marked the process for this procsub as dead, close the
6395 associated file descriptor. */
8868edaf
CR
6396static void
6397reap_some_procsubs (max)
6398 int max;
726f6388 6399{
d233b485 6400 int i;
726f6388 6401
8868edaf 6402 for (i = 0; nfds > 0 && i < max; i++)
d233b485
CR
6403 if (dev_fd_list[i] == (pid_t)-1)
6404 unlink_fifo (i);
726f6388
JA
6405}
6406
8868edaf
CR
6407void
6408reap_procsubs ()
6409{
6410 reap_some_procsubs (totfds);
6411}
6412
6413#if 0
6414/* UNUSED */
495aee44 6415void
d233b485 6416wait_procsubs ()
495aee44 6417{
d233b485 6418 int i, r;
495aee44 6419
d233b485 6420 for (i = 0; nfds > 0 && i < totfds; i++)
495aee44 6421 {
d233b485
CR
6422 if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0)
6423 {
8868edaf
CR
6424 r = wait_for (dev_fd_list[i], 0);
6425 save_proc_status (dev_fd_list[i], r);
d233b485
CR
6426 dev_fd_list[i] = (pid_t)-1;
6427 }
495aee44 6428 }
495aee44 6429}
8868edaf 6430#endif
495aee44 6431
726f6388
JA
6432#if defined (NOTDEF)
6433print_dev_fd_list ()
6434{
6435 register int i;
6436
f73dda09 6437 fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
726f6388
JA
6438 fflush (stderr);
6439
6440 for (i = 0; i < totfds; i++)
6441 {
6442 if (dev_fd_list[i])
6443 fprintf (stderr, " %d", i);
6444 }
6445 fprintf (stderr, "\n");
6446}
6447#endif /* NOTDEF */
6448
6449static char *
6450make_dev_fd_filename (fd)
6451 int fd;
6452{
f73dda09 6453 char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
726f6388 6454
17345e5a 6455 ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
bb70624e
JA
6456
6457 strcpy (ret, DEV_FD_PREFIX);
6458 p = inttostr (fd, intbuf, sizeof (intbuf));
6459 strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
6460
726f6388
JA
6461 add_fifo_list (fd);
6462 return (ret);
6463}
6464
6465#endif /* HAVE_DEV_FD */
6466
6467/* Return a filename that will open a connection to the process defined by
6468 executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
6469 a filename in /dev/fd corresponding to a descriptor that is one of the
6470 ends of the pipe. If not defined, we use named pipes on systems that have
6471 them. Systems without /dev/fd and named pipes are out of luck.
6472
6473 OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
6474 use the read end of the pipe and dup that file descriptor to fd 0 in
6475 the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
6476 writing or use the write end of the pipe in the child, and dup that
6477 file descriptor to fd 1 in the child. The parent does the opposite. */
6478
6479static char *
6480process_substitute (string, open_for_read_in_child)
6481 char *string;
6482 int open_for_read_in_child;
6483{
6484 char *pathname;
d233b485 6485 int fd, result, rc, function_value;
726f6388
JA
6486 pid_t old_pid, pid;
6487#if defined (HAVE_DEV_FD)
6488 int parent_pipe_fd, child_pipe_fd;
6489 int fildes[2];
6490#endif /* HAVE_DEV_FD */
6491#if defined (JOB_CONTROL)
6492 pid_t old_pipeline_pgrp;
ccc6cda3 6493#endif
726f6388 6494
cce855bc 6495 if (!string || !*string || wordexp_only)
726f6388
JA
6496 return ((char *)NULL);
6497
6498#if !defined (HAVE_DEV_FD)
6499 pathname = make_named_pipe ();
6500#else /* HAVE_DEV_FD */
6501 if (pipe (fildes) < 0)
6502 {
a0c0a00f 6503 sys_error ("%s", _("cannot make pipe for process substitution"));
726f6388
JA
6504 return ((char *)NULL);
6505 }
6506 /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
6507 the pipe in the parent, otherwise the read end. */
6508 parent_pipe_fd = fildes[open_for_read_in_child];
6509 child_pipe_fd = fildes[1 - open_for_read_in_child];
d166f048
JA
6510 /* Move the parent end of the pipe to some high file descriptor, to
6511 avoid clashes with FDs used by the script. */
6512 parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
6513
726f6388
JA
6514 pathname = make_dev_fd_filename (parent_pipe_fd);
6515#endif /* HAVE_DEV_FD */
6516
3185942a 6517 if (pathname == 0)
726f6388 6518 {
a0c0a00f 6519 sys_error ("%s", _("cannot make pipe for process substitution"));
726f6388
JA
6520 return ((char *)NULL);
6521 }
6522
6523 old_pid = last_made_pid;
6524
6525#if defined (JOB_CONTROL)
6526 old_pipeline_pgrp = pipeline_pgrp;
a0c0a00f
CR
6527 if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0)
6528 pipeline_pgrp = shell_pgrp;
ccc6cda3 6529 save_pipeline (1);
ccc6cda3
JA
6530#endif /* JOB_CONTROL */
6531
8868edaf 6532 pid = make_child ((char *)NULL, FORK_ASYNC);
726f6388
JA
6533 if (pid == 0)
6534 {
8868edaf
CR
6535#if 0
6536 int old_interactive;
6537
6538 old_interactive = interactive;
6539#endif
6540 /* The currently-executing shell is not interactive */
6541 interactive = 0;
6542
ccc6cda3 6543 reset_terminating_signals (); /* XXX */
b80f6443 6544 free_pushed_string_input ();
726f6388 6545 /* Cancel traps, in trap.c. */
495aee44 6546 restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */
15409324 6547 subshell_environment &= ~SUBSHELL_IGNTRAP;
a0c0a00f 6548 QUIT; /* catch any interrupts we got post-fork */
726f6388 6549 setup_async_signals ();
8868edaf
CR
6550#if 0
6551 if (open_for_read_in_child == 0 && old_interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))
6552 async_redirect_stdin ();
6553#endif
6554
6555 subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB|SUBSHELL_ASYNC;
a0c0a00f 6556
d233b485
CR
6557 /* We don't inherit the verbose option for command substitutions now, so
6558 let's try it for process substitutions. */
6559 change_flag ('v', FLAG_OFF);
6560
a0c0a00f
CR
6561 /* if we're expanding a redirection, we shouldn't have access to the
6562 temporary environment, but commands in the subshell should have
6563 access to their own temporary environment. */
6564 if (expanding_redir)
6565 flush_temporary_env ();
726f6388 6566 }
ccc6cda3
JA
6567
6568#if defined (JOB_CONTROL)
726f6388
JA
6569 set_sigchld_handler ();
6570 stop_making_children ();
3185942a 6571 /* XXX - should we only do this in the parent? (as in command subst) */
726f6388 6572 pipeline_pgrp = old_pipeline_pgrp;
a0c0a00f
CR
6573#else
6574 stop_making_children ();
ccc6cda3 6575#endif /* JOB_CONTROL */
726f6388
JA
6576
6577 if (pid < 0)
6578 {
a0c0a00f 6579 sys_error ("%s", _("cannot make child for process substitution"));
726f6388
JA
6580 free (pathname);
6581#if defined (HAVE_DEV_FD)
6582 close (parent_pipe_fd);
6583 close (child_pipe_fd);
6584#endif /* HAVE_DEV_FD */
d233b485
CR
6585#if defined (JOB_CONTROL)
6586 restore_pipeline (1);
6587#endif
726f6388
JA
6588 return ((char *)NULL);
6589 }
6590
6591 if (pid > 0)
6592 {
ccc6cda3 6593#if defined (JOB_CONTROL)
a0c0a00f 6594 last_procsub_child = restore_pipeline (0);
8868edaf
CR
6595 /* We assume that last_procsub_child->next == last_procsub_child because
6596 of how jobs.c:add_process() works. */
6597 last_procsub_child->next = 0;
6598 procsub_add (last_procsub_child);
ccc6cda3
JA
6599#endif
6600
d233b485
CR
6601#if defined (HAVE_DEV_FD)
6602 dev_fd_list[parent_pipe_fd] = pid;
6603#else
f73dda09
JA
6604 fifo_list[nfifo-1].proc = pid;
6605#endif
6606
726f6388
JA
6607 last_made_pid = old_pid;
6608
6609#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
6610 close_pgrp_pipe ();
6611#endif /* JOB_CONTROL && PGRP_PIPE */
6612
6613#if defined (HAVE_DEV_FD)
6614 close (child_pipe_fd);
6615#endif /* HAVE_DEV_FD */
6616
6617 return (pathname);
6618 }
6619
6620 set_sigint_handler ();
6621
6622#if defined (JOB_CONTROL)
d233b485 6623 /* make sure we don't have any job control */
726f6388 6624 set_job_control (0);
d233b485 6625
8868edaf
CR
6626 /* Clear out any existing list of process substitutions */
6627 procsub_clear ();
6628
d233b485
CR
6629 /* The idea is that we want all the jobs we start from an async process
6630 substitution to be in the same process group, but not the same pgrp
6631 as our parent shell, since we don't want to affect our parent shell's
6632 jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example.
6633 If pipeline_pgrp != shell_pgrp, we assume that there is a job control
6634 shell somewhere in our parent process chain (since make_child initializes
6635 pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this
6636 case is to set pipeline_pgrp to our PID, so all jobs started by this
6637 process have that same pgrp and we are basically the process group leader.
6638 This should not have negative effects on child processes surviving
6639 after we exit, since we wait for the children we create, but that is
6640 something to watch for. */
6641
6642 if (pipeline_pgrp != shell_pgrp)
6643 pipeline_pgrp = getpid ();
726f6388
JA
6644#endif /* JOB_CONTROL */
6645
6646#if !defined (HAVE_DEV_FD)
6647 /* Open the named pipe in the child. */
ac50fbac 6648 fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY);
726f6388
JA
6649 if (fd < 0)
6650 {
b80f6443
JA
6651 /* Two separate strings for ease of translation. */
6652 if (open_for_read_in_child)
6653 sys_error (_("cannot open named pipe %s for reading"), pathname);
6654 else
6655 sys_error (_("cannot open named pipe %s for writing"), pathname);
6656
726f6388
JA
6657 exit (127);
6658 }
bb70624e
JA
6659 if (open_for_read_in_child)
6660 {
28ef6c31 6661 if (sh_unset_nodelay_mode (fd) < 0)
bb70624e 6662 {
3185942a 6663 sys_error (_("cannot reset nodelay mode for fd %d"), fd);
bb70624e
JA
6664 exit (127);
6665 }
6666 }
726f6388
JA
6667#else /* HAVE_DEV_FD */
6668 fd = child_pipe_fd;
6669#endif /* HAVE_DEV_FD */
6670
a0c0a00f
CR
6671 /* Discard buffered stdio output before replacing the underlying file
6672 descriptor. */
6673 if (open_for_read_in_child == 0)
6674 fpurge (stdout);
6675
726f6388
JA
6676 if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
6677 {
b80f6443 6678 sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
ccc6cda3 6679 open_for_read_in_child ? 0 : 1);
726f6388
JA
6680 exit (127);
6681 }
6682
f73dda09
JA
6683 if (fd != (open_for_read_in_child ? 0 : 1))
6684 close (fd);
726f6388
JA
6685
6686 /* Need to close any files that this process has open to pipes inherited
6687 from its parent. */
6688 if (current_fds_to_close)
6689 {
6690 close_fd_bitmap (current_fds_to_close);
6691 current_fds_to_close = (struct fd_bitmap *)NULL;
6692 }
6693
6694#if defined (HAVE_DEV_FD)
6695 /* Make sure we close the parent's end of the pipe and clear the slot
6696 in the fd list so it is not closed later, if reallocated by, for
6697 instance, pipe(2). */
6698 close (parent_pipe_fd);
6699 dev_fd_list[parent_pipe_fd] = 0;
6700#endif /* HAVE_DEV_FD */
6701
8dea6e87 6702 /* subshells shouldn't have this flag, which controls using the temporary
a0c0a00f
CR
6703 environment for variable lookups. We have already flushed the temporary
6704 environment above in the case we're expanding a redirection, so processes
6705 executed by this command need to be able to set it independently of their
6706 parent. */
8dea6e87
CR
6707 expanding_redir = 0;
6708
9cce630e
CR
6709 remove_quoted_escapes (string);
6710
8868edaf
CR
6711 startup_state = 2; /* see if we can avoid a fork */
6712 parse_and_execute_level = 0;
8868edaf 6713
d233b485
CR
6714 /* Give process substitution a place to jump back to on failure,
6715 so we don't go back up to main (). */
6716 result = setjmp_nosigs (top_level);
6717
6718 /* If we're running a process substitution inside a shell function,
6719 trap `return' so we don't return from the function in the subshell
6720 and go off to never-never land. */
6721 if (result == 0 && return_catch_flag)
6722 function_value = setjmp_nosigs (return_catch);
6723 else
6724 function_value = 0;
6725
6726 if (result == ERREXIT)
6727 rc = last_command_exit_value;
74091dd4 6728 else if (result == EXITPROG || result == EXITBLTIN)
d233b485
CR
6729 rc = last_command_exit_value;
6730 else if (result)
6731 rc = EXECUTION_FAILURE;
6732 else if (function_value)
6733 rc = return_catch_value;
6734 else
6735 {
6736 subshell_level++;
6737 rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
6738 /* leave subshell level intact for any exit trap */
6739 }
726f6388
JA
6740
6741#if !defined (HAVE_DEV_FD)
6742 /* Make sure we close the named pipe in the child before we exit. */
6743 close (open_for_read_in_child ? 0 : 1);
6744#endif /* !HAVE_DEV_FD */
6745
d233b485
CR
6746 last_command_exit_value = rc;
6747 rc = run_exit_trap ();
6748 exit (rc);
726f6388
JA
6749 /*NOTREACHED*/
6750}
6751#endif /* PROCESS_SUBSTITUTION */
6752
cce855bc
JA
6753/***********************************/
6754/* */
6755/* Command Substitution */
6756/* */
6757/***********************************/
6758
74091dd4
CR
6759#define COMSUB_PIPEBUF 4096
6760
6761static char *
6762optimize_cat_file (r, quoted, flags, flagp)
6763 REDIRECT *r;
6764 int quoted, flags, *flagp;
6765{
6766 char *ret;
6767 int fd;
6768
6769 fd = open_redir_file (r, (char **)0);
6770 if (fd < 0)
6771 return &expand_param_error;
6772
6773 ret = read_comsub (fd, quoted, flags, flagp);
6774 close (fd);
6775
6776 return ret;
6777}
6778
d166f048 6779static char *
d233b485
CR
6780read_comsub (fd, quoted, flags, rflag)
6781 int fd, quoted, flags;
3185942a 6782 int *rflag;
d166f048 6783{
74091dd4
CR
6784 char *istring, buf[COMSUB_PIPEBUF], *bufp;
6785 int c, tflag, skip_ctlesc, skip_ctlnul;
8868edaf 6786 int mb_cur_max;
74091dd4 6787 size_t istring_index;
d233b485 6788 size_t istring_size;
f73dda09 6789 ssize_t bufn;
280bd77d 6790 int nullbyte;
8868edaf
CR
6791#if defined (HANDLE_MULTIBYTE)
6792 mbstate_t ps;
6793 wchar_t wc;
6794 size_t mblen;
6795 int i;
6796#endif
d166f048
JA
6797
6798 istring = (char *)NULL;
3185942a
JA
6799 istring_index = istring_size = bufn = tflag = 0;
6800
d233b485
CR
6801 skip_ctlesc = ifs_cmap[CTLESC];
6802 skip_ctlnul = ifs_cmap[CTLNUL];
d166f048 6803
8868edaf 6804 mb_cur_max = MB_CUR_MAX;
280bd77d
CR
6805 nullbyte = 0;
6806
8868edaf 6807 /* Read the output of the command through the pipe. */
d166f048
JA
6808 while (1)
6809 {
6810 if (fd < 0)
28ef6c31 6811 break;
d166f048
JA
6812 if (--bufn <= 0)
6813 {
bb70624e 6814 bufn = zread (fd, buf, sizeof (buf));
d166f048
JA
6815 if (bufn <= 0)
6816 break;
6817 bufp = buf;
6818 }
6819 c = *bufp++;
6820
28ef6c31
JA
6821 if (c == 0)
6822 {
a0c0a00f 6823#if 1
280bd77d
CR
6824 if (nullbyte == 0)
6825 {
6826 internal_warning ("%s", _("command substitution: ignored null byte in input"));
6827 nullbyte = 1;
6828 }
28ef6c31
JA
6829#endif
6830 continue;
6831 }
6832
d166f048 6833 /* Add the character to ISTRING, possibly after resizing it. */
8868edaf 6834 RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512);
d166f048 6835
f1be666c
JA
6836 /* This is essentially quote_string inline */
6837 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
6838 istring[istring_index++] = CTLESC;
d233b485
CR
6839 else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC)
6840 istring[istring_index++] = CTLESC;
f1be666c
JA
6841 /* Escape CTLESC and CTLNUL in the output to protect those characters
6842 from the rest of the word expansions (word splitting and globbing.)
6843 This is essentially quote_escapes inline. */
3185942a 6844 else if (skip_ctlesc == 0 && c == CTLESC)
d233b485 6845 istring[istring_index++] = CTLESC;
3185942a 6846 else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
d166f048
JA
6847 istring[istring_index++] = CTLESC;
6848
8868edaf
CR
6849#if defined (HANDLE_MULTIBYTE)
6850 if ((locale_utf8locale && (c & 0x80)) ||
6851 (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127))
6852 {
6853 /* read a multibyte character from buf */
6854 /* punt on the hard case for now */
6855 memset (&ps, '\0', sizeof (mbstate_t));
72912fb8 6856 mblen = mbrtowc (&wc, bufp-1, bufn, &ps);
8868edaf
CR
6857 if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1)
6858 istring[istring_index++] = c;
6859 else
6860 {
6861 istring[istring_index++] = c;
6862 for (i = 0; i < mblen-1; i++)
6863 istring[istring_index++] = *bufp++;
6864 bufn -= mblen - 1;
6865 }
6866 continue;
28ef6c31
JA
6867 }
6868#endif
8868edaf
CR
6869
6870 istring[istring_index++] = c;
d166f048
JA
6871 }
6872
6873 if (istring)
6874 istring[istring_index] = '\0';
6875
6876 /* If we read no output, just return now and save ourselves some
6877 trouble. */
6878 if (istring_index == 0)
6879 {
6880 FREE (istring);
3185942a
JA
6881 if (rflag)
6882 *rflag = tflag;
d166f048
JA
6883 return (char *)NULL;
6884 }
6885
6886 /* Strip trailing newlines from the output of the command. */
6887 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6888 {
6889 while (istring_index > 0)
6890 {
6891 if (istring[istring_index - 1] == '\n')
6892 {
6893 --istring_index;
6894
6895 /* If the newline was quoted, remove the quoting char. */
6896 if (istring[istring_index - 1] == CTLESC)
6897 --istring_index;
6898 }
6899 else
6900 break;
6901 }
6902 istring[istring_index] = '\0';
6903 }
6904 else
6905 strip_trailing (istring, istring_index - 1, 1);
6906
3185942a
JA
6907 if (rflag)
6908 *rflag = tflag;
d166f048
JA
6909 return istring;
6910}
6911
3185942a
JA
6912/* Perform command substitution on STRING. This returns a WORD_DESC * with the
6913 contained string possibly quoted. */
6914WORD_DESC *
d233b485 6915command_substitute (string, quoted, flags)
726f6388
JA
6916 char *string;
6917 int quoted;
d233b485 6918 int flags;
726f6388 6919{
95732b49 6920 pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
a0c0a00f 6921 char *istring, *s;
8868edaf 6922 int result, fildes[2], function_value, pflags, rc, tflag, fork_flags;
3185942a 6923 WORD_DESC *ret;
8868edaf 6924 sigset_t set, oset;
726f6388 6925
ccc6cda3 6926 istring = (char *)NULL;
726f6388
JA
6927
6928 /* Don't fork () if there is no need to. In the case of no command to
6929 run, just return NULL. */
a0c0a00f
CR
6930 for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++)
6931 ;
6932 if (s == 0 || *s == 0)
6933 return ((WORD_DESC *)NULL);
74091dd4
CR
6934
6935 if (*s == '<' && (s[1] != '<' && s[1] != '>' && s[1] != '&'))
6936 {
6937 COMMAND *cmd;
6938
6939 cmd = parse_string_to_command (string, 0); /* XXX - flags */
6940 if (cmd && can_optimize_cat_file (cmd))
6941 {
6942 tflag = 0;
6943 istring = optimize_cat_file (cmd->value.Simple->redirects, quoted, flags, &tflag);
6944 if (istring == &expand_param_error)
6945 {
6946 last_command_exit_value = EXECUTION_FAILURE;
6947 istring = 0;
6948 }
6949 else
6950 last_command_exit_value = EXECUTION_SUCCESS; /* compat */
6951 last_command_subst_pid = dollar_dollar_pid;
6952
6953 dispose_command (cmd);
6954 ret = alloc_word_desc ();
6955 ret->word = istring;
6956 ret->flags = tflag;
6957
6958 return ret;
6959 }
6960 dispose_command (cmd);
6961 }
726f6388 6962
cce855bc
JA
6963 if (wordexp_only && read_but_dont_execute)
6964 {
0001803f 6965 last_command_exit_value = EX_WEXPCOMSUB;
cce855bc
JA
6966 jump_to_top_level (EXITPROG);
6967 }
6968
bb70624e
JA
6969 /* We're making the assumption here that the command substitution will
6970 eventually run a command from the file system. Since we'll run
6971 maybe_make_export_env in this subshell before executing that command,
6972 the parent shell and any other shells it starts will have to remake
6973 the environment. If we make it before we fork, other shells won't
6974 have to. Don't bother if we have any temporary variable assignments,
6975 though, because the export environment will be remade after this
6976 command completes anyway, but do it if all the words to be expanded
6977 are variable assignments. */
6978 if (subst_assign_varlist == 0 || garglist == 0)
6979 maybe_make_export_env (); /* XXX */
6980
b80f6443 6981 /* Flags to pass to parse_and_execute() */
0001803f 6982 pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
b80f6443 6983
d233b485
CR
6984 old_pid = last_made_pid;
6985
726f6388
JA
6986 /* Pipe the output of executing STRING into the current shell. */
6987 if (pipe (fildes) < 0)
6988 {
a0c0a00f 6989 sys_error ("%s", _("cannot make pipe for command substitution"));
726f6388
JA
6990 goto error_exit;
6991 }
6992
726f6388 6993#if defined (JOB_CONTROL)
ccc6cda3 6994 old_pipeline_pgrp = pipeline_pgrp;
a042c731
CR
6995 /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline or
6996 we've already forked to run a disk command (and are expanding redirections,
6997 for example). */
6998 if ((subshell_environment & (SUBSHELL_FORK|SUBSHELL_PIPE)) == 0)
28ef6c31 6999 pipeline_pgrp = shell_pgrp;
ccc6cda3 7000 cleanup_the_pipeline ();
95732b49 7001#endif /* JOB_CONTROL */
726f6388 7002
95732b49 7003 old_async_pid = last_asynchronous_pid;
8868edaf
CR
7004 fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0;
7005 pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM);
95732b49
JA
7006 last_asynchronous_pid = old_async_pid;
7007
726f6388 7008 if (pid == 0)
495aee44
CR
7009 {
7010 /* Reset the signal handlers in the child, but don't free the
7011 trap strings. Set a flag noting that we have to free the
7012 trap strings if we run trap to change a signal disposition. */
7013 reset_signal_handlers ();
a0c0a00f
CR
7014 if (ISINTERRUPT)
7015 {
7016 kill (getpid (), SIGINT);
7017 CLRINTERRUPT; /* if we're ignoring SIGINT somehow */
7018 }
7019 QUIT; /* catch any interrupts we got post-fork */
495aee44 7020 subshell_environment |= SUBSHELL_RESETTRAP;
15409324 7021 subshell_environment &= ~SUBSHELL_IGNTRAP;
495aee44 7022 }
ccc6cda3
JA
7023
7024#if defined (JOB_CONTROL)
3185942a 7025 /* XXX DO THIS ONLY IN PARENT ? XXX */
ccc6cda3
JA
7026 set_sigchld_handler ();
7027 stop_making_children ();
f1be666c
JA
7028 if (pid != 0)
7029 pipeline_pgrp = old_pipeline_pgrp;
f73dda09
JA
7030#else
7031 stop_making_children ();
ccc6cda3 7032#endif /* JOB_CONTROL */
726f6388
JA
7033
7034 if (pid < 0)
7035 {
b80f6443 7036 sys_error (_("cannot make child for command substitution"));
726f6388
JA
7037 error_exit:
7038
ac50fbac
CR
7039 last_made_pid = old_pid;
7040
726f6388
JA
7041 FREE (istring);
7042 close (fildes[0]);
7043 close (fildes[1]);
3185942a 7044 return ((WORD_DESC *)NULL);
726f6388
JA
7045 }
7046
7047 if (pid == 0)
7048 {
a0c0a00f
CR
7049 /* The currently executing shell is not interactive. */
7050 interactive = 0;
7051
f3cd936b
CR
7052#if defined (JOB_CONTROL)
7053 /* Invariant: in child processes started to run command substitutions,
7054 pipeline_pgrp == shell_pgrp. Other parts of the shell assume this. */
7055 if (pipeline_pgrp > 0 && pipeline_pgrp != shell_pgrp)
7056 shell_pgrp = pipeline_pgrp;
7057#endif
7058
726f6388 7059 set_sigint_handler (); /* XXX */
28ef6c31 7060
b80f6443
JA
7061 free_pushed_string_input ();
7062
a0c0a00f
CR
7063 /* Discard buffered stdio output before replacing the underlying file
7064 descriptor. */
7065 fpurge (stdout);
7066
726f6388
JA
7067 if (dup2 (fildes[1], 1) < 0)
7068 {
a0c0a00f 7069 sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1"));
726f6388
JA
7070 exit (EXECUTION_FAILURE);
7071 }
7072
7073 /* If standard output is closed in the parent shell
7074 (such as after `exec >&-'), file descriptor 1 will be
7075 the lowest available file descriptor, and end up in
7076 fildes[0]. This can happen for stdin and stderr as well,
7077 but stdout is more important -- it will cause no output
7078 to be generated from this command. */
7079 if ((fildes[1] != fileno (stdin)) &&
7080 (fildes[1] != fileno (stdout)) &&
7081 (fildes[1] != fileno (stderr)))
7082 close (fildes[1]);
7083
7084 if ((fildes[0] != fileno (stdin)) &&
7085 (fildes[0] != fileno (stdout)) &&
7086 (fildes[0] != fileno (stderr)))
7087 close (fildes[0]);
7088
495aee44
CR
7089#ifdef __CYGWIN__
7090 /* Let stdio know the fd may have changed from text to binary mode, and
7091 make sure to preserve stdout line buffering. */
7092 freopen (NULL, "w", stdout);
7093 sh_setlinebuf (stdout);
7094#endif /* __CYGWIN__ */
7095
ccc6cda3 7096 /* This is a subshell environment. */
28ef6c31 7097 subshell_environment |= SUBSHELL_COMSUB;
ccc6cda3 7098
a0c0a00f
CR
7099 /* Many shells do not appear to inherit the -v option for command
7100 substitutions. */
7101 change_flag ('v', FLAG_OFF);
7102
7103 /* When inherit_errexit option is not enabled, command substitution does
7104 not inherit the -e flag. It is enabled when Posix mode is enabled */
7105 if (inherit_errexit == 0)
ac50fbac
CR
7106 {
7107 builtin_ignoring_errexit = 0;
7108 change_flag ('e', FLAG_OFF);
ac50fbac 7109 }
a0c0a00f
CR
7110 set_shellopts ();
7111
7112 /* If we are expanding a redirection, we can dispose of any temporary
7113 environment we received, since redirections are not supposed to have
7114 access to the temporary environment. We will have to see whether this
7115 affects temporary environments supplied to `eval', but the temporary
7116 environment gets copied to builtin_env at some point. */
7117 if (expanding_redir)
7118 {
7119 flush_temporary_env ();
7120 expanding_redir = 0;
7121 }
726f6388
JA
7122
7123 remove_quoted_escapes (string);
7124
74091dd4 7125 /* We want to expand aliases on this pass if we are not in posix mode
6ddc9cf2
CR
7126 for backwards compatibility. parse_and_execute() takes care of
7127 setting expand_aliases back to the global value when executing the
7128 parsed string. We only do this for $(...) command substitution,
7129 since that is what parse_comsub handles; `` comsubs are processed
7130 using parse.y:parse_matched_pair(). */
7131 if (expand_aliases && (flags & PF_BACKQUOTE) == 0)
74091dd4
CR
7132 expand_aliases = posixly_correct == 0;
7133
ccc6cda3 7134 startup_state = 2; /* see if we can avoid a fork */
d233b485
CR
7135 parse_and_execute_level = 0;
7136
726f6388
JA
7137 /* Give command substitution a place to jump back to on failure,
7138 so we don't go back up to main (). */
ac50fbac 7139 result = setjmp_nosigs (top_level);
726f6388 7140
bb70624e
JA
7141 /* If we're running a command substitution inside a shell function,
7142 trap `return' so we don't return from the function in the subshell
7143 and go off to never-never land. */
7144 if (result == 0 && return_catch_flag)
ac50fbac 7145 function_value = setjmp_nosigs (return_catch);
bb70624e
JA
7146 else
7147 function_value = 0;
7148
b80f6443
JA
7149 if (result == ERREXIT)
7150 rc = last_command_exit_value;
74091dd4 7151 else if (result == EXITPROG || result == EXITBLTIN)
b80f6443 7152 rc = last_command_exit_value;
726f6388 7153 else if (result)
b80f6443 7154 rc = EXECUTION_FAILURE;
bb70624e 7155 else if (function_value)
b80f6443 7156 rc = return_catch_value;
726f6388 7157 else
b80f6443
JA
7158 {
7159 subshell_level++;
7160 rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
d233b485 7161 /* leave subshell level intact for any exit trap */
b80f6443
JA
7162 }
7163
7164 last_command_exit_value = rc;
7165 rc = run_exit_trap ();
f1be666c
JA
7166#if defined (PROCESS_SUBSTITUTION)
7167 unlink_fifo_list ();
7168#endif
b80f6443 7169 exit (rc);
726f6388
JA
7170 }
7171 else
7172 {
8868edaf
CR
7173 int dummyfd;
7174
726f6388
JA
7175#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
7176 close_pgrp_pipe ();
7177#endif /* JOB_CONTROL && PGRP_PIPE */
7178
7179 close (fildes[1]);
7180
8868edaf
CR
7181 begin_unwind_frame ("read-comsub");
7182 dummyfd = fildes[0];
7183 add_unwind_protect (close, dummyfd);
7184
7185 /* Block SIGINT while we're reading from the pipe. If the child
7186 process gets a SIGINT, it will either handle it or die, and the
7187 read will return. */
7188 BLOCK_SIGNAL (SIGINT, set, oset);
3185942a 7189 tflag = 0;
d233b485 7190 istring = read_comsub (fildes[0], quoted, flags, &tflag);
ccc6cda3 7191
726f6388 7192 close (fildes[0]);
8868edaf
CR
7193 discard_unwind_frame ("read-comsub");
7194 UNBLOCK_SIGNAL (oset);
726f6388 7195
b72432fd 7196 current_command_subst_pid = pid;
8868edaf 7197 last_command_exit_value = wait_for (pid, JWAIT_NOTERM);
726f6388
JA
7198 last_command_subst_pid = pid;
7199 last_made_pid = old_pid;
7200
7201#if defined (JOB_CONTROL)
7202 /* If last_command_exit_value > 128, then the substituted command
7203 was terminated by a signal. If that signal was SIGINT, then send
7204 SIGINT to ourselves. This will break out of loops, for instance. */
b80f6443 7205 if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
726f6388 7206 kill (getpid (), SIGINT);
726f6388
JA
7207#endif /* JOB_CONTROL */
7208
3185942a
JA
7209 ret = alloc_word_desc ();
7210 ret->word = istring;
7211 ret->flags = tflag;
7212
7213 return ret;
726f6388
JA
7214 }
7215}
7216
7217/********************************************************
7218 * *
7219 * Utility functions for parameter expansion *
7220 * *
7221 ********************************************************/
7222
ccc6cda3 7223#if defined (ARRAY_VARS)
ccc6cda3 7224
f73dda09 7225static arrayind_t
ccc6cda3
JA
7226array_length_reference (s)
7227 char *s;
7228{
f73dda09
JA
7229 int len;
7230 arrayind_t ind;
3185942a 7231 char *akey;
f73dda09 7232 char *t, c;
ccc6cda3 7233 ARRAY *array;
495aee44 7234 HASH_TABLE *h;
ccc6cda3
JA
7235 SHELL_VAR *var;
7236
d233b485 7237 var = array_variable_part (s, 0, &t, &len);
726f6388 7238
ccc6cda3
JA
7239 /* If unbound variables should generate an error, report one and return
7240 failure. */
ac50fbac 7241 if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
726f6388 7242 {
f73dda09 7243 c = *--t;
ccc6cda3 7244 *t = '\0';
8868edaf 7245 set_exit_status (EXECUTION_FAILURE);
7117c2d2 7246 err_unboundvar (s);
f73dda09 7247 *t = c;
ccc6cda3 7248 return (-1);
726f6388 7249 }
ac50fbac 7250 else if (var == 0 || invisible_p (var))
ccc6cda3 7251 return 0;
726f6388 7252
28ef6c31
JA
7253 /* We support a couple of expansions for variables that are not arrays.
7254 We'll return the length of the value for v[0], and 1 for v[@] or
7255 v[*]. Return 0 for everything else. */
7256
7257 array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
495aee44 7258 h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
726f6388 7259
d233b485 7260 if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK)
ccc6cda3 7261 {
3185942a 7262 if (assoc_p (var))
495aee44 7263 return (h ? assoc_num_elements (h) : 0);
3185942a 7264 else if (array_p (var))
495aee44 7265 return (array ? array_num_elements (array) : 0);
3185942a 7266 else
495aee44 7267 return (var_isset (var) ? 1 : 0);
ccc6cda3 7268 }
ccc6cda3 7269
3185942a
JA
7270 if (assoc_p (var))
7271 {
7272 t[len - 1] = '\0';
74091dd4 7273 akey = expand_subscript_string (t, 0); /* [ */
d233b485 7274 t[len - 1] = RBRACK;
3185942a
JA
7275 if (akey == 0 || *akey == 0)
7276 {
7277 err_badarraysub (t);
ac50fbac 7278 FREE (akey);
3185942a
JA
7279 return (-1);
7280 }
7281 t = assoc_reference (assoc_cell (var), akey);
ac50fbac 7282 free (akey);
3185942a 7283 }
28ef6c31 7284 else
3185942a 7285 {
d233b485 7286 ind = array_expand_index (var, t, len, 0);
ac50fbac
CR
7287 /* negative subscripts to indexed arrays count back from end */
7288 if (var && array_p (var) && ind < 0)
7289 ind = array_max_index (array_cell (var)) + 1 + ind;
3185942a
JA
7290 if (ind < 0)
7291 {
7292 err_badarraysub (t);
7293 return (-1);
7294 }
7295 if (array_p (var))
7296 t = array_reference (array, ind);
7297 else
7298 t = (ind == 0) ? value_cell (var) : (char *)NULL;
7299 }
28ef6c31 7300
f1be666c 7301 len = MB_STRLEN (t);
ccc6cda3 7302 return (len);
726f6388 7303}
ccc6cda3 7304#endif /* ARRAY_VARS */
726f6388
JA
7305
7306static int
7307valid_brace_expansion_word (name, var_is_special)
7308 char *name;
7309 int var_is_special;
7310{
f73dda09 7311 if (DIGIT (*name) && all_digits (name))
726f6388
JA
7312 return 1;
7313 else if (var_is_special)
7314 return 1;
ccc6cda3 7315#if defined (ARRAY_VARS)
a0c0a00f 7316 else if (valid_array_reference (name, 0))
ccc6cda3
JA
7317 return 1;
7318#endif /* ARRAY_VARS */
726f6388
JA
7319 else if (legal_identifier (name))
7320 return 1;
7321 else
7322 return 0;
7323}
ccc6cda3 7324
b80f6443 7325static int
8868edaf 7326chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
b80f6443 7327 char *name;
8868edaf 7328 int quoted, pflags;
b80f6443
JA
7329 int *quoted_dollar_atp, *contains_dollar_at;
7330{
7331 char *temp1;
7332
7333 if (name == 0)
7334 {
7335 if (quoted_dollar_atp)
7336 *quoted_dollar_atp = 0;
7337 if (contains_dollar_at)
7338 *contains_dollar_at = 0;
7339 return 0;
7340 }
7341
7342 /* check for $@ and $* */
7343 if (name[0] == '@' && name[1] == 0)
7344 {
7345 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7346 *quoted_dollar_atp = 1;
7347 if (contains_dollar_at)
7348 *contains_dollar_at = 1;
7349 return 1;
7350 }
7351 else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
7352 {
8868edaf
CR
7353 /* Need more checks here that parallel what string_list_pos_params and
7354 param_expand do. Check expand_no_split_dollar_star and ??? */
7355 if (contains_dollar_at && expand_no_split_dollar_star == 0)
b80f6443
JA
7356 *contains_dollar_at = 1;
7357 return 1;
7358 }
7359
7360 /* Now check for ${array[@]} and ${array[*]} */
7361#if defined (ARRAY_VARS)
a0c0a00f 7362 else if (valid_array_reference (name, 0))
b80f6443 7363 {
d233b485
CR
7364 temp1 = mbschr (name, LBRACK);
7365 if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK)
b80f6443
JA
7366 {
7367 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7368 *quoted_dollar_atp = 1;
7369 if (contains_dollar_at)
7370 *contains_dollar_at = 1;
7371 return 1;
d233b485 7372 }
b80f6443
JA
7373 /* ${array[*]}, when unquoted, should be treated like ${array[@]},
7374 which should result in separate words even when IFS is unset. */
d233b485 7375 if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0)
b80f6443
JA
7376 {
7377 if (contains_dollar_at)
7378 *contains_dollar_at = 1;
7379 return 1;
7380 }
7381 }
7382#endif
7383 return 0;
7384}
7385
726f6388 7386/* Parameter expand NAME, and return a new string which is the expansion,
d233b485 7387 or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}.
726f6388
JA
7388 VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
7389 the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
7390 NAME was found inside of a double-quoted expression. */
95732b49 7391static WORD_DESC *
74091dd4 7392parameter_brace_expand_word (name, var_is_special, quoted, pflags, estatep)
726f6388 7393 char *name;
89a92869 7394 int var_is_special, quoted, pflags;
74091dd4 7395 array_eltstate_t *estatep;
726f6388 7396{
95732b49 7397 WORD_DESC *ret;
ccc6cda3 7398 char *temp, *tt;
7117c2d2 7399 intmax_t arg_index;
ccc6cda3 7400 SHELL_VAR *var;
74091dd4
CR
7401 int rflags;
7402 array_eltstate_t es;
726f6388 7403
95732b49
JA
7404 ret = 0;
7405 temp = 0;
f1be666c 7406 rflags = 0;
95732b49 7407
74091dd4
CR
7408#if defined (ARRAY_VARS)
7409 if (estatep)
7410 es = *estatep; /* structure copy */
7411 else
7412 {
7413 init_eltstate (&es);
7414 es.ind = INTMAX_MIN;
7415 }
7416#endif
495aee44 7417
95732b49 7418 /* Handle multiple digit arguments, as in ${11}. */
f73dda09 7419 if (legal_number (name, &arg_index))
7117c2d2
JA
7420 {
7421 tt = get_dollar_var_value (arg_index);
b80f6443
JA
7422 if (tt)
7423 temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7424 ? quote_string (tt)
7425 : quote_escapes (tt);
7426 else
7427 temp = (char *)NULL;
7117c2d2
JA
7428 FREE (tt);
7429 }
726f6388
JA
7430 else if (var_is_special) /* ${@} */
7431 {
cce855bc 7432 int sindex;
f73dda09 7433 tt = (char *)xmalloc (2 + strlen (name));
cce855bc 7434 tt[sindex = 0] = '$';
726f6388 7435 strcpy (tt + 1, name);
7117c2d2 7436
95732b49 7437 ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
89a92869 7438 (int *)NULL, (int *)NULL, pflags);
74091dd4
CR
7439
7440 /* Make sure we note that we saw a quoted null string and pass the flag back
7441 to the caller in addition to the value. */
7442 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && STR_DOLLAR_AT_STAR (name) &&
7443 ret && ret->word && QUOTED_NULL (ret->word))
7444 ret->flags |= W_HASQUOTEDNULL;
7445
cce855bc 7446 free (tt);
726f6388 7447 }
ccc6cda3 7448#if defined (ARRAY_VARS)
a0c0a00f 7449 else if (valid_array_reference (name, 0))
ccc6cda3 7450 {
ac50fbac 7451expand_arrayref:
d233b485
CR
7452 var = array_variable_part (name, 0, &tt, (int *)0);
7453 /* These are the cases where word splitting will not be performed */
ac50fbac 7454 if (pflags & PF_ASSIGNRHS)
a0c0a00f 7455 {
d233b485 7456 if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK)
a0c0a00f
CR
7457 {
7458 /* Only treat as double quoted if array variable */
7459 if (var && (array_p (var) || assoc_p (var)))
74091dd4 7460 temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &es);
a0c0a00f 7461 else
74091dd4 7462 temp = array_value (name, quoted, 0, &es);
a0c0a00f 7463 }
ac50fbac 7464 else
74091dd4 7465 temp = array_value (name, quoted, 0, &es);
a0c0a00f 7466 }
d233b485
CR
7467 /* Posix interp 888 */
7468 else if (pflags & PF_NOSPLIT2)
7469 {
7470 /* Special cases, then general case, for each of A[@], A[*], A[n] */
7471#if defined (HANDLE_MULTIBYTE)
7472 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
7473#else
7474 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
7475#endif
74091dd4 7476 temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &es);
d233b485 7477 else if (tt[0] == '@' && tt[1] == RBRACK)
74091dd4 7478 temp = array_value (name, quoted, 0, &es);
d233b485 7479 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
74091dd4 7480 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &es);
d233b485 7481 else if (tt[0] == '*' && tt[1] == RBRACK)
74091dd4 7482 temp = array_value (name, quoted, 0, &es);
d233b485 7483 else
74091dd4 7484 temp = array_value (name, quoted, 0, &es);
d233b485
CR
7485 }
7486 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
74091dd4 7487 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &es);
ac50fbac 7488 else
74091dd4
CR
7489 temp = array_value (name, quoted, 0, &es);
7490 if (es.subtype == 0 && temp)
495aee44
CR
7491 {
7492 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7493 ? quote_string (temp)
7494 : quote_escapes (temp);
7495 rflags |= W_ARRAYIND;
74091dd4
CR
7496 if (estatep)
7497 *estatep = es; /* structure copy */
7498 }
7499 /* Note that array[*] and array[@] expanded to a quoted null string by
7500 returning the W_HASQUOTEDNULL flag to the caller in addition to TEMP. */
7501 else if (es.subtype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7502 rflags |= W_HASQUOTEDNULL;
7503 else if (es.subtype == 2 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
f1be666c 7504 rflags |= W_HASQUOTEDNULL;
74091dd4
CR
7505
7506 if (estatep == 0)
7507 flush_eltstate (&es);
ccc6cda3
JA
7508 }
7509#endif
7510 else if (var = find_variable (name))
7511 {
7117c2d2 7512 if (var_isset (var) && invisible_p (var) == 0)
28ef6c31 7513 {
ccc6cda3 7514#if defined (ARRAY_VARS)
8868edaf
CR
7515 /* We avoid a memory leak by saving TT as the memory allocated by
7516 assoc_to_string or array_to_string and leaving it 0 otherwise,
7517 then freeing TT after quoting temp. */
7518 tt = (char *)NULL;
7519 if ((pflags & PF_ALLINDS) && assoc_p (var))
7520 tt = temp = assoc_empty (assoc_cell (var)) ? (char *)NULL : assoc_to_string (assoc_cell (var), " ", quoted);
7521 else if ((pflags & PF_ALLINDS) && array_p (var))
7522 tt = temp = array_empty (array_cell (var)) ? (char *)NULL : array_to_string (array_cell (var), " ", quoted);
7523 else if (assoc_p (var))
3185942a
JA
7524 temp = assoc_reference (assoc_cell (var), "0");
7525 else if (array_p (var))
7526 temp = array_reference (array_cell (var), 0);
7527 else
7528 temp = value_cell (var);
ccc6cda3
JA
7529#else
7530 temp = value_cell (var);
7531#endif
7532
7533 if (temp)
b80f6443
JA
7534 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7535 ? quote_string (temp)
d233b485
CR
7536 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
7537 : quote_escapes (temp));
8868edaf 7538 FREE (tt);
28ef6c31 7539 }
ccc6cda3
JA
7540 else
7541 temp = (char *)NULL;
7542 }
a0c0a00f 7543 else if (var = find_variable_last_nameref (name, 0))
ac50fbac
CR
7544 {
7545 temp = nameref_cell (var);
7546#if defined (ARRAY_VARS)
7547 /* Handle expanding nameref whose value is x[n] */
a0c0a00f 7548 if (temp && *temp && valid_array_reference (temp, 0))
ac50fbac
CR
7549 {
7550 name = temp;
7551 goto expand_arrayref;
7552 }
7553 else
7554#endif
7555 /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */
7556 if (temp && *temp && legal_identifier (temp) == 0)
7557 {
8868edaf 7558 set_exit_status (EXECUTION_FAILURE);
ac50fbac
CR
7559 report_error (_("%s: invalid variable name for name reference"), temp);
7560 temp = &expand_param_error;
7561 }
7562 else
7563 temp = (char *)NULL;
7564 }
726f6388 7565 else
ccc6cda3 7566 temp = (char *)NULL;
726f6388 7567
95732b49
JA
7568 if (ret == 0)
7569 {
7570 ret = alloc_word_desc ();
7571 ret->word = temp;
f1be666c 7572 ret->flags |= rflags;
95732b49
JA
7573 }
7574 return ret;
726f6388
JA
7575}
7576
ac50fbac
CR
7577static char *
7578parameter_brace_find_indir (name, var_is_special, quoted, find_nameref)
ccc6cda3 7579 char *name;
ac50fbac 7580 int var_is_special, quoted, find_nameref;
ccc6cda3
JA
7581{
7582 char *temp, *t;
95732b49 7583 WORD_DESC *w;
ac50fbac 7584 SHELL_VAR *v;
d233b485 7585 int pflags, oldex;
ac50fbac 7586
a0c0a00f 7587 if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) &&
ac50fbac
CR
7588 nameref_p (v) && (t = nameref_cell (v)) && *t)
7589 return (savestring (t));
ccc6cda3 7590
ac50fbac
CR
7591 /* If var_is_special == 0, and name is not an array reference, this does
7592 more expansion than necessary. It should really look up the variable's
7593 value and not try to expand it. */
d233b485
CR
7594 pflags = PF_IGNUNBOUND;
7595 /* Note that we're not going to be doing word splitting here */
7596 if (var_is_special)
7597 {
7598 pflags |= PF_ASSIGNRHS; /* suppresses word splitting */
7599 oldex = expand_no_split_dollar_star;
7600 expand_no_split_dollar_star = 1;
7601 }
7602 w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0);
7603 if (var_is_special)
7604 expand_no_split_dollar_star = oldex;
7605
95732b49 7606 t = w->word;
b80f6443
JA
7607 /* Have to dequote here if necessary */
7608 if (t)
7609 {
d233b485 7610 temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special)
b80f6443
JA
7611 ? dequote_string (t)
7612 : dequote_escapes (t);
7613 free (t);
7614 t = temp;
7615 }
95732b49
JA
7616 dispose_word_desc (w);
7617
ac50fbac
CR
7618 return t;
7619}
7620
7621/* Expand an indirect reference to a variable: ${!NAME} expands to the
7622 value of the variable whose name is the value of NAME. */
7623static WORD_DESC *
8868edaf 7624parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
ac50fbac 7625 char *name;
8868edaf 7626 int var_is_special, quoted, pflags;
ac50fbac
CR
7627 int *quoted_dollar_atp, *contains_dollar_at;
7628{
d233b485 7629 char *t;
ac50fbac
CR
7630 WORD_DESC *w;
7631 SHELL_VAR *v;
7632
7633 /* See if it's a nameref first, behave in ksh93-compatible fashion.
7634 There is at least one incompatibility: given ${!foo[0]} where foo=bar,
7635 bash performs an indirect lookup on foo[0] and expands the result;
7636 ksh93 expands bar[0]. We could do that here -- there are enough usable
7637 primitives to do that -- but do not at this point. */
a0c0a00f 7638 if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0)))
ac50fbac
CR
7639 {
7640 if (nameref_p (v) && (t = nameref_cell (v)) && *t)
7641 {
7642 w = alloc_word_desc ();
7643 w->word = savestring (t);
7644 w->flags = 0;
7645 return w;
7646 }
7647 }
7648
d233b485
CR
7649 /* An indirect reference to a positional parameter or a special parameter
7650 is ok. Indirect references to array references, as explained above, are
7651 ok (currently). Only references to unset variables are errors at this
7652 point. */
7653 if (legal_identifier (name) && v == 0)
7654 {
7655 report_error (_("%s: invalid indirect expansion"), name);
7656 w = alloc_word_desc ();
7657 w->word = &expand_param_error;
7658 w->flags = 0;
7659 return (w);
7660 }
7661
ac50fbac
CR
7662 t = parameter_brace_find_indir (name, var_is_special, quoted, 0);
7663
8868edaf 7664 chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at);
d233b485
CR
7665
7666#if defined (ARRAY_VARS)
7667 /* Array references to unset variables are also an error */
7668 if (t == 0 && valid_array_reference (name, 0))
7669 {
7670 v = array_variable_part (name, 0, (char **)0, (int *)0);
7671 if (v == 0)
7672 {
7673 report_error (_("%s: invalid indirect expansion"), name);
7674 w = alloc_word_desc ();
7675 w->word = &expand_param_error;
7676 w->flags = 0;
7677 return (w);
7678 }
7679 else
7680 return (WORD_DESC *)NULL;
7681 }
7682#endif
7683
ccc6cda3 7684 if (t == 0)
95732b49
JA
7685 return (WORD_DESC *)NULL;
7686
a0c0a00f
CR
7687 if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0)
7688 {
d233b485 7689 report_error (_("%s: invalid variable name"), t);
a0c0a00f
CR
7690 free (t);
7691 w = alloc_word_desc ();
7692 w->word = &expand_param_error;
7693 w->flags = 0;
7694 return (w);
7695 }
7696
8868edaf 7697 w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0);
ccc6cda3 7698 free (t);
95732b49
JA
7699
7700 return w;
ccc6cda3
JA
7701}
7702
726f6388
JA
7703/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
7704 depending on the value of C, the separating character. C can be one of
ccc6cda3
JA
7705 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
7706 between double quotes. */
95732b49 7707static WORD_DESC *
d233b485 7708parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat)
726f6388 7709 char *name, *value;
d233b485 7710 int op, quoted, pflags, *qdollaratp, *hasdollarat;
726f6388 7711{
95732b49 7712 WORD_DESC *w;
8868edaf 7713 WORD_LIST *l, *tl;
74091dd4
CR
7714 char *t, *t1, *temp, *vname, *newval;
7715 int l_hasdollat, sindex, arrayref;
d233b485 7716 SHELL_VAR *v;
74091dd4 7717 array_eltstate_t es;
726f6388 7718
a0c0a00f 7719/*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/
ccc6cda3
JA
7720 /* If the entire expression is between double quotes, we want to treat
7721 the value as a double-quoted string, with the exception that we strip
3185942a 7722 embedded unescaped double quotes (for sh backwards compatibility). */
95732b49 7723 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
726f6388 7724 {
a0c0a00f
CR
7725 sindex = 0;
7726 temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ);
726f6388 7727 }
95732b49
JA
7728 else
7729 temp = value;
ccc6cda3 7730
95732b49 7731 w = alloc_word_desc ();
a0c0a00f 7732 l_hasdollat = 0;
d233b485 7733 l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL)
ccc6cda3
JA
7734 : (WORD_LIST *)0;
7735 if (hasdollarat)
a0c0a00f 7736 *hasdollarat = l_hasdollat || (l && l->next);
95732b49
JA
7737 if (temp != value)
7738 free (temp);
8868edaf
CR
7739
7740 /* list_string takes multiple CTLNULs and turns them into an empty word
7741 with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the
7742 rest of this function and the caller. */
7743 for (tl = l; tl; tl = tl->next)
7744 {
7745 if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) &&
7746 (tl->word->flags | W_SAWQUOTEDNULL))
7747 {
7748 t = make_quoted_char ('\0');
7749 FREE (tl->word->word);
7750 tl->word->word = t;
7751 tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL;
7752 tl->word->flags &= ~W_SAWQUOTEDNULL;
7753 }
7754 }
7755
726f6388
JA
7756 if (l)
7757 {
a0c0a00f
CR
7758 /* If l->next is not null, we know that TEMP contained "$@", since that
7759 is the only expansion that creates more than one word. */
7760 if (qdollaratp && ((l_hasdollat && quoted) || l->next))
7761 {
7762/*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/
7763 *qdollaratp = 1;
7764 }
7765
ccc6cda3 7766 /* The expansion of TEMP returned something. We need to treat things
a0c0a00f
CR
7767 slightly differently if L_HASDOLLAT is non-zero. If we have "$@",
7768 the individual words have already been quoted. We need to turn them
b80f6443
JA
7769 into a string with the words separated by the first character of
7770 $IFS without any additional quoting, so string_list_dollar_at won't
a0c0a00f
CR
7771 do the right thing. If IFS is null, we want "$@" to split into
7772 separate arguments, not be concatenated, so we use string_list_internal
7773 and mark the word to be split on spaces later. We use
7774 string_list_dollar_star for "$@" otherwise. */
7775 if (l->next && ifs_is_null)
7776 {
7777 temp = string_list_internal (l, " ");
7778 w->flags |= W_SPLITSPACE;
7779 }
d233b485
CR
7780 else if (l_hasdollat || l->next)
7781 temp = string_list_dollar_star (l, quoted, 0);
a0c0a00f 7782 else
d233b485
CR
7783 {
7784 temp = string_list (l);
7785 if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL))
7786 w->flags |= W_SAWQUOTEDNULL; /* XXX */
7787 }
b80f6443 7788
cd110fdf
CR
7789 /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
7790 a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
7791 flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
7792 expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7793 (which is more paranoia than anything else), we need to return the
7794 quoted null string and set the flags to indicate it. */
ac50fbac 7795 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
7796 {
7797 w->flags |= W_HASQUOTEDNULL;
a0c0a00f
CR
7798/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/
7799 /* If we return a quoted null with L_HASDOLLARAT, we either have a
7800 construct like "${@-$@}" or "${@-${@-$@}}" with no positional
7801 parameters or a quoted expansion of "$@" with $1 == ''. In either
7802 case, we don't want to enable special handling of $@. */
7803 if (qdollaratp && l_hasdollat)
7804 *qdollaratp = 0;
cd110fdf 7805 }
726f6388
JA
7806 dispose_words (l);
7807 }
a0c0a00f 7808 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat)
726f6388 7809 {
a0c0a00f
CR
7810 /* Posix interp 221 changed the rules on this. The idea is that
7811 something like "$xxx$@" should expand the same as "${foo-$xxx$@}"
7812 when foo and xxx are unset. The problem is that it's not in any
7813 way backwards compatible and few other shells do it. We're eventually
7814 going to try and split the difference (heh) a little bit here. */
7815 /* l_hasdollat == 1 means we saw a quoted dollar at. */
7816
ccc6cda3
JA
7817 /* The brace expansion occurred between double quotes and there was
7818 a $@ in TEMP. It does not matter if the $@ is quoted, as long as
7117c2d2 7819 it does not expand to anything. In this case, we want to return
a0c0a00f 7820 a quoted empty string. Posix interp 888 */
0628567a 7821 temp = make_quoted_char ('\0');
95732b49 7822 w->flags |= W_HASQUOTEDNULL;
a0c0a00f 7823/*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/
726f6388
JA
7824 }
7825 else
7826 temp = (char *)NULL;
7827
d233b485 7828 if (op == '-' || op == '+')
95732b49
JA
7829 {
7830 w->word = temp;
7831 return w;
7832 }
726f6388 7833
d233b485
CR
7834 /* op == '=' */
7835 t1 = temp ? dequote_string (temp) : savestring ("");
7836 free (temp);
a0c0a00f
CR
7837
7838 /* bash-4.4/5.0 */
7839 vname = name;
7840 if (*name == '!' &&
7841 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1])))
7842 {
7843 vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1);
7844 if (vname == 0 || *vname == 0)
7845 {
7846 report_error (_("%s: invalid indirect expansion"), name);
7847 free (vname);
d233b485 7848 free (t1);
a0c0a00f
CR
7849 dispose_word (w);
7850 return &expand_wdesc_error;
7851 }
7852 if (legal_identifier (vname) == 0)
7853 {
7854 report_error (_("%s: invalid variable name"), vname);
7855 free (vname);
d233b485 7856 free (t1);
a0c0a00f
CR
7857 dispose_word (w);
7858 return &expand_wdesc_error;
7859 }
7860 }
7861
74091dd4 7862 arrayref = 0;
b80f6443 7863#if defined (ARRAY_VARS)
a0c0a00f 7864 if (valid_array_reference (vname, 0))
74091dd4
CR
7865 {
7866 init_eltstate (&es);
7867 v = assign_array_element (vname, t1, ASS_ALLOWALLSUB, &es);
7868 arrayref = 1;
7869 newval = es.value;
7870 }
b80f6443
JA
7871 else
7872#endif /* ARRAY_VARS */
d233b485
CR
7873 v = bind_variable (vname, t1, 0);
7874
7875 if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */
7876 {
7877 if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct)
7878 {
7879 last_command_exit_value = EXECUTION_FAILURE;
7880 exp_jump_to_top_level (FORCE_EOF);
7881 }
7882 else
7883 {
7884 if (vname != name)
7885 free (vname);
7886 last_command_exit_value = EX_BADUSAGE;
7887 exp_jump_to_top_level (DISCARD);
7888 }
7889 }
a0c0a00f
CR
7890
7891 stupidly_hack_special_variables (vname);
7892
74091dd4
CR
7893 /* "In all cases, the final value of parameter shall be substituted." */
7894 if (shell_compatibility_level > 51)
7895 {
7896 FREE (t1);
7897#if defined (ARRAY_VARS)
7898 if (arrayref)
7899 {
7900 t1 = newval;
7901 flush_eltstate (&es);
7902 }
7903 else
7904 t1 = get_variable_value (v);
7905#else
7906 t1 = value_cell (v);
7907#endif
7908 }
7909
a0c0a00f
CR
7910 if (vname != name)
7911 free (vname);
95732b49 7912
495aee44 7913 /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
495aee44 7914
d233b485
CR
7915 /* If we are double-quoted or if we are not going to be performing word
7916 splitting, we want to quote the value we return appropriately, like
7917 the other expansions this function handles. */
7918 w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1);
74091dd4 7919 /* If we have something that's non-null, but not a quoted null string,
8868edaf
CR
7920 and we're not going to be performing word splitting (we know we're not
7921 because the operator is `='), we can forget we saw a quoted null. */
7922 if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0)
7923 w->flags &= ~W_SAWQUOTEDNULL;
d233b485 7924
8868edaf
CR
7925 /* If we convert a null string into a quoted null, make sure the caller
7926 knows it. */
7927 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word))
7928 w->flags |= W_HASQUOTEDNULL;
7929
95732b49 7930 return w;
726f6388
JA
7931}
7932
7933/* Deal with the right hand side of a ${name:?value} expansion in the case
7934 that NAME is null or not set. If VALUE is non-null it is expanded and
7935 used as the error message to print, otherwise a standard message is
7936 printed. */
7937static void
d233b485 7938parameter_brace_expand_error (name, value, check_null)
726f6388 7939 char *name, *value;
d233b485 7940 int check_null;
726f6388 7941{
ccc6cda3
JA
7942 WORD_LIST *l;
7943 char *temp;
7944
8868edaf 7945 set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */
726f6388
JA
7946 if (value && *value)
7947 {
95732b49 7948 l = expand_string (value, 0);
ccc6cda3
JA
7949 temp = string_list (l);
7950 report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
7951 FREE (temp);
726f6388
JA
7952 dispose_words (l);
7953 }
d233b485
CR
7954 else if (check_null == 0)
7955 report_error (_("%s: parameter not set"), name);
726f6388 7956 else
b80f6443 7957 report_error (_("%s: parameter null or not set"), name);
726f6388
JA
7958
7959 /* Free the data we have allocated during this expansion, since we
7960 are about to longjmp out. */
7961 free (name);
7962 FREE (value);
7963}
7964
7965/* Return 1 if NAME is something for which parameter_brace_expand_length is
7966 OK to do. */
7967static int
7968valid_length_expression (name)
7969 char *name;
7970{
28ef6c31 7971 return (name[1] == '\0' || /* ${#} */
f73dda09
JA
7972 ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */
7973 (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
ccc6cda3 7974#if defined (ARRAY_VARS)
a0c0a00f 7975 valid_array_reference (name + 1, 0) || /* ${#a[7]} */
ccc6cda3 7976#endif
726f6388
JA
7977 legal_identifier (name + 1)); /* ${#PS1} */
7978}
7979
7980/* Handle the parameter brace expansion that requires us to return the
7981 length of a parameter. */
7117c2d2 7982static intmax_t
726f6388
JA
7983parameter_brace_expand_length (name)
7984 char *name;
7985{
ccc6cda3 7986 char *t, *newname;
7117c2d2 7987 intmax_t number, arg_index;
ccc6cda3 7988 WORD_LIST *list;
ccc6cda3 7989 SHELL_VAR *var;
8868edaf
CR
7990
7991 var = (SHELL_VAR *)NULL;
ccc6cda3
JA
7992
7993 if (name[1] == '\0') /* ${#} */
7994 number = number_of_args ();
a0c0a00f 7995 else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */
cce855bc 7996 number = number_of_args ();
f73dda09 7997 else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
cce855bc
JA
7998 {
7999 /* Take the lengths of some of the shell's special parameters. */
8000 switch (name[1])
8001 {
8002 case '-':
8003 t = which_set_flags ();
8004 break;
8005 case '?':
8006 t = itos (last_command_exit_value);
8007 break;
8008 case '$':
8009 t = itos (dollar_dollar_pid);
8010 break;
8011 case '!':
8012 if (last_asynchronous_pid == NO_PID)
495aee44 8013 t = (char *)NULL; /* XXX - error if set -u set? */
cce855bc 8014 else
f73dda09 8015 t = itos (last_asynchronous_pid);
cce855bc
JA
8016 break;
8017 case '#':
8018 t = itos (number_of_args ());
8019 break;
8020 }
8021 number = STRLEN (t);
8022 FREE (t);
8023 }
ccc6cda3 8024#if defined (ARRAY_VARS)
a0c0a00f 8025 else if (valid_array_reference (name + 1, 0))
ccc6cda3
JA
8026 number = array_length_reference (name + 1);
8027#endif /* ARRAY_VARS */
cce855bc 8028 else
ccc6cda3
JA
8029 {
8030 number = 0;
8031
f73dda09 8032 if (legal_number (name + 1, &arg_index)) /* ${#1} */
ccc6cda3 8033 {
f73dda09 8034 t = get_dollar_var_value (arg_index);
495aee44
CR
8035 if (t == 0 && unbound_vars_is_error)
8036 return INTMAX_MIN;
eb873671 8037 number = MB_STRLEN (t);
ccc6cda3
JA
8038 FREE (t);
8039 }
8040#if defined (ARRAY_VARS)
3185942a 8041 else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
ccc6cda3 8042 {
3185942a
JA
8043 if (assoc_p (var))
8044 t = assoc_reference (assoc_cell (var), "0");
8045 else
8046 t = array_reference (array_cell (var), 0);
495aee44
CR
8047 if (t == 0 && unbound_vars_is_error)
8048 return INTMAX_MIN;
eb873671 8049 number = MB_STRLEN (t);
ccc6cda3
JA
8050 }
8051#endif
8868edaf
CR
8052 /* Fast path for the common case of taking the length of a non-dynamic
8053 scalar variable value. */
8054 else if ((var || (var = find_variable (name + 1))) &&
8055 invisible_p (var) == 0 &&
8056 array_p (var) == 0 && assoc_p (var) == 0 &&
8057 var->dynamic_value == 0)
8058 number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0;
8059 else if (var == 0 && unbound_vars_is_error == 0)
8060 number = 0;
ccc6cda3
JA
8061 else /* ${#PS1} */
8062 {
8063 newname = savestring (name);
8064 newname[0] = '$';
8065 list = expand_string (newname, Q_DOUBLE_QUOTES);
8066 t = list ? string_list (list) : (char *)NULL;
8067 free (newname);
8068 if (list)
8069 dispose_words (list);
8070
495aee44 8071 number = t ? MB_STRLEN (t) : 0;
ccc6cda3
JA
8072 FREE (t);
8073 }
8074 }
ccc6cda3
JA
8075
8076 return (number);
8077}
8078
28ef6c31
JA
8079/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression,
8080 so we do some ad-hoc parsing of an arithmetic expression to find
8081 the first DELIM, instead of using strchr(3). Two rules:
8082 1. If the substring contains a `(', read until closing `)'.
8083 2. If the substring contains a `?', read past one `:' for each `?'.
a0c0a00f 8084 The SD_ARITHEXP flag to skip_to_delim takes care of doing this.
28ef6c31
JA
8085*/
8086
8087static char *
8088skiparith (substr, delim)
8089 char *substr;
8090 int delim;
8091{
a0c0a00f
CR
8092 int i;
8093 char delims[2];
28ef6c31 8094
a0c0a00f
CR
8095 delims[0] = delim;
8096 delims[1] = '\0';
7117c2d2 8097
a0c0a00f 8098 i = skip_to_delim (substr, 0, delims, SD_ARITHEXP);
7117c2d2 8099 return (substr + i);
28ef6c31
JA
8100}
8101
ccc6cda3
JA
8102/* Verify and limit the start and end of the desired substring. If
8103 VTYPE == 0, a regular shell variable is being used; if it is 1,
cce855bc 8104 then the positional parameters are being used; if it is 2, then
e8ce775d
JA
8105 VALUE is really a pointer to an array variable that should be used.
8106 Return value is 1 if both values were OK, 0 if there was a problem
8107 with an invalid expression, or -1 if the values were out of range. */
ccc6cda3 8108static int
3185942a
JA
8109verify_substring_values (v, value, substr, vtype, e1p, e2p)
8110 SHELL_VAR *v;
ccc6cda3 8111 char *value, *substr;
f73dda09 8112 int vtype;
7117c2d2 8113 intmax_t *e1p, *e2p;
ccc6cda3 8114{
bb70624e 8115 char *t, *temp1, *temp2;
f73dda09 8116 arrayind_t len;
74091dd4 8117 int expok, eflag;
ccc6cda3
JA
8118#if defined (ARRAY_VARS)
8119 ARRAY *a;
3185942a 8120 HASH_TABLE *h;
ccc6cda3
JA
8121#endif
8122
28ef6c31
JA
8123 /* duplicate behavior of strchr(3) */
8124 t = skiparith (substr, ':');
8125 if (*t && *t == ':')
7117c2d2 8126 *t = '\0';
28ef6c31
JA
8127 else
8128 t = (char *)0;
f73dda09 8129
74091dd4
CR
8130 temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES|Q_ARITH);
8131 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
8132
8133 *e1p = evalexp (temp1, eflag, &expok);
ccc6cda3 8134 free (temp1);
d166f048
JA
8135 if (expok == 0)
8136 return (0);
ccc6cda3 8137
f73dda09 8138 len = -1; /* paranoia */
ccc6cda3
JA
8139 switch (vtype)
8140 {
8141 case VT_VARIABLE:
d166f048 8142 case VT_ARRAYMEMBER:
eb873671 8143 len = MB_STRLEN (value);
ccc6cda3
JA
8144 break;
8145 case VT_POSPARMS:
8146 len = number_of_args () + 1;
3185942a
JA
8147 if (*e1p == 0)
8148 len++; /* add one arg if counting from $0 */
ccc6cda3
JA
8149 break;
8150#if defined (ARRAY_VARS)
8151 case VT_ARRAYVAR:
eb873671 8152 /* For arrays, the first value deals with array indices. Negative
3185942a
JA
8153 offsets count from one past the array's maximum index. Associative
8154 arrays treat the number of elements as the maximum index. */
8155 if (assoc_p (v))
8156 {
8157 h = assoc_cell (v);
8158 len = assoc_num_elements (h) + (*e1p < 0);
8159 }
8160 else
8161 {
8162 a = (ARRAY *)value;
8163 len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
8164 }
ccc6cda3
JA
8165 break;
8166#endif
8167 }
8168
f73dda09
JA
8169 if (len == -1) /* paranoia */
8170 return -1;
8171
ccc6cda3
JA
8172 if (*e1p < 0) /* negative offsets count from end */
8173 *e1p += len;
8174
eb873671 8175 if (*e1p > len || *e1p < 0)
e8ce775d 8176 return (-1);
d166f048 8177
b80f6443
JA
8178#if defined (ARRAY_VARS)
8179 /* For arrays, the second offset deals with the number of elements. */
8180 if (vtype == VT_ARRAYVAR)
3185942a 8181 len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
b80f6443
JA
8182#endif
8183
ccc6cda3
JA
8184 if (t)
8185 {
8186 t++;
bb70624e 8187 temp2 = savestring (t);
74091dd4 8188 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
bb70624e 8189 free (temp2);
ccc6cda3 8190 t[-1] = ':';
74091dd4 8191 *e2p = evalexp (temp1, eflag, &expok);
ccc6cda3 8192 free (temp1);
d166f048 8193 if (expok == 0)
28ef6c31 8194 return (0);
d233b485
CR
8195
8196 /* Should we allow positional parameter length < 0 to count backwards
8197 from end of positional parameters? */
ac50fbac 8198#if 1
495aee44 8199 if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
74091dd4 8200#else /* XXX - postponed; this isn't really a valuable feature */
ac50fbac
CR
8201 if (vtype == VT_ARRAYVAR && *e2p < 0)
8202#endif
28ef6c31 8203 {
b80f6443 8204 internal_error (_("%s: substring expression < 0"), t);
ccc6cda3 8205 return (0);
28ef6c31 8206 }
b80f6443
JA
8207#if defined (ARRAY_VARS)
8208 /* In order to deal with sparse arrays, push the intelligence about how
8209 to deal with the number of elements desired down to the array-
8210 specific functions. */
8211 if (vtype != VT_ARRAYVAR)
8212#endif
8213 {
495aee44
CR
8214 if (*e2p < 0)
8215 {
8216 *e2p += len;
8217 if (*e2p < 0 || *e2p < *e1p)
8218 {
8219 internal_error (_("%s: substring expression < 0"), t);
8220 return (0);
8221 }
8222 }
8223 else
8224 *e2p += *e1p; /* want E2 chars starting at E1 */
b80f6443
JA
8225 if (*e2p > len)
8226 *e2p = len;
8227 }
ccc6cda3
JA
8228 }
8229 else
8230 *e2p = len;
8231
8232 return (1);
8233}
8234
ccc6cda3 8235/* Return the type of variable specified by VARNAME (simple variable,
cce855bc 8236 positional param, or array variable). Also return the value specified
7117c2d2 8237 by VARNAME (value of a variable or a reference to an array element).
495aee44
CR
8238 QUOTED is the standard description of quoting state, using Q_* defines.
8239 FLAGS is currently a set of flags to pass to array_value. If IND is
74091dd4 8240 not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
495aee44 8241 passed to array_value so the array index is not computed again.
7117c2d2
JA
8242 If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
8243 characters in the value are quoted with CTLESC and takes appropriate
8244 steps. For convenience, *VALP is set to the dequoted VALUE. */
ccc6cda3 8245static int
74091dd4 8246get_var_and_type (varname, value, estatep, quoted, flags, varp, valp)
ccc6cda3 8247 char *varname, *value;
74091dd4 8248 array_eltstate_t *estatep;
495aee44 8249 int quoted, flags;
ccc6cda3
JA
8250 SHELL_VAR **varp;
8251 char **valp;
8252{
ac50fbac
CR
8253 int vtype, want_indir;
8254 char *temp, *vname;
ccc6cda3 8255 SHELL_VAR *v;
ccc6cda3 8256
ac50fbac
CR
8257 want_indir = *varname == '!' &&
8258 (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1])
8259 || VALID_INDIR_PARAM (varname[1]));
8260 if (want_indir)
8261 vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1);
a0c0a00f 8262 /* XXX - what if vname == 0 || *vname == 0 ? */
ac50fbac
CR
8263 else
8264 vname = varname;
a0c0a00f
CR
8265
8266 if (vname == 0)
8267 {
8268 vtype = VT_VARIABLE;
8269 *varp = (SHELL_VAR *)NULL;
8270 *valp = (char *)NULL;
8271 return (vtype);
8272 }
8273
7117c2d2 8274 /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
a0c0a00f 8275 vtype = STR_DOLLAR_AT_STAR (vname);
ac50fbac 8276 if (vtype == VT_POSPARMS && vname[0] == '*')
b80f6443 8277 vtype |= VT_STARSUB;
ccc6cda3
JA
8278 *varp = (SHELL_VAR *)NULL;
8279
8280#if defined (ARRAY_VARS)
a0c0a00f 8281 if (valid_array_reference (vname, 0))
ccc6cda3 8282 {
d233b485 8283 v = array_variable_part (vname, 0, &temp, (int *)0);
495aee44 8284 /* If we want to signal array_value to use an already-computed index,
74091dd4
CR
8285 the caller will set ESTATEP->IND to that index and pass AV_USEIND in
8286 FLAGS. */
8287 if (estatep && (flags & AV_USEIND) == 0)
8288 estatep->ind = INTMAX_MIN;
8289
ac50fbac
CR
8290 if (v && invisible_p (v))
8291 {
8292 vtype = VT_ARRAYMEMBER;
8293 *varp = (SHELL_VAR *)NULL;
8294 *valp = (char *)NULL;
8295 }
3185942a 8296 if (v && (array_p (v) || assoc_p (v)))
d233b485
CR
8297 {
8298 if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)
ccc6cda3 8299 {
ac50fbac 8300 /* Callers have to differentiate between indexed and associative */
ccc6cda3 8301 vtype = VT_ARRAYVAR;
b80f6443
JA
8302 if (temp[0] == '*')
8303 vtype |= VT_STARSUB;
3185942a 8304 *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
ccc6cda3
JA
8305 }
8306 else
8307 {
d166f048 8308 vtype = VT_ARRAYMEMBER;
74091dd4 8309 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
ccc6cda3
JA
8310 }
8311 *varp = v;
8312 }
d233b485
CR
8313 else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK))
8314 {
8315 vtype = VT_VARIABLE;
8316 *varp = v;
8317 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8868edaf 8318 *valp = value ? dequote_string (value) : (char *)NULL;
d233b485
CR
8319 else
8320 *valp = value ? dequote_escapes (value) : (char *)NULL;
8321 }
8322 else
8323 {
8324 vtype = VT_ARRAYMEMBER;
8325 *varp = v;
74091dd4 8326 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
d233b485
CR
8327 }
8328 }
8329 else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
8330 {
8331 vtype = VT_ARRAYMEMBER;
8332 *varp = v;
8333 *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
8334 }
8335 else
8336#endif
8337 {
8338 if (value && vtype == VT_VARIABLE)
8339 {
8340 *varp = find_variable (vname);
8341 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8342 *valp = dequote_string (value);
8343 else
8344 *valp = dequote_escapes (value);
8345 }
8346 else
8347 *valp = value;
8348 }
8349
8350 if (want_indir)
8351 free (vname);
8352
8353 return vtype;
8354}
8355
8356/***********************************************************/
8357/* */
8358/* Functions to perform transformations on variable values */
8359/* */
8360/***********************************************************/
8361
8362static char *
8363string_var_assignment (v, s)
8364 SHELL_VAR *v;
8365 char *s;
8366{
8367 char flags[MAX_ATTRIBUTES], *ret, *val;
8368 int i;
8369
8868edaf 8370 val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0);
d233b485 8371 i = var_attribute_string (v, 0, flags);
8868edaf
CR
8372 if (i == 0 && val == 0)
8373 return (char *)NULL;
8374
8375 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES);
8376 if (i > 0 && val == 0)
8377 sprintf (ret, "declare -%s %s", flags, v->name);
8378 else if (i > 0)
d233b485
CR
8379 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
8380 else
8381 sprintf (ret, "%s=%s", v->name, val);
8382 free (val);
8383 return ret;
8384}
8385
8386#if defined (ARRAY_VARS)
8387static char *
8868edaf 8388array_var_assignment (v, itype, quoted, atype)
d233b485 8389 SHELL_VAR *v;
8868edaf 8390 int itype, quoted, atype;
d233b485
CR
8391{
8392 char *ret, *val, flags[MAX_ATTRIBUTES];
8393 int i;
8394
8395 if (v == 0)
8396 return (char *)NULL;
8868edaf
CR
8397 if (atype == 2)
8398 val = array_p (v) ? array_to_kvpair (array_cell (v), 0)
8399 : assoc_to_kvpair (assoc_cell (v), 0);
8400 else
8401 val = array_p (v) ? array_to_assign (array_cell (v), 0)
8402 : assoc_to_assign (assoc_cell (v), 0);
8403
8404 if (val == 0 && (invisible_p (v) || var_isset (v) == 0))
8405 ; /* placeholder */
8406 else if (val == 0)
d233b485
CR
8407 {
8408 val = (char *)xmalloc (3);
8409 val[0] = LPAREN;
8410 val[1] = RPAREN;
8411 val[2] = 0;
8412 }
8413 else
8414 {
8415 ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val);
8416 free (val);
8417 val = ret;
8418 }
8868edaf
CR
8419
8420 if (atype == 2)
8421 return val;
8422
d233b485 8423 i = var_attribute_string (v, 0, flags);
8868edaf
CR
8424 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16);
8425 if (val)
8426 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
8427 else
8428 sprintf (ret, "declare -%s %s", flags, v->name);
d233b485
CR
8429 free (val);
8430 return ret;
8431}
8432#endif
8433
8434static char *
8435pos_params_assignment (list, itype, quoted)
8436 WORD_LIST *list;
8437 int itype;
8438 int quoted;
8439{
8440 char *temp, *ret;
8441
8442 /* first, we transform the list to quote each word. */
8443 temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted);
8444 ret = (char *)xmalloc (strlen (temp) + 8);
8445 strcpy (ret, "set -- ");
8446 strcpy (ret + 7, temp);
8447 free (temp);
8448 return ret;
8449}
8450
8451static char *
8452string_transform (xc, v, s)
8453 int xc;
8454 SHELL_VAR *v;
8455 char *s;
8456{
8457 char *ret, flags[MAX_ATTRIBUTES], *t;
8458 int i;
8459
8868edaf
CR
8460 if (((xc == 'A' || xc == 'a') && v == 0))
8461 return (char *)NULL;
8462 else if (xc != 'a' && xc != 'A' && s == 0)
d233b485
CR
8463 return (char *)NULL;
8464
8465 switch (xc)
8466 {
8467 /* Transformations that interrogate the variable */
8468 case 'a':
8469 i = var_attribute_string (v, 0, flags);
8470 ret = (i > 0) ? savestring (flags) : (char *)NULL;
8471 break;
8472 case 'A':
8473 ret = string_var_assignment (v, s);
8474 break;
8868edaf 8475 case 'K':
74091dd4 8476 case 'k':
8868edaf
CR
8477 ret = sh_quote_reusable (s, 0);
8478 break;
d233b485
CR
8479 /* Transformations that modify the variable's value */
8480 case 'E':
8481 t = ansiexpand (s, 0, strlen (s), (int *)0);
8482 ret = dequote_escapes (t);
8483 free (t);
8484 break;
8485 case 'P':
8486 ret = decode_prompt_string (s);
8487 break;
8488 case 'Q':
8489 ret = sh_quote_reusable (s, 0);
8490 break;
8868edaf
CR
8491 case 'U':
8492 ret = sh_modcase (s, 0, CASE_UPPER);
8493 break;
8494 case 'u':
8495 ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */
8496 break;
8497 case 'L':
8498 ret = sh_modcase (s, 0, CASE_LOWER);
8499 break;
d233b485
CR
8500 default:
8501 ret = (char *)NULL;
8502 break;
8503 }
8504 return ret;
8505}
8506
8507static char *
8508list_transform (xc, v, list, itype, quoted)
8509 int xc;
8510 SHELL_VAR *v;
8511 WORD_LIST *list;
8512 int itype, quoted;
8513{
8514 WORD_LIST *new, *l;
8515 WORD_DESC *w;
8516 char *tword;
8517 int qflags;
8518
8519 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
8520 {
8521 tword = string_transform (xc, v, l->word->word);
8522 w = alloc_word_desc ();
8523 w->word = tword ? tword : savestring (""); /* XXX */
8524 new = make_word_list (w, new);
8525 }
8526 l = REVERSE_LIST (new, WORD_LIST *);
8527
8528 qflags = quoted;
8529 /* If we are expanding in a context where word splitting will not be
8530 performed, treat as quoted. This changes how $* will be expanded. */
8531 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
8532 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8533
8868edaf 8534 tword = string_list_pos_params (itype, l, qflags, 0);
d233b485
CR
8535 dispose_words (l);
8536
8537 return (tword);
8538}
8539
8540static char *
8541parameter_list_transform (xc, itype, quoted)
8542 int xc;
8543 int itype;
8544 int quoted;
8545{
8546 char *ret;
8547 WORD_LIST *list;
8548
8549 list = list_rest_of_args ();
8550 if (list == 0)
8551 return ((char *)NULL);
8552 if (xc == 'A')
8553 ret = pos_params_assignment (list, itype, quoted);
8554 else
8555 ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted);
8556 dispose_words (list);
8557 return (ret);
8558}
8559
8560#if defined (ARRAY_VARS)
8561static char *
8868edaf 8562array_transform (xc, var, starsub, quoted)
d233b485
CR
8563 int xc;
8564 SHELL_VAR *var;
8868edaf 8565 int starsub; /* so we can figure out how it's indexed */
d233b485
CR
8566 int quoted;
8567{
8568 ARRAY *a;
8569 HASH_TABLE *h;
74091dd4 8570 int itype, qflags;
d233b485
CR
8571 char *ret;
8572 WORD_LIST *list;
8573 SHELL_VAR *v;
8574
8868edaf 8575 v = var; /* XXX - for now */
d233b485 8576
8868edaf 8577 itype = starsub ? '*' : '@';
d233b485
CR
8578
8579 if (xc == 'A')
8868edaf
CR
8580 return (array_var_assignment (v, itype, quoted, 1));
8581 else if (xc == 'K')
8582 return (array_var_assignment (v, itype, quoted, 2));
8583
8584 /* special case for unset arrays and attributes */
8585 if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0))
8586 {
8587 char flags[MAX_ATTRIBUTES];
8588 int i;
8589
8590 i = var_attribute_string (v, 0, flags);
8591 return ((i > 0) ? savestring (flags) : (char *)NULL);
8592 }
d233b485
CR
8593
8594 a = (v && array_p (v)) ? array_cell (v) : 0;
8595 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
8868edaf 8596
74091dd4
CR
8597 /* XXX - for now */
8598 if (xc == 'k')
8599 {
8600 if (v == 0)
8601 return ((char *)NULL);
8602 list = array_p (v) ? array_to_kvpair_list (a) : assoc_to_kvpair_list (h);
8603 qflags = quoted;
8604 /* If we are expanding in a context where word splitting will not be
8605 performed, treat as quoted. This changes how $* will be expanded. */
8606 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
8607 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8608
8609 ret = string_list_pos_params (itype, list, qflags, 0);
8610 dispose_words (list);
8611 return ret;
8612 }
8613
d233b485
CR
8614 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
8615 if (list == 0)
8616 return ((char *)NULL);
8617 ret = list_transform (xc, v, list, itype, quoted);
8618 dispose_words (list);
8619
8620 return ret;
8621}
8622#endif /* ARRAY_VARS */
8623
8868edaf
CR
8624static int
8625valid_parameter_transform (xform)
8626 char *xform;
8627{
8628 if (xform[1])
8629 return 0;
8630
8631 /* check for valid values of xform[0] */
8632 switch (xform[0])
8633 {
8634 case 'a': /* expand to a string with just attributes */
8635 case 'A': /* expand as an assignment statement with attributes */
8636 case 'K': /* expand assoc array to list of key/value pairs */
74091dd4 8637 case 'k': /* XXX - for now */
8868edaf
CR
8638 case 'E': /* expand like $'...' */
8639 case 'P': /* expand like prompt string */
8640 case 'Q': /* quote reusably */
8641 case 'U': /* transform to uppercase */
74091dd4 8642 case 'u': /* transform by capitalizing */
8868edaf
CR
8643 case 'L': /* transform to lowercase */
8644 return 1;
8645 default:
8646 return 0;
8647 }
8648}
8649
d233b485 8650static char *
74091dd4 8651parameter_brace_transform (varname, value, estatep, xform, rtype, quoted, pflags, flags)
d233b485 8652 char *varname, *value;
74091dd4 8653 array_eltstate_t *estatep;
d233b485
CR
8654 char *xform;
8655 int rtype, quoted, pflags, flags;
8656{
8868edaf 8657 int vtype, xc, starsub;
d233b485
CR
8658 char *temp1, *val, *oname;
8659 SHELL_VAR *v;
8660
8661 xc = xform[0];
8662 if (value == 0 && xc != 'A' && xc != 'a')
8663 return ((char *)NULL);
8664
8665 oname = this_command_name;
8666 this_command_name = varname;
8667
74091dd4 8668 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
d233b485
CR
8669 if (vtype == -1)
8670 {
8671 this_command_name = oname;
8672 return ((char *)NULL);
8673 }
8674
74091dd4 8675 if (xform[0] == 0 || valid_parameter_transform (xform) == 0)
d233b485 8676 {
d233b485 8677 this_command_name = oname;
74091dd4
CR
8678 if (vtype == VT_VARIABLE)
8679 FREE (val);
8868edaf 8680 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
d233b485
CR
8681 }
8682
8868edaf
CR
8683 starsub = vtype & VT_STARSUB;
8684 vtype &= ~VT_STARSUB;
8685
d233b485
CR
8686 /* If we are asked to display the attributes of an unset variable, V will
8687 be NULL after the call to get_var_and_type. Double-check here. */
8868edaf 8688 if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0)
d233b485
CR
8689 v = find_variable (varname);
8690
8691 temp1 = (char *)NULL; /* shut up gcc */
8868edaf 8692 switch (vtype)
d233b485
CR
8693 {
8694 case VT_VARIABLE:
8695 case VT_ARRAYMEMBER:
8696 temp1 = string_transform (xc, v, val);
8697 if (vtype == VT_VARIABLE)
8698 FREE (val);
8699 if (temp1)
8700 {
8701 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8702 ? quote_string (temp1)
8703 : quote_escapes (temp1);
8704 free (temp1);
8705 temp1 = val;
8706 }
8707 break;
8708#if defined (ARRAY_VARS)
8709 case VT_ARRAYVAR:
8868edaf 8710 temp1 = array_transform (xc, v, starsub, quoted);
d233b485 8711 if (temp1 && quoted == 0 && ifs_is_null)
95732b49 8712 {
d233b485 8713 /* Posix interp 888 */
95732b49 8714 }
d233b485 8715 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3185942a 8716 {
d233b485
CR
8717 val = quote_escapes (temp1);
8718 free (temp1);
8719 temp1 = val;
3185942a 8720 }
d233b485 8721 break;
ccc6cda3 8722#endif
d233b485
CR
8723 case VT_POSPARMS:
8724 temp1 = parameter_list_transform (xc, varname[0], quoted);
8725 if (temp1 && quoted == 0 && ifs_is_null)
b80f6443 8726 {
d233b485 8727 /* Posix interp 888 */
b80f6443 8728 }
d233b485
CR
8729 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
8730 {
8731 val = quote_escapes (temp1);
8732 free (temp1);
8733 temp1 = val;
8734 }
8735 break;
b80f6443 8736 }
ccc6cda3 8737
d233b485
CR
8738 this_command_name = oname;
8739 return temp1;
ccc6cda3
JA
8740}
8741
cce855bc
JA
8742/******************************************************/
8743/* */
8744/* Functions to extract substrings of variable values */
8745/* */
8746/******************************************************/
8747
b80f6443
JA
8748#if defined (HANDLE_MULTIBYTE)
8749/* Character-oriented rather than strictly byte-oriented substrings. S and
8750 E, rather being strict indices into STRING, indicate character (possibly
8751 multibyte character) positions that require calculation.
8752 Used by the ${param:offset[:length]} expansion. */
8753static char *
8754mb_substring (string, s, e)
8755 char *string;
8756 int s, e;
8757{
8758 char *tt;
a0c0a00f
CR
8759 int start, stop, i;
8760 size_t slen;
b80f6443
JA
8761 DECLARE_MBSTATE;
8762
8763 start = 0;
95732b49
JA
8764 /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
8765 slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
b80f6443
JA
8766
8767 i = s;
8768 while (string[start] && i--)
8769 ADVANCE_CHAR (string, slen, start);
8770 stop = start;
8771 i = e - s;
8772 while (string[stop] && i--)
8773 ADVANCE_CHAR (string, slen, stop);
8774 tt = substring (string, start, stop);
8775 return tt;
8776}
8777#endif
8778
ccc6cda3
JA
8779/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
8780 is `@', use the positional parameters; otherwise, use the value of
8781 VARNAME. If VARNAME is an array variable, use the array elements. */
8782
8783static char *
74091dd4 8784parameter_brace_substring (varname, value, estatep, substr, quoted, pflags, flags)
495aee44 8785 char *varname, *value;
74091dd4 8786 array_eltstate_t *estatep;
495aee44 8787 char *substr;
d233b485 8788 int quoted, pflags, flags;
ccc6cda3 8789{
7117c2d2 8790 intmax_t e1, e2;
b80f6443 8791 int vtype, r, starsub;
0628567a 8792 char *temp, *val, *tt, *oname;
ccc6cda3
JA
8793 SHELL_VAR *v;
8794
a0c0a00f 8795 if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1]))
ccc6cda3
JA
8796 return ((char *)NULL);
8797
0628567a 8798 oname = this_command_name;
ccc6cda3
JA
8799 this_command_name = varname;
8800
74091dd4 8801 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
ccc6cda3 8802 if (vtype == -1)
0628567a
JA
8803 {
8804 this_command_name = oname;
8805 return ((char *)NULL);
8806 }
ccc6cda3 8807
b80f6443
JA
8808 starsub = vtype & VT_STARSUB;
8809 vtype &= ~VT_STARSUB;
8810
3185942a 8811 r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
0628567a 8812 this_command_name = oname;
e8ce775d 8813 if (r <= 0)
ac50fbac
CR
8814 {
8815 if (vtype == VT_VARIABLE)
8816 FREE (val);
8817 return ((r == 0) ? &expand_param_error : (char *)NULL);
8818 }
ccc6cda3
JA
8819
8820 switch (vtype)
8821 {
8822 case VT_VARIABLE:
d166f048 8823 case VT_ARRAYMEMBER:
b80f6443
JA
8824#if defined (HANDLE_MULTIBYTE)
8825 if (MB_CUR_MAX > 1)
8826 tt = mb_substring (val, e1, e2);
8827 else
8828#endif
7117c2d2 8829 tt = substring (val, e1, e2);
b80f6443 8830
7117c2d2
JA
8831 if (vtype == VT_VARIABLE)
8832 FREE (val);
8833 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8834 temp = quote_string (tt);
8835 else
8836 temp = tt ? quote_escapes (tt) : (char *)NULL;
8837 FREE (tt);
ccc6cda3
JA
8838 break;
8839 case VT_POSPARMS:
d233b485
CR
8840 case VT_ARRAYVAR:
8841 if (vtype == VT_POSPARMS)
8868edaf 8842 tt = pos_params (varname, e1, e2, quoted, pflags);
d233b485
CR
8843#if defined (ARRAY_VARS)
8844 /* assoc_subrange and array_subrange both call string_list_pos_params,
8845 so we can treat this case just like VT_POSPARAMS. */
8846 else if (assoc_p (v))
8847 /* we convert to list and take first e2 elements starting at e1th
8848 element -- officially undefined for now */
8868edaf 8849 tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags);
d233b485
CR
8850 else
8851 /* We want E2 to be the number of elements desired (arrays can be
8852 sparse, so verify_substring_values just returns the numbers
8853 specified and we rely on array_subrange to understand how to
8854 deal with them). */
8868edaf 8855 tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags);
d233b485
CR
8856#endif
8857 /* We want to leave this alone in every case where pos_params/
8858 string_list_pos_params quotes the list members */
8859 if (tt && quoted == 0 && ifs_is_null)
8860 {
8861 temp = tt; /* Posix interp 888 */
8862 }
8868edaf
CR
8863 else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS))
8864 {
8865 temp = tt; /* Posix interp 888 */
8866 }
d233b485 8867 else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
7117c2d2
JA
8868 {
8869 temp = tt ? quote_escapes (tt) : (char *)NULL;
8870 FREE (tt);
8871 }
8872 else
8873 temp = tt;
ccc6cda3 8874 break;
d233b485 8875
f73dda09
JA
8876 default:
8877 temp = (char *)NULL;
ccc6cda3
JA
8878 }
8879
8880 return temp;
8881}
8882
cce855bc
JA
8883/****************************************************************/
8884/* */
8885/* Functions to perform pattern substitution on variable values */
8886/* */
8887/****************************************************************/
8888
495aee44
CR
8889static int
8890shouldexp_replacement (s)
8891 char *s;
8892{
74091dd4
CR
8893 size_t slen;
8894 int sindex, c;
8895 DECLARE_MBSTATE;
495aee44 8896
74091dd4
CR
8897 sindex = 0;
8898 slen = STRLEN (s);
8899 while (c = s[sindex])
495aee44 8900 {
74091dd4
CR
8901 if (c == '\\')
8902 {
8903 sindex++;
8904 if (s[sindex] == 0)
8905 return 0;
8906 /* We want to remove this backslash because we treat it as special
8907 in this context. THIS ASSUMES THE STRING IS PROCESSED BY
8908 strcreplace() OR EQUIVALENT that handles removing backslashes
8909 preceding the special character. */
8910 if (s[sindex] == '&')
8911 return 1;
8912 if (s[sindex] == '\\')
8913 return 1;
8914 }
8915 else if (c == '&')
495aee44 8916 return 1;
74091dd4 8917 ADVANCE_CHAR (s, slen, sindex);
495aee44
CR
8918 }
8919 return 0;
8920}
8921
ccc6cda3
JA
8922char *
8923pat_subst (string, pat, rep, mflags)
8924 char *string, *pat, *rep;
8925 int mflags;
8926{
8868edaf 8927 char *ret, *s, *e, *str, *rstr, *mstr, *send;
a0c0a00f
CR
8928 int rptr, mtype, rxpand, mlen;
8929 size_t rsize, l, replen, rslen;
8868edaf 8930 DECLARE_MBSTATE;
495aee44 8931
d233b485 8932 if (string == 0)
495aee44 8933 return (savestring (""));
ccc6cda3 8934
b72432fd 8935 mtype = mflags & MATCH_TYPEMASK;
74091dd4 8936 rxpand = mflags & MATCH_EXPREP;
495aee44 8937
b72432fd
JA
8938 /* Special cases:
8939 * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
8940 * with REP and return the result.
8941 * 2. A null pattern with mtype == MATCH_END means to append REP to
8942 * STRING and return the result.
a0c0a00f
CR
8943 * 3. A null STRING with a matching pattern means to append REP to
8944 * STRING and return the result.
74091dd4
CR
8945 *
8946 * These process `&' in the replacement string, like `sed' does when
8947 * presented with a BRE of `^' or `$'.
b72432fd
JA
8948 */
8949 if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
8950 {
74091dd4
CR
8951 rstr = (mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2) : rep;
8952 rslen = STRLEN (rstr);
495aee44 8953 l = STRLEN (string);
74091dd4
CR
8954 ret = (char *)xmalloc (rslen + l + 2);
8955 if (rslen == 0)
bb70624e
JA
8956 strcpy (ret, string);
8957 else if (mtype == MATCH_BEG)
b72432fd 8958 {
74091dd4
CR
8959 strcpy (ret, rstr);
8960 strcpy (ret + rslen, string);
b72432fd
JA
8961 }
8962 else
8963 {
8964 strcpy (ret, string);
74091dd4 8965 strcpy (ret + l, rstr);
b72432fd 8966 }
74091dd4
CR
8967 if (rstr != rep)
8968 free (rstr);
b72432fd
JA
8969 return (ret);
8970 }
a0c0a00f 8971 else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
7b9954e6
CR
8972 return (mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2)
8973 : (rep ? savestring (rep) : savestring (""));
b72432fd 8974
f73dda09 8975 ret = (char *)xmalloc (rsize = 64);
ccc6cda3 8976 ret[0] = '\0';
8868edaf 8977 send = string + strlen (string);
ccc6cda3 8978
a0c0a00f 8979 for (replen = STRLEN (rep), rptr = 0, str = string; *str;)
ccc6cda3
JA
8980 {
8981 if (match_pattern (str, pat, mtype, &s, &e) == 0)
8982 break;
8983 l = s - str;
495aee44 8984
a0c0a00f 8985 if (rep && rxpand)
495aee44 8986 {
a0c0a00f
CR
8987 int x;
8988 mlen = e - s;
8989 mstr = xmalloc (mlen + 1);
495aee44
CR
8990 for (x = 0; x < mlen; x++)
8991 mstr[x] = s[x];
a0c0a00f 8992 mstr[mlen] = '\0';
74091dd4 8993 rstr = strcreplace (rep, '&', mstr, 2);
a0c0a00f
CR
8994 free (mstr);
8995 rslen = strlen (rstr);
495aee44
CR
8996 }
8997 else
a0c0a00f
CR
8998 {
8999 rstr = rep;
9000 rslen = replen;
9001 }
495aee44
CR
9002
9003 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
ccc6cda3
JA
9004
9005 /* OK, now copy the leading unmatched portion of the string (from
9006 str to s) to ret starting at rptr (the current offset). Then copy
28ef6c31
JA
9007 the replacement string at ret + rptr + (s - str). Increment
9008 rptr (if necessary) and str and go on. */
ccc6cda3
JA
9009 if (l)
9010 {
9011 strncpy (ret + rptr, str, l);
9012 rptr += l;
9013 }
9014 if (replen)
9015 {
495aee44
CR
9016 strncpy (ret + rptr, rstr, rslen);
9017 rptr += rslen;
ccc6cda3
JA
9018 }
9019 str = e; /* e == end of match */
b80f6443 9020
495aee44
CR
9021 if (rstr != rep)
9022 free (rstr);
9023
ccc6cda3 9024 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
28ef6c31 9025 break;
b80f6443
JA
9026
9027 if (s == e)
0001803f
CR
9028 {
9029 /* On a zero-length match, make sure we copy one character, since
9030 we increment one character to avoid infinite recursion. */
8868edaf
CR
9031 char *p, *origp, *origs;
9032 size_t clen;
9033
9034 RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64);
9035#if defined (HANDLE_MULTIBYTE)
9036 p = origp = ret + rptr;
9037 origs = str;
9038 COPY_CHAR_P (p, str, send);
9039 rptr += p - origp;
9040 e += str - origs;
9041#else
0001803f
CR
9042 ret[rptr++] = *str++;
9043 e++; /* avoid infinite recursion on zero-length match */
8868edaf 9044#endif
0001803f 9045 }
ccc6cda3
JA
9046 }
9047
9048 /* Now copy the unmatched portion of the input string */
495aee44 9049 if (str && *str)
d166f048 9050 {
74091dd4
CR
9051 l = send - str + 1;
9052 RESIZE_MALLOCED_BUFFER (ret, rptr, l, rsize, 64);
d166f048
JA
9053 strcpy (ret + rptr, str);
9054 }
ccc6cda3
JA
9055 else
9056 ret[rptr] = '\0';
9057
9058 return ret;
9059}
9060
9061/* Do pattern match and replacement on the positional parameters. */
9062static char *
9063pos_params_pat_subst (string, pat, rep, mflags)
9064 char *string, *pat, *rep;
9065 int mflags;
9066{
9067 WORD_LIST *save, *params;
9068 WORD_DESC *w;
0628567a 9069 char *ret;
8868edaf 9070 int pchar, qflags, pflags;
ccc6cda3
JA
9071
9072 save = params = list_rest_of_args ();
9073 if (save == 0)
9074 return ((char *)NULL);
9075
9076 for ( ; params; params = params->next)
9077 {
9078 ret = pat_subst (params->word->word, pat, rep, mflags);
95732b49
JA
9079 w = alloc_word_desc ();
9080 w->word = ret ? ret : savestring ("");
ccc6cda3
JA
9081 dispose_word (params->word);
9082 params->word = w;
ccc6cda3
JA
9083 }
9084
3185942a
JA
9085 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
9086 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
8868edaf 9087 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
3185942a 9088
d233b485
CR
9089 /* If we are expanding in a context where word splitting will not be
9090 performed, treat as quoted. This changes how $* will be expanded. */
9091 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null)
9092 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
3185942a 9093
8868edaf 9094 ret = string_list_pos_params (pchar, save, qflags, pflags);
ccc6cda3
JA
9095 dispose_words (save);
9096
9097 return (ret);
9098}
9099
cce855bc
JA
9100/* Perform pattern substitution on VALUE, which is the expansion of
9101 VARNAME. PATSUB is an expression supplying the pattern to match
9102 and the string to substitute. QUOTED is a flags word containing
9103 the type of quoting currently in effect. */
ccc6cda3 9104static char *
74091dd4 9105parameter_brace_patsub (varname, value, estatep, patsub, quoted, pflags, flags)
495aee44 9106 char *varname, *value;
74091dd4 9107 array_eltstate_t *estatep;
495aee44 9108 char *patsub;
a0c0a00f 9109 int quoted, pflags, flags;
ccc6cda3 9110{
3185942a 9111 int vtype, mflags, starsub, delim;
d233b485 9112 char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname;
ccc6cda3
JA
9113 SHELL_VAR *v;
9114
9115 if (value == 0)
9116 return ((char *)NULL);
9117
d233b485
CR
9118 oname = this_command_name;
9119 this_command_name = varname; /* error messages */
ccc6cda3 9120
74091dd4 9121 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
ccc6cda3 9122 if (vtype == -1)
d233b485
CR
9123 {
9124 this_command_name = oname;
9125 return ((char *)NULL);
9126 }
ccc6cda3 9127
b80f6443
JA
9128 starsub = vtype & VT_STARSUB;
9129 vtype &= ~VT_STARSUB;
9130
ccc6cda3 9131 mflags = 0;
ac50fbac
CR
9132 /* PATSUB is never NULL when this is called. */
9133 if (*patsub == '/')
f1be666c
JA
9134 {
9135 mflags |= MATCH_GLOBREP;
9136 patsub++;
9137 }
7117c2d2
JA
9138
9139 /* Malloc this because expand_string_if_necessary or one of the expansion
9140 functions in its call chain may free it on a substitution error. */
bb70624e 9141 lpatsub = savestring (patsub);
ccc6cda3
JA
9142
9143 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9144 mflags |= MATCH_QUOTED;
9145
b80f6443
JA
9146 if (starsub)
9147 mflags |= MATCH_STARSUB;
9148
a0c0a00f
CR
9149 if (pflags & PF_ASSIGNRHS)
9150 mflags |= MATCH_ASSIGNRHS;
9151
0628567a
JA
9152 /* If the pattern starts with a `/', make sure we skip over it when looking
9153 for the replacement delimiter. */
3185942a
JA
9154 delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
9155 if (lpatsub[delim] == '/')
9156 {
9157 lpatsub[delim] = 0;
9158 rep = lpatsub + delim + 1;
9159 }
9160 else
9161 rep = (char *)NULL;
ccc6cda3
JA
9162
9163 if (rep && *rep == '\0')
9164 rep = (char *)NULL;
9165
b80f6443
JA
9166 /* Perform the same expansions on the pattern as performed by the
9167 pattern removal expansions. */
9168 pat = getpattern (lpatsub, quoted, 1);
bb70624e 9169
ccc6cda3 9170 if (rep)
d166f048 9171 {
ac50fbac
CR
9172 /* We want to perform quote removal on the expanded replacement even if
9173 the entire expansion is double-quoted because the parser and string
9174 extraction functions treated quotes in the replacement string as
9175 special. THIS IS NOT BACKWARDS COMPATIBLE WITH BASH-4.2. */
74091dd4 9176 if (shell_compatibility_level > 42 && patsub_replacement == 0)
ac50fbac 9177 rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
74091dd4
CR
9178 else if (shell_compatibility_level > 42 && patsub_replacement)
9179 rep = expand_string_for_patsub (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT));
ac50fbac
CR
9180 /* This is the bash-4.2 code. */
9181 else if ((mflags & MATCH_QUOTED) == 0)
f73dda09 9182 rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
d166f048 9183 else
f73dda09 9184 rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
74091dd4
CR
9185
9186 /* Check whether or not to replace `&' in the replacement string after
9187 expanding it, since we want to treat backslashes quoting the `&'
9188 consistently. */
9189 if (patsub_replacement && rep && *rep && shouldexp_replacement (rep))
9190 mflags |= MATCH_EXPREP;
9191
d166f048 9192 }
ccc6cda3 9193
0628567a 9194 /* ksh93 doesn't allow the match specifier to be a part of the expanded
f1be666c
JA
9195 pattern. This is an extension. Make sure we don't anchor the pattern
9196 at the beginning or end of the string if we're doing global replacement,
9197 though. */
ccc6cda3 9198 p = pat;
f1be666c
JA
9199 if (mflags & MATCH_GLOBREP)
9200 mflags |= MATCH_ANY;
0628567a 9201 else if (pat && pat[0] == '#')
ccc6cda3
JA
9202 {
9203 mflags |= MATCH_BEG;
9204 p++;
9205 }
d166f048 9206 else if (pat && pat[0] == '%')
ccc6cda3
JA
9207 {
9208 mflags |= MATCH_END;
9209 p++;
9210 }
9211 else
9212 mflags |= MATCH_ANY;
9213
cce855bc
JA
9214 /* OK, we now want to substitute REP for PAT in VAL. If
9215 flags & MATCH_GLOBREP is non-zero, the substitution is done
9216 everywhere, otherwise only the first occurrence of PAT is
7117c2d2
JA
9217 replaced. The pattern matching code doesn't understand
9218 CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
9219 values passed in (VT_VARIABLE) so the pattern substitution
9220 code works right. We need to requote special chars after
9221 we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
9222 other cases if QUOTED == 0, since the posparams and arrays
9223 indexed by * or @ do special things when QUOTED != 0. */
9224
ccc6cda3
JA
9225 switch (vtype)
9226 {
9227 case VT_VARIABLE:
d166f048 9228 case VT_ARRAYMEMBER:
ccc6cda3 9229 temp = pat_subst (val, p, rep, mflags);
7117c2d2
JA
9230 if (vtype == VT_VARIABLE)
9231 FREE (val);
9232 if (temp)
9233 {
3185942a 9234 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
7117c2d2
JA
9235 free (temp);
9236 temp = tt;
9237 }
ccc6cda3
JA
9238 break;
9239 case VT_POSPARMS:
d233b485
CR
9240 /* This does the right thing for the case where we are not performing
9241 word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and
9242 pos_params_pat_subst/string_list_pos_params will do the right thing
9243 in turn for the case where ifs_is_null. Posix interp 888 */
9244 if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB))
9245 mflags |= MATCH_ASSIGNRHS;
ccc6cda3 9246 temp = pos_params_pat_subst (val, p, rep, mflags);
d233b485
CR
9247 if (temp && quoted == 0 && ifs_is_null)
9248 {
9249 /* Posix interp 888 */
9250 }
8868edaf
CR
9251 else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS))
9252 {
9253 /* Posix interp 888 */
9254 }
d233b485 9255 else if (temp && (mflags & MATCH_QUOTED) == 0)
7117c2d2
JA
9256 {
9257 tt = quote_escapes (temp);
9258 free (temp);
9259 temp = tt;
9260 }
ccc6cda3
JA
9261 break;
9262#if defined (ARRAY_VARS)
9263 case VT_ARRAYVAR:
d233b485
CR
9264 /* If we are expanding in a context where word splitting will not be
9265 performed, treat as quoted. This changes how ${A[*]} will be
9266 expanded to make it identical to $*. */
9267 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9268 mflags |= MATCH_QUOTED; /* Posix interp 888 */
9269
9270 /* these eventually call string_list_pos_params */
9271 if (assoc_p (v))
9272 temp = assoc_patsub (assoc_cell (v), p, rep, mflags);
9273 else
9274 temp = array_patsub (array_cell (v), p, rep, mflags);
9275
9276 if (temp && quoted == 0 && ifs_is_null)
9277 {
9278 /* Posix interp 888 */
9279 }
9280 else if (temp && (mflags & MATCH_QUOTED) == 0)
9281 {
9282 tt = quote_escapes (temp);
9283 free (temp);
9284 temp = tt;
9285 }
3185942a
JA
9286 break;
9287#endif
9288 }
9289
9290 FREE (pat);
9291 FREE (rep);
9292 free (lpatsub);
9293
d233b485
CR
9294 this_command_name = oname;
9295
3185942a
JA
9296 return temp;
9297}
9298
9299/****************************************************************/
9300/* */
9301/* Functions to perform case modification on variable values */
9302/* */
9303/****************************************************************/
9304
9305/* Do case modification on the positional parameters. */
9306
9307static char *
9308pos_params_modcase (string, pat, modop, mflags)
9309 char *string, *pat;
9310 int modop;
9311 int mflags;
9312{
9313 WORD_LIST *save, *params;
9314 WORD_DESC *w;
9315 char *ret;
8868edaf 9316 int pchar, qflags, pflags;
3185942a
JA
9317
9318 save = params = list_rest_of_args ();
9319 if (save == 0)
9320 return ((char *)NULL);
9321
9322 for ( ; params; params = params->next)
9323 {
9324 ret = sh_modcase (params->word->word, pat, modop);
9325 w = alloc_word_desc ();
9326 w->word = ret ? ret : savestring ("");
9327 dispose_word (params->word);
9328 params->word = w;
9329 }
9330
9331 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
9332 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
8868edaf 9333 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
3185942a 9334
d233b485
CR
9335 /* If we are expanding in a context where word splitting will not be
9336 performed, treat as quoted. This changes how $* will be expanded. */
9337 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9338 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
9339
8868edaf 9340 ret = string_list_pos_params (pchar, save, qflags, pflags);
3185942a
JA
9341 dispose_words (save);
9342
9343 return (ret);
9344}
9345
9346/* Perform case modification on VALUE, which is the expansion of
9347 VARNAME. MODSPEC is an expression supplying the type of modification
9348 to perform. QUOTED is a flags word containing the type of quoting
9349 currently in effect. */
9350static char *
74091dd4 9351parameter_brace_casemod (varname, value, estatep, modspec, patspec, quoted, pflags, flags)
3185942a 9352 char *varname, *value;
74091dd4
CR
9353 array_eltstate_t *estatep;
9354 int modspec;
3185942a 9355 char *patspec;
d233b485 9356 int quoted, pflags, flags;
3185942a
JA
9357{
9358 int vtype, starsub, modop, mflags, x;
d233b485 9359 char *val, *temp, *pat, *p, *lpat, *tt, *oname;
3185942a
JA
9360 SHELL_VAR *v;
9361
9362 if (value == 0)
9363 return ((char *)NULL);
9364
d233b485 9365 oname = this_command_name;
3185942a
JA
9366 this_command_name = varname;
9367
74091dd4 9368 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
3185942a 9369 if (vtype == -1)
d233b485
CR
9370 {
9371 this_command_name = oname;
9372 return ((char *)NULL);
9373 }
3185942a
JA
9374
9375 starsub = vtype & VT_STARSUB;
9376 vtype &= ~VT_STARSUB;
9377
9378 modop = 0;
9379 mflags = 0;
9380 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9381 mflags |= MATCH_QUOTED;
9382 if (starsub)
9383 mflags |= MATCH_STARSUB;
d233b485
CR
9384 if (pflags & PF_ASSIGNRHS)
9385 mflags |= MATCH_ASSIGNRHS;
3185942a
JA
9386
9387 p = patspec;
9388 if (modspec == '^')
9389 {
9390 x = p && p[0] == modspec;
17345e5a 9391 modop = x ? CASE_UPPER : CASE_UPFIRST;
3185942a
JA
9392 p += x;
9393 }
9394 else if (modspec == ',')
9395 {
9396 x = p && p[0] == modspec;
17345e5a 9397 modop = x ? CASE_LOWER : CASE_LOWFIRST;
3185942a
JA
9398 p += x;
9399 }
9400 else if (modspec == '~')
9401 {
9402 x = p && p[0] == modspec;
9403 modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
9404 p += x;
9405 }
9406
9407 lpat = p ? savestring (p) : 0;
9408 /* Perform the same expansions on the pattern as performed by the
d233b485 9409 pattern removal expansions. */
3185942a
JA
9410 pat = lpat ? getpattern (lpat, quoted, 1) : 0;
9411
9412 /* OK, now we do the case modification. */
9413 switch (vtype)
9414 {
9415 case VT_VARIABLE:
9416 case VT_ARRAYMEMBER:
9417 temp = sh_modcase (val, pat, modop);
9418 if (vtype == VT_VARIABLE)
9419 FREE (val);
9420 if (temp)
9421 {
9422 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
9423 free (temp);
9424 temp = tt;
9425 }
9426 break;
9427
9428 case VT_POSPARMS:
9429 temp = pos_params_modcase (val, pat, modop, mflags);
d233b485
CR
9430 if (temp && quoted == 0 && ifs_is_null)
9431 {
9432 /* Posix interp 888 */
9433 }
9434 else if (temp && (mflags & MATCH_QUOTED) == 0)
7117c2d2
JA
9435 {
9436 tt = quote_escapes (temp);
9437 free (temp);
9438 temp = tt;
9439 }
3185942a
JA
9440 break;
9441
9442#if defined (ARRAY_VARS)
9443 case VT_ARRAYVAR:
d233b485
CR
9444 /* If we are expanding in a context where word splitting will not be
9445 performed, treat as quoted. This changes how ${A[*]} will be
9446 expanded to make it identical to $*. */
9447 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9448 mflags |= MATCH_QUOTED; /* Posix interp 888 */
9449
3185942a
JA
9450 temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
9451 : array_modcase (array_cell (v), pat, modop, mflags);
d233b485
CR
9452
9453 if (temp && quoted == 0 && ifs_is_null)
9454 {
9455 /* Posix interp 888 */
9456 }
9457 else if (temp && (mflags & MATCH_QUOTED) == 0)
9458 {
9459 tt = quote_escapes (temp);
9460 free (temp);
9461 temp = tt;
9462 }
9463
ccc6cda3
JA
9464 break;
9465#endif
9466 }
9467
9468 FREE (pat);
3185942a 9469 free (lpat);
ccc6cda3 9470
d233b485
CR
9471 this_command_name = oname;
9472
ccc6cda3
JA
9473 return temp;
9474}
9475
0628567a
JA
9476/* Check for unbalanced parens in S, which is the contents of $(( ... )). If
9477 any occur, this must be a nested command substitution, so return 0.
9478 Otherwise, return 1. A valid arithmetic expression must always have a
9479 ( before a matching ), so any cases where there are more right parens
9480 means that this must not be an arithmetic expression, though the parser
9481 will not accept it without a balanced total number of parens. */
9482static int
9483chk_arithsub (s, len)
9484 const char *s;
9485 int len;
9486{
9487 int i, count;
9488 DECLARE_MBSTATE;
9489
9490 i = count = 0;
9491 while (i < len)
9492 {
0001803f 9493 if (s[i] == LPAREN)
0628567a 9494 count++;
0001803f 9495 else if (s[i] == RPAREN)
0628567a
JA
9496 {
9497 count--;
9498 if (count < 0)
9499 return 0;
9500 }
9501
9502 switch (s[i])
9503 {
9504 default:
9505 ADVANCE_CHAR (s, len, i);
9506 break;
9507
9508 case '\\':
9509 i++;
9510 if (s[i])
9511 ADVANCE_CHAR (s, len, i);
9512 break;
9513
9514 case '\'':
a0c0a00f 9515 i = skip_single_quoted (s, len, ++i, 0);
0628567a
JA
9516 break;
9517
9518 case '"':
a0c0a00f 9519 i = skip_double_quoted ((char *)s, len, ++i, 0);
0628567a
JA
9520 break;
9521 }
9522 }
9523
9524 return (count == 0);
9525}
9526
cce855bc
JA
9527/****************************************************************/
9528/* */
9529/* Functions to perform parameter expansion on a string */
9530/* */
9531/****************************************************************/
9532
3185942a 9533/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
95732b49 9534static WORD_DESC *
0001803f 9535parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
ccc6cda3 9536 char *string;
a0c0a00f 9537 int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at;
ccc6cda3
JA
9538{
9539 int check_nullness, var_is_set, var_is_null, var_is_special;
8868edaf 9540 int want_substring, want_indir, want_patsub, want_casemod, want_attributes;
ccc6cda3 9541 char *name, *value, *temp, *temp1;
95732b49 9542 WORD_DESC *tdesc, *ret;
8868edaf 9543 int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref;
7117c2d2 9544 intmax_t number;
74091dd4 9545 array_eltstate_t es;
ccc6cda3 9546
3185942a 9547 temp = temp1 = value = (char *)NULL;
ccc6cda3 9548 var_is_set = var_is_null = var_is_special = check_nullness = 0;
8868edaf 9549 want_substring = want_indir = want_patsub = want_casemod = want_attributes = 0;
ccc6cda3 9550
8868edaf 9551 local_pflags = 0;
a0c0a00f
CR
9552 all_element_arrayref = 0;
9553
cce855bc
JA
9554 sindex = *indexp;
9555 t_index = ++sindex;
0628567a
JA
9556 /* ${#var} doesn't have any of the other parameter expansions on it. */
9557 if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
3185942a 9558 name = string_extract (string, &t_index, "}", SX_VARNAME);
0628567a 9559 else
3185942a
JA
9560#if defined (CASEMOD_EXPANSIONS)
9561 /* To enable case-toggling expansions using the `~' operator character
8868edaf
CR
9562 define CASEMOD_TOGGLECASE in config-top.h */
9563# if defined (CASEMOD_TOGGLECASE)
a0c0a00f 9564 name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME);
3185942a 9565# else
a0c0a00f 9566 name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME);
8868edaf 9567# endif /* CASEMOD_TOGGLECASE */
3185942a 9568#else
a0c0a00f 9569 name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME);
3185942a 9570#endif /* CASEMOD_EXPANSIONS */
cce855bc 9571
a0c0a00f
CR
9572 /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly
9573 the cleanest code ever. */
9574 if (*name == 0 && sindex == t_index && string[sindex] == '@')
9575 {
9576 name = (char *)xrealloc (name, 2);
9577 name[0] = '@';
9578 name[1] = '\0';
9579 t_index++;
9580 }
d233b485 9581 else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE)
a0c0a00f
CR
9582 {
9583 name = (char *)xrealloc (name, t_index - sindex + 2);
9584 name[t_index - sindex] = '@';
9585 name[t_index - sindex + 1] = '\0';
9586 t_index++;
9587 }
9588
95732b49
JA
9589 ret = 0;
9590 tflag = 0;
9591
74091dd4
CR
9592#if defined (ARRAY_VARS)
9593 init_eltstate (&es);
9594#endif
9595 es.ind = INTMAX_MIN; /* XXX */
495aee44 9596
cce855bc
JA
9597 /* If the name really consists of a special variable, then make sure
9598 that we have the entire name. We don't allow indirect references
a0c0a00f
CR
9599 to special variables except `#', `?', `@' and `*'. This clause is
9600 designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more
9601 general. */
495aee44 9602 if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
a0c0a00f 9603 (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) ||
495aee44 9604 (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
ccc6cda3
JA
9605 {
9606 t_index++;
a0c0a00f 9607 temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0);
ac50fbac 9608 name = (char *)xrealloc (name, 3 + (strlen (temp1)));
ccc6cda3
JA
9609 *name = string[sindex];
9610 if (string[sindex] == '!')
9611 {
28ef6c31
JA
9612 /* indirect reference of $#, $?, $@, or $* */
9613 name[1] = string[sindex + 1];
9614 strcpy (name + 2, temp1);
ccc6cda3 9615 }
cce855bc 9616 else
ccc6cda3
JA
9617 strcpy (name + 1, temp1);
9618 free (temp1);
9619 }
9620 sindex = t_index;
9621
9622 /* Find out what character ended the variable name. Then
9623 do the appropriate thing. */
9624 if (c = string[sindex])
9625 sindex++;
9626
9627 /* If c is followed by one of the valid parameter expansion
9628 characters, move past it as normal. If not, assume that
9629 a substring specification is being given, and do not move
9630 past it. */
28ef6c31 9631 if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
ccc6cda3
JA
9632 {
9633 check_nullness++;
9634 if (c = string[sindex])
9635 sindex++;
9636 }
cce855bc 9637 else if (c == ':' && string[sindex] != RBRACE)
ccc6cda3 9638 want_substring = 1;
ac50fbac 9639 else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */
ccc6cda3 9640 want_patsub = 1;
3185942a
JA
9641#if defined (CASEMOD_EXPANSIONS)
9642 else if (c == '^' || c == ',' || c == '~')
9643 {
9644 modspec = c;
9645 want_casemod = 1;
9646 }
9647#endif
8868edaf
CR
9648 else if (c == '@' && (string[sindex] == 'a' || string[sindex] == 'A') && string[sindex+1] == RBRACE)
9649 {
9650 /* special case because we do not want to shortcut foo as foo[0] here */
9651 want_attributes = 1;
9652 local_pflags |= PF_ALLINDS;
9653 }
ccc6cda3 9654
cce855bc
JA
9655 /* Catch the valid and invalid brace expressions that made it through the
9656 tests above. */
9657 /* ${#-} is a valid expansion and means to take the length of $-.
9658 Similarly for ${#?} and ${##}... */
9659 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
28ef6c31 9660 VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
cce855bc 9661 {
f73dda09 9662 name = (char *)xrealloc (name, 3);
cce855bc
JA
9663 name[1] = c;
9664 name[2] = '\0';
9665 c = string[sindex++];
9666 }
9667
9668 /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
9669 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
9670 member (c, "%:=+/") && string[sindex] == RBRACE)
9671 {
9672 temp = (char *)NULL;
a0c0a00f 9673 goto bad_substitution; /* XXX - substitution error */
cce855bc
JA
9674 }
9675
9676 /* Indirect expansion begins with a `!'. A valid indirect expansion is
9677 either a variable name, one of the positional parameters or a special
9678 variable that expands to one of the positional parameters. */
9679 want_indir = *name == '!' &&
f73dda09 9680 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
7117c2d2 9681 || VALID_INDIR_PARAM (name[1]));
ccc6cda3 9682
d233b485 9683 /* Determine the value of this variable whose name is NAME. */
ccc6cda3 9684
cce855bc 9685 /* Check for special variables, directly referenced. */
bb70624e 9686 if (SPECIAL_VAR (name, want_indir))
ccc6cda3
JA
9687 var_is_special++;
9688
cce855bc
JA
9689 /* Check for special expansion things, like the length of a parameter */
9690 if (*name == '#' && name[1])
ccc6cda3 9691 {
cce855bc 9692 /* If we are not pointing at the character just after the
28ef6c31
JA
9693 closing brace, then we haven't gotten all of the name.
9694 Since it begins with a special character, this is a bad
9695 substitution. Also check NAME for validity before trying
9696 to go on. */
cce855bc 9697 if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
ccc6cda3
JA
9698 {
9699 temp = (char *)NULL;
a0c0a00f 9700 goto bad_substitution; /* substitution error */
ccc6cda3
JA
9701 }
9702
9703 number = parameter_brace_expand_length (name);
495aee44
CR
9704 if (number == INTMAX_MIN && unbound_vars_is_error)
9705 {
8868edaf 9706 set_exit_status (EXECUTION_FAILURE);
495aee44
CR
9707 err_unboundvar (name+1);
9708 free (name);
9709 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9710 }
ccc6cda3
JA
9711 free (name);
9712
9713 *indexp = sindex;
95732b49
JA
9714 if (number < 0)
9715 return (&expand_wdesc_error);
9716 else
9717 {
9718 ret = alloc_word_desc ();
9719 ret->word = itos (number);
9720 return ret;
9721 }
ccc6cda3
JA
9722 }
9723
9724 /* ${@} is identical to $@. */
9725 if (name[0] == '@' && name[1] == '\0')
9726 {
9727 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9728 *quoted_dollar_atp = 1;
9729
9730 if (contains_dollar_at)
9731 *contains_dollar_at = 1;
ac50fbac
CR
9732
9733 tflag |= W_DOLLARAT;
ccc6cda3
JA
9734 }
9735
b80f6443 9736 /* Process ${!PREFIX*} expansion. */
bb70624e
JA
9737 if (want_indir && string[sindex - 1] == RBRACE &&
9738 (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
f73dda09 9739 legal_variable_starter ((unsigned char) name[1]))
bb70624e
JA
9740 {
9741 char **x;
9742 WORD_LIST *xlist;
9743
9744 temp1 = savestring (name + 1);
9745 number = strlen (temp1);
9746 temp1[number - 1] = '\0';
9747 x = all_variables_matching_prefix (temp1);
7117c2d2 9748 xlist = strvec_to_word_list (x, 0, 0);
28ef6c31 9749 if (string[sindex - 2] == '*')
d233b485 9750 temp = string_list_dollar_star (xlist, quoted, 0);
28ef6c31
JA
9751 else
9752 {
a0c0a00f 9753 temp = string_list_dollar_at (xlist, quoted, 0);
28ef6c31
JA
9754 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9755 *quoted_dollar_atp = 1;
9756 if (contains_dollar_at)
9757 *contains_dollar_at = 1;
ac50fbac
CR
9758
9759 tflag |= W_DOLLARAT;
28ef6c31 9760 }
bb70624e 9761 free (x);
89a92869 9762 dispose_words (xlist);
bb70624e
JA
9763 free (temp1);
9764 *indexp = sindex;
95732b49 9765
ac50fbac
CR
9766 free (name);
9767
95732b49
JA
9768 ret = alloc_word_desc ();
9769 ret->word = temp;
ac50fbac 9770 ret->flags = tflag; /* XXX */
95732b49 9771 return ret;
bb70624e 9772 }
b80f6443
JA
9773
9774#if defined (ARRAY_VARS)
d233b485 9775 /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */
b80f6443 9776 if (want_indir && string[sindex - 1] == RBRACE &&
d233b485 9777 string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0))
b80f6443
JA
9778 {
9779 char *x, *x1;
9780
9781 temp1 = savestring (name + 1);
d233b485 9782 x = array_variable_name (temp1, 0, &x1, (int *)0);
b80f6443 9783 FREE (x);
d233b485 9784 if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK)
b80f6443 9785 {
8868edaf 9786 temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */
b80f6443
JA
9787 if (x1[0] == '@')
9788 {
9789 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9790 *quoted_dollar_atp = 1;
9791 if (contains_dollar_at)
9792 *contains_dollar_at = 1;
ac50fbac
CR
9793
9794 tflag |= W_DOLLARAT;
b80f6443
JA
9795 }
9796
a0c0a00f 9797 free (name);
b80f6443
JA
9798 free (temp1);
9799 *indexp = sindex;
95732b49
JA
9800
9801 ret = alloc_word_desc ();
9802 ret->word = temp;
ac50fbac 9803 ret->flags = tflag; /* XXX */
95732b49 9804 return ret;
b80f6443
JA
9805 }
9806
9807 free (temp1);
9808 }
9809#endif /* ARRAY_VARS */
bb70624e 9810
ccc6cda3
JA
9811 /* Make sure that NAME is valid before trying to go on. */
9812 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
9813 var_is_special) == 0)
9814 {
9815 temp = (char *)NULL;
a0c0a00f 9816 goto bad_substitution; /* substitution error */
ccc6cda3
JA
9817 }
9818
9819 if (want_indir)
1a1f8b54 9820 {
8868edaf 9821 tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags|local_pflags, quoted_dollar_atp, contains_dollar_at);
a0c0a00f
CR
9822 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9823 {
9824 temp = (char *)NULL;
9825 goto bad_substitution;
9826 }
d233b485 9827
1a1f8b54
CR
9828 /* Turn off the W_ARRAYIND flag because there is no way for this function
9829 to return the index we're supposed to be using. */
9830 if (tdesc && tdesc->flags)
9831 tdesc->flags &= ~W_ARRAYIND;
74091dd4
CR
9832
9833 /* If the indir expansion contains $@/$*, extend the special treatment
9834 of the case of no positional parameters and `set -u' to it. */
9835 if (contains_dollar_at && *contains_dollar_at)
9836 all_element_arrayref = 1;
1a1f8b54 9837 }
95732b49 9838 else
8868edaf
CR
9839 {
9840 local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS));
74091dd4 9841 tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &es);
8868edaf 9842 }
95732b49 9843
d233b485
CR
9844 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9845 {
9846 tflag = 0;
9847 tdesc = 0;
9848 }
9849
95732b49
JA
9850 if (tdesc)
9851 {
9852 temp = tdesc->word;
9853 tflag = tdesc->flags;
9854 dispose_word_desc (tdesc);
9855 }
ccc6cda3 9856 else
74091dd4 9857 temp = (char *)0;
ccc6cda3 9858
ac50fbac
CR
9859 if (temp == &expand_param_error || temp == &expand_param_fatal)
9860 {
9861 FREE (name);
9862 FREE (value);
9863 return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9864 }
9865
ccc6cda3 9866#if defined (ARRAY_VARS)
a0c0a00f
CR
9867 if (valid_array_reference (name, 0))
9868 {
9869 int qflags;
9870 char *t;
9871
9872 qflags = quoted;
9873 /* If in a context where word splitting will not take place, treat as
9874 if double-quoted. Has effects with $* and ${array[*]} */
d233b485 9875
a0c0a00f
CR
9876 if (pflags & PF_ASSIGNRHS)
9877 qflags |= Q_DOUBLE_QUOTES;
a0c0a00f 9878 /* We duplicate a little code here */
d233b485
CR
9879 t = mbschr (name, LBRACK);
9880 if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK)
9881 {
9882 all_element_arrayref = 1;
9883 if (expand_no_split_dollar_star && t[1] == '*') /* XXX */
9884 qflags |= Q_DOUBLE_QUOTES;
9885 }
8868edaf 9886 chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at);
a0c0a00f 9887 }
ccc6cda3
JA
9888#endif
9889
9890 var_is_set = temp != (char *)0;
9891 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
ac50fbac
CR
9892 /* XXX - this may not need to be restricted to special variables */
9893 if (check_nullness)
9894 var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp);
d233b485
CR
9895#if defined (ARRAY_VARS)
9896 if (check_nullness)
9897 var_is_null |= var_is_set &&
9898 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) &&
9899 QUOTED_NULL (temp) &&
9900 valid_array_reference (name, 0) &&
8868edaf 9901 chk_atstar (name, 0, 0, (int *)0, (int *)0);
d233b485 9902#endif
ccc6cda3
JA
9903
9904 /* Get the rest of the stuff inside the braces. */
cce855bc 9905 if (c && c != RBRACE)
ccc6cda3
JA
9906 {
9907 /* Extract the contents of the ${ ... } expansion
28ef6c31 9908 according to the Posix.2 rules. */
49ed961b 9909 value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
cce855bc 9910 if (string[sindex] == RBRACE)
28ef6c31 9911 sindex++;
ccc6cda3 9912 else
a0c0a00f 9913 goto bad_substitution; /* substitution error */
ccc6cda3
JA
9914 }
9915 else
9916 value = (char *)NULL;
726f6388 9917
ccc6cda3
JA
9918 *indexp = sindex;
9919
495aee44
CR
9920 /* All the cases where an expansion can possibly generate an unbound
9921 variable error. */
8868edaf 9922 if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE)
495aee44 9923 {
a0c0a00f 9924 if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0)
495aee44 9925 {
8868edaf 9926 set_exit_status (EXECUTION_FAILURE);
495aee44
CR
9927 err_unboundvar (name);
9928 FREE (value);
9929 FREE (temp);
9930 free (name);
9931 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9932 }
9933 }
9934
ccc6cda3
JA
9935 /* If this is a substring spec, process it and add the result. */
9936 if (want_substring)
726f6388 9937 {
74091dd4 9938 temp1 = parameter_brace_substring (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
ccc6cda3
JA
9939 FREE (value);
9940 FREE (temp);
74091dd4
CR
9941#if defined (ARRAY_VARS)
9942 flush_eltstate (&es);
9943#endif
95732b49 9944
d233b485
CR
9945 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9946 {
9947 FREE (name);
9948 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9949 }
95732b49
JA
9950
9951 ret = alloc_word_desc ();
9952 ret->word = temp1;
ac50fbac
CR
9953 /* We test quoted_dollar_atp because we want variants with double-quoted
9954 "$@" to take a different code path. In fact, we make sure at the end
9955 of expand_word_internal that we're only looking at these flags if
9956 quoted_dollar_at == 0. */
8868edaf 9957 if (temp1 &&
ac50fbac
CR
9958 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9959 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
0628567a 9960 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
8868edaf
CR
9961 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 &&
9962 (pflags & PF_ASSIGNRHS))
9963 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
d233b485
CR
9964 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9965 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9966 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9967
9968 FREE (name);
95732b49 9969 return ret;
726f6388 9970 }
ccc6cda3 9971 else if (want_patsub)
726f6388 9972 {
74091dd4 9973 temp1 = parameter_brace_patsub (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
ccc6cda3
JA
9974 FREE (value);
9975 FREE (temp);
74091dd4
CR
9976#if defined (ARRAY_VARS)
9977 flush_eltstate (&es);
9978#endif
95732b49 9979
d233b485
CR
9980 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9981 {
9982 FREE (name);
9983 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9984 }
95732b49
JA
9985
9986 ret = alloc_word_desc ();
9987 ret->word = temp1;
ac50fbac
CR
9988 if (temp1 &&
9989 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9990 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
3185942a 9991 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
d233b485
CR
9992 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9993 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9994 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9995
9996 FREE (name);
95732b49 9997 return ret;
ccc6cda3 9998 }
3185942a
JA
9999#if defined (CASEMOD_EXPANSIONS)
10000 else if (want_casemod)
10001 {
74091dd4 10002 temp1 = parameter_brace_casemod (name, temp, &es, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
3185942a
JA
10003 FREE (value);
10004 FREE (temp);
74091dd4
CR
10005#if defined (ARRAY_VARS)
10006 flush_eltstate (&es);
10007#endif
3185942a 10008
d233b485
CR
10009 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
10010 {
10011 FREE (name);
10012 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
10013 }
3185942a
JA
10014
10015 ret = alloc_word_desc ();
10016 ret->word = temp1;
ac50fbac
CR
10017 if (temp1 &&
10018 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
10019 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
3185942a 10020 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
d233b485
CR
10021 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10022 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10023 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10024
10025 FREE (name);
3185942a
JA
10026 return ret;
10027 }
10028#endif
726f6388 10029
ccc6cda3
JA
10030 /* Do the right thing based on which character ended the variable name. */
10031 switch (c)
10032 {
10033 default:
10034 case '\0':
a0c0a00f 10035bad_substitution:
8868edaf 10036 set_exit_status (EXECUTION_FAILURE);
b80f6443 10037 report_error (_("%s: bad substitution"), string ? string : "??");
ccc6cda3
JA
10038 FREE (value);
10039 FREE (temp);
10040 free (name);
74091dd4
CR
10041#if defined (ARRAY_VARS)
10042 flush_eltstate (&es);
10043#endif
a0c0a00f
CR
10044 if (shell_compatibility_level <= 43)
10045 return &expand_wdesc_error;
10046 else
10047 return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error);
ccc6cda3 10048
cce855bc 10049 case RBRACE:
ccc6cda3 10050 break;
726f6388 10051
a0c0a00f 10052 case '@':
74091dd4 10053 temp1 = parameter_brace_transform (name, temp, &es, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
a0c0a00f
CR
10054 free (temp);
10055 free (value);
74091dd4
CR
10056#if defined (ARRAY_VARS)
10057 flush_eltstate (&es);
10058#endif
d233b485 10059
a0c0a00f
CR
10060 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
10061 {
d233b485 10062 free (name);
8868edaf 10063 set_exit_status (EXECUTION_FAILURE);
a0c0a00f
CR
10064 report_error (_("%s: bad substitution"), string ? string : "??");
10065 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
10066 }
10067
10068 ret = alloc_word_desc ();
10069 ret->word = temp1;
10070 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10071 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
d233b485
CR
10072 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10073 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10074 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10075
10076 free (name);
a0c0a00f
CR
10077 return ret;
10078
ccc6cda3
JA
10079 case '#': /* ${param#[#]pattern} */
10080 case '%': /* ${param%[%]pattern} */
10081 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
28ef6c31
JA
10082 {
10083 FREE (value);
ccc6cda3 10084 break;
28ef6c31 10085 }
74091dd4 10086 temp1 = parameter_brace_remove_pattern (name, temp, &es, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
ccc6cda3
JA
10087 free (temp);
10088 free (value);
74091dd4
CR
10089#if defined (ARRAY_VARS)
10090 flush_eltstate (&es);
10091#endif
3185942a
JA
10092
10093 ret = alloc_word_desc ();
10094 ret->word = temp1;
10095 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10096 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
d233b485
CR
10097 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10098 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10099 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10100
10101 free (name);
3185942a 10102 return ret;
ccc6cda3
JA
10103
10104 case '-':
10105 case '=':
10106 case '?':
10107 case '+':
10108 if (var_is_set && var_is_null == 0)
28ef6c31
JA
10109 {
10110 /* If the operator is `+', we don't want the value of the named
10111 variable for anything, just the value of the right hand side. */
ccc6cda3
JA
10112 if (c == '+')
10113 {
28ef6c31
JA
10114 /* XXX -- if we're double-quoted and the named variable is "$@",
10115 we want to turn off any special handling of "$@" --
10116 we're not using it, so whatever is on the rhs applies. */
10117 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
10118 *quoted_dollar_atp = 0;
10119 if (contains_dollar_at)
10120 *contains_dollar_at = 0;
10121
ccc6cda3
JA
10122 FREE (temp);
10123 if (value)
28ef6c31 10124 {
495aee44
CR
10125 /* From Posix discussion on austin-group list. Issue 221
10126 requires that backslashes escaping `}' inside
10127 double-quoted ${...} be removed. */
10128 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10129 quoted |= Q_DOLBRACE;
95732b49
JA
10130 ret = parameter_brace_expand_rhs (name, value, c,
10131 quoted,
a0c0a00f 10132 pflags,
95732b49
JA
10133 quoted_dollar_atp,
10134 contains_dollar_at);
10135 /* XXX - fix up later, esp. noting presence of
10136 W_HASQUOTEDNULL in ret->flags */
ccc6cda3
JA
10137 free (value);
10138 }
10139 else
28ef6c31 10140 temp = (char *)NULL;
ccc6cda3
JA
10141 }
10142 else
10143 {
10144 FREE (value);
10145 }
10146 /* Otherwise do nothing; just use the value in TEMP. */
726f6388 10147 }
ccc6cda3 10148 else /* VAR not set or VAR is NULL. */
28ef6c31 10149 {
74091dd4
CR
10150 /* If we're freeing a quoted null here, we need to remember we saw
10151 it so we can restore it later if needed, or the caller can note it.
10152 The check against `+' doesn't really matter, since the other cases
10153 don't use or return TFLAG, but it's good for clarity. */
10154 if (c == '+' && temp && QUOTED_NULL (temp) &&
10155 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
10156 tflag |= W_HASQUOTEDNULL;
10157
ccc6cda3
JA
10158 FREE (temp);
10159 temp = (char *)NULL;
10160 if (c == '=' && var_is_special)
10161 {
8868edaf 10162 set_exit_status (EXECUTION_FAILURE);
b80f6443 10163 report_error (_("$%s: cannot assign in this way"), name);
ccc6cda3
JA
10164 free (name);
10165 free (value);
74091dd4
CR
10166#if defined (ARRAY_VARS)
10167 flush_eltstate (&es);
10168#endif
95732b49 10169 return &expand_wdesc_error;
ccc6cda3
JA
10170 }
10171 else if (c == '?')
10172 {
d233b485 10173 parameter_brace_expand_error (name, value, check_nullness);
74091dd4
CR
10174#if defined (ARRAY_VARS)
10175 flush_eltstate (&es);
10176#endif
95732b49 10177 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
ccc6cda3
JA
10178 }
10179 else if (c != '+')
28ef6c31
JA
10180 {
10181 /* XXX -- if we're double-quoted and the named variable is "$@",
10182 we want to turn off any special handling of "$@" --
10183 we're not using it, so whatever is on the rhs applies. */
10184 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
10185 *quoted_dollar_atp = 0;
10186 if (contains_dollar_at)
10187 *contains_dollar_at = 0;
10188
495aee44
CR
10189 /* From Posix discussion on austin-group list. Issue 221 requires
10190 that backslashes escaping `}' inside double-quoted ${...} be
10191 removed. */
10192 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10193 quoted |= Q_DOLBRACE;
a0c0a00f 10194 ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags,
95732b49
JA
10195 quoted_dollar_atp,
10196 contains_dollar_at);
10197 /* XXX - fix up later, esp. noting presence of
10198 W_HASQUOTEDNULL in tdesc->flags */
28ef6c31 10199 }
ccc6cda3 10200 free (value);
726f6388 10201 }
28ef6c31 10202
ccc6cda3 10203 break;
726f6388 10204 }
ccc6cda3 10205 free (name);
74091dd4
CR
10206#if defined (ARRAY_VARS)
10207 flush_eltstate (&es);
10208#endif
95732b49
JA
10209
10210 if (ret == 0)
10211 {
10212 ret = alloc_word_desc ();
10213 ret->flags = tflag;
10214 ret->word = temp;
10215 }
10216 return (ret);
726f6388
JA
10217}
10218
cce855bc
JA
10219/* Expand a single ${xxx} expansion. The braces are optional. When
10220 the braces are used, parameter_brace_expand() does the work,
10221 possibly calling param_expand recursively. */
95732b49 10222static WORD_DESC *
cce855bc
JA
10223param_expand (string, sindex, quoted, expanded_something,
10224 contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
10225 pflags)
10226 char *string;
10227 int *sindex, quoted, *expanded_something, *contains_dollar_at;
10228 int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
10229{
a0c0a00f 10230 char *temp, *temp1, uerror[3], *savecmd;
74091dd4 10231 int zindex, t_index, expok, eflag;
f73dda09 10232 unsigned char c;
7117c2d2 10233 intmax_t number;
cce855bc 10234 SHELL_VAR *var;
8868edaf 10235 WORD_LIST *list, *l;
95732b49 10236 WORD_DESC *tdesc, *ret;
8868edaf 10237 int tflag, nullarg;
cce855bc 10238
a0c0a00f 10239/*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/
cce855bc
JA
10240 zindex = *sindex;
10241 c = string[++zindex];
10242
10243 temp = (char *)NULL;
95732b49
JA
10244 ret = tdesc = (WORD_DESC *)NULL;
10245 tflag = 0;
cce855bc
JA
10246
10247 /* Do simple cases first. Switch on what follows '$'. */
10248 switch (c)
10249 {
10250 /* $0 .. $9? */
10251 case '0':
10252 case '1':
10253 case '2':
10254 case '3':
10255 case '4':
10256 case '5':
10257 case '6':
10258 case '7':
10259 case '8':
10260 case '9':
f73dda09 10261 temp1 = dollar_vars[TODIGIT (c)];
d233b485 10262 /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */
cce855bc
JA
10263 if (unbound_vars_is_error && temp1 == (char *)NULL)
10264 {
7117c2d2
JA
10265 uerror[0] = '$';
10266 uerror[1] = c;
10267 uerror[2] = '\0';
8868edaf 10268 set_exit_status (EXECUTION_FAILURE);
0001803f 10269 err_unboundvar (uerror);
95732b49 10270 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
cce855bc 10271 }
b80f6443
JA
10272 if (temp1)
10273 temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10274 ? quote_string (temp1)
10275 : quote_escapes (temp1);
10276 else
10277 temp = (char *)NULL;
95732b49 10278
cce855bc
JA
10279 break;
10280
10281 /* $$ -- pid of the invoking shell. */
10282 case '$':
10283 temp = itos (dollar_dollar_pid);
10284 break;
10285
10286 /* $# -- number of positional parameters. */
10287 case '#':
10288 temp = itos (number_of_args ());
10289 break;
10290
10291 /* $? -- return value of the last synchronous command. */
10292 case '?':
10293 temp = itos (last_command_exit_value);
10294 break;
10295
10296 /* $- -- flags supplied to the shell on invocation or by `set'. */
10297 case '-':
10298 temp = which_set_flags ();
10299 break;
10300
10301 /* $! -- Pid of the last asynchronous command. */
10302 case '!':
10303 /* If no asynchronous pids have been created, expand to nothing.
10304 If `set -u' has been executed, and no async processes have
10305 been created, this is an expansion error. */
10306 if (last_asynchronous_pid == NO_PID)
10307 {
10308 if (expanded_something)
10309 *expanded_something = 0;
10310 temp = (char *)NULL;
d233b485 10311 if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
cce855bc 10312 {
7117c2d2
JA
10313 uerror[0] = '$';
10314 uerror[1] = c;
10315 uerror[2] = '\0';
8868edaf 10316 set_exit_status (EXECUTION_FAILURE);
0001803f 10317 err_unboundvar (uerror);
95732b49 10318 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
cce855bc
JA
10319 }
10320 }
10321 else
f73dda09 10322 temp = itos (last_asynchronous_pid);
cce855bc
JA
10323 break;
10324
10325 /* The only difference between this and $@ is when the arg is quoted. */
10326 case '*': /* `$*' */
10327 list = list_rest_of_args ();
10328
89a92869
CR
10329#if 0
10330 /* According to austin-group posix proposal by Geoff Clare in
10331 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
10332
10333 "The shell shall write a message to standard error and
10334 immediately exit when it tries to expand an unset parameter
10335 other than the '@' and '*' special parameters."
10336 */
10337
10338 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
3185942a
JA
10339 {
10340 uerror[0] = '$';
10341 uerror[1] = '*';
10342 uerror[2] = '\0';
8868edaf 10343 set_exit_status (EXECUTION_FAILURE);
89a92869 10344 err_unboundvar (uerror);
3185942a
JA
10345 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10346 }
89a92869 10347#endif
3185942a 10348
cce855bc
JA
10349 /* If there are no command-line arguments, this should just
10350 disappear if there are other characters in the expansion,
10351 even if it's quoted. */
10352 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
10353 temp = (char *)NULL;
0001803f 10354 else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
cce855bc
JA
10355 {
10356 /* If we have "$*" we want to make a string of the positional
10357 parameters, separated by the first character of $IFS, and
10358 quote the whole string, including the separators. If IFS
10359 is unset, the parameters are separated by ' '; if $IFS is
10360 null, the parameters are concatenated. */
d233b485 10361 temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list);
495aee44
CR
10362 if (temp)
10363 {
a0c0a00f 10364 temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp;
495aee44
CR
10365 if (*temp == 0)
10366 tflag |= W_HASQUOTEDNULL;
a0c0a00f
CR
10367 if (temp != temp1)
10368 free (temp);
495aee44
CR
10369 temp = temp1;
10370 }
cce855bc
JA
10371 }
10372 else
28ef6c31 10373 {
95732b49
JA
10374 /* We check whether or not we're eventually going to split $* here,
10375 for example when IFS is empty and we are processing the rhs of
10376 an assignment statement. In that case, we don't separate the
10377 arguments at all. Otherwise, if the $* is not quoted it is
10378 identical to $@ */
d233b485
CR
10379 if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS))
10380 {
8868edaf
CR
10381 /* Posix interp 888: RHS of assignment, IFS unset: no splitting,
10382 separate with space */
10383 temp1 = string_list_dollar_star (list, quoted, pflags);
10384 temp = temp1 ? quote_string (temp1) : temp1;
10385 /* XXX - tentative - note that we saw a quoted null here */
10386 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
10387 tflag |= W_SAWQUOTEDNULL;
10388 FREE (temp1);
d233b485
CR
10389 }
10390 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS))
10391 {
10392 /* Posix interp 888: RHS of assignment, IFS set to '' */
10393 temp1 = string_list_dollar_star (list, quoted, pflags);
10394 temp = temp1 ? quote_escapes (temp1) : temp1;
10395 FREE (temp1);
10396 }
10397 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS))
10398 {
10399 /* Posix interp 888: RHS of assignment, IFS set to non-null value */
10400 temp1 = string_list_dollar_star (list, quoted, pflags);
10401 temp = temp1 ? quote_string (temp1) : temp1;
8868edaf
CR
10402
10403 /* XXX - tentative - note that we saw a quoted null here */
10404 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
10405 tflag |= W_SAWQUOTEDNULL;
d233b485
CR
10406 FREE (temp1);
10407 }
10408 /* XXX - should we check ifs_is_set here as well? */
95732b49 10409# if defined (HANDLE_MULTIBYTE)
d233b485 10410 else if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
95732b49 10411# else
d233b485 10412 else if (expand_no_split_dollar_star && ifs_firstc == 0)
95732b49 10413# endif
d233b485
CR
10414 /* Posix interp 888: not RHS, no splitting, IFS set to '' */
10415 temp = string_list_dollar_star (list, quoted, 0);
95732b49 10416 else
ac50fbac 10417 {
a0c0a00f 10418 temp = string_list_dollar_at (list, quoted, 0);
d233b485
CR
10419 /* Set W_SPLITSPACE to make sure the individual positional
10420 parameters are split into separate arguments */
10421#if 0
ac50fbac 10422 if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null))
d233b485
CR
10423#else /* change with bash-5.0 */
10424 if (quoted == 0 && ifs_is_null)
10425#endif
ac50fbac 10426 tflag |= W_SPLITSPACE;
a0c0a00f
CR
10427 /* If we're not quoted but we still don't want word splitting, make
10428 we quote the IFS characters to protect them from splitting (e.g.,
10429 when $@ is in the string as well). */
10430 else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS))
10431 {
10432 temp1 = quote_string (temp);
10433 free (temp);
10434 temp = temp1;
10435 }
ac50fbac
CR
10436 }
10437
28ef6c31
JA
10438 if (expand_no_split_dollar_star == 0 && contains_dollar_at)
10439 *contains_dollar_at = 1;
10440 }
cce855bc
JA
10441
10442 dispose_words (list);
10443 break;
10444
10445 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
10446 means that we have to turn quoting off after we split into
10447 the individually quoted arguments so that the final split
10448 on the first character of $IFS is still done. */
10449 case '@': /* `$@' */
10450 list = list_rest_of_args ();
10451
89a92869
CR
10452#if 0
10453 /* According to austin-group posix proposal by Geoff Clare in
10454 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
10455
10456 "The shell shall write a message to standard error and
10457 immediately exit when it tries to expand an unset parameter
10458 other than the '@' and '*' special parameters."
10459 */
10460
10461 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
3185942a
JA
10462 {
10463 uerror[0] = '$';
10464 uerror[1] = '@';
10465 uerror[2] = '\0';
8868edaf 10466 set_exit_status (EXECUTION_FAILURE);
89a92869 10467 err_unboundvar (uerror);
3185942a
JA
10468 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10469 }
89a92869 10470#endif
3185942a 10471
8868edaf
CR
10472 for (nullarg = 0, l = list; l; l = l->next)
10473 {
10474 if (l->word && (l->word->word == 0 || l->word->word[0] == 0))
10475 nullarg = 1;
10476 }
10477
cce855bc
JA
10478 /* We want to flag the fact that we saw this. We can't turn
10479 off quoting entirely, because other characters in the
10480 string might need it (consider "\"$@\""), but we need some
10481 way to signal that the final split on the first character
10482 of $IFS should be done, even though QUOTED is 1. */
0001803f 10483 /* XXX - should this test include Q_PATQUOTE? */
cce855bc
JA
10484 if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10485 *quoted_dollar_at_p = 1;
10486 if (contains_dollar_at)
10487 *contains_dollar_at = 1;
10488
10489 /* We want to separate the positional parameters with the first
10490 character of $IFS in case $IFS is something other than a space.
10491 We also want to make sure that splitting is done no matter what --
10492 according to POSIX.2, this expands to a list of the positional
10493 parameters no matter what IFS is set to. */
3b34f6e6
CR
10494 /* XXX - what to do when in a context where word splitting is not
10495 performed? Even when IFS is not the default, posix seems to imply
8868edaf
CR
10496 that we have to expand $@ to all the positional parameters and
10497 separate them with spaces, which are preserved because word splitting
10498 doesn't take place. See below for how we use PF_NOSPLIT2 here. */
d233b485
CR
10499
10500 /* These are the cases where word splitting will not be performed. */
10501 if (pflags & PF_ASSIGNRHS)
8868edaf
CR
10502 {
10503 temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags);
10504 if (nullarg)
10505 tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */
10506 }
10507
d233b485
CR
10508 /* This needs to match what expand_word_internal does with non-quoted $@
10509 does with separating with spaces. Passing Q_DOUBLE_QUOTES means that
10510 the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that
10511 they will separated by spaces. After doing this, we need the special
10512 handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC
10513 quotes. */
10514 else if (pflags & PF_NOSPLIT2)
10515 {
10516#if defined (HANDLE_MULTIBYTE)
10517 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
10518#else
10519 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
10520#endif
10521 /* Posix interp 888 */
10522 temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags);
10523 else
10524 temp = string_list_dollar_at (list, quoted, pflags);
10525 }
10526 else
10527 temp = string_list_dollar_at (list, quoted, pflags);
cce855bc 10528
ac50fbac 10529 tflag |= W_DOLLARAT;
cce855bc
JA
10530 dispose_words (list);
10531 break;
10532
10533 case LBRACE:
0001803f 10534 tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
95732b49
JA
10535 quoted_dollar_at_p,
10536 contains_dollar_at);
10537
95732b49
JA
10538 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
10539 return (tdesc);
10540 temp = tdesc ? tdesc->word : (char *)0;
cce855bc
JA
10541
10542 /* XXX */
bb70624e 10543 /* Quoted nulls should be removed if there is anything else
cce855bc
JA
10544 in the string. */
10545 /* Note that we saw the quoted null so we can add one back at
10546 the end of this function if there are no other characters
28ef6c31
JA
10547 in the string, discard TEMP, and go on. The exception to
10548 this is when we have "${@}" and $1 is '', since $@ needs
10549 special handling. */
95732b49 10550 if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
cce855bc
JA
10551 {
10552 if (had_quoted_null_p)
10553 *had_quoted_null_p = 1;
28ef6c31
JA
10554 if (*quoted_dollar_at_p == 0)
10555 {
10556 free (temp);
95732b49 10557 tdesc->word = temp = (char *)NULL;
28ef6c31
JA
10558 }
10559
cce855bc
JA
10560 }
10561
95732b49 10562 ret = tdesc;
cce855bc
JA
10563 goto return0;
10564
10565 /* Do command or arithmetic substitution. */
10566 case LPAREN:
10567 /* We have to extract the contents of this paren substitution. */
10568 t_index = zindex + 1;
a0c0a00f
CR
10569 /* XXX - might want to check for string[t_index+2] == LPAREN and parse
10570 as arithmetic substitution immediately. */
10571 temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0);
cce855bc
JA
10572 zindex = t_index;
10573
10574 /* For Posix.2-style `$(( ))' arithmetic substitution,
28ef6c31 10575 extract the expression and pass it to the evaluator. */
cce855bc
JA
10576 if (temp && *temp == LPAREN)
10577 {
10578 char *temp2;
10579 temp1 = temp + 1;
10580 temp2 = savestring (temp1);
10581 t_index = strlen (temp2) - 1;
10582
10583 if (temp2[t_index] != RPAREN)
10584 {
10585 free (temp2);
10586 goto comsub;
10587 }
10588
10589 /* Cut off ending `)' */
10590 temp2[t_index] = '\0';
10591
0628567a
JA
10592 if (chk_arithsub (temp2, t_index) == 0)
10593 {
10594 free (temp2);
0001803f
CR
10595#if 0
10596 internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
10597#endif
0628567a
JA
10598 goto comsub;
10599 }
10600
cce855bc 10601 /* Expand variables found inside the expression. */
a0c0a00f 10602 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
cce855bc
JA
10603 free (temp2);
10604
10605arithsub:
10606 /* No error messages. */
a0c0a00f 10607 savecmd = this_command_name;
cce855bc 10608 this_command_name = (char *)NULL;
74091dd4
CR
10609
10610 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
10611 number = evalexp (temp1, eflag, &expok);
a0c0a00f 10612 this_command_name = savecmd;
cce855bc
JA
10613 free (temp);
10614 free (temp1);
10615 if (expok == 0)
10616 {
10617 if (interactive_shell == 0 && posixly_correct)
10618 {
8868edaf 10619 set_exit_status (EXECUTION_FAILURE);
95732b49 10620 return (&expand_wdesc_fatal);
cce855bc
JA
10621 }
10622 else
95732b49 10623 return (&expand_wdesc_error);
cce855bc
JA
10624 }
10625 temp = itos (number);
10626 break;
10627 }
10628
10629comsub:
b80f6443
JA
10630 if (pflags & PF_NOCOMSUB)
10631 /* we need zindex+1 because string[zindex] == RPAREN */
10632 temp1 = substring (string, *sindex, zindex+1);
10633 else
3185942a 10634 {
d233b485 10635 tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS);
3185942a
JA
10636 temp1 = tdesc ? tdesc->word : (char *)NULL;
10637 if (tdesc)
10638 dispose_word_desc (tdesc);
10639 }
cce855bc
JA
10640 FREE (temp);
10641 temp = temp1;
10642 break;
10643
10644 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
10645 away in a future bash release. */
d233b485 10646 case '[': /*]*/
bb70624e 10647 /* Extract the contents of this arithmetic substitution. */
cce855bc
JA
10648 t_index = zindex + 1;
10649 temp = extract_arithmetic_subst (string, &t_index);
10650 zindex = t_index;
3185942a
JA
10651 if (temp == 0)
10652 {
10653 temp = savestring (string);
10654 if (expanded_something)
10655 *expanded_something = 0;
10656 goto return0;
10657 }
cce855bc
JA
10658
10659 /* Do initial variable expansion. */
a0c0a00f 10660 temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH);
cce855bc
JA
10661
10662 goto arithsub;
10663
10664 default:
10665 /* Find the variable in VARIABLE_LIST. */
10666 temp = (char *)NULL;
10667
10668 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
10669 ;
10670 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
10671
10672 /* If this isn't a variable name, then just output the `$'. */
10673 if (temp1 == 0 || *temp1 == '\0')
10674 {
10675 FREE (temp1);
f73dda09 10676 temp = (char *)xmalloc (2);
cce855bc
JA
10677 temp[0] = '$';
10678 temp[1] = '\0';
10679 if (expanded_something)
10680 *expanded_something = 0;
10681 goto return0;
10682 }
10683
10684 /* If the variable exists, return its value cell. */
10685 var = find_variable (temp1);
10686
7117c2d2 10687 if (var && invisible_p (var) == 0 && var_isset (var))
cce855bc
JA
10688 {
10689#if defined (ARRAY_VARS)
3185942a 10690 if (assoc_p (var) || array_p (var))
cce855bc 10691 {
3185942a
JA
10692 temp = array_p (var) ? array_reference (array_cell (var), 0)
10693 : assoc_reference (assoc_cell (var), "0");
cce855bc 10694 if (temp)
b80f6443
JA
10695 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10696 ? quote_string (temp)
10697 : quote_escapes (temp);
10698 else if (unbound_vars_is_error)
10699 goto unbound_variable;
cce855bc
JA
10700 }
10701 else
10702#endif
b80f6443
JA
10703 {
10704 temp = value_cell (var);
10705
10706 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10707 ? quote_string (temp)
d233b485
CR
10708 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
10709 : quote_escapes (temp));
b80f6443
JA
10710 }
10711
cce855bc 10712 free (temp1);
7117c2d2 10713
cce855bc
JA
10714 goto return0;
10715 }
b64a0e1d
CR
10716 else if (var && (invisible_p (var) || var_isset (var) == 0))
10717 temp = (char *)NULL;
a0c0a00f 10718 else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0)
ac50fbac
CR
10719 {
10720 temp = nameref_cell (var);
10721#if defined (ARRAY_VARS)
a0c0a00f 10722 if (temp && *temp && valid_array_reference (temp, 0))
ac50fbac 10723 {
74091dd4
CR
10724 chk_atstar (temp, quoted, pflags, quoted_dollar_at_p, contains_dollar_at);
10725 tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, 0);
ac50fbac
CR
10726 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
10727 return (tdesc);
10728 ret = tdesc;
10729 goto return0;
10730 }
10731 else
10732#endif
10733 /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */
10734 if (temp && *temp && legal_identifier (temp) == 0)
10735 {
8868edaf 10736 set_exit_status (EXECUTION_FAILURE);
ac50fbac
CR
10737 report_error (_("%s: invalid variable name for name reference"), temp);
10738 return (&expand_wdesc_error); /* XXX */
10739 }
10740 else
10741 temp = (char *)NULL;
10742 }
cce855bc
JA
10743
10744 temp = (char *)NULL;
10745
b80f6443 10746unbound_variable:
cce855bc 10747 if (unbound_vars_is_error)
0001803f 10748 {
8868edaf 10749 set_exit_status (EXECUTION_FAILURE);
0001803f
CR
10750 err_unboundvar (temp1);
10751 }
cce855bc
JA
10752 else
10753 {
10754 free (temp1);
10755 goto return0;
10756 }
10757
10758 free (temp1);
8868edaf 10759 set_exit_status (EXECUTION_FAILURE);
cce855bc 10760 return ((unbound_vars_is_error && interactive_shell == 0)
95732b49
JA
10761 ? &expand_wdesc_fatal
10762 : &expand_wdesc_error);
cce855bc
JA
10763 }
10764
10765 if (string[zindex])
10766 zindex++;
10767
10768return0:
10769 *sindex = zindex;
95732b49
JA
10770
10771 if (ret == 0)
10772 {
10773 ret = alloc_word_desc ();
10774 ret->flags = tflag; /* XXX */
10775 ret->word = temp;
10776 }
10777 return ret;
cce855bc
JA
10778}
10779
74091dd4
CR
10780#if defined (ARRAY_VARS)
10781/* Characters that need to be backslash-quoted after expanding array subscripts */
10782static char abstab[256] = { '\1' };
10783
10784/* Run an array subscript through the appropriate word expansions. */
10785char *
10786expand_subscript_string (string, quoted)
10787 char *string;
10788 int quoted;
10789{
10790 WORD_DESC td;
10791 WORD_LIST *tlist;
10792 int oe;
10793 char *ret;
10794
10795 if (string == 0 || *string == 0)
10796 return (char *)NULL;
10797
10798 oe = expand_no_split_dollar_star;
10799 ret = (char *)NULL;
10800
10801 td.flags = W_NOPROCSUB|W_NOTILDE|W_NOSPLIT2; /* XXX - W_NOCOMSUB? */
10802 td.word = savestring (string); /* in case it's freed on error */
10803
10804 expand_no_split_dollar_star = 1;
10805 tlist = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
10806 expand_no_split_dollar_star = oe;
10807
10808 if (tlist)
10809 {
10810 if (tlist->word)
10811 {
10812 remove_quoted_nulls (tlist->word->word);
10813 tlist->word->flags &= ~W_HASQUOTEDNULL;
10814 }
10815 dequote_list (tlist);
10816 ret = string_list (tlist);
10817 dispose_words (tlist);
10818 }
10819
10820 free (td.word);
10821 return (ret);
10822}
10823
10824/* Expand the subscript in STRING, which is an array reference. To ensure we
10825 only expand it once, we quote the characters that would start another
10826 expansion and the bracket characters that are special to array subscripts. */
10827static char *
10828expand_array_subscript (string, sindex, quoted, flags)
10829 char *string;
10830 int *sindex;
10831 int quoted, flags;
10832{
10833 char *ret, *exp, *t;
10834 size_t slen;
10835 int si, ni;
10836
10837 si = *sindex;
10838 slen = STRLEN (string);
10839
10840 if (abstab[0] == '\1')
10841 {
10842 /* These are basically the characters that start shell expansions plus
10843 the characters that delimit subscripts. */
10844 memset (abstab, '\0', sizeof (abstab));
10845 abstab[LBRACK] = abstab[RBRACK] = 1;
10846 abstab['$'] = abstab['`'] = abstab['~'] = 1;
10847 abstab['\\'] = abstab['\''] = 1;
10848 abstab['"'] = 1; /* XXX */
10849 /* We don't quote `@' or `*' in the subscript at all. */
10850 }
10851
10852 /* string[si] == LBRACK */
10853 ni = skipsubscript (string, si, 0);
10854 /* These checks mirror the ones in valid_array_reference. The check for
10855 (ni - si) == 1 checks for empty subscripts. We don't check that the
10856 subscript is a separate word if we're parsing an arithmetic expression. */
10857 if (ni >= slen || string[ni] != RBRACK || (ni - si) == 1 ||
10858 (string[ni+1] != '\0' && (quoted & Q_ARITH) == 0))
10859 {
10860 /* let's check and see what fails this check */
10861 INTERNAL_DEBUG (("expand_array_subscript: bad subscript string: `%s'", string+si));
10862 ret = (char *)xmalloc (2); /* badly-formed subscript */
10863 ret[0] = string[si];
10864 ret[1] = '\0';
10865 *sindex = si + 1;
10866 return ret;
10867 }
10868
10869 /* STRING[ni] == RBRACK */
10870 exp = substring (string, si+1, ni);
10871 t = expand_subscript_string (exp, quoted & ~(Q_ARITH|Q_DOUBLE_QUOTES));
10872 free (exp);
a1e58b8c 10873 exp = t ? sh_backslash_quote (t, abstab, 0) : savestring ("");
74091dd4
CR
10874 free (t);
10875
10876 slen = STRLEN (exp);
10877 ret = xmalloc (slen + 2 + 1);
10878 ret[0] ='[';
10879 strcpy (ret + 1, exp);
10880 ret[slen + 1] = ']';
10881 ret[slen + 2] = '\0';
10882
10883 free (exp);
10884 *sindex = ni + 1;
10885
10886 return ret;
10887}
10888#endif
10889
a0c0a00f
CR
10890void
10891invalidate_cached_quoted_dollar_at ()
10892{
10893 dispose_words (cached_quoted_dollar_at);
10894 cached_quoted_dollar_at = 0;
10895}
10896
cce855bc
JA
10897/* Make a word list which is the result of parameter and variable
10898 expansion, command substitution, arithmetic substitution, and
10899 quote removal of WORD. Return a pointer to a WORD_LIST which is
10900 the result of the expansion. If WORD contains a null word, the
10901 word list returned is also null.
726f6388 10902
ccc6cda3
JA
10903 QUOTED contains flag values defined in shell.h.
10904
b72432fd
JA
10905 ISEXP is used to tell expand_word_internal that the word should be
10906 treated as the result of an expansion. This has implications for
10907 how IFS characters in the word are treated.
10908
726f6388
JA
10909 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
10910 they point to an integer value which receives information about expansion.
10911 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
10912 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
10913 else zero.
10914
10915 This only does word splitting in the case of $@ expansion. In that
10916 case, we split on ' '. */
10917
10918/* Values for the local variable quoted_state. */
10919#define UNQUOTED 0
10920#define PARTIALLY_QUOTED 1
10921#define WHOLLY_QUOTED 2
10922
10923static WORD_LIST *
b72432fd 10924expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
726f6388 10925 WORD_DESC *word;
b72432fd 10926 int quoted, isexp;
726f6388
JA
10927 int *contains_dollar_at;
10928 int *expanded_something;
10929{
ccc6cda3
JA
10930 WORD_LIST *list;
10931 WORD_DESC *tword;
726f6388
JA
10932
10933 /* The intermediate string that we build while expanding. */
ccc6cda3 10934 char *istring;
726f6388
JA
10935
10936 /* The current size of the above object. */
a0c0a00f 10937 size_t istring_size;
726f6388
JA
10938
10939 /* Index into ISTRING. */
74091dd4 10940 size_t istring_index;
726f6388
JA
10941
10942 /* Temporary string storage. */
ccc6cda3 10943 char *temp, *temp1;
726f6388
JA
10944
10945 /* The text of WORD. */
ccc6cda3 10946 register char *string;
726f6388 10947
7117c2d2
JA
10948 /* The size of STRING. */
10949 size_t string_size;
10950
726f6388 10951 /* The index into STRING. */
ccc6cda3 10952 int sindex;
726f6388
JA
10953
10954 /* This gets 1 if we see a $@ while quoted. */
ccc6cda3 10955 int quoted_dollar_at;
726f6388
JA
10956
10957 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
10958 whether WORD contains no quoting characters, a partially quoted
10959 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
ccc6cda3
JA
10960 int quoted_state;
10961
95732b49 10962 /* State flags */
ccc6cda3 10963 int had_quoted_null;
d233b485 10964 int has_quoted_ifs; /* did we add a quoted $IFS character here? */
0b913689 10965 int has_dollar_at, temp_has_dollar_at;
74091dd4 10966 int internal_tilde;
ac50fbac 10967 int split_on_spaces;
d233b485 10968 int local_expanded;
28ef6c31 10969 int tflag;
0001803f 10970 int pflags; /* flags passed to param_expand */
a0c0a00f 10971 int mb_cur_max;
726f6388 10972
95732b49
JA
10973 int assignoff; /* If assignment, offset of `=' */
10974
f73dda09 10975 register unsigned char c; /* Current character. */
726f6388 10976 int t_index; /* For calls to string_extract_xxx. */
726f6388 10977
bb70624e 10978 char twochars[2];
b72432fd 10979
7117c2d2
JA
10980 DECLARE_MBSTATE;
10981
74091dd4
CR
10982 /* OK, let's see if we can optimize a common idiom: "$@". This needs to make sure
10983 that all of the flags callers care about (e.g., W_HASQUOTEDNULL) are set in
10984 list->flags. */
a0c0a00f
CR
10985 if (STREQ (word->word, "\"$@\"") &&
10986 (word->flags == (W_HASDOLLAR|W_QUOTED)) &&
10987 dollar_vars[1]) /* XXX - check IFS here as well? */
10988 {
10989 if (contains_dollar_at)
10990 *contains_dollar_at = 1;
10991 if (expanded_something)
10992 *expanded_something = 1;
10993 if (cached_quoted_dollar_at)
10994 return (copy_word_list (cached_quoted_dollar_at));
10995 list = list_rest_of_args ();
10996 list = quote_list (list);
10997 cached_quoted_dollar_at = copy_word_list (list);
10998 return (list);
10999 }
11000
f73dda09 11001 istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
ccc6cda3 11002 istring[istring_index = 0] = '\0';
cce855bc 11003 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
d233b485 11004 has_quoted_ifs = 0;
ac50fbac 11005 split_on_spaces = 0;
74091dd4 11006 internal_tilde = 0; /* expanding =~ or :~ */
ccc6cda3
JA
11007 quoted_state = UNQUOTED;
11008
11009 string = word->word;
11010 if (string == 0)
11011 goto finished_with_string;
a0c0a00f
CR
11012 mb_cur_max = MB_CUR_MAX;
11013
95732b49 11014 /* Don't need the string length for the SADD... and COPY_ macros unless
d233b485 11015 multibyte characters are possible, but do need it for bounds checking. */
a0c0a00f 11016 string_size = (mb_cur_max > 1) ? strlen (string) : 1;
726f6388
JA
11017
11018 if (contains_dollar_at)
11019 *contains_dollar_at = 0;
11020
95732b49
JA
11021 assignoff = -1;
11022
726f6388
JA
11023 /* Begin the expansion. */
11024
ccc6cda3 11025 for (sindex = 0; ;)
726f6388
JA
11026 {
11027 c = string[sindex];
11028
ac50fbac 11029 /* Case on top-level character. */
726f6388
JA
11030 switch (c)
11031 {
11032 case '\0':
11033 goto finished_with_string;
11034
11035 case CTLESC:
7117c2d2
JA
11036 sindex++;
11037#if HANDLE_MULTIBYTE
a0c0a00f 11038 if (mb_cur_max > 1 && string[sindex])
7117c2d2 11039 {
b80f6443 11040 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7117c2d2
JA
11041 }
11042 else
11043#endif
11044 {
11045 temp = (char *)xmalloc (3);
11046 temp[0] = CTLESC;
11047 temp[1] = c = string[sindex];
11048 temp[2] = '\0';
11049 }
726f6388 11050
cce855bc 11051dollar_add_string:
726f6388
JA
11052 if (string[sindex])
11053 sindex++;
11054
cce855bc
JA
11055add_string:
11056 if (temp)
11057 {
11058 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
11059 temp = (char *)0;
11060 }
11061
11062 break;
726f6388
JA
11063
11064#if defined (PROCESS_SUBSTITUTION)
11065 /* Process substitution. */
11066 case '<':
11067 case '>':
11068 {
d233b485 11069 /* XXX - technically this should only be expanded at the start
a0c0a00f 11070 of a word */
74091dd4 11071 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & W_NOPROCSUB))
726f6388 11072 {
bb70624e 11073 sindex--; /* add_character: label increments sindex */
726f6388
JA
11074 goto add_character;
11075 }
11076 else
cce855bc 11077 t_index = sindex + 1; /* skip past both '<' and LPAREN */
726f6388 11078
85b94814 11079 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/
ccc6cda3 11080 sindex = t_index;
726f6388
JA
11081
11082 /* If the process substitution specification is `<()', we want to
11083 open the pipe for writing in the child and produce output; if
11084 it is `>()', we want to open the pipe for reading in the child
11085 and consume input. */
ccc6cda3 11086 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
726f6388
JA
11087
11088 FREE (temp1);
11089
11090 goto dollar_add_string;
11091 }
11092#endif /* PROCESS_SUBSTITUTION */
11093
74091dd4
CR
11094#if defined (ARRAY_VARS)
11095 case '[': /*]*/
11096 if ((quoted & Q_ARITH) == 0 || shell_compatibility_level <= 51)
11097 {
11098 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
11099 goto add_ifs_character;
11100 else
11101 goto add_character;
11102 }
11103 else
11104 {
11105 temp = expand_array_subscript (string, &sindex, quoted, word->flags);
11106 goto add_string;
11107 }
11108#endif
11109
95732b49
JA
11110 case '=':
11111 /* Posix.2 section 3.6.1 says that tildes following `=' in words
11112 which are not assignment statements are not expanded. If the
11113 shell isn't in posix mode, though, we perform tilde expansion
11114 on `likely candidate' unquoted assignment statements (flags
11115 include W_ASSIGNMENT but not W_QUOTED). A likely candidate
11116 contains an unquoted :~ or =~. Something to think about: we
11117 now have a flag that says to perform tilde expansion on arguments
11118 to `assignment builtins' like declare and export that look like
11119 assignment statements. We now do tilde expansion on such words
11120 even in POSIX mode. */
11121 if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
17345e5a 11122 {
0001803f 11123 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
17345e5a
JA
11124 goto add_ifs_character;
11125 else
11126 goto add_character;
11127 }
95732b49 11128 /* If we're not in posix mode or forcing assignment-statement tilde
8868edaf
CR
11129 expansion, note where the first `=' appears in the word and prepare
11130 to do tilde expansion following the first `='. We have to keep
11131 track of the first `=' (using assignoff) to avoid being confused
11132 by an `=' in the rhs of the assignment statement. */
95732b49
JA
11133 if ((word->flags & W_ASSIGNMENT) &&
11134 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
11135 assignoff == -1 && sindex > 0)
11136 assignoff = sindex;
11137 if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
74091dd4 11138 internal_tilde = 1;
a0c0a00f 11139
a0c0a00f
CR
11140 if (word->flags & W_ASSIGNARG)
11141 word->flags |= W_ASSIGNRHS; /* affects $@ */
11142
0001803f 11143 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
d233b485
CR
11144 {
11145 has_quoted_ifs++;
11146 goto add_ifs_character;
11147 }
17345e5a
JA
11148 else
11149 goto add_character;
95732b49
JA
11150
11151 case ':':
d233b485 11152 if (word->flags & (W_NOTILDE|W_NOASSNTILDE))
17345e5a 11153 {
0001803f 11154 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
17345e5a
JA
11155 goto add_ifs_character;
11156 else
11157 goto add_character;
11158 }
95732b49 11159
8868edaf
CR
11160 if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) &&
11161 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
95732b49 11162 string[sindex+1] == '~')
74091dd4 11163 internal_tilde = 1;
17345e5a 11164
0001803f 11165 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
17345e5a
JA
11166 goto add_ifs_character;
11167 else
11168 goto add_character;
95732b49
JA
11169
11170 case '~':
11171 /* If the word isn't supposed to be tilde expanded, or we're not
11172 at the start of a word or after an unquoted : or = in an
d233b485
CR
11173 assignment statement, we don't do tilde expansion. We don't
11174 do tilde expansion if quoted or in an arithmetic context. */
11175
74091dd4
CR
11176 if ((word->flags & W_NOTILDE) ||
11177 (sindex > 0 && (internal_tilde == 0)) ||
d233b485 11178 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
95732b49 11179 {
74091dd4 11180 internal_tilde = 0;
0001803f 11181 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
17345e5a
JA
11182 goto add_ifs_character;
11183 else
11184 goto add_character;
95732b49
JA
11185 }
11186
11187 if (word->flags & W_ASSIGNRHS)
11188 tflag = 2;
11189 else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
11190 tflag = 1;
11191 else
11192 tflag = 0;
11193
11194 temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
11195
74091dd4 11196 internal_tilde = 0;
95732b49
JA
11197
11198 if (temp && *temp && t_index > 0)
11199 {
11200 temp1 = bash_tilde_expand (temp, tflag);
0628567a
JA
11201 if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
11202 {
11203 FREE (temp);
11204 FREE (temp1);
11205 goto add_character; /* tilde expansion failed */
11206 }
95732b49
JA
11207 free (temp);
11208 temp = temp1;
11209 sindex += t_index;
3185942a 11210 goto add_quoted_string; /* XXX was add_string */
95732b49
JA
11211 }
11212 else
11213 {
11214 FREE (temp);
11215 goto add_character;
11216 }
11217
726f6388 11218 case '$':
726f6388
JA
11219 if (expanded_something)
11220 *expanded_something = 1;
d233b485 11221 local_expanded = 1;
726f6388 11222
0b913689 11223 temp_has_dollar_at = 0;
0001803f
CR
11224 pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
11225 if (word->flags & W_NOSPLIT2)
11226 pflags |= PF_NOSPLIT2;
ac50fbac
CR
11227 if (word->flags & W_ASSIGNRHS)
11228 pflags |= PF_ASSIGNRHS;
a0c0a00f
CR
11229 if (word->flags & W_COMPLETE)
11230 pflags |= PF_COMPLETE;
8868edaf 11231
95732b49 11232 tword = param_expand (string, &sindex, quoted, expanded_something,
0b913689 11233 &temp_has_dollar_at, &quoted_dollar_at,
0001803f 11234 &had_quoted_null, pflags);
0b913689 11235 has_dollar_at += temp_has_dollar_at;
ac50fbac 11236 split_on_spaces += (tword->flags & W_SPLITSPACE);
726f6388 11237
95732b49 11238 if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
726f6388 11239 {
cce855bc
JA
11240 free (string);
11241 free (istring);
95732b49
JA
11242 return ((tword == &expand_wdesc_error) ? &expand_word_error
11243 : &expand_word_fatal);
cce855bc
JA
11244 }
11245 if (contains_dollar_at && has_dollar_at)
11246 *contains_dollar_at = 1;
95732b49
JA
11247
11248 if (tword && (tword->flags & W_HASQUOTEDNULL))
d233b485
CR
11249 had_quoted_null = 1; /* note for later */
11250 if (tword && (tword->flags & W_SAWQUOTEDNULL))
11251 had_quoted_null = 1; /* XXX */
95732b49 11252
ac50fbac 11253 temp = tword ? tword->word : (char *)NULL;
95732b49
JA
11254 dispose_word_desc (tword);
11255
a601c749
CR
11256 /* Kill quoted nulls; we will add them back at the end of
11257 expand_word_internal if nothing else in the string */
11258 if (had_quoted_null && temp && QUOTED_NULL (temp))
11259 {
11260 FREE (temp);
11261 temp = (char *)NULL;
11262 }
11263
cce855bc
JA
11264 goto add_string;
11265 break;
726f6388 11266
cce855bc
JA
11267 case '`': /* Backquoted command substitution. */
11268 {
b80f6443 11269 t_index = sindex++;
726f6388 11270
74091dd4 11271 temp = string_extract (string, &sindex, "`", (word->flags & W_COMPLETE) ? SX_COMPLETE : SX_REQMATCH);
95732b49
JA
11272 /* The test of sindex against t_index is to allow bare instances of
11273 ` to pass through, for backwards compatibility. */
11274 if (temp == &extract_string_error || temp == &extract_string_fatal)
11275 {
11276 if (sindex - 1 == t_index)
11277 {
11278 sindex = t_index;
11279 goto add_character;
11280 }
8868edaf 11281 set_exit_status (EXECUTION_FAILURE);
3185942a 11282 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
95732b49
JA
11283 free (string);
11284 free (istring);
11285 return ((temp == &extract_string_error) ? &expand_word_error
11286 : &expand_word_fatal);
11287 }
11288
cce855bc
JA
11289 if (expanded_something)
11290 *expanded_something = 1;
d233b485 11291 local_expanded = 1;
726f6388 11292
b80f6443
JA
11293 if (word->flags & W_NOCOMSUB)
11294 /* sindex + 1 because string[sindex] == '`' */
11295 temp1 = substring (string, t_index, sindex + 1);
11296 else
11297 {
11298 de_backslash (temp);
6ddc9cf2 11299 tword = command_substitute (temp, quoted, PF_BACKQUOTE);
3185942a
JA
11300 temp1 = tword ? tword->word : (char *)NULL;
11301 if (tword)
11302 dispose_word_desc (tword);
b80f6443 11303 }
cce855bc
JA
11304 FREE (temp);
11305 temp = temp1;
11306 goto dollar_add_string;
11307 }
ccc6cda3 11308
cce855bc
JA
11309 case '\\':
11310 if (string[sindex + 1] == '\n')
11311 {
11312 sindex += 2;
11313 continue;
11314 }
726f6388 11315
cce855bc 11316 c = string[++sindex];
726f6388 11317
8868edaf
CR
11318 /* "However, the double-quote character ( '"' ) shall not be treated
11319 specially within a here-document, except when the double-quote
11320 appears within "$()", "``", or "${}"." */
11321 if ((quoted & Q_HERE_DOCUMENT) && (quoted & Q_DOLBRACE) && c == '"')
11322 tflag = CBSDQUOTE; /* special case */
11323 else if (quoted & Q_HERE_DOCUMENT)
28ef6c31 11324 tflag = CBSHDOC;
cce855bc 11325 else if (quoted & Q_DOUBLE_QUOTES)
28ef6c31 11326 tflag = CBSDQUOTE;
cce855bc 11327 else
28ef6c31
JA
11328 tflag = 0;
11329
495aee44
CR
11330 /* From Posix discussion on austin-group list: Backslash escaping
11331 a } in ${...} is removed. Issue 0000221 */
11332 if ((quoted & Q_DOLBRACE) && c == RBRACE)
11333 {
ac50fbac
CR
11334 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11335 }
11336 /* This is the fix for " $@\ " */
11337 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c))
11338 {
11339 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11340 DEFAULT_ARRAY_SIZE);
11341 istring[istring_index++] = CTLESC;
11342 istring[istring_index++] = '\\';
11343 istring[istring_index] = '\0';
11344
495aee44
CR
11345 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11346 }
d233b485
CR
11347 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0)
11348 {
11349 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11350 DEFAULT_ARRAY_SIZE);
11351 istring[istring_index++] = CTLESC;
11352 istring[istring_index++] = '\\';
11353 istring[istring_index] = '\0';
11354 break;
11355 }
495aee44 11356 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
cce855bc 11357 {
7117c2d2 11358 SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
bb70624e
JA
11359 }
11360 else if (c == 0)
11361 {
11362 c = CTLNUL;
11363 sindex--; /* add_character: label increments sindex */
11364 goto add_character;
cce855bc
JA
11365 }
11366 else
bb70624e 11367 {
7117c2d2 11368 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
bb70624e 11369 }
726f6388 11370
bb70624e
JA
11371 sindex++;
11372add_twochars:
11373 /* BEFORE jumping here, we need to increment sindex if appropriate */
11374 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11375 DEFAULT_ARRAY_SIZE);
11376 istring[istring_index++] = twochars[0];
11377 istring[istring_index++] = twochars[1];
11378 istring[istring_index] = '\0';
11379
11380 break;
726f6388 11381
cce855bc 11382 case '"':
74091dd4 11383 /* XXX - revisit this */
a0c0a00f 11384 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0))
cce855bc 11385 goto add_character;
ccc6cda3
JA
11386
11387 t_index = ++sindex;
a0c0a00f 11388 temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0);
ccc6cda3
JA
11389
11390 /* If the quotes surrounded the entire string, then the
11391 whole word was quoted. */
11392 quoted_state = (t_index == 1 && string[sindex] == '\0')
11393 ? WHOLLY_QUOTED
7117c2d2 11394 : PARTIALLY_QUOTED;
ccc6cda3
JA
11395
11396 if (temp && *temp)
726f6388 11397 {
95732b49
JA
11398 tword = alloc_word_desc ();
11399 tword->word = temp;
11400
a0c0a00f 11401 if (word->flags & W_ASSIGNARG)
d233b485 11402 tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */
a0c0a00f
CR
11403 if (word->flags & W_COMPLETE)
11404 tword->flags |= W_COMPLETE; /* for command substitutions */
4f747edc
CR
11405 if (word->flags & W_NOCOMSUB)
11406 tword->flags |= W_NOCOMSUB;
11407 if (word->flags & W_NOPROCSUB)
11408 tword->flags |= W_NOPROCSUB;
a0c0a00f 11409
8868edaf
CR
11410 if (word->flags & W_ASSIGNRHS)
11411 tword->flags |= W_ASSIGNRHS;
11412
ccc6cda3
JA
11413 temp = (char *)NULL;
11414
d233b485 11415 temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */
95732b49 11416 /* Need to get W_HASQUOTEDNULL flag through this function. */
74091dd4
CR
11417 /* XXX - preserve Q_ARITH here? */
11418 list = expand_word_internal (tword, Q_DOUBLE_QUOTES|(quoted&Q_ARITH), 0, &temp_has_dollar_at, (int *)NULL);
0b913689 11419 has_dollar_at += temp_has_dollar_at;
726f6388 11420
ccc6cda3
JA
11421 if (list == &expand_word_error || list == &expand_word_fatal)
11422 {
11423 free (istring);
11424 free (string);
11425 /* expand_word_internal has already freed temp_word->word
11426 for us because of the way it prints error messages. */
11427 tword->word = (char *)NULL;
11428 dispose_word (tword);
11429 return list;
11430 }
726f6388 11431
ccc6cda3 11432 dispose_word (tword);
726f6388 11433
ccc6cda3
JA
11434 /* "$@" (a double-quoted dollar-at) expands into nothing,
11435 not even a NULL word, when there are no positional
d233b485
CR
11436 parameters. Posix interp 888 says that other parts of the
11437 word that expand to quoted nulls result in quoted nulls, so
11438 we can't just throw the entire word away if we have "$@"
11439 anywhere in it. We use had_quoted_null to keep track */
a0c0a00f 11440 if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */
726f6388 11441 {
ccc6cda3
JA
11442 quoted_dollar_at++;
11443 break;
11444 }
11445
d233b485
CR
11446 /* If this list comes back with a quoted null from expansion,
11447 we have either "$x" or "$@" with $1 == ''. In either case,
11448 we need to make sure we add a quoted null argument and
11449 disable the special handling that "$@" gets. */
11450 if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL))
11451 {
d233b485 11452 if (had_quoted_null && temp_has_dollar_at)
8868edaf 11453 quoted_dollar_at++;
d233b485
CR
11454 had_quoted_null = 1; /* XXX */
11455 }
11456
ccc6cda3
JA
11457 /* If we get "$@", we know we have expanded something, so we
11458 need to remember it for the final split on $IFS. This is
11459 a special case; it's the only case where a quoted string
11460 can expand into more than one word. It's going to come back
11461 from the above call to expand_word_internal as a list with
8868edaf 11462 multiple words. */
ccc6cda3
JA
11463 if (list)
11464 dequote_list (list);
11465
a0c0a00f 11466 if (temp_has_dollar_at) /* XXX - was has_dollar_at */
ccc6cda3
JA
11467 {
11468 quoted_dollar_at++;
11469 if (contains_dollar_at)
11470 *contains_dollar_at = 1;
11471 if (expanded_something)
11472 *expanded_something = 1;
d233b485 11473 local_expanded = 1;
ccc6cda3
JA
11474 }
11475 }
11476 else
11477 {
11478 /* What we have is "". This is a minor optimization. */
f73dda09 11479 FREE (temp);
ccc6cda3 11480 list = (WORD_LIST *)NULL;
d233b485 11481 had_quoted_null = 1; /* note for later */
ccc6cda3
JA
11482 }
11483
11484 /* The code above *might* return a list (consider the case of "$@",
11485 where it returns "$1", "$2", etc.). We can't throw away the
11486 rest of the list, and we have to make sure each word gets added
11487 as quoted. We test on tresult->next: if it is non-NULL, we
11488 quote the whole list, save it to a string with string_list, and
11489 add that string. We don't need to quote the results of this
11490 (and it would be wrong, since that would quote the separators
11491 as well), so we go directly to add_string. */
11492 if (list)
11493 {
11494 if (list->next)
11495 {
bc4cd23c
JA
11496 /* Testing quoted_dollar_at makes sure that "$@" is
11497 split correctly when $IFS does not contain a space. */
11498 temp = quoted_dollar_at
a0c0a00f 11499 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0)
bc4cd23c 11500 : string_list (quote_list (list));
ccc6cda3 11501 dispose_words (list);
726f6388
JA
11502 goto add_string;
11503 }
11504 else
11505 {
ccc6cda3 11506 temp = savestring (list->word->word);
95732b49 11507 tflag = list->word->flags;
ccc6cda3 11508 dispose_words (list);
95732b49 11509
cce855bc
JA
11510 /* If the string is not a quoted null string, we want
11511 to remove any embedded unquoted CTLNUL characters.
11512 We do not want to turn quoted null strings back into
11513 the empty string, though. We do this because we
11514 want to remove any quoted nulls from expansions that
11515 contain other characters. For example, if we have
11516 x"$*"y or "x$*y" and there are no positional parameters,
7117c2d2 11517 the $* should expand into nothing. */
95732b49
JA
11518 /* We use the W_HASQUOTEDNULL flag to differentiate the
11519 cases: a quoted null character as above and when
11520 CTLNUL is contained in the (non-null) expansion
11521 of some variable. We use the had_quoted_null flag to
11522 pass the value through this function to its caller. */
11523 if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
cce855bc 11524 remove_quoted_nulls (temp); /* XXX */
726f6388
JA
11525 }
11526 }
ccc6cda3
JA
11527 else
11528 temp = (char *)NULL;
726f6388 11529
d233b485
CR
11530 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
11531 had_quoted_null = 1; /* note for later */
11532
ccc6cda3 11533 /* We do not want to add quoted nulls to strings that are only
ac50fbac
CR
11534 partially quoted; we can throw them away. The exception to
11535 this is when we are going to be performing word splitting,
11536 since we have to preserve a null argument if the next character
11537 will cause word splitting. */
8868edaf
CR
11538 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
11539 {
11540 c = CTLNUL;
11541 sindex--;
11542 had_quoted_null = 1;
11543 goto add_character;
11544 }
495aee44 11545 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
cce855bc 11546 continue;
726f6388 11547
ccc6cda3 11548 add_quoted_string:
726f6388 11549
ccc6cda3
JA
11550 if (temp)
11551 {
11552 temp1 = temp;
11553 temp = quote_string (temp);
11554 free (temp1);
bb70624e 11555 goto add_string;
ccc6cda3
JA
11556 }
11557 else
11558 {
11559 /* Add NULL arg. */
bb70624e
JA
11560 c = CTLNUL;
11561 sindex--; /* add_character: label increments sindex */
d233b485 11562 had_quoted_null = 1; /* note for later */
bb70624e 11563 goto add_character;
ccc6cda3 11564 }
bb70624e 11565
ccc6cda3 11566 /* break; */
726f6388 11567
ccc6cda3 11568 case '\'':
95732b49 11569 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
ccc6cda3 11570 goto add_character;
726f6388 11571
ccc6cda3 11572 t_index = ++sindex;
74091dd4 11573 temp = string_extract_single_quoted (string, &sindex, 0);
726f6388 11574
ccc6cda3
JA
11575 /* If the entire STRING was surrounded by single quotes,
11576 then the string is wholly quoted. */
11577 quoted_state = (t_index == 1 && string[sindex] == '\0')
11578 ? WHOLLY_QUOTED
7117c2d2 11579 : PARTIALLY_QUOTED;
726f6388 11580
ccc6cda3
JA
11581 /* If all we had was '', it is a null expansion. */
11582 if (*temp == '\0')
11583 {
11584 free (temp);
11585 temp = (char *)NULL;
11586 }
11587 else
7117c2d2 11588 remove_quoted_escapes (temp); /* ??? */
726f6388 11589
d233b485
CR
11590 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
11591 had_quoted_null = 1; /* note for later */
11592
ccc6cda3 11593 /* We do not want to add quoted nulls to strings that are only
a0c0a00f 11594 partially quoted; such nulls are discarded. See above for the
d233b485 11595 exception, which is when the string is going to be split.
8868edaf
CR
11596 Posix interp 888/1129 */
11597 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
11598 {
11599 c = CTLNUL;
11600 sindex--;
11601 goto add_character;
11602 }
11603
a0c0a00f 11604 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
ccc6cda3 11605 continue;
726f6388 11606
bb70624e
JA
11607 /* If we have a quoted null expansion, add a quoted NULL to istring. */
11608 if (temp == 0)
11609 {
11610 c = CTLNUL;
11611 sindex--; /* add_character: label increments sindex */
11612 goto add_character;
11613 }
11614 else
11615 goto add_quoted_string;
11616
ccc6cda3 11617 /* break; */
726f6388 11618
8868edaf
CR
11619 case ' ':
11620 /* If we are in a context where the word is not going to be split, but
11621 we need to account for $@ and $* producing one word for each
11622 positional parameter, add quoted spaces so the spaces in the
11623 expansion of "$@", if any, behave correctly. We still may need to
11624 split if we are expanding the rhs of a word expansion. */
11625 if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0))
11626 {
11627 if (string[sindex])
11628 sindex++;
11629 twochars[0] = CTLESC;
11630 twochars[1] = c;
11631 goto add_twochars;
11632 }
11633 /* FALLTHROUGH */
11634
726f6388 11635 default:
726f6388 11636 /* This is the fix for " $@ " */
8868edaf 11637add_ifs_character:
a0c0a00f 11638 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0))
726f6388 11639 {
d233b485
CR
11640 if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)
11641 has_quoted_ifs++;
8868edaf 11642add_quoted_character:
bb70624e
JA
11643 if (string[sindex]) /* from old goto dollar_add_string */
11644 sindex++;
11645 if (c == 0)
11646 {
11647 c = CTLNUL;
11648 goto add_character;
11649 }
11650 else
11651 {
7117c2d2 11652#if HANDLE_MULTIBYTE
d233b485
CR
11653 /* XXX - should make sure that c is actually multibyte,
11654 otherwise we can use the twochars branch */
a0c0a00f 11655 if (mb_cur_max > 1)
b80f6443
JA
11656 sindex--;
11657
a0c0a00f 11658 if (mb_cur_max > 1)
7117c2d2 11659 {
b80f6443 11660 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7117c2d2
JA
11661 }
11662 else
11663#endif
11664 {
11665 twochars[0] = CTLESC;
11666 twochars[1] = c;
11667 goto add_twochars;
11668 }
bb70624e 11669 }
726f6388
JA
11670 }
11671
7117c2d2
JA
11672 SADD_MBCHAR (temp, string, sindex, string_size);
11673
8868edaf 11674add_character:
ccc6cda3
JA
11675 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
11676 DEFAULT_ARRAY_SIZE);
726f6388
JA
11677 istring[istring_index++] = c;
11678 istring[istring_index] = '\0';
11679
11680 /* Next character. */
11681 sindex++;
11682 }
11683 }
11684
11685finished_with_string:
726f6388
JA
11686 /* OK, we're ready to return. If we have a quoted string, and
11687 quoted_dollar_at is not set, we do no splitting at all; otherwise
11688 we split on ' '. The routines that call this will handle what to
11689 do if nothing has been expanded. */
ccc6cda3
JA
11690
11691 /* Partially and wholly quoted strings which expand to the empty
11692 string are retained as an empty arguments. Unquoted strings
11693 which expand to the empty string are discarded. The single
11694 exception is the case of expanding "$@" when there are no
11695 positional parameters. In that case, we discard the expansion. */
11696
11697 /* Because of how the code that handles "" and '' in partially
11698 quoted strings works, we need to make ISTRING into a QUOTED_NULL
11699 if we saw quoting characters, but the expansion was empty.
11700 "" and '' are tossed away before we get to this point when
11701 processing partially quoted strings. This makes "" and $xxx""
11702 equivalent when xxx is unset. We also look to see whether we
11703 saw a quoted null from a ${} expansion and add one back if we
11704 need to. */
11705
11706 /* If we expand to nothing and there were no single or double quotes
11707 in the word, we throw it away. Otherwise, we return a NULL word.
11708 The single exception is for $@ surrounded by double quotes when
11709 there are no positional parameters. In that case, we also throw
11710 the word away. */
11711
11712 if (*istring == '\0')
11713 {
74091dd4 11714#if 0
ccc6cda3 11715 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
74091dd4
CR
11716#else
11717 if (had_quoted_null || (quoted_dollar_at == 0 && quoted_state == PARTIALLY_QUOTED))
11718#endif
726f6388 11719 {
726f6388
JA
11720 istring[0] = CTLNUL;
11721 istring[1] = '\0';
d233b485
CR
11722 tword = alloc_word_desc ();
11723 tword->word = istring;
11724 istring = 0; /* avoid later free() */
95732b49 11725 tword->flags |= W_HASQUOTEDNULL; /* XXX */
ccc6cda3
JA
11726 list = make_word_list (tword, (WORD_LIST *)NULL);
11727 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
11728 tword->flags |= W_QUOTED;
726f6388 11729 }
ccc6cda3
JA
11730 /* According to sh, ksh, and Posix.2, if a word expands into nothing
11731 and a double-quoted "$@" appears anywhere in it, then the entire
11732 word is removed. */
a0c0a00f
CR
11733 /* XXX - exception appears to be that quoted null strings result in
11734 null arguments */
ccc6cda3
JA
11735 else if (quoted_state == UNQUOTED || quoted_dollar_at)
11736 list = (WORD_LIST *)NULL;
f73dda09
JA
11737 else
11738 list = (WORD_LIST *)NULL;
ccc6cda3
JA
11739 }
11740 else if (word->flags & W_NOSPLIT)
11741 {
d233b485
CR
11742 tword = alloc_word_desc ();
11743 tword->word = istring;
11744 if (had_quoted_null && QUOTED_NULL (istring))
11745 tword->flags |= W_HASQUOTEDNULL;
11746 istring = 0; /* avoid later free() */
ccc6cda3
JA
11747 if (word->flags & W_ASSIGNMENT)
11748 tword->flags |= W_ASSIGNMENT; /* XXX */
95732b49
JA
11749 if (word->flags & W_COMPASSIGN)
11750 tword->flags |= W_COMPASSIGN; /* XXX */
b72432fd
JA
11751 if (word->flags & W_NOGLOB)
11752 tword->flags |= W_NOGLOB; /* XXX */
ac50fbac
CR
11753 if (word->flags & W_NOBRACE)
11754 tword->flags |= W_NOBRACE; /* XXX */
74091dd4
CR
11755 if (word->flags & W_ARRAYREF)
11756 tword->flags |= W_ARRAYREF;
ccc6cda3 11757 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
28ef6c31 11758 tword->flags |= W_QUOTED;
95732b49 11759 list = make_word_list (tword, (WORD_LIST *)NULL);
ccc6cda3 11760 }
8868edaf
CR
11761 else if (word->flags & W_ASSIGNRHS)
11762 {
11763 list = list_string (istring, "", quoted);
11764 tword = list->word;
11765 if (had_quoted_null && QUOTED_NULL (istring))
11766 tword->flags |= W_HASQUOTEDNULL;
11767 free (list);
11768 free (istring);
11769 istring = 0; /* avoid later free() */
11770 goto set_word_flags;
11771 }
ccc6cda3
JA
11772 else
11773 {
11774 char *ifs_chars;
11775
7117c2d2 11776 ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
726f6388 11777
cce855bc
JA
11778 /* If we have $@, we need to split the results no matter what. If
11779 IFS is unset or NULL, string_list_dollar_at has separated the
11780 positional parameters with a space, so we split on space (we have
11781 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
11782 string_list_dollar_at has separated the positional parameters
ac50fbac
CR
11783 with the first character of $IFS, so we split on $IFS. If
11784 SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
11785 unset or null, and we want to make sure that we split on spaces
a0c0a00f
CR
11786 regardless of what else has happened to IFS since the expansion,
11787 or we expanded "$@" with IFS null and we need to split the positional
11788 parameters into separate words. */
ac50fbac 11789 if (split_on_spaces)
d233b485
CR
11790 {
11791 /* If IFS is not set, and the word is not quoted, we want to split
11792 the individual words on $' \t\n'. We rely on previous steps to
11793 quote the portions of the word that should not be split */
11794 if (ifs_is_set == 0)
11795 list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */
11796 else
11797 list = list_string (istring, " ", 1); /* XXX quoted == 1? */
11798 }
11799
3b34f6e6
CR
11800 /* If we have $@ (has_dollar_at != 0) and we are in a context where we
11801 don't want to split the result (W_NOSPLIT2), and we are not quoted,
11802 we have already separated the arguments with the first character of
11803 $IFS. In this case, we want to return a list with a single word
11804 with the separator possibly replaced with a space (it's what other
11805 shells seem to do).
11806 quoted_dollar_at is internal to this function and is set if we are
11807 passed an argument that is unquoted (quoted == 0) but we encounter a
11808 double-quoted $@ while expanding it. */
11809 else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2))
11810 {
d233b485 11811 tword = alloc_word_desc ();
3b34f6e6
CR
11812 /* Only split and rejoin if we have to */
11813 if (*ifs_chars && *ifs_chars != ' ')
11814 {
d233b485
CR
11815 /* list_string dequotes CTLESCs in the string it's passed, so we
11816 need it to get the space separation right if space isn't the
11817 first character in IFS (but is present) and to remove the
11818 quoting we added back in param_expand(). */
3b34f6e6 11819 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
d233b485
CR
11820 /* This isn't exactly right in the case where we're expanding
11821 the RHS of an expansion like ${var-$@} where IFS=: (for
11822 example). The W_NOSPLIT2 means we do the separation with :;
11823 the list_string removes the quotes and breaks the string into
11824 a list, and the string_list rejoins it on spaces. When we
11825 return, we expect to be able to split the results, but the
11826 space separation means the right split doesn't happen. */
11827 tword->word = string_list (list);
3b34f6e6
CR
11828 }
11829 else
d233b485
CR
11830 tword->word = istring;
11831 if (had_quoted_null && QUOTED_NULL (istring))
11832 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11833 if (tword->word != istring)
11834 free (istring);
11835 istring = 0; /* avoid later free() */
a0c0a00f
CR
11836 goto set_word_flags;
11837 }
ac50fbac 11838 else if (has_dollar_at && ifs_chars)
cce855bc 11839 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
ccc6cda3
JA
11840 else
11841 {
d233b485
CR
11842 tword = alloc_word_desc ();
11843 if (expanded_something && *expanded_something == 0 && has_quoted_ifs)
11844 tword->word = remove_quoted_ifs (istring);
11845 else
11846 tword->word = istring;
8868edaf 11847 if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */
d233b485
CR
11848 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11849 else if (had_quoted_null)
11850 tword->flags |= W_SAWQUOTEDNULL; /* XXX */
11851 if (tword->word != istring)
11852 free (istring);
11853 istring = 0; /* avoid later free() */
3b34f6e6 11854set_word_flags:
ccc6cda3
JA
11855 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
11856 tword->flags |= W_QUOTED;
11857 if (word->flags & W_ASSIGNMENT)
11858 tword->flags |= W_ASSIGNMENT;
95732b49
JA
11859 if (word->flags & W_COMPASSIGN)
11860 tword->flags |= W_COMPASSIGN;
b72432fd
JA
11861 if (word->flags & W_NOGLOB)
11862 tword->flags |= W_NOGLOB;
ac50fbac
CR
11863 if (word->flags & W_NOBRACE)
11864 tword->flags |= W_NOBRACE;
74091dd4
CR
11865 if (word->flags & W_ARRAYREF)
11866 tword->flags |= W_ARRAYREF;
95732b49 11867 list = make_word_list (tword, (WORD_LIST *)NULL);
726f6388 11868 }
726f6388 11869 }
726f6388 11870
ccc6cda3
JA
11871 free (istring);
11872 return (list);
726f6388
JA
11873}
11874
11875/* **************************************************************** */
11876/* */
11877/* Functions for Quote Removal */
11878/* */
11879/* **************************************************************** */
11880
11881/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
7117c2d2 11882 backslash quoting rules for within double quotes or a here document. */
726f6388
JA
11883char *
11884string_quote_removal (string, quoted)
11885 char *string;
11886 int quoted;
11887{
7117c2d2
JA
11888 size_t slen;
11889 char *r, *result_string, *temp, *send;
f73dda09
JA
11890 int sindex, tindex, dquote;
11891 unsigned char c;
7117c2d2 11892 DECLARE_MBSTATE;
726f6388
JA
11893
11894 /* The result can be no longer than the original string. */
7117c2d2
JA
11895 slen = strlen (string);
11896 send = string + slen;
11897
11898 r = result_string = (char *)xmalloc (slen + 1);
726f6388 11899
ccc6cda3 11900 for (dquote = sindex = 0; c = string[sindex];)
726f6388
JA
11901 {
11902 switch (c)
11903 {
11904 case '\\':
11905 c = string[++sindex];
3185942a
JA
11906 if (c == 0)
11907 {
11908 *r++ = '\\';
11909 break;
11910 }
28ef6c31 11911 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
726f6388 11912 *r++ = '\\';
ccc6cda3 11913 /* FALLTHROUGH */
726f6388
JA
11914
11915 default:
7117c2d2 11916 SCOPY_CHAR_M (r, string, send, sindex);
726f6388
JA
11917 break;
11918
11919 case '\'':
ccc6cda3 11920 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
726f6388
JA
11921 {
11922 *r++ = c;
11923 sindex++;
ccc6cda3 11924 break;
726f6388 11925 }
ccc6cda3 11926 tindex = sindex + 1;
74091dd4 11927 temp = string_extract_single_quoted (string, &tindex, 0);
ccc6cda3 11928 if (temp)
726f6388 11929 {
ccc6cda3
JA
11930 strcpy (r, temp);
11931 r += strlen (r);
11932 free (temp);
726f6388 11933 }
ccc6cda3 11934 sindex = tindex;
726f6388
JA
11935 break;
11936
11937 case '"':
11938 dquote = 1 - dquote;
11939 sindex++;
11940 break;
11941 }
11942 }
11943 *r = '\0';
11944 return (result_string);
11945}
11946
ccc6cda3
JA
11947#if 0
11948/* UNUSED */
726f6388
JA
11949/* Perform quote removal on word WORD. This allocates and returns a new
11950 WORD_DESC *. */
11951WORD_DESC *
11952word_quote_removal (word, quoted)
11953 WORD_DESC *word;
11954 int quoted;
11955{
11956 WORD_DESC *w;
11957 char *t;
11958
11959 t = string_quote_removal (word->word, quoted);
95732b49
JA
11960 w = alloc_word_desc ();
11961 w->word = t ? t : savestring ("");
726f6388
JA
11962 return (w);
11963}
11964
11965/* Perform quote removal on all words in LIST. If QUOTED is non-zero,
11966 the members of the list are treated as if they are surrounded by
11967 double quotes. Return a new list, or NULL if LIST is NULL. */
11968WORD_LIST *
11969word_list_quote_removal (list, quoted)
11970 WORD_LIST *list;
11971 int quoted;
11972{
95732b49 11973 WORD_LIST *result, *t, *tresult, *e;
726f6388 11974
ccc6cda3 11975 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
726f6388 11976 {
7117c2d2 11977 tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
95732b49 11978#if 0
726f6388 11979 result = (WORD_LIST *) list_append (result, tresult);
95732b49
JA
11980#else
11981 if (result == 0)
11982 result = e = tresult;
11983 else
11984 {
11985 e->next = tresult;
11986 while (e->next)
11987 e = e->next;
11988 }
11989#endif
726f6388
JA
11990 }
11991 return (result);
11992}
ccc6cda3 11993#endif
726f6388 11994
726f6388
JA
11995/*******************************************
11996 * *
11997 * Functions to perform word splitting *
11998 * *
11999 *******************************************/
12000
7117c2d2
JA
12001void
12002setifs (v)
12003 SHELL_VAR *v;
b72432fd 12004{
7117c2d2
JA
12005 char *t;
12006 unsigned char uc;
12007
12008 ifs_var = v;
95732b49 12009 ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
b72432fd 12010
ac50fbac
CR
12011 ifs_is_set = ifs_var != 0;
12012 ifs_is_null = ifs_is_set && (*ifs_value == 0);
12013
95732b49
JA
12014 /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
12015 handle multibyte chars in IFS */
7117c2d2
JA
12016 memset (ifs_cmap, '\0', sizeof (ifs_cmap));
12017 for (t = ifs_value ; t && *t; t++)
12018 {
12019 uc = *t;
12020 ifs_cmap[uc] = 1;
12021 }
12022
95732b49
JA
12023#if defined (HANDLE_MULTIBYTE)
12024 if (ifs_value == 0)
12025 {
d233b485 12026 ifs_firstc[0] = '\0'; /* XXX - ? */
95732b49
JA
12027 ifs_firstc_len = 1;
12028 }
12029 else
12030 {
d233b485
CR
12031 if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value))
12032 ifs_firstc_len = (*ifs_value != 0) ? 1 : 0;
12033 else
12034 {
12035 size_t ifs_len;
12036 ifs_len = strnlen (ifs_value, MB_CUR_MAX);
12037 ifs_firstc_len = MBLEN (ifs_value, ifs_len);
12038 }
95732b49
JA
12039 if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
12040 {
12041 ifs_firstc[0] = ifs_value[0];
12042 ifs_firstc[1] = '\0';
12043 ifs_firstc_len = 1;
12044 }
12045 else
12046 memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
12047 }
12048#else
7117c2d2 12049 ifs_firstc = ifs_value ? *ifs_value : 0;
95732b49 12050#endif
7117c2d2
JA
12051}
12052
12053char *
12054getifs ()
12055{
12056 return ifs_value;
b72432fd
JA
12057}
12058
726f6388
JA
12059/* This splits a single word into a WORD LIST on $IFS, but only if the word
12060 is not quoted. list_string () performs quote removal for us, even if we
12061 don't do any splitting. */
12062WORD_LIST *
7117c2d2 12063word_split (w, ifs_chars)
726f6388 12064 WORD_DESC *w;
7117c2d2 12065 char *ifs_chars;
726f6388
JA
12066{
12067 WORD_LIST *result;
12068
12069 if (w)
12070 {
7117c2d2 12071 char *xifs;
726f6388 12072
7117c2d2
JA
12073 xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
12074 result = list_string (w->word, xifs, w->flags & W_QUOTED);
726f6388
JA
12075 }
12076 else
12077 result = (WORD_LIST *)NULL;
ccc6cda3 12078
726f6388
JA
12079 return (result);
12080}
12081
12082/* Perform word splitting on LIST and return the RESULT. It is possible
12083 to return (WORD_LIST *)NULL. */
12084static WORD_LIST *
12085word_list_split (list)
12086 WORD_LIST *list;
12087{
95732b49 12088 WORD_LIST *result, *t, *tresult, *e;
d233b485 12089 WORD_DESC *w;
726f6388 12090
ccc6cda3 12091 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
726f6388 12092 {
7117c2d2 12093 tresult = word_split (t->word, ifs_value);
d233b485
CR
12094 /* POSIX 2.6: "If the complete expansion appropriate for a word results
12095 in an empty field, that empty field shall be deleted from the list
12096 of fields that form the completely expanded command, unless the
12097 original word contained single-quote or double-quote characters."
12098 This is where we handle these words that contain quoted null strings
12099 and other characters that expand to nothing after word splitting. */
12100 if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */
12101 {
12102 w = alloc_word_desc ();
12103 w->word = (char *)xmalloc (1);
12104 w->word[0] = '\0';
12105 tresult = make_word_list (w, (WORD_LIST *)NULL);
12106 }
74091dd4
CR
12107#if defined (ARRAY_VARS)
12108 /* pass W_ARRAYREF through for words that are not split and are
12109 identical to the original word. */
12110 if (tresult && tresult->next == 0 && t->next == 0 && (t->word->flags & W_ARRAYREF) && STREQ (t->word->word, tresult->word->word))
12111 tresult->word->flags |= W_ARRAYREF;
12112#endif
95732b49
JA
12113 if (result == 0)
12114 result = e = tresult;
12115 else
12116 {
12117 e->next = tresult;
12118 while (e->next)
12119 e = e->next;
12120 }
726f6388
JA
12121 }
12122 return (result);
12123}
12124
12125/**************************************************
12126 * *
cce855bc 12127 * Functions to expand an entire WORD_LIST *
726f6388
JA
12128 * *
12129 **************************************************/
12130
b80f6443
JA
12131/* Do any word-expansion-specific cleanup and jump to top_level */
12132static void
12133exp_jump_to_top_level (v)
12134 int v;
12135{
3185942a
JA
12136 set_pipestatus_from_exit (last_command_exit_value);
12137
b80f6443
JA
12138 /* Cleanup code goes here. */
12139 expand_no_split_dollar_star = 0; /* XXX */
d233b485
CR
12140 if (expanding_redir)
12141 undo_partial_redirects ();
b80f6443 12142 expanding_redir = 0;
3185942a 12143 assigning_in_environment = 0;
b80f6443 12144
f1be666c
JA
12145 if (parse_and_execute_level == 0)
12146 top_level_cleanup (); /* from sig.c */
12147
b80f6443
JA
12148 jump_to_top_level (v);
12149}
12150
cce855bc
JA
12151/* Put NLIST (which is a WORD_LIST * of only one element) at the front of
12152 ELIST, and set ELIST to the new list. */
12153#define PREPEND_LIST(nlist, elist) \
12154 do { nlist->next = elist; elist = nlist; } while (0)
12155
726f6388
JA
12156/* Separate out any initial variable assignments from TLIST. If set -k has
12157 been executed, remove all assignment statements from TLIST. Initial
12158 variable assignments and other environment assignments are placed
bb70624e 12159 on SUBST_ASSIGN_VARLIST. */
726f6388
JA
12160static WORD_LIST *
12161separate_out_assignments (tlist)
12162 WORD_LIST *tlist;
12163{
12164 register WORD_LIST *vp, *lp;
12165
0001803f 12166 if (tlist == 0)
726f6388
JA
12167 return ((WORD_LIST *)NULL);
12168
bb70624e
JA
12169 if (subst_assign_varlist)
12170 dispose_words (subst_assign_varlist); /* Clean up after previous error */
b72432fd 12171
bb70624e 12172 subst_assign_varlist = (WORD_LIST *)NULL;
726f6388
JA
12173 vp = lp = tlist;
12174
12175 /* Separate out variable assignments at the start of the command.
12176 Loop invariant: vp->next == lp
12177 Loop postcondition:
7117c2d2
JA
12178 lp = list of words left after assignment statements skipped
12179 tlist = original list of words
726f6388 12180 */
ccc6cda3 12181 while (lp && (lp->word->flags & W_ASSIGNMENT))
726f6388
JA
12182 {
12183 vp = lp;
12184 lp = lp->next;
12185 }
12186
bb70624e
JA
12187 /* If lp != tlist, we have some initial assignment statements.
12188 We make SUBST_ASSIGN_VARLIST point to the list of assignment
12189 words and TLIST point to the remaining words. */
726f6388
JA
12190 if (lp != tlist)
12191 {
bb70624e 12192 subst_assign_varlist = tlist;
726f6388
JA
12193 /* ASSERT(vp->next == lp); */
12194 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
12195 tlist = lp; /* remainder of word list */
12196 }
12197
12198 /* vp == end of variable list */
12199 /* tlist == remainder of original word list without variable assignments */
12200 if (!tlist)
12201 /* All the words in tlist were assignment statements */
12202 return ((WORD_LIST *)NULL);
12203
12204 /* ASSERT(tlist != NULL); */
ccc6cda3 12205 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
726f6388
JA
12206
12207 /* If the -k option is in effect, we need to go through the remaining
bb70624e
JA
12208 words, separate out the assignment words, and place them on
12209 SUBST_ASSIGN_VARLIST. */
726f6388
JA
12210 if (place_keywords_in_env)
12211 {
12212 WORD_LIST *tp; /* tp == running pointer into tlist */
12213
12214 tp = tlist;
12215 lp = tlist->next;
12216
12217 /* Loop Invariant: tp->next == lp */
12218 /* Loop postcondition: tlist == word list without assignment statements */
12219 while (lp)
12220 {
ccc6cda3 12221 if (lp->word->flags & W_ASSIGNMENT)
726f6388
JA
12222 {
12223 /* Found an assignment statement, add this word to end of
bb70624e
JA
12224 subst_assign_varlist (vp). */
12225 if (!subst_assign_varlist)
12226 subst_assign_varlist = vp = lp;
726f6388
JA
12227 else
12228 {
12229 vp->next = lp;
12230 vp = lp;
12231 }
12232
12233 /* Remove the word pointed to by LP from TLIST. */
12234 tp->next = lp->next;
12235 /* ASSERT(vp == lp); */
12236 lp->next = (WORD_LIST *)NULL;
12237 lp = tp->next;
12238 }
12239 else
12240 {
12241 tp = lp;
12242 lp = lp->next;
12243 }
12244 }
12245 }
12246 return (tlist);
12247}
12248
cce855bc
JA
12249#define WEXP_VARASSIGN 0x001
12250#define WEXP_BRACEEXP 0x002
12251#define WEXP_TILDEEXP 0x004
12252#define WEXP_PARAMEXP 0x008
12253#define WEXP_PATHEXP 0x010
12254
12255/* All of the expansions, including variable assignments at the start of
12256 the list. */
12257#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
12258
12259/* All of the expansions except variable assignments at the start of
12260 the list. */
12261#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
12262
12263/* All of the `shell expansions': brace expansion, tilde expansion, parameter
12264 expansion, command substitution, arithmetic expansion, word splitting, and
12265 quote removal. */
12266#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
12267
726f6388
JA
12268/* Take the list of words in LIST and do the various substitutions. Return
12269 a new list of words which is the expanded list, and without things like
12270 variable assignments. */
12271
12272WORD_LIST *
12273expand_words (list)
12274 WORD_LIST *list;
12275{
cce855bc 12276 return (expand_word_list_internal (list, WEXP_ALL));
726f6388
JA
12277}
12278
12279/* Same as expand_words (), but doesn't hack variable or environment
12280 variables. */
12281WORD_LIST *
12282expand_words_no_vars (list)
12283 WORD_LIST *list;
12284{
cce855bc 12285 return (expand_word_list_internal (list, WEXP_NOVARS));
726f6388
JA
12286}
12287
cce855bc
JA
12288WORD_LIST *
12289expand_words_shellexp (list)
726f6388 12290 WORD_LIST *list;
726f6388 12291{
cce855bc
JA
12292 return (expand_word_list_internal (list, WEXP_SHELLEXP));
12293}
726f6388 12294
cce855bc
JA
12295static WORD_LIST *
12296glob_expand_word_list (tlist, eflags)
12297 WORD_LIST *tlist;
12298 int eflags;
12299{
12300 char **glob_array, *temp_string;
12301 register int glob_index;
12302 WORD_LIST *glob_list, *output_list, *disposables, *next;
12303 WORD_DESC *tword;
8868edaf 12304 int x;
726f6388 12305
cce855bc
JA
12306 output_list = disposables = (WORD_LIST *)NULL;
12307 glob_array = (char **)NULL;
12308 while (tlist)
12309 {
12310 /* For each word, either globbing is attempted or the word is
12311 added to orig_list. If globbing succeeds, the results are
12312 added to orig_list and the word (tlist) is added to the list
12313 of disposable words. If globbing fails and failed glob
12314 expansions are left unchanged (the shell default), the
12315 original word is added to orig_list. If globbing fails and
12316 failed glob expansions are removed, the original word is
12317 added to the list of disposable words. orig_list ends up
7117c2d2 12318 in reverse order and requires a call to REVERSE_LIST to
cce855bc
JA
12319 be set right. After all words are examined, the disposable
12320 words are freed. */
12321 next = tlist->next;
726f6388 12322
cce855bc 12323 /* If the word isn't an assignment and contains an unquoted
28ef6c31 12324 pattern matching character, then glob it. */
b72432fd 12325 if ((tlist->word->flags & W_NOGLOB) == 0 &&
cce855bc 12326 unquoted_glob_pattern_p (tlist->word->word))
726f6388 12327 {
8868edaf 12328 glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */
cce855bc
JA
12329
12330 /* Handle error cases.
12331 I don't think we should report errors like "No such file
12332 or directory". However, I would like to report errors
12333 like "Read failed". */
12334
b80f6443 12335 if (glob_array == 0 || GLOB_FAILED (glob_array))
726f6388 12336 {
bb70624e 12337 glob_array = (char **)xmalloc (sizeof (char *));
cce855bc
JA
12338 glob_array[0] = (char *)NULL;
12339 }
12340
12341 /* Dequote the current word in case we have to use it. */
12342 if (glob_array[0] == NULL)
12343 {
12344 temp_string = dequote_string (tlist->word->word);
12345 free (tlist->word->word);
12346 tlist->word->word = temp_string;
12347 }
12348
12349 /* Make the array into a word list. */
12350 glob_list = (WORD_LIST *)NULL;
12351 for (glob_index = 0; glob_array[glob_index]; glob_index++)
12352 {
12353 tword = make_bare_word (glob_array[glob_index]);
cce855bc
JA
12354 glob_list = make_word_list (tword, glob_list);
12355 }
12356
12357 if (glob_list)
12358 {
12359 output_list = (WORD_LIST *)list_append (glob_list, output_list);
12360 PREPEND_LIST (tlist, disposables);
12361 }
b80f6443
JA
12362 else if (fail_glob_expansion != 0)
12363 {
ac50fbac 12364 last_command_exit_value = EXECUTION_FAILURE;
b80f6443 12365 report_error (_("no match: %s"), tlist->word->word);
f1be666c 12366 exp_jump_to_top_level (DISCARD);
b80f6443 12367 }
cce855bc
JA
12368 else if (allow_null_glob_expansion == 0)
12369 {
12370 /* Failed glob expressions are left unchanged. */
12371 PREPEND_LIST (tlist, output_list);
12372 }
12373 else
12374 {
12375 /* Failed glob expressions are removed. */
12376 PREPEND_LIST (tlist, disposables);
726f6388 12377 }
726f6388 12378 }
cce855bc
JA
12379 else
12380 {
12381 /* Dequote the string. */
12382 temp_string = dequote_string (tlist->word->word);
12383 free (tlist->word->word);
12384 tlist->word->word = temp_string;
12385 PREPEND_LIST (tlist, output_list);
12386 }
12387
7117c2d2 12388 strvec_dispose (glob_array);
cce855bc
JA
12389 glob_array = (char **)NULL;
12390
12391 tlist = next;
726f6388
JA
12392 }
12393
cce855bc
JA
12394 if (disposables)
12395 dispose_words (disposables);
12396
12397 if (output_list)
12398 output_list = REVERSE_LIST (output_list, WORD_LIST *);
12399
12400 return (output_list);
12401}
726f6388
JA
12402
12403#if defined (BRACE_EXPANSION)
cce855bc
JA
12404static WORD_LIST *
12405brace_expand_word_list (tlist, eflags)
12406 WORD_LIST *tlist;
12407 int eflags;
12408{
12409 register char **expansions;
12410 char *temp_string;
12411 WORD_LIST *disposables, *output_list, *next;
12412 WORD_DESC *w;
12413 int eindex;
12414
12415 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
726f6388 12416 {
cce855bc 12417 next = tlist->next;
726f6388 12418
ac50fbac
CR
12419 if (tlist->word->flags & W_NOBRACE)
12420 {
12421/*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/
12422 PREPEND_LIST (tlist, output_list);
12423 continue;
12424 }
12425
0001803f
CR
12426 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
12427 {
12428/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
12429 PREPEND_LIST (tlist, output_list);
12430 continue;
12431 }
ac50fbac 12432
cce855bc
JA
12433 /* Only do brace expansion if the word has a brace character. If
12434 not, just add the word list element to BRACES and continue. In
12435 the common case, at least when running shell scripts, this will
0001803f 12436 degenerate to a bunch of calls to `mbschr', and then what is
cce855bc 12437 basically a reversal of TLIST into BRACES, which is corrected
7117c2d2 12438 by a call to REVERSE_LIST () on BRACES when the end of TLIST
cce855bc 12439 is reached. */
0001803f 12440 if (mbschr (tlist->word->word, LBRACE))
726f6388 12441 {
cce855bc 12442 expansions = brace_expand (tlist->word->word);
726f6388 12443
cce855bc 12444 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
726f6388 12445 {
ac50fbac
CR
12446 w = alloc_word_desc ();
12447 w->word = temp_string;
12448
cce855bc
JA
12449 /* If brace expansion didn't change the word, preserve
12450 the flags. We may want to preserve the flags
12451 unconditionally someday -- XXX */
12452 if (STREQ (temp_string, tlist->word->word))
12453 w->flags = tlist->word->flags;
ac50fbac
CR
12454 else
12455 w = make_word_flags (w, temp_string);
12456
cce855bc 12457 output_list = make_word_list (w, output_list);
726f6388 12458 }
cce855bc 12459 free (expansions);
726f6388 12460
cce855bc
JA
12461 /* Add TLIST to the list of words to be freed after brace
12462 expansion has been performed. */
12463 PREPEND_LIST (tlist, disposables);
12464 }
12465 else
12466 PREPEND_LIST (tlist, output_list);
726f6388 12467 }
cce855bc
JA
12468
12469 if (disposables)
12470 dispose_words (disposables);
12471
12472 if (output_list)
12473 output_list = REVERSE_LIST (output_list, WORD_LIST *);
12474
12475 return (output_list);
12476}
12477#endif
12478
3185942a 12479#if defined (ARRAY_VARS)
8868edaf
CR
12480/* Take WORD, a compound array assignment, and internally run (for example),
12481 'declare -A w', where W is the variable name portion of WORD. OPTION is
12482 the list of options to supply to `declare'. CMD is the declaration command
12483 we are expanding right now; it's unused currently. */
3185942a 12484static int
a0c0a00f 12485make_internal_declare (word, option, cmd)
3185942a
JA
12486 char *word;
12487 char *option;
a0c0a00f 12488 char *cmd;
3185942a 12489{
a0c0a00f 12490 int t, r;
3185942a
JA
12491 WORD_LIST *wl;
12492 WORD_DESC *w;
12493
12494 w = make_word (word);
12495
12496 t = assignment (w->word, 0);
a0c0a00f
CR
12497 if (w->word[t] == '=')
12498 {
12499 w->word[t] = '\0';
12500 if (w->word[t - 1] == '+') /* cut off any append op */
12501 w->word[t - 1] = '\0';
12502 }
3185942a
JA
12503
12504 wl = make_word_list (w, (WORD_LIST *)NULL);
12505 wl = make_word_list (make_word (option), wl);
12506
a0c0a00f
CR
12507 r = declare_builtin (wl);
12508
12509 dispose_words (wl);
12510 return r;
3185942a 12511}
8868edaf
CR
12512
12513/* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME
12514 is an associative array.
12515
12516 If we are processing an indexed array, expand_compound_array_assignment
12517 will expand all the individual words and quote_compound_array_list will
12518 single-quote them. If we are processing an associative array, we use
12519 parse_string_to_word_list to split VALUE into a list of words instead of
12520 faking up a shell variable and calling expand_compound_array_assignment.
12521 expand_and_quote_assoc_word expands and single-quotes each word in VALUE
12522 together so we don't have problems finding the end of the subscript when
12523 quoting it.
12524
12525 Words in VALUE can be individual words, which are expanded and single-quoted,
12526 or words of the form [IND]=VALUE, which end up as explained below, as
12527 ['expanded-ind']='expanded-value'. */
12528
12529static WORD_LIST *
12530expand_oneword (value, flags)
12531 char *value;
12532 int flags;
12533{
12534 WORD_LIST *l, *nl;
12535 char *t;
76404c85 12536 int kvpair;
8868edaf
CR
12537
12538 if (flags == 0)
12539 {
12540 /* Indexed array */
12541 l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags);
12542 /* Now we quote the results of the expansion above to prevent double
12543 expansion. */
12544 quote_compound_array_list (l, flags);
12545 return l;
12546 }
12547 else
12548 {
12549 /* Associative array */
12550 l = parse_string_to_word_list (value, 1, "array assign");
76404c85
CR
12551#if ASSOC_KVPAIR_ASSIGNMENT
12552 kvpair = kvpair_assignment_p (l);
12553#endif
12554
8868edaf
CR
12555 /* For associative arrays, with their arbitrary subscripts, we have to
12556 expand and quote in one step so we don't have to search for the
12557 closing right bracket more than once. */
12558 for (nl = l; nl; nl = nl->next)
12559 {
76404c85
CR
12560#if ASSOC_KVPAIR_ASSIGNMENT
12561 if (kvpair)
12562 /* keys and values undergo the same set of expansions */
12563 t = expand_and_quote_kvpair_word (nl->word->word);
12564 else
12565#endif
8868edaf
CR
12566 if ((nl->word->flags & W_ASSIGNMENT) == 0)
12567 t = sh_single_quote (nl->word->word ? nl->word->word : "");
12568 else
12569 t = expand_and_quote_assoc_word (nl->word->word, flags);
12570 free (nl->word->word);
12571 nl->word->word = t;
12572 }
12573 return l;
12574 }
12575}
12576
12577/* Expand a single compound assignment argument to a declaration builtin.
12578 This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through
12579 unchanged. The VALUE is expanded and each word in the result is single-
12580 quoted. Words of the form [key]=value end up as
12581 ['expanded-key']='expanded-value'. Associative arrays have special
12582 handling, see expand_oneword() above. The return value is
12583 NAME[+]=( expanded-and-quoted-VALUE ). */
12584static void
12585expand_compound_assignment_word (tlist, flags)
12586 WORD_LIST *tlist;
12587 int flags;
12588{
12589 WORD_LIST *l;
12590 int wlen, oind, t;
12591 char *value, *temp;
12592
12593/*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/
12594 t = assignment (tlist->word->word, 0);
12595
12596 /* value doesn't have the open and close parens */
12597 oind = 1;
12598 value = extract_array_assignment_list (tlist->word->word + t + 1, &oind);
12599 /* This performs one round of expansion on the index/key and value and
12600 single-quotes each word in the result. */
12601 l = expand_oneword (value, flags);
12602 free (value);
12603
12604 value = string_list (l);
cc978a67
CR
12605 dispose_words (l);
12606
8868edaf
CR
12607 wlen = STRLEN (value);
12608
12609 /* Now, let's rebuild the string */
12610 temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */
12611 memcpy (temp, tlist->word->word, ++t);
12612 temp[t++] = '(';
12613 if (value)
12614 memcpy (temp + t, value, wlen);
12615 t += wlen;
12616 temp[t++] = ')';
12617 temp[t] = '\0';
12618/*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/
12619
12620 free (tlist->word->word);
12621 tlist->word->word = temp;
12622
12623 free (value);
12624}
12625
12626/* Expand and process an argument to a declaration command. We have already
12627 set flags in TLIST->word->flags depending on the declaration command
12628 (declare, local, etc.) and the options supplied to it (-a, -A, etc.).
12629 TLIST->word->word is of the form NAME[+]=( VALUE ).
12630
12631 This does several things, all using pieces of other functions to get the
12632 evaluation sequence right. It's called for compound array assignments with
12633 the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs).
12634 It parses out which flags need to be set for declare to create the variable
12635 correctly, then calls declare internally (make_internal_declare) to make
12636 sure the variable exists with the correct attributes. Before the variable
12637 is created, it calls expand_compound_assignment_word to expand VALUE to a
12638 list of words, appropriately quoted for further evaluation. This preserves
12639 the semantics of word-expansion-before-calling-builtins. Finally, it calls
12640 do_word_assignment to perform the expansion and assignment with the same
12641 expansion semantics as a standalone assignment statement (no word splitting,
12642 etc.) even though the word is single-quoted so all that needs to happen is
12643 quote removal. */
12644static WORD_LIST *
12645expand_declaration_argument (tlist, wcmd)
12646 WORD_LIST *tlist, *wcmd;
12647{
12648 char opts[16], omap[128];
12649 int t, opti, oind, skip, inheriting;
12650 WORD_LIST *l;
12651
12652 inheriting = localvar_inherit;
12653 opti = 0;
12654 if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY))
12655 opts[opti++] = '-';
12656
12657 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
12658 {
12659 opts[opti++] = 'g';
12660 opts[opti++] = 'A';
12661 }
12662 else if (tlist->word->flags & W_ASSIGNASSOC)
12663 {
12664 opts[opti++] = 'A';
12665 }
12666 else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
12667 {
12668 opts[opti++] = 'g';
12669 opts[opti++] = 'a';
12670 }
12671 else if (tlist->word->flags & W_ASSIGNARRAY)
12672 {
12673 opts[opti++] = 'a';
12674 }
12675 else if (tlist->word->flags & W_ASSNGLOBAL)
12676 opts[opti++] = 'g';
12677
12678 if (tlist->word->flags & W_CHKLOCAL)
12679 opts[opti++] = 'G';
12680
12681 /* If we have special handling note the integer attribute and others
12682 that transform the value upon assignment. What we do is take all
12683 of the option arguments and scan through them looking for options
12684 that cause such transformations, and add them to the `opts' array. */
12685
12686 memset (omap, '\0', sizeof (omap));
12687 for (l = wcmd->next; l != tlist; l = l->next)
12688 {
74091dd4
CR
12689 int optchar;
12690
12691 if (l->word->word[0] != '-' && l->word->word[0] != '+')
8868edaf
CR
12692 break; /* non-option argument */
12693 if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0)
12694 break; /* -- signals end of options */
74091dd4 12695 optchar = l->word->word[0];
8868edaf
CR
12696 for (oind = 1; l->word->word[oind]; oind++)
12697 switch (l->word->word[oind])
12698 {
12699 case 'I':
12700 inheriting = 1;
12701 case 'i':
12702 case 'l':
12703 case 'u':
12704 case 'c':
12705 omap[l->word->word[oind]] = 1;
12706 if (opti == 0)
74091dd4 12707 opts[opti++] = optchar;
8868edaf
CR
12708 break;
12709 default:
12710 break;
12711 }
12712 }
12713
12714 for (oind = 0; oind < sizeof (omap); oind++)
12715 if (omap[oind])
12716 opts[opti++] = oind;
12717
12718 /* If there are no -a/-A options, but we have a compound assignment,
12719 we have a choice: we can set opts[0]='-', opts[1]='a', since the
12720 default is to create an indexed array, and call
12721 make_internal_declare with that, or we can just skip the -a and let
12722 declare_builtin deal with it. Once we're here, we're better set
12723 up for the latter, since we don't want to deal with looking up
12724 any existing variable here -- better to let declare_builtin do it.
12725 We need the variable created, though, especially if it's local, so
12726 we get the scoping right before we call do_word_assignment.
12727 To ensure that make_local_declare gets called, we add `--' if there
12728 aren't any options. */
12729 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0)
12730 {
12731 if (opti == 0)
12732 {
12733 opts[opti++] = '-';
12734 opts[opti++] = '-';
12735 }
12736 }
12737 opts[opti] = '\0';
12738
12739 /* This isn't perfect, but it's a start. Improvements later. We expand
12740 tlist->word->word and single-quote the results to avoid multiple
12741 expansions by, say, do_assignment_internal(). We have to weigh the
12742 cost of reconstructing the compound assignment string with its single
12743 quoting and letting the declare builtin handle it. The single quotes
12744 will prevent any unwanted additional expansion or word splitting. */
12745 expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0);
12746
12747 skip = 0;
12748 if (opti > 0)
12749 {
12750 t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0);
12751 if (t != EXECUTION_SUCCESS)
12752 {
12753 last_command_exit_value = t;
12754 if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */
12755 skip = 1;
12756 else
12757 exp_jump_to_top_level (DISCARD);
12758 }
12759 }
12760
12761 if (skip == 0)
12762 {
12763 t = do_word_assignment (tlist->word, 0);
12764 if (t == 0)
12765 {
12766 last_command_exit_value = EXECUTION_FAILURE;
12767 exp_jump_to_top_level (DISCARD);
12768 }
12769 }
12770
12771 /* Now transform the word as ksh93 appears to do and go on */
12772 t = assignment (tlist->word->word, 0);
12773 tlist->word->word[t] = '\0';
12774 if (tlist->word->word[t - 1] == '+')
12775 tlist->word->word[t - 1] = '\0'; /* cut off append op */
12776 tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
12777
12778 return (tlist);
12779}
12780#endif /* ARRAY_VARS */
3185942a 12781
cce855bc
JA
12782static WORD_LIST *
12783shell_expand_word_list (tlist, eflags)
12784 WORD_LIST *tlist;
12785 int eflags;
12786{
a0c0a00f 12787 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd;
cce855bc 12788 int expanded_something, has_dollar_at;
726f6388 12789
726f6388 12790 /* We do tilde expansion all the time. This is what 1003.2 says. */
8868edaf 12791 wcmd = new_list = (WORD_LIST *)NULL;
a0c0a00f 12792
cce855bc 12793 for (orig_list = tlist; tlist; tlist = next)
726f6388 12794 {
8868edaf
CR
12795 if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN))
12796 wcmd = tlist;
12797
726f6388
JA
12798 next = tlist->next;
12799
95732b49
JA
12800#if defined (ARRAY_VARS)
12801 /* If this is a compound array assignment to a builtin that accepts
12802 such assignments (e.g., `declare'), take the assignment and perform
12803 it separately, handling the semantics of declarations inside shell
12804 functions. This avoids the double-evaluation of such arguments,
12805 because `declare' does some evaluation of compound assignments on
12806 its own. */
12807 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
8868edaf 12808 expand_declaration_argument (tlist, wcmd);
95732b49 12809#endif
726f6388 12810
ccc6cda3 12811 expanded_something = 0;
726f6388 12812 expanded = expand_word_internal
b72432fd 12813 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
726f6388
JA
12814
12815 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
12816 {
12817 /* By convention, each time this error is returned,
12818 tlist->word->word has already been freed. */
12819 tlist->word->word = (char *)NULL;
ccc6cda3 12820
726f6388
JA
12821 /* Dispose our copy of the original list. */
12822 dispose_words (orig_list);
d166f048 12823 /* Dispose the new list we're building. */
726f6388
JA
12824 dispose_words (new_list);
12825
28ef6c31 12826 last_command_exit_value = EXECUTION_FAILURE;
726f6388 12827 if (expanded == &expand_word_error)
b80f6443 12828 exp_jump_to_top_level (DISCARD);
726f6388 12829 else
b80f6443 12830 exp_jump_to_top_level (FORCE_EOF);
726f6388
JA
12831 }
12832
ccc6cda3
JA
12833 /* Don't split words marked W_NOSPLIT. */
12834 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
726f6388 12835 {
ccc6cda3 12836 temp_list = word_list_split (expanded);
726f6388
JA
12837 dispose_words (expanded);
12838 }
12839 else
12840 {
12841 /* If no parameter expansion, command substitution, process
12842 substitution, or arithmetic substitution took place, then
12843 do not do word splitting. We still have to remove quoted
12844 null characters from the result. */
12845 word_list_remove_quoted_nulls (expanded);
ccc6cda3 12846 temp_list = expanded;
726f6388
JA
12847 }
12848
ccc6cda3
JA
12849 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
12850 new_list = (WORD_LIST *)list_append (expanded, new_list);
726f6388
JA
12851 }
12852
cce855bc
JA
12853 if (orig_list)
12854 dispose_words (orig_list);
726f6388 12855
726f6388 12856 if (new_list)
cce855bc 12857 new_list = REVERSE_LIST (new_list, WORD_LIST *);
726f6388 12858
cce855bc
JA
12859 return (new_list);
12860}
726f6388 12861
74091dd4
CR
12862/* Perform assignment statements optionally preceding a command name COMMAND.
12863 If COMMAND == NULL, is_nullcmd usually == 1. Follow the POSIX rules for
12864 variable assignment errors. */
12865static int
12866do_assignment_statements (varlist, command, is_nullcmd)
12867 WORD_LIST *varlist;
12868 char *command;
12869 int is_nullcmd;
12870{
12871 WORD_LIST *temp_list;
12872 char *savecmd;
12873 sh_wassign_func_t *assign_func;
12874 int is_special_builtin, is_builtin_or_func, tint;
12875
12876 /* If the remainder of the words expand to nothing, Posix.2 requires
12877 that the variable and environment assignments affect the shell's
12878 environment (do_word_assignment). */
12879 assign_func = is_nullcmd ? do_word_assignment : assign_in_env;
12880 tempenv_assign_error = 0;
12881
12882 is_builtin_or_func = command && (find_shell_builtin (command) || find_function (command));
12883 /* Posix says that special builtins exit if a variable assignment error
12884 occurs in an assignment preceding it. (XXX - this is old -- current Posix
12885 says that any variable assignment error causes a non-interactive shell
12886 to exit. See the STRICT_POSIX checks below. */
12887 is_special_builtin = posixly_correct && command && find_special_builtin (command);
12888
12889 savecmd = this_command_name;
12890 for (temp_list = varlist; temp_list; temp_list = temp_list->next)
12891 {
12892 this_command_name = (char *)NULL;
12893 assigning_in_environment = is_nullcmd == 0;
12894 tint = (*assign_func) (temp_list->word, is_builtin_or_func);
12895 assigning_in_environment = 0;
12896 this_command_name = savecmd;
12897
12898 /* Variable assignment errors in non-interactive shells running
12899 in posix mode cause the shell to exit. */
12900 if (tint == 0)
12901 {
12902 if (is_nullcmd) /* assignment statement */
12903 {
12904 last_command_exit_value = EXECUTION_FAILURE;
12905#if defined (STRICT_POSIX)
12906 if (posixly_correct && interactive_shell == 0)
12907#else
12908 if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
12909#endif
12910 exp_jump_to_top_level (FORCE_EOF);
12911 else
12912 exp_jump_to_top_level (DISCARD);
12913 }
12914 /* In posix mode, assignment errors in the temporary environment
12915 cause a non-interactive shell executing a special builtin to
12916 exit and a non-interactive shell to otherwise jump back to the
12917 top level. This is what POSIX says to do for variable assignment
12918 errors, and POSIX says errors in assigning to the temporary
12919 environment are treated as variable assignment errors.
12920 (XXX - this is not what current POSIX says - look at the
12921 STRICT_POSIX defines. */
12922 else if (posixly_correct)
12923 {
12924 last_command_exit_value = EXECUTION_FAILURE;
12925#if defined (STRICT_POSIX)
12926 exp_jump_to_top_level ((interactive_shell == 0) ? FORCE_EOF : DISCARD);
12927#else
12928 if (interactive_shell == 0 && is_special_builtin)
12929 exp_jump_to_top_level (FORCE_EOF);
12930 else if (interactive_shell == 0)
12931 exp_jump_to_top_level (DISCARD); /* XXX - maybe change later */
12932 else
12933 exp_jump_to_top_level (DISCARD);
12934#endif
12935 }
12936 else
12937 tempenv_assign_error++;
12938 }
12939 }
12940 return (tempenv_assign_error);
12941}
12942
cce855bc
JA
12943/* The workhorse for expand_words () and expand_words_no_vars ().
12944 First arg is LIST, a WORD_LIST of words.
b72432fd
JA
12945 Second arg EFLAGS is a flags word controlling which expansions are
12946 performed.
726f6388 12947
cce855bc
JA
12948 This does all of the substitutions: brace expansion, tilde expansion,
12949 parameter expansion, command substitution, arithmetic expansion,
12950 process substitution, word splitting, and pathname expansion, according
12951 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
12952 set, or for which no expansion is done, do not undergo word splitting.
ac50fbac
CR
12953 Words with the W_NOGLOB bit set do not undergo pathname expansion; words
12954 with W_NOBRACE set do not undergo brace expansion (see
12955 brace_expand_word_list above). */
cce855bc
JA
12956static WORD_LIST *
12957expand_word_list_internal (list, eflags)
12958 WORD_LIST *list;
12959 int eflags;
12960{
12961 WORD_LIST *new_list, *temp_list;
726f6388 12962
ac50fbac 12963 tempenv_assign_error = 0;
cce855bc
JA
12964 if (list == 0)
12965 return ((WORD_LIST *)NULL);
726f6388 12966
bb70624e 12967 garglist = new_list = copy_word_list (list);
cce855bc
JA
12968 if (eflags & WEXP_VARASSIGN)
12969 {
bb70624e 12970 garglist = new_list = separate_out_assignments (new_list);
cce855bc
JA
12971 if (new_list == 0)
12972 {
bb70624e 12973 if (subst_assign_varlist)
74091dd4
CR
12974 do_assignment_statements (subst_assign_varlist, (char *)NULL, 1);
12975
12976 dispose_words (subst_assign_varlist);
12977 subst_assign_varlist = (WORD_LIST *)NULL;
12978
cce855bc
JA
12979 return ((WORD_LIST *)NULL);
12980 }
12981 }
726f6388 12982
cce855bc
JA
12983 /* Begin expanding the words that remain. The expansions take place on
12984 things that aren't really variable assignments. */
726f6388 12985
cce855bc
JA
12986#if defined (BRACE_EXPANSION)
12987 /* Do brace expansion on this word if there are any brace characters
12988 in the string. */
12989 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
12990 new_list = brace_expand_word_list (new_list, eflags);
12991#endif /* BRACE_EXPANSION */
726f6388 12992
cce855bc
JA
12993 /* Perform the `normal' shell expansions: tilde expansion, parameter and
12994 variable substitution, command substitution, arithmetic expansion,
12995 and word splitting. */
12996 new_list = shell_expand_word_list (new_list, eflags);
726f6388 12997
cce855bc
JA
12998 /* Okay, we're almost done. Now let's just do some filename
12999 globbing. */
13000 if (new_list)
13001 {
13002 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
13003 /* Glob expand the word list unless globbing has been disabled. */
13004 new_list = glob_expand_word_list (new_list, eflags);
726f6388 13005 else
cce855bc
JA
13006 /* Dequote the words, because we're not performing globbing. */
13007 new_list = dequote_list (new_list);
726f6388
JA
13008 }
13009
bb70624e 13010 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
726f6388 13011 {
74091dd4 13012 do_assignment_statements (subst_assign_varlist, (new_list && new_list->word) ? new_list->word->word : (char *)NULL, new_list == 0);
726f6388 13013
bb70624e
JA
13014 dispose_words (subst_assign_varlist);
13015 subst_assign_varlist = (WORD_LIST *)NULL;
726f6388
JA
13016 }
13017
cce855bc 13018 return (new_list);
ccc6cda3 13019}