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