]> git.ipfire.org Git - thirdparty/bash.git/blame - subst.c
commit bash-20130404 snapshot
[thirdparty/bash.git] / subst.c
CommitLineData
cc87ba64
CR
1/* subst.c -- The part of the shell that does parameter, command, arithmetic,
2 and globbing substitutions. */
726f6388 3
bb70624e
JA
4/* ``Have a little faith, there's magic in the night. You ain't a
5 beauty, but, hey, you're alright.'' */
6
73a146be 7/* Copyright (C) 1987-2013 Free Software Foundation, Inc.
726f6388
JA
8
9 This file is part of GNU Bash, the Bourne Again SHell.
10
2e4498b3
CR
11 Bash is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 Bash is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with Bash. If not, see <http://www.gnu.org/licenses/>.
23*/
726f6388 24
ccc6cda3
JA
25#include "config.h"
26
726f6388
JA
27#include "bashtypes.h"
28#include <stdio.h>
f73dda09 29#include "chartypes.h"
e77a3058
CR
30#if defined (HAVE_PWD_H)
31# include <pwd.h>
32#endif
726f6388
JA
33#include <signal.h>
34#include <errno.h>
ccc6cda3
JA
35
36#if defined (HAVE_UNISTD_H)
37# include <unistd.h>
38#endif
726f6388
JA
39
40#include "bashansi.h"
41#include "posixstat.h"
5e13499c 42#include "bashintl.h"
726f6388
JA
43
44#include "shell.h"
9e51a74d 45#include "parser.h"
726f6388
JA
46#include "flags.h"
47#include "jobs.h"
48#include "execute_cmd.h"
49#include "filecntl.h"
ccc6cda3
JA
50#include "trap.h"
51#include "pathexp.h"
52#include "mailcheck.h"
53
7117c2d2 54#include "shmbutil.h"
06dff54a 55#include "typemax.h"
7117c2d2 56
ccc6cda3
JA
57#include "builtins/getopt.h"
58#include "builtins/common.h"
726f6388 59
48ff5447
CR
60#include "builtins/builtext.h"
61
cce855bc 62#include <tilde/tilde.h>
f73dda09 63#include <glob/strmatch.h>
ccc6cda3
JA
64
65#if !defined (errno)
66extern int errno;
67#endif /* !errno */
726f6388
JA
68
69/* The size that strings change by. */
d166f048 70#define DEFAULT_INITIAL_ARRAY_SIZE 112
ccc6cda3
JA
71#define DEFAULT_ARRAY_SIZE 128
72
73/* Variable types. */
74#define VT_VARIABLE 0
75#define VT_POSPARMS 1
76#define VT_ARRAYVAR 2
d166f048 77#define VT_ARRAYMEMBER 3
e33f2203 78#define VT_ASSOCVAR 4
726f6388 79
d3a24ed2
CR
80#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
81
ccc6cda3
JA
82/* Flags for quoted_strchr */
83#define ST_BACKSL 0x01
84#define ST_CTLESC 0x02
7117c2d2
JA
85#define ST_SQUOTE 0x04 /* unused yet */
86#define ST_DQUOTE 0x08 /* unused yet */
87
d3a24ed2
CR
88/* Flags for the `pflags' argument to param_expand() */
89#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
1231ac47 90#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */
e1e48bba 91#define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 */
40647963 92#define PF_ASSIGNRHS 0x08 /* same as W_ASSIGNRHS */
d3a24ed2 93
cce855bc
JA
94/* These defs make it easier to use the editor. */
95#define LBRACE '{'
96#define RBRACE '}'
97#define LPAREN '('
98#define RPAREN ')'
726f6388 99
176b12ee
CR
100#if defined (HANDLE_MULTIBYTE)
101#define WLPAREN L'('
102#define WRPAREN L')'
103#endif
104
28ef6c31
JA
105/* Evaluates to 1 if C is one of the shell's special parameters whose length
106 can be taken, but is also one of the special expansion characters. */
107#define VALID_SPECIAL_LENGTH_PARAM(c) \
108 ((c) == '-' || (c) == '?' || (c) == '#')
109
110/* Evaluates to 1 if C is one of the shell's special parameters for which an
111 indirect variable reference may be made. */
112#define VALID_INDIR_PARAM(c) \
e05be32d 113 ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
28ef6c31
JA
114
115/* Evaluates to 1 if C is one of the OP characters that follows the parameter
116 in ${parameter[:]OPword}. */
7117c2d2 117#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)
28ef6c31 118
bb70624e
JA
119/* Evaluates to 1 if this is one of the shell's special variables. */
120#define SPECIAL_VAR(name, wi) \
f73dda09
JA
121 ((DIGIT (*name) && all_digits (name)) || \
122 (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \
28ef6c31 123 (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1])))
bb70624e 124
f73dda09
JA
125/* An expansion function that takes a string and a quoted flag and returns
126 a WORD_LIST *. Used as the type of the third argument to
127 expand_string_if_necessary(). */
128typedef WORD_LIST *EXPFUNC __P((char *, int));
129
726f6388
JA
130/* Process ID of the last command executed within command substitution. */
131pid_t last_command_subst_pid = NO_PID;
b72432fd 132pid_t current_command_subst_pid = NO_PID;
726f6388 133
7117c2d2
JA
134/* Variables used to keep track of the characters in IFS. */
135SHELL_VAR *ifs_var;
136char *ifs_value;
137unsigned char ifs_cmap[UCHAR_MAX + 1];
f0c4de40 138int ifs_is_set, ifs_is_null;
633e5c6d
CR
139
140#if defined (HANDLE_MULTIBYTE)
141unsigned char ifs_firstc[MB_LEN_MAX];
142size_t ifs_firstc_len;
143#else
7117c2d2 144unsigned char ifs_firstc;
633e5c6d 145#endif
7117c2d2 146
0527c903
CR
147/* Sentinel to tell when we are performing variable assignments preceding a
148 command name and putting them into the environment. Used to make sure
149 we use the temporary environment when looking up variable values. */
d7f49990
CR
150int assigning_in_environment;
151
0527c903
CR
152/* Used to hold a list of variable assignments preceding a command. Global
153 so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
154 SIGCHLD trap and so it can be saved and restored by the trap handlers. */
155WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
156
726f6388 157/* Extern functions and variables from different files. */
d3a24ed2 158extern int last_command_exit_value, last_command_exit_signal;
f486d0a1
CR
159extern int subshell_environment, line_number;
160extern int subshell_level, parse_and_execute_level, sourcelevel;
7117c2d2 161extern int eof_encountered;
bb70624e 162extern int return_catch_flag, return_catch_value;
f73dda09 163extern pid_t dollar_dollar_pid;
726f6388 164extern int posixly_correct;
726f6388 165extern char *this_command_name;
ccc6cda3 166extern struct fd_bitmap *current_fds_to_close;
cce855bc 167extern int wordexp_only;
d3a24ed2 168extern int expanding_redir;
56299fa5 169extern int tempenv_assign_error;
77b3aacb 170extern int builtin_ignoring_errexit;
726f6388 171
d3ad40de
CR
172#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)
173extern wchar_t *wcsdup __P((const wchar_t *));
174#endif
175
ccc6cda3
JA
176/* Non-zero means to allow unmatched globbed filenames to expand to
177 a null file. */
178int allow_null_glob_expansion;
179
d3a24ed2
CR
180/* Non-zero means to throw an error when globbing fails to match anything. */
181int fail_glob_expansion;
182
f73dda09 183#if 0
ccc6cda3
JA
184/* Variables to keep track of which words in an expanded word list (the
185 output of expand_word_list_internal) are the result of globbing
f73dda09
JA
186 expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c.
187 (CURRENTLY UNUSED). */
ccc6cda3
JA
188char *glob_argv_flags;
189static int glob_argv_flags_size;
f73dda09 190#endif
726f6388
JA
191
192static WORD_LIST expand_word_error, expand_word_fatal;
227f982e 193static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
726f6388 194static char expand_param_error, expand_param_fatal;
7027abcb 195static char extract_string_error, extract_string_fatal;
726f6388 196
28ef6c31
JA
197/* Tell the expansion functions to not longjmp back to top_level on fatal
198 errors. Enabled when doing completion and prompt string expansion. */
199static int no_longjmp_on_fatal_error = 0;
200
201/* Set by expand_word_unsplit; used to inhibit splitting and re-joining
202 $* on $IFS, primarily when doing assignment statements. */
203static int expand_no_split_dollar_star = 0;
bb70624e 204
bb70624e
JA
205/* A WORD_LIST of words to be expanded by expand_word_list_internal,
206 without any leading variable assignments. */
207static WORD_LIST *garglist = (WORD_LIST *)NULL;
b72432fd 208
f73dda09 209static char *quoted_substring __P((char *, int, int));
7117c2d2
JA
210static int quoted_strlen __P((char *));
211static char *quoted_strchr __P((char *, int, int));
f73dda09
JA
212
213static char *expand_string_if_necessary __P((char *, int, EXPFUNC *));
214static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *));
215static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *));
216static WORD_LIST *expand_string_internal __P((char *, int));
217static WORD_LIST *expand_string_leave_quoted __P((char *, int));
218static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *));
219
f73dda09
JA
220static WORD_LIST *list_quote_escapes __P((WORD_LIST *));
221static char *make_quoted_char __P((int));
222static WORD_LIST *quote_list __P((WORD_LIST *));
f73dda09
JA
223
224static int unquoted_substring __P((char *, char *));
225static int unquoted_member __P((int, char *));
226
43df7bbb
CR
227#if defined (ARRAY_VARS)
228static SHELL_VAR *do_compound_assignment __P((char *, char *, int));
229#endif
230static int do_assignment_internal __P((const WORD_DESC *, int));
f73dda09 231
d3ad40de 232static char *string_extract_verbatim __P((char *, size_t, int *, char *, int));
f73dda09
JA
233static char *string_extract __P((char *, int *, char *, int));
234static char *string_extract_double_quoted __P((char *, int *, int));
7117c2d2 235static inline char *string_extract_single_quoted __P((char *, int *));
d3ad40de 236static inline int skip_single_quoted __P((const char *, size_t, int));
7117c2d2
JA
237static int skip_double_quoted __P((char *, size_t, int));
238static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int));
239static char *extract_dollar_brace_string __P((char *, int *, int, int));
6932f7f5 240static int skip_matched_pair __P((const char *, int, int, int, int));
f73dda09 241
f73dda09
JA
242static char *pos_params __P((char *, int, int, int));
243
545f34cf
CR
244static unsigned char *mb_getcharlens __P((char *, int));
245
704a1a2a 246static char *remove_upattern __P((char *, char *, int));
d3ad40de 247#if defined (HANDLE_MULTIBYTE)
704a1a2a
CR
248static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int));
249#endif
f73dda09 250static char *remove_pattern __P((char *, char *, int));
704a1a2a 251
704a1a2a
CR
252static int match_upattern __P((char *, char *, int, char **, char **));
253#if defined (HANDLE_MULTIBYTE)
704a1a2a
CR
254static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
255#endif
f73dda09
JA
256static int match_pattern __P((char *, char *, int, char **, char **));
257static int getpatspec __P((int, char *));
258static char *getpattern __P((char *, int, int));
7117c2d2 259static char *variable_remove_pattern __P((char *, char *, int, int));
f73dda09 260static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int));
7117c2d2 261static char *parameter_list_remove_pattern __P((int, char *, int, int));
f73dda09 262#ifdef ARRAY_VARS
fdf670ea 263static char *array_remove_pattern __P((SHELL_VAR *, char *, int, char *, int));
f73dda09 264#endif
5f8cde23 265static char *parameter_brace_remove_pattern __P((char *, char *, int, char *, int, int, int));
f73dda09
JA
266
267static char *process_substitute __P((char *, int));
268
d3ad40de 269static char *read_comsub __P((int, int, int *));
f73dda09
JA
270
271#ifdef ARRAY_VARS
272static arrayind_t array_length_reference __P((char *));
273#endif
274
275static int valid_brace_expansion_word __P((char *, int));
d3a24ed2 276static int chk_atstar __P((char *, int, int *, int *));
d3ad40de 277static int chk_arithsub __P((const char *, int));
d3a24ed2 278
5f8cde23 279static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int, arrayind_t *));
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);*/
21af69d5 1473 if (posixly_correct && shell_compatibility_level > 42 && 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 1493 else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
21af69d5 1494 dolbrace_state = DOLBRACE_QUOTE2; /* XXX */
3d35553a
CR
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{
21af69d5
CR
3132 WORD_DESC td;
3133 WORD_LIST *list, *tlist;
3134 size_t slen;
3135 int i, saw_quote;
3136 char *ret;
3137 DECLARE_MBSTATE;
3138
3139 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3140 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
3141 i = saw_quote = 0;
3142 while (string[i])
3143 {
3144 if (EXP_CHAR (string[i]))
3145 break;
3146 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3147 saw_quote = 1;
3148 ADVANCE_CHAR (string, slen, i);
3149 }
3150
3151 if (string[i])
3152 {
3153 /* This is expanded version of expand_string_internal as it's called by
3154 expand_string_leave_quoted */
3155 td.flags = W_NOPROCSUB; /* don't want process substitution */
3156 td.word = savestring (string);
3157 list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3158 /* This takes care of the calls from expand_string_leave_quoted and
3159 expand_string */
3160 if (list)
3161 {
3162 tlist = word_list_split (list);
3163 dispose_words (list);
3164 list = tlist;
3165 if (list)
3166 dequote_list (list);
3167 }
3168 /* This comes from expand_string_if_necessary */
3169 if (list)
3170 {
3171 ret = string_list (list);
3172 dispose_words (list);
3173 }
3174 else
3175 ret = (char *)NULL;
3176 FREE (td.word);
3177 }
3178 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3179 ret = string_quote_removal (string, quoted);
3180 else
3181 ret = savestring (string);
3182
3183 return ret;
dc8fbaf9
CR
3184}
3185
cce855bc
JA
3186#if defined (COND_COMMAND)
3187/* Just remove backslashes in STRING. Returns a new string. */
3188char *
3189remove_backslashes (string)
3190 char *string;
3191{
3192 char *r, *ret, *s;
3193
f73dda09 3194 r = ret = (char *)xmalloc (strlen (string) + 1);
cce855bc
JA
3195 for (s = string; s && *s; )
3196 {
3197 if (*s == '\\')
28ef6c31 3198 s++;
cce855bc 3199 if (*s == 0)
28ef6c31 3200 break;
cce855bc
JA
3201 *r++ = *s++;
3202 }
3203 *r = '\0';
3204 return ret;
3205}
3206
3207/* This needs better error handling. */
3208/* Expand W for use as an argument to a unary or binary operator in a
d3ad40de 3209 [[...]] expression. If SPECIAL is 1, this is the rhs argument
cce855bc 3210 to the != or == operator, and should be treated as a pattern. In
d3ad40de
CR
3211 this case, we quote the string specially for the globbing code. If
3212 SPECIAL is 2, this is an rhs argument for the =~ operator, and should
3213 be quoted appropriately for regcomp/regexec. The caller is responsible
3214 for removing the backslashes if the unquoted word is needed later. */
cce855bc
JA
3215char *
3216cond_expand_word (w, special)
3217 WORD_DESC *w;
3218 int special;
3219{
3220 char *r, *p;
3221 WORD_LIST *l;
d3ad40de 3222 int qflags;
cce855bc
JA
3223
3224 if (w->word == 0 || w->word[0] == '\0')
3225 return ((char *)NULL);
3226
e1e48bba 3227 w->flags |= W_NOSPLIT2;
b72432fd 3228 l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
cce855bc
JA
3229 if (l)
3230 {
3231 if (special == 0)
3232 {
3233 dequote_list (l);
3234 r = string_list (l);
3235 }
3236 else
28ef6c31 3237 {
d3ad40de
CR
3238 qflags = QGLOB_CVTNULL;
3239 if (special == 2)
3240 qflags |= QGLOB_REGEXP;
28ef6c31 3241 p = string_list (l);
d3ad40de 3242 r = quote_string_for_globbing (p, qflags);
28ef6c31
JA
3243 free (p);
3244 }
cce855bc
JA
3245 dispose_words (l);
3246 }
3247 else
3248 r = (char *)NULL;
3249
3250 return r;
3251}
3252#endif
3253
3254/* Call expand_word_internal to expand W and handle error returns.
3255 A convenience function for functions that don't want to handle
3256 any errors or free any memory before aborting. */
3257static WORD_LIST *
b72432fd 3258call_expand_word_internal (w, q, i, c, e)
cce855bc 3259 WORD_DESC *w;
b72432fd 3260 int q, i, *c, *e;
cce855bc
JA
3261{
3262 WORD_LIST *result;
3263
b72432fd 3264 result = expand_word_internal (w, q, i, c, e);
bb70624e 3265 if (result == &expand_word_error || result == &expand_word_fatal)
cce855bc
JA
3266 {
3267 /* By convention, each time this error is returned, w->word has
bb70624e
JA
3268 already been freed (it sometimes may not be in the fatal case,
3269 but that doesn't result in a memory leak because we're going
3270 to exit in most cases). */
cce855bc 3271 w->word = (char *)NULL;
28ef6c31 3272 last_command_exit_value = EXECUTION_FAILURE;
d3a24ed2 3273 exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
cce855bc 3274 /* NOTREACHED */
c7e43312 3275 return (NULL);
cce855bc 3276 }
cce855bc
JA
3277 else
3278 return (result);
3279}
3280
3281/* Perform parameter expansion, command substitution, and arithmetic
9c2db999
CR
3282 expansion on STRING, as if it were a word. Leave the result quoted.
3283 Since this does not perform word splitting, it leaves quoted nulls
3284 in the result. */
cce855bc
JA
3285static WORD_LIST *
3286expand_string_internal (string, quoted)
3287 char *string;
3288 int quoted;
3289{
3290 WORD_DESC td;
3291 WORD_LIST *tresult;
3292
3293 if (string == 0 || *string == 0)
3294 return ((WORD_LIST *)NULL);
3295
28ef6c31
JA
3296 td.flags = 0;
3297 td.word = savestring (string);
3298
b72432fd 3299 tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
28ef6c31
JA
3300
3301 FREE (td.word);
cce855bc 3302 return (tresult);
726f6388
JA
3303}
3304
3305/* Expand STRING by performing parameter expansion, command substitution,
3306 and arithmetic expansion. Dequote the resulting WORD_LIST before
3307 returning it, but do not perform word splitting. The call to
3308 remove_quoted_nulls () is in here because word splitting normally
3309 takes care of quote removal. */
3310WORD_LIST *
3311expand_string_unsplit (string, quoted)
3312 char *string;
3313 int quoted;
3314{
3315 WORD_LIST *value;
3316
28ef6c31 3317 if (string == 0 || *string == '\0')
726f6388
JA
3318 return ((WORD_LIST *)NULL);
3319
28ef6c31 3320 expand_no_split_dollar_star = 1;
726f6388 3321 value = expand_string_internal (string, quoted);
28ef6c31
JA
3322 expand_no_split_dollar_star = 0;
3323
726f6388
JA
3324 if (value)
3325 {
3326 if (value->word)
227f982e
CR
3327 {
3328 remove_quoted_nulls (value->word->word);
3329 value->word->flags &= ~W_HASQUOTEDNULL;
3330 }
726f6388
JA
3331 dequote_list (value);
3332 }
3333 return (value);
3334}
3335
22e63b05
CR
3336/* Expand the rhs of an assignment statement */
3337WORD_LIST *
3338expand_string_assignment (string, quoted)
3339 char *string;
3340 int quoted;
3341{
3342 WORD_DESC td;
3343 WORD_LIST *value;
3344
3345 if (string == 0 || *string == '\0')
3346 return ((WORD_LIST *)NULL);
3347
3348 expand_no_split_dollar_star = 1;
3349
3350 td.flags = W_ASSIGNRHS;
3351 td.word = savestring (string);
3352 value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3353 FREE (td.word);
3354
3355 expand_no_split_dollar_star = 0;
3356
3357 if (value)
3358 {
3359 if (value->word)
227f982e
CR
3360 {
3361 remove_quoted_nulls (value->word->word);
3362 value->word->flags &= ~W_HASQUOTEDNULL;
3363 }
22e63b05
CR
3364 dequote_list (value);
3365 }
3366 return (value);
3367}
3368
bb70624e
JA
3369
3370/* Expand one of the PS? prompt strings. This is a sort of combination of
3371 expand_string_unsplit and expand_string_internal, but returns the
3372 passed string when an error occurs. Might want to trap other calls
3373 to jump_to_top_level here so we don't endlessly loop. */
3374WORD_LIST *
4d8d005b 3375expand_prompt_string (string, quoted, wflags)
bb70624e
JA
3376 char *string;
3377 int quoted;
4d8d005b 3378 int wflags;
bb70624e
JA
3379{
3380 WORD_LIST *value;
3381 WORD_DESC td;
3382
3383 if (string == 0 || *string == 0)
3384 return ((WORD_LIST *)NULL);
3385
4d8d005b 3386 td.flags = wflags;
bb70624e 3387 td.word = savestring (string);
28ef6c31
JA
3388
3389 no_longjmp_on_fatal_error = 1;
bb70624e 3390 value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
28ef6c31
JA
3391 no_longjmp_on_fatal_error = 0;
3392
bb70624e
JA
3393 if (value == &expand_word_error || value == &expand_word_fatal)
3394 {
3395 value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
3396 return value;
3397 }
3398 FREE (td.word);
3399 if (value)
3400 {
3401 if (value->word)
227f982e
CR
3402 {
3403 remove_quoted_nulls (value->word->word);
3404 value->word->flags &= ~W_HASQUOTEDNULL;
3405 }
bb70624e
JA
3406 dequote_list (value);
3407 }
3408 return (value);
3409}
3410
726f6388
JA
3411/* Expand STRING just as if you were expanding a word, but do not dequote
3412 the resultant WORD_LIST. This is called only from within this file,
3413 and is used to correctly preserve quoted characters when expanding
3414 things like ${1+"$@"}. This does parameter expansion, command
b72432fd 3415 substitution, arithmetic expansion, and word splitting. */
726f6388
JA
3416static WORD_LIST *
3417expand_string_leave_quoted (string, quoted)
3418 char *string;
3419 int quoted;
3420{
3421 WORD_LIST *tlist;
3422 WORD_LIST *tresult;
3423
ccc6cda3 3424 if (string == 0 || *string == '\0')
726f6388
JA
3425 return ((WORD_LIST *)NULL);
3426
3427 tlist = expand_string_internal (string, quoted);
3428
3429 if (tlist)
3430 {
3431 tresult = word_list_split (tlist);
3432 dispose_words (tlist);
3433 return (tresult);
3434 }
3435 return ((WORD_LIST *)NULL);
3436}
3437
ccc6cda3
JA
3438/* This does not perform word splitting or dequote the WORD_LIST
3439 it returns. */
3440static WORD_LIST *
3441expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at)
3442 char *string;
3443 int quoted, *dollar_at_p, *has_dollar_at;
3444{
3445 WORD_DESC td;
3446 WORD_LIST *tresult;
3447
3448 if (string == 0 || *string == '\0')
3449 return (WORD_LIST *)NULL;
3450
9c2db999 3451 td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */
ccc6cda3 3452 td.word = string;
b72432fd 3453 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at);
ccc6cda3
JA
3454 return (tresult);
3455}
3456
726f6388
JA
3457/* Expand STRING just as if you were expanding a word. This also returns
3458 a list of words. Note that filename globbing is *NOT* done for word
3459 or string expansion, just when the shell is expanding a command. This
3460 does parameter expansion, command substitution, arithmetic expansion,
3461 and word splitting. Dequote the resultant WORD_LIST before returning. */
3462WORD_LIST *
3463expand_string (string, quoted)
3464 char *string;
3465 int quoted;
3466{
3467 WORD_LIST *result;
3468
28ef6c31 3469 if (string == 0 || *string == '\0')
726f6388
JA
3470 return ((WORD_LIST *)NULL);
3471
3472 result = expand_string_leave_quoted (string, quoted);
ccc6cda3 3473 return (result ? dequote_list (result) : result);
726f6388
JA
3474}
3475
3476/***************************************************
3477 * *
3478 * Functions to handle quoting chars *
3479 * *
3480 ***************************************************/
3481
cce855bc
JA
3482/* Conventions:
3483
3484 A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
3485 The parser passes CTLNUL as CTLESC CTLNUL. */
3486
cce855bc
JA
3487/* Quote escape characters in string s, but no other characters. This is
3488 used to protect CTLESC and CTLNUL in variable values from the rest of
e6598ba4
CR
3489 the word expansion process after the variable is expanded (word splitting
3490 and filename generation). If IFS is null, we quote spaces as well, just
3491 in case we split on spaces later (in the case of unquoted $@, we will
3492 eventually attempt to split the entire word on spaces). Corresponding
3493 code exists in dequote_escapes. Even if we don't end up splitting on
3494 spaces, quoting spaces is not a problem. This should never be called on
3495 a string that is quoted with single or double quotes or part of a here
3496 document (effectively double-quoted). */
f73dda09 3497char *
cce855bc
JA
3498quote_escapes (string)
3499 char *string;
3500{
3501 register char *s, *t;
7117c2d2
JA
3502 size_t slen;
3503 char *result, *send;
e6598ba4 3504 int quote_spaces, skip_ctlesc, skip_ctlnul;
7117c2d2 3505 DECLARE_MBSTATE;
cce855bc 3506
7117c2d2
JA
3507 slen = strlen (string);
3508 send = string + slen;
3509
d3ad40de 3510 quote_spaces = (ifs_value && *ifs_value == 0);
e6598ba4
CR
3511
3512 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
3513 skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
3514
7117c2d2
JA
3515 t = result = (char *)xmalloc ((slen * 2) + 1);
3516 s = string;
3517
3518 while (*s)
cce855bc 3519 {
e6598ba4 3520 if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
cce855bc 3521 *t++ = CTLESC;
7117c2d2 3522 COPY_CHAR_P (t, s, send);
cce855bc
JA
3523 }
3524 *t = '\0';
3525 return (result);
3526}
3527
3528static WORD_LIST *
3529list_quote_escapes (list)
3530 WORD_LIST *list;
3531{
3532 register WORD_LIST *w;
3533 char *t;
3534
3535 for (w = list; w; w = w->next)
3536 {
3537 t = w->word->word;
3538 w->word->word = quote_escapes (t);
3539 free (t);
3540 }
3541 return list;
3542}
3543
7117c2d2
JA
3544/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
3545
3546 The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
3547 This is necessary to make unquoted CTLESC and CTLNUL characters in the
3548 data stream pass through properly.
3549
3550 We need to remove doubled CTLESC characters inside quoted strings before
3551 quoting the entire string, so we do not double the number of CTLESC
3552 characters.
3553
3554 Also used by parts of the pattern substitution code. */
09767ff0 3555char *
cce855bc
JA
3556dequote_escapes (string)
3557 char *string;
3558{
e6598ba4 3559 register char *s, *t, *s1;
7117c2d2
JA
3560 size_t slen;
3561 char *result, *send;
d3ad40de 3562 int quote_spaces;
7117c2d2 3563 DECLARE_MBSTATE;
cce855bc 3564
7117c2d2
JA
3565 if (string == 0)
3566 return string;
3567
3568 slen = strlen (string);
3569 send = string + slen;
3570
3571 t = result = (char *)xmalloc (slen + 1);
7117c2d2
JA
3572
3573 if (strchr (string, CTLESC) == 0)
e6598ba4 3574 return (strcpy (result, string));
7117c2d2 3575
d3ad40de 3576 quote_spaces = (ifs_value && *ifs_value == 0);
e6598ba4
CR
3577
3578 s = string;
7117c2d2 3579 while (*s)
cce855bc 3580 {
d3ad40de 3581 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
cce855bc
JA
3582 {
3583 s++;
3584 if (*s == '\0')
3585 break;
3586 }
7117c2d2 3587 COPY_CHAR_P (t, s, send);
cce855bc
JA
3588 }
3589 *t = '\0';
3590 return result;
3591}
726f6388 3592
d3ad40de
CR
3593/* Return a new string with the quoted representation of character C.
3594 This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
3595 set in any resultant WORD_DESC where this value is the word. */
726f6388
JA
3596static char *
3597make_quoted_char (c)
3598 int c;
3599{
3600 char *temp;
3601
f73dda09 3602 temp = (char *)xmalloc (3);
726f6388
JA
3603 if (c == 0)
3604 {
3605 temp[0] = CTLNUL;
3606 temp[1] = '\0';
3607 }
3608 else
3609 {
3610 temp[0] = CTLESC;
3611 temp[1] = c;
3612 temp[2] = '\0';
3613 }
3614 return (temp);
3615}
3616
d3ad40de
CR
3617/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so
3618 the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
3619 this value is the word. */
ccc6cda3 3620char *
726f6388
JA
3621quote_string (string)
3622 char *string;
3623{
ccc6cda3 3624 register char *t;
7117c2d2
JA
3625 size_t slen;
3626 char *result, *send;
726f6388 3627
ccc6cda3 3628 if (*string == 0)
726f6388 3629 {
f73dda09 3630 result = (char *)xmalloc (2);
726f6388
JA
3631 result[0] = CTLNUL;
3632 result[1] = '\0';
3633 }
3634 else
3635 {
7117c2d2 3636 DECLARE_MBSTATE;
726f6388 3637
7117c2d2
JA
3638 slen = strlen (string);
3639 send = string + slen;
3640
3641 result = (char *)xmalloc ((slen * 2) + 1);
3642
3643 for (t = result; string < send; )
726f6388
JA
3644 {
3645 *t++ = CTLESC;
7117c2d2 3646 COPY_CHAR_P (t, string, send);
726f6388
JA
3647 }
3648 *t = '\0';
3649 }
3650 return (result);
3651}
3652
d3ad40de 3653/* De-quote quoted characters in STRING. */
726f6388
JA
3654char *
3655dequote_string (string)
3656 char *string;
3657{
7117c2d2
JA
3658 register char *s, *t;
3659 size_t slen;
3660 char *result, *send;
3661 DECLARE_MBSTATE;
726f6388 3662
7117c2d2
JA
3663 slen = strlen (string);
3664
3665 t = result = (char *)xmalloc (slen + 1);
726f6388
JA
3666
3667 if (QUOTED_NULL (string))
3668 {
3669 result[0] = '\0';
3670 return (result);
3671 }
3672
3673 /* If no character in the string can be quoted, don't bother examining
3674 each character. Just return a copy of the string passed to us. */
7117c2d2
JA
3675 if (strchr (string, CTLESC) == NULL)
3676 return (strcpy (result, string));
726f6388 3677
7117c2d2
JA
3678 send = string + slen;
3679 s = string;
3680 while (*s)
726f6388 3681 {
7117c2d2 3682 if (*s == CTLESC)
726f6388 3683 {
7117c2d2
JA
3684 s++;
3685 if (*s == '\0')
726f6388
JA
3686 break;
3687 }
7117c2d2 3688 COPY_CHAR_P (t, s, send);
726f6388
JA
3689 }
3690
3691 *t = '\0';
3692 return (result);
3693}
3694
3695/* Quote the entire WORD_LIST list. */
ccc6cda3 3696static WORD_LIST *
726f6388
JA
3697quote_list (list)
3698 WORD_LIST *list;
3699{
3700 register WORD_LIST *w;
ccc6cda3 3701 char *t;
726f6388
JA
3702
3703 for (w = list; w; w = w->next)
3704 {
ccc6cda3 3705 t = w->word->word;
726f6388 3706 w->word->word = quote_string (t);
e33f2203
CR
3707 if (*t == 0)
3708 w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
ccc6cda3 3709 w->word->flags |= W_QUOTED;
e33f2203 3710 free (t);
726f6388 3711 }
ccc6cda3 3712 return list;
726f6388
JA
3713}
3714
d3ad40de
CR
3715/* De-quote quoted characters in each word in LIST. */
3716WORD_LIST *
7117c2d2
JA
3717dequote_list (list)
3718 WORD_LIST *list;
3719{
3720 register char *s;
3721 register WORD_LIST *tlist;
3722
3723 for (tlist = list; tlist; tlist = tlist->next)
3724 {
3725 s = dequote_string (tlist->word->word);
e33f2203
CR
3726 if (QUOTED_NULL (tlist->word->word))
3727 tlist->word->flags &= ~W_HASQUOTEDNULL;
7117c2d2
JA
3728 free (tlist->word->word);
3729 tlist->word->word = s;
3730 }
3731 return list;
3732}
3733
3734/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
3735 string. */
b0c16657 3736char *
7117c2d2
JA
3737remove_quoted_escapes (string)
3738 char *string;
3739{
3740 char *t;
3741
3742 if (string)
3743 {
3744 t = dequote_escapes (string);
3745 strcpy (string, t);
3746 free (t);
3747 }
3748
3749 return (string);
3750}
3751
cce855bc
JA
3752/* Perform quoted null character removal on STRING. We don't allow any
3753 quoted null characters in the middle or at the ends of strings because
3754 of how expand_word_internal works. remove_quoted_nulls () turns
3755 STRING into an empty string iff it only consists of a quoted null,
3756 and removes all unquoted CTLNUL characters. */
09767ff0 3757char *
cce855bc
JA
3758remove_quoted_nulls (string)
3759 char *string;
3760{
7117c2d2
JA
3761 register size_t slen;
3762 register int i, j, prev_i;
3763 DECLARE_MBSTATE;
3764
3765 if (strchr (string, CTLNUL) == 0) /* XXX */
3766 return string; /* XXX */
3767
3768 slen = strlen (string);
3769 i = j = 0;
3770
3771 while (i < slen)
3772 {
3773 if (string[i] == CTLESC)
704a1a2a 3774 {
d3a24ed2
CR
3775 /* Old code had j++, but we cannot assume that i == j at this
3776 point -- what if a CTLNUL has already been removed from the
3777 string? We don't want to drop the CTLESC or recopy characters
3778 that we've already copied down. */
3779 i++; string[j++] = CTLESC;
704a1a2a
CR
3780 if (i == slen)
3781 break;
3782 }
7117c2d2 3783 else if (string[i] == CTLNUL)
f4f5e1c2
CR
3784 {
3785 i++;
3786 continue;
3787 }
7117c2d2
JA
3788
3789 prev_i = i;
3790 ADVANCE_CHAR (string, slen, i);
3791 if (j < prev_i)
cce855bc 3792 {
7117c2d2 3793 do string[j++] = string[prev_i++]; while (prev_i < i);
cce855bc 3794 }
7117c2d2
JA
3795 else
3796 j = i;
cce855bc 3797 }
7117c2d2
JA
3798 string[j] = '\0';
3799
3800 return (string);
cce855bc
JA
3801}
3802
3803/* Perform quoted null character removal on each element of LIST.
3804 This modifies LIST. */
3805void
3806word_list_remove_quoted_nulls (list)
3807 WORD_LIST *list;
3808{
3809 register WORD_LIST *t;
3810
3811 for (t = list; t; t = t->next)
227f982e
CR
3812 {
3813 remove_quoted_nulls (t->word->word);
3814 t->word->flags &= ~W_HASQUOTEDNULL;
3815 }
cce855bc
JA
3816}
3817
3818/* **************************************************************** */
3819/* */
3820/* Functions for Matching and Removing Patterns */
3821/* */
3822/* **************************************************************** */
3823
545f34cf 3824#if defined (HANDLE_MULTIBYTE)
704a1a2a 3825#if 0 /* Currently unused */
545f34cf
CR
3826static unsigned char *
3827mb_getcharlens (string, len)
3828 char *string;
3829 int len;
3830{
704a1a2a
CR
3831 int i, offset, last;
3832 unsigned char *ret;
545f34cf
CR
3833 char *p;
3834 DECLARE_MBSTATE;
3835
3836 i = offset = 0;
3837 last = 0;
3838 ret = (unsigned char *)xmalloc (len);
3839 memset (ret, 0, len);
3840 while (string[last])
3841 {
3842 ADVANCE_CHAR (string, len, offset);
3843 ret[last] = offset - last;
3844 last = offset;
3845 }
3846 return ret;
3847}
3848#endif
704a1a2a 3849#endif
545f34cf 3850
cce855bc
JA
3851/* Remove the portion of PARAM matched by PATTERN according to OP, where OP
3852 can have one of 4 values:
3853 RP_LONG_LEFT remove longest matching portion at start of PARAM
726f6388
JA
3854 RP_SHORT_LEFT remove shortest matching portion at start of PARAM
3855 RP_LONG_RIGHT remove longest matching portion at end of PARAM
3856 RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
3857*/
3858
3859#define RP_LONG_LEFT 1
3860#define RP_SHORT_LEFT 2
3861#define RP_LONG_RIGHT 3
3862#define RP_SHORT_RIGHT 4
3863
3d35553a 3864/* Returns its first argument if nothing matched; new memory otherwise */
726f6388 3865static char *
704a1a2a 3866remove_upattern (param, pattern, op)
726f6388
JA
3867 char *param, *pattern;
3868 int op;
3869{
ccc6cda3
JA
3870 register int len;
3871 register char *end;
726f6388 3872 register char *p, *ret, c;
726f6388 3873
ccc6cda3
JA
3874 len = STRLEN (param);
3875 end = param + len;
726f6388
JA
3876
3877 switch (op)
3878 {
3879 case RP_LONG_LEFT: /* remove longest match at start */
704a1a2a 3880 for (p = end; p >= param; p--)
726f6388
JA
3881 {
3882 c = *p; *p = '\0';
f73dda09 3883 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
726f6388
JA
3884 {
3885 *p = c;
3886 return (savestring (p));
3887 }
3888 *p = c;
545f34cf 3889
726f6388
JA
3890 }
3891 break;
3892
3893 case RP_SHORT_LEFT: /* remove shortest match at start */
704a1a2a 3894 for (p = param; p <= end; p++)
726f6388
JA
3895 {
3896 c = *p; *p = '\0';
f73dda09 3897 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
726f6388
JA
3898 {
3899 *p = c;
3900 return (savestring (p));
3901 }
3902 *p = c;
3903 }
3904 break;
3905
ccc6cda3 3906 case RP_LONG_RIGHT: /* remove longest match at end */
704a1a2a 3907 for (p = param; p <= end; p++)
ccc6cda3 3908 {
f73dda09 3909 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
ccc6cda3
JA
3910 {
3911 c = *p; *p = '\0';
3912 ret = savestring (param);
3913 *p = c;
3914 return (ret);
3915 }
3916 }
3917 break;
3918
3919 case RP_SHORT_RIGHT: /* remove shortest match at end */
704a1a2a 3920 for (p = end; p >= param; p--)
ccc6cda3 3921 {
f73dda09 3922 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
ccc6cda3
JA
3923 {
3924 c = *p; *p = '\0';
3925 ret = savestring (param);
3926 *p = c;
3927 return (ret);
3928 }
704a1a2a
CR
3929 }
3930 break;
3931 }
3932
3d35553a 3933 return (param); /* no match, return original string */
704a1a2a
CR
3934}
3935
3936#if defined (HANDLE_MULTIBYTE)
3d35553a 3937/* Returns its first argument if nothing matched; new memory otherwise */
704a1a2a
CR
3938static wchar_t *
3939remove_wpattern (wparam, wstrlen, wpattern, op)
3940 wchar_t *wparam;
3941 size_t wstrlen;
3942 wchar_t *wpattern;
3943 int op;
3944{
d3ad40de
CR
3945 wchar_t wc, *ret;
3946 int n;
545f34cf 3947
704a1a2a
CR
3948 switch (op)
3949 {
3950 case RP_LONG_LEFT: /* remove longest match at start */
3951 for (n = wstrlen; n >= 0; n--)
3952 {
3953 wc = wparam[n]; wparam[n] = L'\0';
3954 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
545f34cf 3955 {
704a1a2a
CR
3956 wparam[n] = wc;
3957 return (wcsdup (wparam + n));
3958 }
3959 wparam[n] = wc;
3960 }
3961 break;
3962
3963 case RP_SHORT_LEFT: /* remove shortest match at start */
3964 for (n = 0; n <= wstrlen; n++)
3965 {
3966 wc = wparam[n]; wparam[n] = L'\0';
3967 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3968 {
3969 wparam[n] = wc;
3970 return (wcsdup (wparam + n));
3971 }
3972 wparam[n] = wc;
3973 }
3974 break;
3975
3976 case RP_LONG_RIGHT: /* remove longest match at end */
3977 for (n = 0; n <= wstrlen; n++)
3978 {
3979 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3980 {
3981 wc = wparam[n]; wparam[n] = L'\0';
3982 ret = wcsdup (wparam);
3983 wparam[n] = wc;
3984 return (ret);
3985 }
3986 }
3987 break;
3988
3989 case RP_SHORT_RIGHT: /* remove shortest match at end */
3990 for (n = wstrlen; n >= 0; n--)
3991 {
3992 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3993 {
3994 wc = wparam[n]; wparam[n] = L'\0';
3995 ret = wcsdup (wparam);
3996 wparam[n] = wc;
3997 return (ret);
545f34cf 3998 }
ccc6cda3
JA
3999 }
4000 break;
4001 }
545f34cf 4002
3d35553a 4003 return (wparam); /* no match, return original string */
704a1a2a
CR
4004}
4005#endif /* HANDLE_MULTIBYTE */
4006
4007static char *
4008remove_pattern (param, pattern, op)
4009 char *param, *pattern;
4010 int op;
4011{
3d35553a
CR
4012 char *xret;
4013
704a1a2a
CR
4014 if (param == NULL)
4015 return (param);
4016 if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
4017 return (savestring (param));
4018
4019#if defined (HANDLE_MULTIBYTE)
4020 if (MB_CUR_MAX > 1)
4021 {
4022 wchar_t *ret, *oret;
4023 size_t n;
4024 wchar_t *wparam, *wpattern;
4025 mbstate_t ps;
704a1a2a
CR
4026
4027 n = xdupmbstowcs (&wpattern, NULL, pattern);
4028 if (n == (size_t)-1)
3d35553a
CR
4029 {
4030 xret = remove_upattern (param, pattern, op);
4031 return ((xret == param) ? savestring (param) : xret);
4032 }
704a1a2a 4033 n = xdupmbstowcs (&wparam, NULL, param);
73a146be 4034
704a1a2a
CR
4035 if (n == (size_t)-1)
4036 {
4037 free (wpattern);
3d35553a
CR
4038 xret = remove_upattern (param, pattern, op);
4039 return ((xret == param) ? savestring (param) : xret);
704a1a2a
CR
4040 }
4041 oret = ret = remove_wpattern (wparam, n, wpattern, op);
3d35553a
CR
4042 /* Don't bother to convert wparam back to multibyte string if nothing
4043 matched; just return copy of original string */
4044 if (ret == wparam)
4045 {
4046 free (wparam);
4047 free (wpattern);
4048 return (savestring (param));
4049 }
704a1a2a
CR
4050
4051 free (wparam);
4052 free (wpattern);
4053
4054 n = strlen (param);
dc8fbaf9 4055 xret = (char *)xmalloc (n + 1);
704a1a2a
CR
4056 memset (&ps, '\0', sizeof (mbstate_t));
4057 n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
4058 xret[n] = '\0'; /* just to make sure */
4059 free (oret);
4060 return xret;
4061 }
4062 else
4063#endif
3d35553a
CR
4064 {
4065 xret = remove_upattern (param, pattern, op);
4066 return ((xret == param) ? savestring (param) : xret);
4067 }
ccc6cda3
JA
4068}
4069
ccc6cda3
JA
4070/* Match PAT anywhere in STRING and return the match boundaries.
4071 This returns 1 in case of a successful match, 0 otherwise. SP
4072 and EP are pointers into the string where the match begins and
4073 ends, respectively. MTYPE controls what kind of match is attempted.
4074 MATCH_BEG and MATCH_END anchor the match at the beginning and end
4075 of the string, respectively. The longest match is returned. */
4076static int
704a1a2a 4077match_upattern (string, pat, mtype, sp, ep)
ccc6cda3
JA
4078 char *string, *pat;
4079 int mtype;
4080 char **sp, **ep;
4081{
5f8cde23 4082 int c, len, mlen;
233564d2 4083 register char *p, *p1, *npat;
ccc6cda3 4084 char *end;
06dff54a 4085 int n1;
ccc6cda3 4086
233564d2
CR
4087 /* If the pattern doesn't match anywhere in the string, go ahead and
4088 short-circuit right away. A minor optimization, saves a bunch of
4089 unnecessary calls to strmatch (up to N calls for a string of N
4090 characters) if the match is unsuccessful. To preserve the semantics
4091 of the substring matches below, we make sure that the pattern has
4092 `*' as first and last character, making a new pattern if necessary. */
4093 /* XXX - check this later if I ever implement `**' with special meaning,
4094 since this will potentially result in `**' at the beginning or end */
4095 len = STRLEN (pat);
176b12ee 4096 if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
233564d2 4097 {
dc8fbaf9 4098 p = npat = (char *)xmalloc (len + 3);
233564d2 4099 p1 = pat;
176b12ee 4100 if (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))
233564d2
CR
4101 *p++ = '*';
4102 while (*p1)
4103 *p++ = *p1++;
4104 if (p1[-1] != '*' || p[-2] == '\\')
4105 *p++ = '*';
4106 *p = '\0';
4107 }
4108 else
4109 npat = pat;
4110 c = strmatch (npat, string, FNMATCH_EXTFLAG);
4111 if (npat != pat)
4112 free (npat);
4113 if (c == FNM_NOMATCH)
4114 return (0);
4115
5e13499c
CR
4116 len = STRLEN (string);
4117 end = string + len;
ccc6cda3 4118
5f8cde23
CR
4119 mlen = umatchlen (pat, len);
4120
ccc6cda3
JA
4121 switch (mtype)
4122 {
4123 case MATCH_ANY:
704a1a2a 4124 for (p = string; p <= end; p++)
ccc6cda3
JA
4125 {
4126 if (match_pattern_char (pat, p))
4127 {
5f8cde23 4128 p1 = (mlen == -1) ? end : p + mlen;
06dff54a
CR
4129 /* p1 - p = length of portion of string to be considered
4130 p = current position in string
4131 mlen = number of characters consumed by match (-1 for entire string)
4132 end = end of string
4133 we want to break immediately if the potential match len
4134 is greater than the number of characters remaining in the
4135 string
4136 */
4137 if (p1 > end)
5f8cde23
CR
4138 break;
4139 for ( ; p1 >= p; p1--)
ccc6cda3
JA
4140 {
4141 c = *p1; *p1 = '\0';
f73dda09 4142 if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
ccc6cda3
JA
4143 {
4144 *p1 = c;
4145 *sp = p;
4146 *ep = p1;
4147 return 1;
4148 }
4149 *p1 = c;
5f8cde23
CR
4150#if 1
4151 /* If MLEN != -1, we have a fixed length pattern. */
4152 if (mlen != -1)
4153 break;
4154#endif
ccc6cda3
JA
4155 }
4156 }
4157 }
545f34cf 4158
ccc6cda3
JA
4159 return (0);
4160
4161 case MATCH_BEG:
4162 if (match_pattern_char (pat, string) == 0)
28ef6c31 4163 return (0);
545f34cf 4164
5f8cde23 4165 for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
ccc6cda3
JA
4166 {
4167 c = *p; *p = '\0';
f73dda09 4168 if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0)
ccc6cda3
JA
4169 {
4170 *p = c;
4171 *sp = string;
4172 *ep = p;
4173 return 1;
4174 }
4175 *p = c;
5f8cde23
CR
4176 /* If MLEN != -1, we have a fixed length pattern. */
4177 if (mlen != -1)
4178 break;
ccc6cda3 4179 }
545f34cf 4180
ccc6cda3 4181 return (0);
726f6388 4182
ccc6cda3 4183 case MATCH_END:
5f8cde23 4184 for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
545f34cf
CR
4185 {
4186 if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
4187 {
4188 *sp = p;
4189 *ep = end;
4190 return 1;
4191 }
5f8cde23
CR
4192 /* If MLEN != -1, we have a fixed length pattern. */
4193 if (mlen != -1)
4194 break;
704a1a2a
CR
4195 }
4196
4197 return (0);
4198 }
4199
4200 return (0);
4201}
4202
4203#if defined (HANDLE_MULTIBYTE)
704a1a2a
CR
4204/* Match WPAT anywhere in WSTRING and return the match boundaries.
4205 This returns 1 in case of a successful match, 0 otherwise. Wide
4206 character version. */
4207static int
4208match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
4209 wchar_t *wstring;
4210 char **indices;
4211 size_t wstrlen;
4212 wchar_t *wpat;
4213 int mtype;
4214 char **sp, **ep;
4215{
233564d2 4216 wchar_t wc, *wp, *nwpat, *wp1;
5f8cde23
CR
4217 size_t len;
4218 int mlen;
adc6cff5
CR
4219 int n, n1, n2, simple;
4220
4221 simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
4222#if defined (EXTENDED_GLOB)
4223 if (extended_glob)
e107650c 4224 simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
adc6cff5 4225#endif
704a1a2a 4226
233564d2
CR
4227 /* If the pattern doesn't match anywhere in the string, go ahead and
4228 short-circuit right away. A minor optimization, saves a bunch of
4229 unnecessary calls to strmatch (up to N calls for a string of N
4230 characters) if the match is unsuccessful. To preserve the semantics
4231 of the substring matches below, we make sure that the pattern has
4232 `*' as first and last character, making a new pattern if necessary. */
233564d2 4233 len = wcslen (wpat);
176b12ee 4234 if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
233564d2 4235 {
dc8fbaf9 4236 wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
233564d2 4237 wp1 = wpat;
176b12ee 4238 if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
233564d2
CR
4239 *wp++ = L'*';
4240 while (*wp1 != L'\0')
4241 *wp++ = *wp1++;
4242 if (wp1[-1] != L'*' || wp1[-2] == L'\\')
4243 *wp++ = L'*';
4244 *wp = '\0';
4245 }
4246 else
4247 nwpat = wpat;
4248 len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG);
4249 if (nwpat != wpat)
4250 free (nwpat);
4251 if (len == FNM_NOMATCH)
4252 return (0);
4253
5f8cde23 4254 mlen = wmatchlen (wpat, wstrlen);
adc6cff5 4255
5f8cde23 4256/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
704a1a2a
CR
4257 switch (mtype)
4258 {
4259 case MATCH_ANY:
4260 for (n = 0; n <= wstrlen; n++)
4261 {
adc6cff5 4262 n2 = simple ? (*wpat == wstring[n]) : match_pattern_wchar (wpat, wstring + n);
adc6cff5 4263 if (n2)
704a1a2a 4264 {
5f8cde23
CR
4265 n1 = (mlen == -1) ? wstrlen : n + mlen;
4266 if (n1 > wstrlen)
4267 break;
4268
4269 for ( ; n1 >= n; n1--)
704a1a2a
CR
4270 {
4271 wc = wstring[n1]; wstring[n1] = L'\0';
4272 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
4273 {
4274 wstring[n1] = wc;
4275 *sp = indices[n];
4276 *ep = indices[n1];
4277 return 1;
4278 }
4279 wstring[n1] = wc;
5f8cde23
CR
4280 /* If MLEN != -1, we have a fixed length pattern. */
4281 if (mlen != -1)
4282 break;
704a1a2a
CR
4283 }
4284 }
4285 }
4286
4287 return (0);
4288
4289 case MATCH_BEG:
4290 if (match_pattern_wchar (wpat, wstring) == 0)
4291 return (0);
4292
5f8cde23 4293 for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
704a1a2a
CR
4294 {
4295 wc = wstring[n]; wstring[n] = L'\0';
4296 if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0)
4297 {
4298 wstring[n] = wc;
4299 *sp = indices[0];
4300 *ep = indices[n];
4301 return 1;
4302 }
4303 wstring[n] = wc;
5f8cde23
CR
4304 /* If MLEN != -1, we have a fixed length pattern. */
4305 if (mlen != -1)
4306 break;
704a1a2a
CR
4307 }
4308
4309 return (0);
4310
4311 case MATCH_END:
5f8cde23 4312 for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
704a1a2a
CR
4313 {
4314 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
545f34cf 4315 {
704a1a2a
CR
4316 *sp = indices[n];
4317 *ep = indices[wstrlen];
4318 return 1;
545f34cf 4319 }
5f8cde23
CR
4320 /* If MLEN != -1, we have a fixed length pattern. */
4321 if (mlen != -1)
4322 break;
545f34cf 4323 }
704a1a2a 4324
ccc6cda3 4325 return (0);
726f6388 4326 }
ccc6cda3
JA
4327
4328 return (0);
726f6388 4329}
704a1a2a
CR
4330#endif /* HANDLE_MULTIBYTE */
4331
4332static int
4333match_pattern (string, pat, mtype, sp, ep)
4334 char *string, *pat;
4335 int mtype;
4336 char **sp, **ep;
4337{
4338#if defined (HANDLE_MULTIBYTE)
4339 int ret;
4340 size_t n;
4341 wchar_t *wstring, *wpat;
4342 char **indices;
adc6cff5 4343 size_t slen, plen, mslen, mplen;
704a1a2a
CR
4344#endif
4345
4346 if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
4347 return (0);
4348
4349#if defined (HANDLE_MULTIBYTE)
4350 if (MB_CUR_MAX > 1)
4351 {
adc6cff5 4352 if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
adc6cff5
CR
4353 return (match_upattern (string, pat, mtype, sp, ep));
4354
704a1a2a
CR
4355 n = xdupmbstowcs (&wpat, NULL, pat);
4356 if (n == (size_t)-1)
4357 return (match_upattern (string, pat, mtype, sp, ep));
4358 n = xdupmbstowcs (&wstring, &indices, string);
4359 if (n == (size_t)-1)
4360 {
4361 free (wpat);
4362 return (match_upattern (string, pat, mtype, sp, ep));
4363 }
4364 ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
4365
4366 free (wpat);
4367 free (wstring);
4368 free (indices);
4369
4370 return (ret);
4371 }
4372 else
4373#endif
4374 return (match_upattern (string, pat, mtype, sp, ep));
4375}
726f6388 4376
cce855bc
JA
4377static int
4378getpatspec (c, value)
4379 int c;
4380 char *value;
4381{
4382 if (c == '#')
4383 return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
4384 else /* c == '%' */
4385 return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
4386}
4387
4388/* Posix.2 says that the WORD should be run through tilde expansion,
4389 parameter expansion, command substitution and arithmetic expansion.
4390 This leaves the result quoted, so quote_string_for_globbing () has
f73dda09 4391 to be called to fix it up for strmatch (). If QUOTED is non-zero,
cce855bc
JA
4392 it means that the entire expression was enclosed in double quotes.
4393 This means that quoting characters in the pattern do not make any
4394 special pattern characters quoted. For example, the `*' in the
4395 following retains its special meaning: "${foo#'*'}". */
4396static char *
4397getpattern (value, quoted, expandpat)
4398 char *value;
4399 int quoted, expandpat;
4400{
4401 char *pat, *tword;
4402 WORD_LIST *l;
d3ad40de 4403#if 0
cce855bc 4404 int i;
d3ad40de 4405#endif
7117c2d2
JA
4406 /* There is a problem here: how to handle single or double quotes in the
4407 pattern string when the whole expression is between double quotes?
4408 POSIX.2 says that enclosing double quotes do not cause the pattern to
4409 be quoted, but does that leave us a problem with @ and array[@] and their
4410 expansions inside a pattern? */
4411#if 0
cce855bc
JA
4412 if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
4413 {
4414 i = 0;
4415 pat = string_extract_double_quoted (tword, &i, 1);
4416 free (tword);
4417 tword = pat;
4418 }
7117c2d2 4419#endif
cce855bc 4420
7117c2d2
JA
4421 /* expand_string_for_rhs () leaves WORD quoted and does not perform
4422 word splitting. */
22e63b05 4423 l = *value ? expand_string_for_rhs (value,
7117c2d2 4424 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
cce855bc 4425 (int *)NULL, (int *)NULL)
cce855bc 4426 : (WORD_LIST *)0;
cce855bc
JA
4427 pat = string_list (l);
4428 dispose_words (l);
4429 if (pat)
4430 {
4431 tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
4432 free (pat);
4433 pat = tword;
4434 }
4435 return (pat);
4436}
4437
7117c2d2 4438#if 0
cce855bc
JA
4439/* Handle removing a pattern from a string as a result of ${name%[%]value}
4440 or ${name#[#]value}. */
4441static char *
7117c2d2
JA
4442variable_remove_pattern (value, pattern, patspec, quoted)
4443 char *value, *pattern;
4444 int patspec, quoted;
cce855bc 4445{
7117c2d2 4446 char *tword;
cce855bc 4447
7117c2d2 4448 tword = remove_pattern (value, pattern, patspec);
cce855bc 4449
cce855bc
JA
4450 return (tword);
4451}
7117c2d2 4452#endif
cce855bc
JA
4453
4454static char *
7117c2d2 4455list_remove_pattern (list, pattern, patspec, itype, quoted)
cce855bc
JA
4456 WORD_LIST *list;
4457 char *pattern;
7117c2d2 4458 int patspec, itype, quoted;
cce855bc
JA
4459{
4460 WORD_LIST *new, *l;
4461 WORD_DESC *w;
4462 char *tword;
4463
4464 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
4465 {
4466 tword = remove_pattern (l->word->word, pattern, patspec);
227f982e
CR
4467 w = alloc_word_desc ();
4468 w->word = tword ? tword : savestring ("");
cce855bc
JA
4469 new = make_word_list (w, new);
4470 }
4471
4472 l = REVERSE_LIST (new, WORD_LIST *);
e33f2203 4473 tword = string_list_pos_params (itype, l, quoted);
cce855bc 4474 dispose_words (l);
e33f2203 4475
cce855bc
JA
4476 return (tword);
4477}
4478
4479static char *
7117c2d2
JA
4480parameter_list_remove_pattern (itype, pattern, patspec, quoted)
4481 int itype;
4482 char *pattern;
4483 int patspec, quoted;
cce855bc 4484{
7117c2d2 4485 char *ret;
cce855bc
JA
4486 WORD_LIST *list;
4487
cce855bc 4488 list = list_rest_of_args ();
7117c2d2
JA
4489 if (list == 0)
4490 return ((char *)NULL);
4491 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
cce855bc 4492 dispose_words (list);
cce855bc
JA
4493 return (ret);
4494}
4495
4496#if defined (ARRAY_VARS)
4497static char *
fdf670ea
CR
4498array_remove_pattern (var, pattern, patspec, varname, quoted)
4499 SHELL_VAR *var;
7117c2d2
JA
4500 char *pattern;
4501 int patspec;
4502 char *varname; /* so we can figure out how it's indexed */
4503 int quoted;
cce855bc 4504{
fdf670ea
CR
4505 ARRAY *a;
4506 HASH_TABLE *h;
7117c2d2
JA
4507 int itype;
4508 char *ret;
4509 WORD_LIST *list;
4510 SHELL_VAR *v;
cce855bc 4511
7117c2d2
JA
4512 /* compute itype from varname here */
4513 v = array_variable_part (varname, &ret, 0);
4514 itype = ret[0];
4515
fdf670ea
CR
4516 a = (v && array_p (v)) ? array_cell (v) : 0;
4517 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
4518
4519 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
7117c2d2
JA
4520 if (list == 0)
4521 return ((char *)NULL);
4522 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
4523 dispose_words (list);
4524
4525 return ret;
4526}
4527#endif /* ARRAY_VARS */
4528
4529static char *
5f8cde23
CR
4530parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags)
4531 char *varname, *value;
4532 int ind;
4533 char *patstr;
4534 int rtype, quoted, flags;
7117c2d2 4535{
d3a24ed2 4536 int vtype, patspec, starsub;
7117c2d2
JA
4537 char *temp1, *val, *pattern;
4538 SHELL_VAR *v;
4539
4540 if (value == 0)
4541 return ((char *)NULL);
4542
4543 this_command_name = varname;
4544
5f8cde23 4545 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
7117c2d2 4546 if (vtype == -1)
cce855bc
JA
4547 return ((char *)NULL);
4548
d3a24ed2
CR
4549 starsub = vtype & VT_STARSUB;
4550 vtype &= ~VT_STARSUB;
4551
7117c2d2 4552 patspec = getpatspec (rtype, patstr);
cce855bc 4553 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
7117c2d2 4554 patstr++;
cce855bc 4555
c40a57dd
CR
4556 /* Need to pass getpattern newly-allocated memory in case of expansion --
4557 the expansion code will free the passed string on an error. */
4558 temp1 = savestring (patstr);
4559 pattern = getpattern (temp1, quoted, 1);
4560 free (temp1);
cce855bc 4561
7117c2d2
JA
4562 temp1 = (char *)NULL; /* shut up gcc */
4563 switch (vtype)
cce855bc 4564 {
7117c2d2
JA
4565 case VT_VARIABLE:
4566 case VT_ARRAYMEMBER:
4567 temp1 = remove_pattern (val, pattern, patspec);
4568 if (vtype == VT_VARIABLE)
4569 FREE (val);
4570 if (temp1)
28ef6c31 4571 {
e6598ba4
CR
4572 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4573 ? quote_string (temp1)
4574 : quote_escapes (temp1);
7117c2d2
JA
4575 free (temp1);
4576 temp1 = val;
28ef6c31 4577 }
7117c2d2
JA
4578 break;
4579#if defined (ARRAY_VARS)
4580 case VT_ARRAYVAR:
fdf670ea 4581 temp1 = array_remove_pattern (v, pattern, patspec, varname, quoted);
7117c2d2 4582 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
cce855bc 4583 {
7117c2d2
JA
4584 val = quote_escapes (temp1);
4585 free (temp1);
4586 temp1 = val;
cce855bc 4587 }
7117c2d2
JA
4588 break;
4589#endif
4590 case VT_POSPARMS:
4591 temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
4592 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4593 {
4594 val = quote_escapes (temp1);
4595 free (temp1);
4596 temp1 = val;
4597 }
4598 break;
cce855bc
JA
4599 }
4600
4601 FREE (pattern);
7117c2d2
JA
4602 return temp1;
4603}
cce855bc 4604
726f6388
JA
4605/*******************************************
4606 * *
4607 * Functions to expand WORD_DESCs *
4608 * *
4609 *******************************************/
4610
4611/* Expand WORD, performing word splitting on the result. This does
4612 parameter expansion, command substitution, arithmetic expansion,
4613 word splitting, and quote removal. */
4614
4615WORD_LIST *
4616expand_word (word, quoted)
4617 WORD_DESC *word;
4618 int quoted;
4619{
4620 WORD_LIST *result, *tresult;
4621
b72432fd 4622 tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
726f6388
JA
4623 result = word_list_split (tresult);
4624 dispose_words (tresult);
ccc6cda3 4625 return (result ? dequote_list (result) : result);
726f6388
JA
4626}
4627
4628/* Expand WORD, but do not perform word splitting on the result. This
4629 does parameter expansion, command substitution, arithmetic expansion,
4630 and quote removal. */
4631WORD_LIST *
28ef6c31 4632expand_word_unsplit (word, quoted)
726f6388
JA
4633 WORD_DESC *word;
4634 int quoted;
4635{
4636 WORD_LIST *result;
4637
28ef6c31 4638 expand_no_split_dollar_star = 1;
1231ac47
CR
4639#if defined (HANDLE_MULTIBYTE)
4640 if (ifs_firstc[0] == 0)
4641#else
4642 if (ifs_firstc == 0)
4643#endif
4644 word->flags |= W_NOSPLIT;
40647963 4645 word->flags |= W_NOSPLIT2;
b72432fd 4646 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
28ef6c31 4647 expand_no_split_dollar_star = 0;
7117c2d2 4648
ccc6cda3 4649 return (result ? dequote_list (result) : result);
726f6388
JA
4650}
4651
4652/* Perform shell expansions on WORD, but do not perform word splitting or
1231ac47
CR
4653 quote removal on the result. Virtually identical to expand_word_unsplit;
4654 could be combined if implementations don't diverge. */
726f6388
JA
4655WORD_LIST *
4656expand_word_leave_quoted (word, quoted)
4657 WORD_DESC *word;
4658 int quoted;
4659{
1231ac47
CR
4660 WORD_LIST *result;
4661
4662 expand_no_split_dollar_star = 1;
4663#if defined (HANDLE_MULTIBYTE)
4664 if (ifs_firstc[0] == 0)
4665#else
4666 if (ifs_firstc == 0)
4667#endif
4668 word->flags |= W_NOSPLIT;
e1e48bba 4669 word->flags |= W_NOSPLIT2;
1231ac47
CR
4670 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4671 expand_no_split_dollar_star = 0;
4672
4673 return result;
726f6388
JA
4674}
4675
726f6388
JA
4676#if defined (PROCESS_SUBSTITUTION)
4677
cce855bc
JA
4678/*****************************************************************/
4679/* */
4680/* Hacking Process Substitution */
4681/* */
4682/*****************************************************************/
726f6388 4683
726f6388
JA
4684#if !defined (HAVE_DEV_FD)
4685/* Named pipes must be removed explicitly with `unlink'. This keeps a list
4686 of FIFOs the shell has open. unlink_fifo_list will walk the list and
4687 unlink all of them. add_fifo_list adds the name of an open FIFO to the
4688 list. NFIFO is a count of the number of FIFOs in the list. */
4689#define FIFO_INCR 20
4690
f73dda09
JA
4691struct temp_fifo {
4692 char *file;
4693 pid_t proc;
4694};
4695
4696static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
ccc6cda3
JA
4697static int nfifo;
4698static int fifo_list_size;
726f6388 4699
112ff2a6
CR
4700char *
4701copy_fifo_list (sizep)
4702 int *sizep;
4703{
4704 if (sizep)
4705 *sizep = 0;
4706 return (char *)NULL;
4707}
4708
726f6388
JA
4709static void
4710add_fifo_list (pathname)
4711 char *pathname;
4712{
4713 if (nfifo >= fifo_list_size - 1)
4714 {
4715 fifo_list_size += FIFO_INCR;
f73dda09
JA
4716 fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
4717 fifo_list_size * sizeof (struct temp_fifo));
726f6388
JA
4718 }
4719
f73dda09
JA
4720 fifo_list[nfifo].file = savestring (pathname);
4721 nfifo++;
726f6388
JA
4722}
4723
112ff2a6
CR
4724void
4725unlink_fifo (i)
4726 int i;
4727{
4728 if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1))
4729 {
4730 unlink (fifo_list[i].file);
4731 free (fifo_list[i].file);
4732 fifo_list[i].file = (char *)NULL;
4733 fifo_list[i].proc = -1;
4734 }
4735}
4736
726f6388
JA
4737void
4738unlink_fifo_list ()
4739{
f73dda09
JA
4740 int saved, i, j;
4741
ccc6cda3 4742 if (nfifo == 0)
726f6388
JA
4743 return;
4744
f73dda09 4745 for (i = saved = 0; i < nfifo; i++)
726f6388 4746 {
f73dda09
JA
4747 if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1))
4748 {
7117c2d2
JA
4749 unlink (fifo_list[i].file);
4750 free (fifo_list[i].file);
4751 fifo_list[i].file = (char *)NULL;
4752 fifo_list[i].proc = -1;
f73dda09
JA
4753 }
4754 else
7117c2d2 4755 saved++;
f73dda09
JA
4756 }
4757
4758 /* If we didn't remove some of the FIFOs, compact the list. */
4759 if (saved)
4760 {
4761 for (i = j = 0; i < nfifo; i++)
4762 if (fifo_list[i].file)
4763 {
4764 fifo_list[j].file = fifo_list[i].file;
4765 fifo_list[j].proc = fifo_list[i].proc;
4766 j++;
4767 }
4768 nfifo = j;
726f6388 4769 }
f73dda09
JA
4770 else
4771 nfifo = 0;
726f6388
JA
4772}
4773
112ff2a6
CR
4774/* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
4775 from some point in the past, and close all open FIFOs in fifo_list
4776 that are not marked as active in LIST. If LIST is NULL, close
4777 everything in fifo_list. LSIZE is the number of elements in LIST, in
4778 case it's larger than fifo_list_size (size of fifo_list). */
4779void
4780close_new_fifos (list, lsize)
4781 char *list;
4782 int lsize;
4783{
4784 int i;
4785
4786 if (list == 0)
4787 {
112ff2a6
CR
4788 unlink_fifo_list ();
4789 return;
4790 }
4791
4792 for (i = 0; i < lsize; i++)
4793 if (list[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
112ff2a6 4794 unlink_fifo (i);
112ff2a6
CR
4795
4796 for (i = lsize; i < fifo_list_size; i++)
112ff2a6
CR
4797 unlink_fifo (i);
4798}
112ff2a6 4799
d3ad40de
CR
4800int
4801fifos_pending ()
4802{
4803 return nfifo;
4804}
4805
112ff2a6
CR
4806int
4807num_fifos ()
4808{
4809 return nfifo;
4810}
4811
726f6388
JA
4812static char *
4813make_named_pipe ()
4814{
4815 char *tname;
4816
d3ad40de 4817 tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
726f6388
JA
4818 if (mkfifo (tname, 0600) < 0)
4819 {
4820 free (tname);
4821 return ((char *)NULL);
4822 }
4823
4824 add_fifo_list (tname);
4825 return (tname);
4826}
4827
726f6388
JA
4828#else /* HAVE_DEV_FD */
4829
4830/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
4831 has open to children. NFDS is a count of the number of bits currently
4832 set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
4833 of open files. */
4834static char *dev_fd_list = (char *)NULL;
ccc6cda3 4835static int nfds;
726f6388
JA
4836static int totfds; /* The highest possible number of open files. */
4837
112ff2a6
CR
4838char *
4839copy_fifo_list (sizep)
4840 int *sizep;
4841{
4842 char *ret;
4843
4844 if (nfds == 0 || totfds == 0)
4845 {
4846 if (sizep)
4847 *sizep = 0;
4848 return (char *)NULL;
4849 }
4850
4851 if (sizep)
4852 *sizep = totfds;
4853 ret = (char *)xmalloc (totfds);
4854 return (memcpy (ret, dev_fd_list, totfds));
4855}
4856
726f6388
JA
4857static void
4858add_fifo_list (fd)
4859 int fd;
4860{
112ff2a6 4861 if (dev_fd_list == 0 || fd >= totfds)
726f6388
JA
4862 {
4863 int ofds;
4864
4865 ofds = totfds;
4866 totfds = getdtablesize ();
4867 if (totfds < 0 || totfds > 256)
4868 totfds = 256;
626d0694 4869 if (fd >= totfds)
726f6388
JA
4870 totfds = fd + 2;
4871
f73dda09 4872 dev_fd_list = (char *)xrealloc (dev_fd_list, totfds);
7117c2d2 4873 memset (dev_fd_list + ofds, '\0', totfds - ofds);
726f6388
JA
4874 }
4875
4876 dev_fd_list[fd] = 1;
4877 nfds++;
4878}
4879
d3ad40de
CR
4880int
4881fifos_pending ()
4882{
4883 return 0; /* used for cleanup; not needed with /dev/fd */
4884}
4885
112ff2a6
CR
4886int
4887num_fifos ()
4888{
4889 return nfds;
4890}
4891
4892void
4893unlink_fifo (fd)
4894 int fd;
4895{
4896 if (dev_fd_list[fd])
4897 {
4898 close (fd);
4899 dev_fd_list[fd] = 0;
4900 nfds--;
4901 }
4902}
4903
726f6388
JA
4904void
4905unlink_fifo_list ()
4906{
4907 register int i;
4908
ccc6cda3 4909 if (nfds == 0)
726f6388
JA
4910 return;
4911
4912 for (i = 0; nfds && i < totfds; i++)
112ff2a6 4913 unlink_fifo (i);
726f6388
JA
4914
4915 nfds = 0;
4916}
4917
112ff2a6
CR
4918/* Take LIST, which is a snapshot copy of dev_fd_list from some point in
4919 the past, and close all open fds in dev_fd_list that are not marked
4920 as open in LIST. If LIST is NULL, close everything in dev_fd_list.
4921 LSIZE is the number of elements in LIST, in case it's larger than
4922 totfds (size of dev_fd_list). */
4923void
4924close_new_fifos (list, lsize)
4925 char *list;
4926 int lsize;
4927{
4928 int i;
4929
4930 if (list == 0)
4931 {
4932 unlink_fifo_list ();
4933 return;
4934 }
4935
4936 for (i = 0; i < lsize; i++)
4937 if (list[i] == 0 && i < totfds && dev_fd_list[i])
4938 unlink_fifo (i);
4939
4940 for (i = lsize; i < totfds; i++)
4941 unlink_fifo (i);
4942}
4943
726f6388
JA
4944#if defined (NOTDEF)
4945print_dev_fd_list ()
4946{
4947 register int i;
4948
f73dda09 4949 fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
726f6388
JA
4950 fflush (stderr);
4951
4952 for (i = 0; i < totfds; i++)
4953 {
4954 if (dev_fd_list[i])
4955 fprintf (stderr, " %d", i);
4956 }
4957 fprintf (stderr, "\n");
4958}
4959#endif /* NOTDEF */
4960
4961static char *
4962make_dev_fd_filename (fd)
4963 int fd;
4964{
f73dda09 4965 char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
726f6388 4966
e141c35a 4967 ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
bb70624e
JA
4968
4969 strcpy (ret, DEV_FD_PREFIX);
4970 p = inttostr (fd, intbuf, sizeof (intbuf));
4971 strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
4972
726f6388
JA
4973 add_fifo_list (fd);
4974 return (ret);
4975}
4976
4977#endif /* HAVE_DEV_FD */
4978
4979/* Return a filename that will open a connection to the process defined by
4980 executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
4981 a filename in /dev/fd corresponding to a descriptor that is one of the
4982 ends of the pipe. If not defined, we use named pipes on systems that have
4983 them. Systems without /dev/fd and named pipes are out of luck.
4984
4985 OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
4986 use the read end of the pipe and dup that file descriptor to fd 0 in
4987 the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
4988 writing or use the write end of the pipe in the child, and dup that
4989 file descriptor to fd 1 in the child. The parent does the opposite. */
4990
4991static char *
4992process_substitute (string, open_for_read_in_child)
4993 char *string;
4994 int open_for_read_in_child;
4995{
4996 char *pathname;
4997 int fd, result;
4998 pid_t old_pid, pid;
4999#if defined (HAVE_DEV_FD)
5000 int parent_pipe_fd, child_pipe_fd;
5001 int fildes[2];
5002#endif /* HAVE_DEV_FD */
5003#if defined (JOB_CONTROL)
5004 pid_t old_pipeline_pgrp;
ccc6cda3 5005#endif
726f6388 5006
cce855bc 5007 if (!string || !*string || wordexp_only)
726f6388
JA
5008 return ((char *)NULL);
5009
5010#if !defined (HAVE_DEV_FD)
5011 pathname = make_named_pipe ();
5012#else /* HAVE_DEV_FD */
5013 if (pipe (fildes) < 0)
5014 {
5e13499c 5015 sys_error (_("cannot make pipe for process substitution"));
726f6388
JA
5016 return ((char *)NULL);
5017 }
5018 /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
5019 the pipe in the parent, otherwise the read end. */
5020 parent_pipe_fd = fildes[open_for_read_in_child];
5021 child_pipe_fd = fildes[1 - open_for_read_in_child];
d166f048
JA
5022 /* Move the parent end of the pipe to some high file descriptor, to
5023 avoid clashes with FDs used by the script. */
5024 parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
5025
726f6388
JA
5026 pathname = make_dev_fd_filename (parent_pipe_fd);
5027#endif /* HAVE_DEV_FD */
5028
36211029 5029 if (pathname == 0)
726f6388 5030 {
5e13499c 5031 sys_error (_("cannot make pipe for process substitution"));
726f6388
JA
5032 return ((char *)NULL);
5033 }
5034
5035 old_pid = last_made_pid;
5036
5037#if defined (JOB_CONTROL)
5038 old_pipeline_pgrp = pipeline_pgrp;
5039 pipeline_pgrp = shell_pgrp;
ccc6cda3 5040 save_pipeline (1);
ccc6cda3
JA
5041#endif /* JOB_CONTROL */
5042
726f6388
JA
5043 pid = make_child ((char *)NULL, 1);
5044 if (pid == 0)
5045 {
ccc6cda3 5046 reset_terminating_signals (); /* XXX */
d3a24ed2 5047 free_pushed_string_input ();
726f6388 5048 /* Cancel traps, in trap.c. */
d1fab3dc 5049 restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */
726f6388 5050 setup_async_signals ();
d3ad40de 5051 subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB;
726f6388 5052 }
ccc6cda3
JA
5053
5054#if defined (JOB_CONTROL)
726f6388
JA
5055 set_sigchld_handler ();
5056 stop_making_children ();
866961ad 5057 /* XXX - should we only do this in the parent? (as in command subst) */
726f6388 5058 pipeline_pgrp = old_pipeline_pgrp;
ccc6cda3 5059#endif /* JOB_CONTROL */
726f6388
JA
5060
5061 if (pid < 0)
5062 {
5e13499c 5063 sys_error (_("cannot make child for process substitution"));
726f6388
JA
5064 free (pathname);
5065#if defined (HAVE_DEV_FD)
5066 close (parent_pipe_fd);
5067 close (child_pipe_fd);
5068#endif /* HAVE_DEV_FD */
5069 return ((char *)NULL);
5070 }
5071
5072 if (pid > 0)
5073 {
ccc6cda3
JA
5074#if defined (JOB_CONTROL)
5075 restore_pipeline (1);
5076#endif
5077
f73dda09
JA
5078#if !defined (HAVE_DEV_FD)
5079 fifo_list[nfifo-1].proc = pid;
5080#endif
5081
726f6388
JA
5082 last_made_pid = old_pid;
5083
5084#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
5085 close_pgrp_pipe ();
5086#endif /* JOB_CONTROL && PGRP_PIPE */
5087
5088#if defined (HAVE_DEV_FD)
5089 close (child_pipe_fd);
5090#endif /* HAVE_DEV_FD */
5091
5092 return (pathname);
5093 }
5094
5095 set_sigint_handler ();
5096
5097#if defined (JOB_CONTROL)
5098 set_job_control (0);
5099#endif /* JOB_CONTROL */
5100
5101#if !defined (HAVE_DEV_FD)
5102 /* Open the named pipe in the child. */
ccc6cda3 5103 fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY);
726f6388
JA
5104 if (fd < 0)
5105 {
5e13499c
CR
5106 /* Two separate strings for ease of translation. */
5107 if (open_for_read_in_child)
5108 sys_error (_("cannot open named pipe %s for reading"), pathname);
5109 else
5110 sys_error (_("cannot open named pipe %s for writing"), pathname);
5111
726f6388
JA
5112 exit (127);
5113 }
bb70624e
JA
5114 if (open_for_read_in_child)
5115 {
28ef6c31 5116 if (sh_unset_nodelay_mode (fd) < 0)
bb70624e 5117 {
d3ad40de 5118 sys_error (_("cannot reset nodelay mode for fd %d"), fd);
bb70624e
JA
5119 exit (127);
5120 }
5121 }
726f6388
JA
5122#else /* HAVE_DEV_FD */
5123 fd = child_pipe_fd;
5124#endif /* HAVE_DEV_FD */
5125
5126 if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
5127 {
5e13499c 5128 sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
ccc6cda3 5129 open_for_read_in_child ? 0 : 1);
726f6388
JA
5130 exit (127);
5131 }
5132
f73dda09
JA
5133 if (fd != (open_for_read_in_child ? 0 : 1))
5134 close (fd);
726f6388
JA
5135
5136 /* Need to close any files that this process has open to pipes inherited
5137 from its parent. */
5138 if (current_fds_to_close)
5139 {
5140 close_fd_bitmap (current_fds_to_close);
5141 current_fds_to_close = (struct fd_bitmap *)NULL;
5142 }
5143
5144#if defined (HAVE_DEV_FD)
5145 /* Make sure we close the parent's end of the pipe and clear the slot
5146 in the fd list so it is not closed later, if reallocated by, for
5147 instance, pipe(2). */
5148 close (parent_pipe_fd);
5149 dev_fd_list[parent_pipe_fd] = 0;
5150#endif /* HAVE_DEV_FD */
5151
3087e51c
CR
5152 /* subshells shouldn't have this flag, which controls using the temporary
5153 environment for variable lookups. */
5154 expanding_redir = 0;
5155
d166f048 5156 result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
726f6388
JA
5157
5158#if !defined (HAVE_DEV_FD)
5159 /* Make sure we close the named pipe in the child before we exit. */
5160 close (open_for_read_in_child ? 0 : 1);
5161#endif /* !HAVE_DEV_FD */
5162
5163 exit (result);
5164 /*NOTREACHED*/
5165}
5166#endif /* PROCESS_SUBSTITUTION */
5167
cce855bc
JA
5168/***********************************/
5169/* */
5170/* Command Substitution */
5171/* */
5172/***********************************/
5173
d166f048 5174static char *
d3ad40de 5175read_comsub (fd, quoted, rflag)
d166f048 5176 int fd, quoted;
d3ad40de 5177 int *rflag;
d166f048 5178{
e6598ba4
CR
5179 char *istring, buf[128], *bufp, *s;
5180 int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul;
f73dda09 5181 ssize_t bufn;
d166f048
JA
5182
5183 istring = (char *)NULL;
d3ad40de 5184 istring_index = istring_size = bufn = tflag = 0;
d166f048 5185
e6598ba4
CR
5186 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
5187 skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
5188
d3ad40de
CR
5189 /* Read the output of the command through the pipe. This may need to be
5190 changed to understand multibyte characters in the future. */
d166f048
JA
5191 while (1)
5192 {
5193 if (fd < 0)
28ef6c31 5194 break;
d166f048
JA
5195 if (--bufn <= 0)
5196 {
bb70624e 5197 bufn = zread (fd, buf, sizeof (buf));
d166f048
JA
5198 if (bufn <= 0)
5199 break;
5200 bufp = buf;
5201 }
5202 c = *bufp++;
5203
28ef6c31
JA
5204 if (c == 0)
5205 {
5206#if 0
5207 internal_warning ("read_comsub: ignored null byte in input");
5208#endif
5209 continue;
5210 }
5211
d166f048
JA
5212 /* Add the character to ISTRING, possibly after resizing it. */
5213 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
5214
d3ad40de
CR
5215 /* This is essentially quote_string inline */
5216 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
5217 istring[istring_index++] = CTLESC;
5218 /* Escape CTLESC and CTLNUL in the output to protect those characters
5219 from the rest of the word expansions (word splitting and globbing.)
5220 This is essentially quote_escapes inline. */
e6598ba4 5221 else if (skip_ctlesc == 0 && c == CTLESC)
d3ad40de
CR
5222 {
5223 tflag |= W_HASCTLESC;
5224 istring[istring_index++] = CTLESC;
5225 }
e6598ba4 5226 else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
d166f048
JA
5227 istring[istring_index++] = CTLESC;
5228
5229 istring[istring_index++] = c;
28ef6c31
JA
5230
5231#if 0
5232#if defined (__CYGWIN__)
5233 if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r')
5234 {
5235 istring_index--;
5236 istring[istring_index - 1] = '\n';
5237 }
5238#endif
5239#endif
d166f048
JA
5240 }
5241
5242 if (istring)
5243 istring[istring_index] = '\0';
5244
5245 /* If we read no output, just return now and save ourselves some
5246 trouble. */
5247 if (istring_index == 0)
5248 {
5249 FREE (istring);
d3ad40de
CR
5250 if (rflag)
5251 *rflag = tflag;
d166f048
JA
5252 return (char *)NULL;
5253 }
5254
5255 /* Strip trailing newlines from the output of the command. */
5256 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5257 {
5258 while (istring_index > 0)
5259 {
5260 if (istring[istring_index - 1] == '\n')
5261 {
5262 --istring_index;
5263
5264 /* If the newline was quoted, remove the quoting char. */
5265 if (istring[istring_index - 1] == CTLESC)
5266 --istring_index;
5267 }
5268 else
5269 break;
5270 }
5271 istring[istring_index] = '\0';
5272 }
5273 else
5274 strip_trailing (istring, istring_index - 1, 1);
5275
d3ad40de
CR
5276 if (rflag)
5277 *rflag = tflag;
d166f048
JA
5278 return istring;
5279}
5280
d3ad40de
CR
5281/* Perform command substitution on STRING. This returns a WORD_DESC * with the
5282 contained string possibly quoted. */
5283WORD_DESC *
726f6388
JA
5284command_substitute (string, quoted)
5285 char *string;
5286 int quoted;
5287{
cac4cdbf 5288 pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
ccc6cda3 5289 char *istring;
d3ad40de
CR
5290 int result, fildes[2], function_value, pflags, rc, tflag;
5291 WORD_DESC *ret;
726f6388 5292
ccc6cda3 5293 istring = (char *)NULL;
726f6388
JA
5294
5295 /* Don't fork () if there is no need to. In the case of no command to
5296 run, just return NULL. */
5297 if (!string || !*string || (string[0] == '\n' && !string[1]))
d3ad40de 5298 return ((WORD_DESC *)NULL);
726f6388 5299
cce855bc
JA
5300 if (wordexp_only && read_but_dont_execute)
5301 {
3eb2d94a 5302 last_command_exit_value = EX_WEXPCOMSUB;
cce855bc
JA
5303 jump_to_top_level (EXITPROG);
5304 }
5305
bb70624e
JA
5306 /* We're making the assumption here that the command substitution will
5307 eventually run a command from the file system. Since we'll run
5308 maybe_make_export_env in this subshell before executing that command,
5309 the parent shell and any other shells it starts will have to remake
5310 the environment. If we make it before we fork, other shells won't
5311 have to. Don't bother if we have any temporary variable assignments,
5312 though, because the export environment will be remade after this
5313 command completes anyway, but do it if all the words to be expanded
5314 are variable assignments. */
5315 if (subst_assign_varlist == 0 || garglist == 0)
5316 maybe_make_export_env (); /* XXX */
5317
d3a24ed2 5318 /* Flags to pass to parse_and_execute() */
f486d0a1 5319 pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
d3a24ed2 5320
726f6388
JA
5321 /* Pipe the output of executing STRING into the current shell. */
5322 if (pipe (fildes) < 0)
5323 {
5e13499c 5324 sys_error (_("cannot make pipe for command substitution"));
726f6388
JA
5325 goto error_exit;
5326 }
5327
5328 old_pid = last_made_pid;
5329#if defined (JOB_CONTROL)
ccc6cda3 5330 old_pipeline_pgrp = pipeline_pgrp;
28ef6c31
JA
5331 /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */
5332 if ((subshell_environment & SUBSHELL_PIPE) == 0)
5333 pipeline_pgrp = shell_pgrp;
ccc6cda3 5334 cleanup_the_pipeline ();
da719982 5335#endif /* JOB_CONTROL */
726f6388 5336
cac4cdbf 5337 old_async_pid = last_asynchronous_pid;
cac4cdbf 5338 pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC);
cac4cdbf
CR
5339 last_asynchronous_pid = old_async_pid;
5340
726f6388 5341 if (pid == 0)
64419627
CR
5342 {
5343 /* Reset the signal handlers in the child, but don't free the
5344 trap strings. Set a flag noting that we have to free the
5345 trap strings if we run trap to change a signal disposition. */
5346 reset_signal_handlers ();
5347 subshell_environment |= SUBSHELL_RESETTRAP;
5348 }
ccc6cda3
JA
5349
5350#if defined (JOB_CONTROL)
525739ba 5351 /* XXX DO THIS ONLY IN PARENT ? XXX */
ccc6cda3
JA
5352 set_sigchld_handler ();
5353 stop_making_children ();
525739ba 5354 if (pid != 0)
525739ba 5355 pipeline_pgrp = old_pipeline_pgrp;
f73dda09
JA
5356#else
5357 stop_making_children ();
ccc6cda3 5358#endif /* JOB_CONTROL */
726f6388
JA
5359
5360 if (pid < 0)
5361 {
5e13499c 5362 sys_error (_("cannot make child for command substitution"));
726f6388
JA
5363 error_exit:
5364
fd58d46e
CR
5365 last_made_pid = old_pid;
5366
726f6388
JA
5367 FREE (istring);
5368 close (fildes[0]);
5369 close (fildes[1]);
d3ad40de 5370 return ((WORD_DESC *)NULL);
726f6388
JA
5371 }
5372
5373 if (pid == 0)
5374 {
5375 set_sigint_handler (); /* XXX */
28ef6c31 5376
d3a24ed2
CR
5377 free_pushed_string_input ();
5378
726f6388
JA
5379 if (dup2 (fildes[1], 1) < 0)
5380 {
5e13499c 5381 sys_error (_("command_substitute: cannot duplicate pipe as fd 1"));
726f6388
JA
5382 exit (EXECUTION_FAILURE);
5383 }
5384
5385 /* If standard output is closed in the parent shell
5386 (such as after `exec >&-'), file descriptor 1 will be
5387 the lowest available file descriptor, and end up in
5388 fildes[0]. This can happen for stdin and stderr as well,
5389 but stdout is more important -- it will cause no output
5390 to be generated from this command. */
5391 if ((fildes[1] != fileno (stdin)) &&
5392 (fildes[1] != fileno (stdout)) &&
5393 (fildes[1] != fileno (stderr)))
5394 close (fildes[1]);
5395
5396 if ((fildes[0] != fileno (stdin)) &&
5397 (fildes[0] != fileno (stdout)) &&
5398 (fildes[0] != fileno (stderr)))
5399 close (fildes[0]);
5400
54a1fa7c
CR
5401#ifdef __CYGWIN__
5402 /* Let stdio know the fd may have changed from text to binary mode, and
5403 make sure to preserve stdout line buffering. */
5404 freopen (NULL, "w", stdout);
5405 sh_setlinebuf (stdout);
5406#endif /* __CYGWIN__ */
5407
726f6388
JA
5408 /* The currently executing shell is not interactive. */
5409 interactive = 0;
5410
ccc6cda3 5411 /* This is a subshell environment. */
28ef6c31 5412 subshell_environment |= SUBSHELL_COMSUB;
ccc6cda3 5413
28ef6c31 5414 /* When not in POSIX mode, command substitution does not inherit
7117c2d2 5415 the -e flag. */
28ef6c31 5416 if (posixly_correct == 0)
26a8e19c 5417 {
77b3aacb
CR
5418 builtin_ignoring_errexit = 0;
5419 change_flag ('e', FLAG_OFF);
26a8e19c
CR
5420 set_shellopts ();
5421 }
726f6388
JA
5422
5423 remove_quoted_escapes (string);
5424
ccc6cda3 5425 startup_state = 2; /* see if we can avoid a fork */
726f6388
JA
5426 /* Give command substitution a place to jump back to on failure,
5427 so we don't go back up to main (). */
36eb585c 5428 result = setjmp_nosigs (top_level);
726f6388 5429
bb70624e
JA
5430 /* If we're running a command substitution inside a shell function,
5431 trap `return' so we don't return from the function in the subshell
5432 and go off to never-never land. */
5433 if (result == 0 && return_catch_flag)
36eb585c 5434 function_value = setjmp_nosigs (return_catch);
bb70624e
JA
5435 else
5436 function_value = 0;
5437
d3a24ed2 5438 if (result == ERREXIT)
5e13499c 5439 rc = last_command_exit_value;
d3a24ed2 5440 else if (result == EXITPROG)
5e13499c 5441 rc = last_command_exit_value;
726f6388 5442 else if (result)
5e13499c 5443 rc = EXECUTION_FAILURE;
bb70624e 5444 else if (function_value)
5e13499c 5445 rc = return_catch_value;
726f6388 5446 else
d3a24ed2
CR
5447 {
5448 subshell_level++;
5449 rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
5450 subshell_level--;
d3a24ed2 5451 }
5e13499c
CR
5452
5453 last_command_exit_value = rc;
5454 rc = run_exit_trap ();
d3ad40de
CR
5455#if defined (PROCESS_SUBSTITUTION)
5456 unlink_fifo_list ();
5457#endif
5e13499c 5458 exit (rc);
726f6388
JA
5459 }
5460 else
5461 {
726f6388
JA
5462#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
5463 close_pgrp_pipe ();
5464#endif /* JOB_CONTROL && PGRP_PIPE */
5465
5466 close (fildes[1]);
5467
d3ad40de
CR
5468 tflag = 0;
5469 istring = read_comsub (fildes[0], quoted, &tflag);
ccc6cda3 5470
726f6388
JA
5471 close (fildes[0]);
5472
b72432fd 5473 current_command_subst_pid = pid;
726f6388
JA
5474 last_command_exit_value = wait_for (pid);
5475 last_command_subst_pid = pid;
5476 last_made_pid = old_pid;
5477
5478#if defined (JOB_CONTROL)
5479 /* If last_command_exit_value > 128, then the substituted command
5480 was terminated by a signal. If that signal was SIGINT, then send
5481 SIGINT to ourselves. This will break out of loops, for instance. */
d3a24ed2 5482 if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
726f6388
JA
5483 kill (getpid (), SIGINT);
5484
5485 /* wait_for gives the terminal back to shell_pgrp. If some other
cce855bc
JA
5486 process group should have it, give it away to that group here.
5487 pipeline_pgrp is non-zero only while we are constructing a
5488 pipline, so what we are concerned about is whether or not that
5489 pipeline was started in the background. A pipeline started in
5490 the background should never get the tty back here. */
28ef6c31 5491 if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0)
28ef6c31 5492 give_terminal_to (pipeline_pgrp, 0);
726f6388
JA
5493#endif /* JOB_CONTROL */
5494
d3ad40de
CR
5495 ret = alloc_word_desc ();
5496 ret->word = istring;
5497 ret->flags = tflag;
5498
5499 return ret;
726f6388
JA
5500 }
5501}
5502
5503/********************************************************
5504 * *
5505 * Utility functions for parameter expansion *
5506 * *
5507 ********************************************************/
5508
ccc6cda3 5509#if defined (ARRAY_VARS)
ccc6cda3 5510
f73dda09 5511static arrayind_t
ccc6cda3
JA
5512array_length_reference (s)
5513 char *s;
5514{
f73dda09
JA
5515 int len;
5516 arrayind_t ind;
fdf670ea 5517 char *akey;
f73dda09 5518 char *t, c;
ccc6cda3 5519 ARRAY *array;
68dfe178 5520 HASH_TABLE *h;
ccc6cda3
JA
5521 SHELL_VAR *var;
5522
5523 var = array_variable_part (s, &t, &len);
726f6388 5524
ccc6cda3
JA
5525 /* If unbound variables should generate an error, report one and return
5526 failure. */
fdf670ea 5527 if ((var == 0 || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
726f6388 5528 {
f73dda09 5529 c = *--t;
ccc6cda3 5530 *t = '\0';
0d8616ff 5531 last_command_exit_value = EXECUTION_FAILURE;
7117c2d2 5532 err_unboundvar (s);
f73dda09 5533 *t = c;
ccc6cda3 5534 return (-1);
726f6388 5535 }
ccc6cda3
JA
5536 else if (var == 0)
5537 return 0;
726f6388 5538
28ef6c31
JA
5539 /* We support a couple of expansions for variables that are not arrays.
5540 We'll return the length of the value for v[0], and 1 for v[@] or
5541 v[*]. Return 0 for everything else. */
5542
5543 array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
68dfe178 5544 h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
726f6388 5545
ccc6cda3 5546 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
ccc6cda3 5547 {
fdf670ea 5548 if (assoc_p (var))
68dfe178 5549 return (h ? assoc_num_elements (h) : 0);
fdf670ea 5550 else if (array_p (var))
68dfe178 5551 return (array ? array_num_elements (array) : 0);
fdf670ea 5552 else
68dfe178 5553 return (var_isset (var) ? 1 : 0);
ccc6cda3 5554 }
ccc6cda3 5555
fdf670ea
CR
5556 if (assoc_p (var))
5557 {
5558 t[len - 1] = '\0';
09767ff0 5559 akey = expand_assignment_string_to_string (t, 0); /* [ */
fdf670ea
CR
5560 t[len - 1] = ']';
5561 if (akey == 0 || *akey == 0)
5562 {
5563 err_badarraysub (t);
631b20c6 5564 FREE (akey);
fdf670ea
CR
5565 return (-1);
5566 }
5567 t = assoc_reference (assoc_cell (var), akey);
631b20c6 5568 free (akey);
fdf670ea 5569 }
28ef6c31 5570 else
fdf670ea 5571 {
d9e1f41e 5572 ind = array_expand_index (var, t, len);
a7ad477f
CR
5573 /* negative subscripts to indexed arrays count back from end */
5574 if (var && array_p (var) && ind < 0)
5575 ind = array_max_index (array_cell (var)) + 1 + ind;
fdf670ea
CR
5576 if (ind < 0)
5577 {
5578 err_badarraysub (t);
5579 return (-1);
5580 }
5581 if (array_p (var))
5582 t = array_reference (array, ind);
5583 else
5584 t = (ind == 0) ? value_cell (var) : (char *)NULL;
5585 }
28ef6c31 5586
30915f17 5587 len = MB_STRLEN (t);
ccc6cda3 5588 return (len);
726f6388 5589}
ccc6cda3 5590#endif /* ARRAY_VARS */
726f6388
JA
5591
5592static int
5593valid_brace_expansion_word (name, var_is_special)
5594 char *name;
5595 int var_is_special;
5596{
f73dda09 5597 if (DIGIT (*name) && all_digits (name))
726f6388
JA
5598 return 1;
5599 else if (var_is_special)
5600 return 1;
ccc6cda3
JA
5601#if defined (ARRAY_VARS)
5602 else if (valid_array_reference (name))
5603 return 1;
5604#endif /* ARRAY_VARS */
726f6388
JA
5605 else if (legal_identifier (name))
5606 return 1;
5607 else
5608 return 0;
5609}
ccc6cda3 5610
d3a24ed2
CR
5611static int
5612chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at)
5613 char *name;
5614 int quoted;
5615 int *quoted_dollar_atp, *contains_dollar_at;
5616{
5617 char *temp1;
5618
5619 if (name == 0)
5620 {
5621 if (quoted_dollar_atp)
5622 *quoted_dollar_atp = 0;
5623 if (contains_dollar_at)
5624 *contains_dollar_at = 0;
5625 return 0;
5626 }
5627
5628 /* check for $@ and $* */
5629 if (name[0] == '@' && name[1] == 0)
5630 {
5631 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5632 *quoted_dollar_atp = 1;
5633 if (contains_dollar_at)
5634 *contains_dollar_at = 1;
5635 return 1;
5636 }
5637 else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
5638 {
5639 if (contains_dollar_at)
5640 *contains_dollar_at = 1;
5641 return 1;
5642 }
5643
5644 /* Now check for ${array[@]} and ${array[*]} */
5645#if defined (ARRAY_VARS)
5646 else if (valid_array_reference (name))
5647 {
d0ca3503 5648 temp1 = mbschr (name, '[');
d3a24ed2
CR
5649 if (temp1 && temp1[1] == '@' && temp1[2] == ']')
5650 {
5651 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5652 *quoted_dollar_atp = 1;
5653 if (contains_dollar_at)
5654 *contains_dollar_at = 1;
5655 return 1;
5656 } /* [ */
5657 /* ${array[*]}, when unquoted, should be treated like ${array[@]},
5658 which should result in separate words even when IFS is unset. */
5659 if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0)
5660 {
5661 if (contains_dollar_at)
5662 *contains_dollar_at = 1;
5663 return 1;
5664 }
5665 }
5666#endif
5667 return 0;
5668}
5669
726f6388
JA
5670/* Parameter expand NAME, and return a new string which is the expansion,
5671 or NULL if there was no expansion.
5672 VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
5673 the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
5674 NAME was found inside of a double-quoted expression. */
227f982e 5675static WORD_DESC *
5f8cde23 5676parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp)
726f6388 5677 char *name;
1231ac47 5678 int var_is_special, quoted, pflags;
5f8cde23 5679 arrayind_t *indp;
726f6388 5680{
227f982e 5681 WORD_DESC *ret;
ccc6cda3 5682 char *temp, *tt;
7117c2d2 5683 intmax_t arg_index;
ccc6cda3 5684 SHELL_VAR *var;
b1a26c01 5685 int atype, rflags;
5f8cde23 5686 arrayind_t ind;
726f6388 5687
227f982e
CR
5688 ret = 0;
5689 temp = 0;
b1a26c01 5690 rflags = 0;
227f982e 5691
5f8cde23
CR
5692 if (indp)
5693 *indp = INTMAX_MIN;
5694
227f982e 5695 /* Handle multiple digit arguments, as in ${11}. */
f73dda09 5696 if (legal_number (name, &arg_index))
7117c2d2
JA
5697 {
5698 tt = get_dollar_var_value (arg_index);
762a763b
CR
5699 if (tt)
5700 temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5701 ? quote_string (tt)
5702 : quote_escapes (tt);
5703 else
5704 temp = (char *)NULL;
7117c2d2
JA
5705 FREE (tt);
5706 }
726f6388
JA
5707 else if (var_is_special) /* ${@} */
5708 {
cce855bc 5709 int sindex;
f73dda09 5710 tt = (char *)xmalloc (2 + strlen (name));
cce855bc 5711 tt[sindex = 0] = '$';
726f6388 5712 strcpy (tt + 1, name);
7117c2d2 5713
227f982e 5714 ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
1231ac47 5715 (int *)NULL, (int *)NULL, pflags);
cce855bc 5716 free (tt);
726f6388 5717 }
ccc6cda3
JA
5718#if defined (ARRAY_VARS)
5719 else if (valid_array_reference (name))
5720 {
d42cb8c1 5721expand_arrayref:
631b20c6 5722 /* XXX - does this leak if name[@] or name[*]? */
208fdb50
CR
5723 if (pflags & PF_ASSIGNRHS)
5724 {
5725 temp = array_variable_name (name, &tt, (int *)0);
5726 if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == ']')
5727 temp = array_value (name, quoted|Q_DOUBLE_QUOTES, 0, &atype, &ind);
5728 else
5729 temp = array_value (name, quoted, 0, &atype, &ind);
5730 }
5731 else
5732 temp = array_value (name, quoted, 0, &atype, &ind);
7117c2d2 5733 if (atype == 0 && temp)
5f8cde23
CR
5734 {
5735 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5736 ? quote_string (temp)
5737 : quote_escapes (temp);
5738 rflags |= W_ARRAYIND;
5739 if (indp)
5740 *indp = ind;
5741 }
b1a26c01
CR
5742 else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5743 rflags |= W_HASQUOTEDNULL;
ccc6cda3
JA
5744 }
5745#endif
5746 else if (var = find_variable (name))
5747 {
7117c2d2 5748 if (var_isset (var) && invisible_p (var) == 0)
28ef6c31 5749 {
ccc6cda3 5750#if defined (ARRAY_VARS)
fdf670ea
CR
5751 if (assoc_p (var))
5752 temp = assoc_reference (assoc_cell (var), "0");
5753 else if (array_p (var))
5754 temp = array_reference (array_cell (var), 0);
5755 else
5756 temp = value_cell (var);
ccc6cda3
JA
5757#else
5758 temp = value_cell (var);
5759#endif
5760
5761 if (temp)
762a763b
CR
5762 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5763 ? quote_string (temp)
5764 : quote_escapes (temp);
28ef6c31 5765 }
ccc6cda3
JA
5766 else
5767 temp = (char *)NULL;
5768 }
d42cb8c1
CR
5769 else if (var = find_variable_last_nameref (name))
5770 {
5771 temp = nameref_cell (var);
15623760
CR
5772#if defined (ARRAY_VARS)
5773 /* Handle expanding nameref whose value is x[n] */
d42cb8c1
CR
5774 if (temp && *temp && valid_array_reference (temp))
5775 {
5776 name = temp;
5777 goto expand_arrayref;
5778 }
c2fa6583 5779 else
d42cb8c1 5780#endif
15623760 5781 /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */
c2fa6583 5782 if (temp && *temp && legal_identifier (temp) == 0)
15623760
CR
5783 {
5784 last_command_exit_value = EXECUTION_FAILURE;
5785 report_error (_("%s: invalid variable name for name reference"), temp);
5786 temp = &expand_param_error;
5787 }
5788 else
5789 temp = (char *)NULL;
5790 }
726f6388 5791 else
ccc6cda3 5792 temp = (char *)NULL;
726f6388 5793
227f982e
CR
5794 if (ret == 0)
5795 {
5796 ret = alloc_word_desc ();
5797 ret->word = temp;
b1a26c01 5798 ret->flags |= rflags;
227f982e
CR
5799 }
5800 return ret;
726f6388
JA
5801}
5802
ccc6cda3
JA
5803/* Expand an indirect reference to a variable: ${!NAME} expands to the
5804 value of the variable whose name is the value of NAME. */
227f982e 5805static WORD_DESC *
d3a24ed2 5806parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at)
ccc6cda3
JA
5807 char *name;
5808 int var_is_special, quoted;
d3a24ed2 5809 int *quoted_dollar_atp, *contains_dollar_at;
ccc6cda3
JA
5810{
5811 char *temp, *t;
227f982e 5812 WORD_DESC *w;
d42cb8c1
CR
5813 SHELL_VAR *v;
5814
5815 /* See if it's a nameref first, behave in ksh93-compatible fashion.
5816 There is at least one incompatibility: given ${!foo[0]} where foo=bar,
5817 bash performs an indirect lookup on foo[0] and expands the result;
5818 ksh93 expands bar[0]. We could do that here -- there are enough usable
5819 primitives to do that -- but do not at this point. */
5820 if (var_is_special == 0 && (v = find_variable_last_nameref (name)))
5821 {
5822 if (nameref_p (v) && (t = nameref_cell (v)) && *t)
5823 {
5824 w = alloc_word_desc ();
5825 w->word = savestring (t);
5826 w->flags = 0;
5827 return w;
5828 }
5829 }
ccc6cda3 5830
15623760
CR
5831 /* If var_is_special == 0, and name is not an array reference, this does
5832 more expansion than necessary. It should really look up the variable's
5833 value and not try to expand it. */
5f8cde23 5834 w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND, 0);
227f982e 5835 t = w->word;
762a763b
CR
5836 /* Have to dequote here if necessary */
5837 if (t)
5838 {
5839 temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
5840 ? dequote_string (t)
5841 : dequote_escapes (t);
5842 free (t);
5843 t = temp;
5844 }
227f982e
CR
5845 dispose_word_desc (w);
5846
d3a24ed2 5847 chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at);
ccc6cda3 5848 if (t == 0)
227f982e
CR
5849 return (WORD_DESC *)NULL;
5850
5f8cde23 5851 w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0, 0);
ccc6cda3 5852 free (t);
227f982e
CR
5853
5854 return w;
ccc6cda3
JA
5855}
5856
726f6388
JA
5857/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
5858 depending on the value of C, the separating character. C can be one of
ccc6cda3
JA
5859 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
5860 between double quotes. */
227f982e 5861static WORD_DESC *
ccc6cda3 5862parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
726f6388 5863 char *name, *value;
ccc6cda3 5864 int c, quoted, *qdollaratp, *hasdollarat;
726f6388 5865{
227f982e 5866 WORD_DESC *w;
726f6388
JA
5867 WORD_LIST *l;
5868 char *t, *t1, *temp;
ccc6cda3 5869 int hasdol;
726f6388 5870
ccc6cda3
JA
5871 /* If the entire expression is between double quotes, we want to treat
5872 the value as a double-quoted string, with the exception that we strip
d3ad40de 5873 embedded unescaped double quotes (for sh backwards compatibility). */
22e63b05 5874 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
726f6388 5875 {
ccc6cda3 5876 hasdol = 0;
22e63b05 5877 temp = string_extract_double_quoted (value, &hasdol, 1);
726f6388 5878 }
22e63b05
CR
5879 else
5880 temp = value;
ccc6cda3 5881
227f982e 5882 w = alloc_word_desc ();
726f6388 5883 hasdol = 0;
ccc6cda3
JA
5884 /* XXX was 0 not quoted */
5885 l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL)
5886 : (WORD_LIST *)0;
5887 if (hasdollarat)
5888 *hasdollarat = hasdol || (l && l->next);
22e63b05
CR
5889 if (temp != value)
5890 free (temp);
726f6388
JA
5891 if (l)
5892 {
ccc6cda3 5893 /* The expansion of TEMP returned something. We need to treat things
12d937f9
CR
5894 slightly differently if HASDOL is non-zero. If we have "$@", the
5895 individual words have already been quoted. We need to turn them
5896 into a string with the words separated by the first character of
5897 $IFS without any additional quoting, so string_list_dollar_at won't
5898 do the right thing. We use string_list_dollar_star instead. */
5899 temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l);
5900
ccc6cda3
JA
5901 /* If l->next is not null, we know that TEMP contained "$@", since that
5902 is the only expansion that creates more than one word. */
12d937f9 5903 if (qdollaratp && ((hasdol && quoted) || l->next))
ccc6cda3 5904 *qdollaratp = 1;
ec860d76
CR
5905 /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
5906 a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
5907 flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
5908 expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5909 (which is more paranoia than anything else), we need to return the
5910 quoted null string and set the flags to indicate it. */
5911 if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL))
5912 {
5913 w->flags |= W_HASQUOTEDNULL;
5914 }
726f6388
JA
5915 dispose_words (l);
5916 }
ccc6cda3 5917 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol)
726f6388 5918 {
ccc6cda3
JA
5919 /* The brace expansion occurred between double quotes and there was
5920 a $@ in TEMP. It does not matter if the $@ is quoted, as long as
7117c2d2
JA
5921 it does not expand to anything. In this case, we want to return
5922 a quoted empty string. */
d3ad40de 5923 temp = make_quoted_char ('\0');
227f982e 5924 w->flags |= W_HASQUOTEDNULL;
726f6388
JA
5925 }
5926 else
5927 temp = (char *)NULL;
5928
5929 if (c == '-' || c == '+')
227f982e
CR
5930 {
5931 w->word = temp;
5932 return w;
5933 }
726f6388
JA
5934
5935 /* c == '=' */
ccc6cda3 5936 t = temp ? savestring (temp) : savestring ("");
726f6388
JA
5937 t1 = dequote_string (t);
5938 free (t);
d3a24ed2
CR
5939#if defined (ARRAY_VARS)
5940 if (valid_array_reference (name))
d11b8b46 5941 assign_array_element (name, t1, 0);
d3a24ed2
CR
5942 else
5943#endif /* ARRAY_VARS */
d11b8b46 5944 bind_variable (name, t1, 0);
f0c4de40 5945#if 0
ad4aef08 5946 if (STREQ (name, "IFS") == 0)
f0c4de40 5947#endif
ad4aef08 5948 stupidly_hack_special_variables (name);
227f982e 5949
9e51a74d 5950 /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
64419627
CR
5951 free (temp);
5952
5953 w->word = t1;
227f982e 5954 return w;
726f6388
JA
5955}
5956
5957/* Deal with the right hand side of a ${name:?value} expansion in the case
5958 that NAME is null or not set. If VALUE is non-null it is expanded and
5959 used as the error message to print, otherwise a standard message is
5960 printed. */
5961static void
5962parameter_brace_expand_error (name, value)
5963 char *name, *value;
5964{
ccc6cda3
JA
5965 WORD_LIST *l;
5966 char *temp;
5967
7f947b68 5968 last_command_exit_value = EXECUTION_FAILURE; /* ensure it's non-zero */
726f6388
JA
5969 if (value && *value)
5970 {
22e63b05 5971 l = expand_string (value, 0);
ccc6cda3
JA
5972 temp = string_list (l);
5973 report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
5974 FREE (temp);
726f6388
JA
5975 dispose_words (l);
5976 }
5977 else
5e13499c 5978 report_error (_("%s: parameter null or not set"), name);
726f6388
JA
5979
5980 /* Free the data we have allocated during this expansion, since we
5981 are about to longjmp out. */
5982 free (name);
5983 FREE (value);
5984}
5985
5986/* Return 1 if NAME is something for which parameter_brace_expand_length is
5987 OK to do. */
5988static int
5989valid_length_expression (name)
5990 char *name;
5991{
28ef6c31 5992 return (name[1] == '\0' || /* ${#} */
f73dda09
JA
5993 ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */
5994 (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
ccc6cda3
JA
5995#if defined (ARRAY_VARS)
5996 valid_array_reference (name + 1) || /* ${#a[7]} */
5997#endif
726f6388
JA
5998 legal_identifier (name + 1)); /* ${#PS1} */
5999}
6000
6001/* Handle the parameter brace expansion that requires us to return the
6002 length of a parameter. */
7117c2d2 6003static intmax_t
726f6388
JA
6004parameter_brace_expand_length (name)
6005 char *name;
6006{
ccc6cda3 6007 char *t, *newname;
7117c2d2 6008 intmax_t number, arg_index;
ccc6cda3
JA
6009 WORD_LIST *list;
6010#if defined (ARRAY_VARS)
6011 SHELL_VAR *var;
6012#endif
6013
6014 if (name[1] == '\0') /* ${#} */
6015 number = number_of_args ();
cce855bc
JA
6016 else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */
6017 number = number_of_args ();
f73dda09 6018 else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
cce855bc
JA
6019 {
6020 /* Take the lengths of some of the shell's special parameters. */
6021 switch (name[1])
6022 {
6023 case '-':
6024 t = which_set_flags ();
6025 break;
6026 case '?':
6027 t = itos (last_command_exit_value);
6028 break;
6029 case '$':
6030 t = itos (dollar_dollar_pid);
6031 break;
6032 case '!':
6033 if (last_asynchronous_pid == NO_PID)
e05be32d 6034 t = (char *)NULL; /* XXX - error if set -u set? */
cce855bc 6035 else
f73dda09 6036 t = itos (last_asynchronous_pid);
cce855bc
JA
6037 break;
6038 case '#':
6039 t = itos (number_of_args ());
6040 break;
6041 }
6042 number = STRLEN (t);
6043 FREE (t);
6044 }
ccc6cda3
JA
6045#if defined (ARRAY_VARS)
6046 else if (valid_array_reference (name + 1))
6047 number = array_length_reference (name + 1);
6048#endif /* ARRAY_VARS */
cce855bc 6049 else
ccc6cda3
JA
6050 {
6051 number = 0;
6052
f73dda09 6053 if (legal_number (name + 1, &arg_index)) /* ${#1} */
ccc6cda3 6054 {
f73dda09 6055 t = get_dollar_var_value (arg_index);
e05be32d
CR
6056 if (t == 0 && unbound_vars_is_error)
6057 return INTMAX_MIN;
898cc92e 6058 number = MB_STRLEN (t);
ccc6cda3
JA
6059 FREE (t);
6060 }
6061#if defined (ARRAY_VARS)
fdf670ea 6062 else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
ccc6cda3 6063 {
fdf670ea
CR
6064 if (assoc_p (var))
6065 t = assoc_reference (assoc_cell (var), "0");
6066 else
6067 t = array_reference (array_cell (var), 0);
e05be32d
CR
6068 if (t == 0 && unbound_vars_is_error)
6069 return INTMAX_MIN;
898cc92e 6070 number = MB_STRLEN (t);
ccc6cda3
JA
6071 }
6072#endif
6073 else /* ${#PS1} */
6074 {
6075 newname = savestring (name);
6076 newname[0] = '$';
6077 list = expand_string (newname, Q_DOUBLE_QUOTES);
6078 t = list ? string_list (list) : (char *)NULL;
6079 free (newname);
6080 if (list)
6081 dispose_words (list);
6082
adc6cff5 6083 number = t ? MB_STRLEN (t) : 0;
ccc6cda3
JA
6084 FREE (t);
6085 }
6086 }
ccc6cda3
JA
6087
6088 return (number);
6089}
6090
28ef6c31
JA
6091/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression,
6092 so we do some ad-hoc parsing of an arithmetic expression to find
6093 the first DELIM, instead of using strchr(3). Two rules:
6094 1. If the substring contains a `(', read until closing `)'.
6095 2. If the substring contains a `?', read past one `:' for each `?'.
6096*/
6097
6098static char *
6099skiparith (substr, delim)
6100 char *substr;
6101 int delim;
6102{
7117c2d2
JA
6103 size_t sublen;
6104 int skipcol, pcount, i;
6105 DECLARE_MBSTATE;
28ef6c31 6106
7117c2d2
JA
6107 sublen = strlen (substr);
6108 i = skipcol = pcount = 0;
6109 while (substr[i])
28ef6c31
JA
6110 {
6111 /* Balance parens */
7117c2d2 6112 if (substr[i] == LPAREN)
28ef6c31
JA
6113 {
6114 pcount++;
7117c2d2 6115 i++;
28ef6c31
JA
6116 continue;
6117 }
7117c2d2 6118 if (substr[i] == RPAREN && pcount)
28ef6c31
JA
6119 {
6120 pcount--;
7117c2d2 6121 i++;
28ef6c31
JA
6122 continue;
6123 }
6124 if (pcount)
7117c2d2
JA
6125 {
6126 ADVANCE_CHAR (substr, sublen, i);
6127 continue;
6128 }
28ef6c31
JA
6129
6130 /* Skip one `:' for each `?' */
7117c2d2 6131 if (substr[i] == ':' && skipcol)
28ef6c31
JA
6132 {
6133 skipcol--;
7117c2d2 6134 i++;
28ef6c31
JA
6135 continue;
6136 }
7117c2d2 6137 if (substr[i] == delim)
28ef6c31 6138 break;
7117c2d2 6139 if (substr[i] == '?')
28ef6c31
JA
6140 {
6141 skipcol++;
7117c2d2 6142 i++;
28ef6c31
JA
6143 continue;
6144 }
7117c2d2 6145 ADVANCE_CHAR (substr, sublen, i);
28ef6c31 6146 }
7117c2d2
JA
6147
6148 return (substr + i);
28ef6c31
JA
6149}
6150
ccc6cda3
JA
6151/* Verify and limit the start and end of the desired substring. If
6152 VTYPE == 0, a regular shell variable is being used; if it is 1,
cce855bc 6153 then the positional parameters are being used; if it is 2, then
e8ce775d
JA
6154 VALUE is really a pointer to an array variable that should be used.
6155 Return value is 1 if both values were OK, 0 if there was a problem
6156 with an invalid expression, or -1 if the values were out of range. */
ccc6cda3 6157static int
09767ff0
CR
6158verify_substring_values (v, value, substr, vtype, e1p, e2p)
6159 SHELL_VAR *v;
ccc6cda3 6160 char *value, *substr;
f73dda09 6161 int vtype;
7117c2d2 6162 intmax_t *e1p, *e2p;
ccc6cda3 6163{
bb70624e 6164 char *t, *temp1, *temp2;
f73dda09
JA
6165 arrayind_t len;
6166 int expok;
ccc6cda3
JA
6167#if defined (ARRAY_VARS)
6168 ARRAY *a;
09767ff0 6169 HASH_TABLE *h;
ccc6cda3
JA
6170#endif
6171
28ef6c31
JA
6172 /* duplicate behavior of strchr(3) */
6173 t = skiparith (substr, ':');
6174 if (*t && *t == ':')
7117c2d2 6175 *t = '\0';
28ef6c31
JA
6176 else
6177 t = (char *)0;
f73dda09 6178
d3ad40de 6179 temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES);
d166f048 6180 *e1p = evalexp (temp1, &expok);
ccc6cda3 6181 free (temp1);
d166f048
JA
6182 if (expok == 0)
6183 return (0);
ccc6cda3 6184
f73dda09 6185 len = -1; /* paranoia */
ccc6cda3
JA
6186 switch (vtype)
6187 {
6188 case VT_VARIABLE:
d166f048 6189 case VT_ARRAYMEMBER:
898cc92e 6190 len = MB_STRLEN (value);
ccc6cda3
JA
6191 break;
6192 case VT_POSPARMS:
6193 len = number_of_args () + 1;
d3ad40de
CR
6194 if (*e1p == 0)
6195 len++; /* add one arg if counting from $0 */
ccc6cda3
JA
6196 break;
6197#if defined (ARRAY_VARS)
6198 case VT_ARRAYVAR:
301e2142 6199 /* For arrays, the first value deals with array indices. Negative
09767ff0
CR
6200 offsets count from one past the array's maximum index. Associative
6201 arrays treat the number of elements as the maximum index. */
6202 if (assoc_p (v))
6203 {
6204 h = assoc_cell (v);
6205 len = assoc_num_elements (h) + (*e1p < 0);
6206 }
6207 else
6208 {
6209 a = (ARRAY *)value;
6210 len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
6211 }
ccc6cda3
JA
6212 break;
6213#endif
6214 }
6215
f73dda09
JA
6216 if (len == -1) /* paranoia */
6217 return -1;
6218
ccc6cda3
JA
6219 if (*e1p < 0) /* negative offsets count from end */
6220 *e1p += len;
6221
8ed8525c 6222 if (*e1p > len || *e1p < 0)
e8ce775d 6223 return (-1);
d166f048 6224
5e13499c
CR
6225#if defined (ARRAY_VARS)
6226 /* For arrays, the second offset deals with the number of elements. */
6227 if (vtype == VT_ARRAYVAR)
dd4f3dd8 6228 len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
5e13499c
CR
6229#endif
6230
ccc6cda3
JA
6231 if (t)
6232 {
6233 t++;
bb70624e 6234 temp2 = savestring (t);
d3ad40de 6235 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
bb70624e 6236 free (temp2);
ccc6cda3 6237 t[-1] = ':';
d166f048 6238 *e2p = evalexp (temp1, &expok);
ccc6cda3 6239 free (temp1);
d166f048 6240 if (expok == 0)
28ef6c31 6241 return (0);
348a457e 6242#if 1
67362c60 6243 if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
348a457e
CR
6244#else
6245 /* bash-4.3: allow positional parameter length < 0 to count backwards
6246 from end of positional parameters */
6247 if (vtype == VT_ARRAYVAR && *e2p < 0)
6248#endif
28ef6c31 6249 {
5e13499c 6250 internal_error (_("%s: substring expression < 0"), t);
ccc6cda3 6251 return (0);
28ef6c31 6252 }
5e13499c
CR
6253#if defined (ARRAY_VARS)
6254 /* In order to deal with sparse arrays, push the intelligence about how
6255 to deal with the number of elements desired down to the array-
6256 specific functions. */
6257 if (vtype != VT_ARRAYVAR)
6258#endif
6259 {
67362c60
CR
6260 if (*e2p < 0)
6261 {
6262 *e2p += len;
6263 if (*e2p < 0 || *e2p < *e1p)
6264 {
6265 internal_error (_("%s: substring expression < 0"), t);
6266 return (0);
6267 }
6268 }
6269 else
6270 *e2p += *e1p; /* want E2 chars starting at E1 */
5e13499c
CR
6271 if (*e2p > len)
6272 *e2p = len;
6273 }
ccc6cda3
JA
6274 }
6275 else
6276 *e2p = len;
6277
6278 return (1);
6279}
6280
ccc6cda3 6281/* Return the type of variable specified by VARNAME (simple variable,
cce855bc 6282 positional param, or array variable). Also return the value specified
7117c2d2 6283 by VARNAME (value of a variable or a reference to an array element).
5f8cde23
CR
6284 QUOTED is the standard description of quoting state, using Q_* defines.
6285 FLAGS is currently a set of flags to pass to array_value. If IND is
6286 non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
6287 passed to array_value so the array index is not computed again.
7117c2d2
JA
6288 If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
6289 characters in the value are quoted with CTLESC and takes appropriate
6290 steps. For convenience, *VALP is set to the dequoted VALUE. */
ccc6cda3 6291static int
5f8cde23 6292get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
ccc6cda3 6293 char *varname, *value;
5f8cde23
CR
6294 arrayind_t ind;
6295 int quoted, flags;
ccc6cda3
JA
6296 SHELL_VAR **varp;
6297 char **valp;
6298{
6299 int vtype;
6300 char *temp;
6301#if defined (ARRAY_VARS)
6302 SHELL_VAR *v;
6303#endif
5f8cde23 6304 arrayind_t lind;
ccc6cda3 6305
7117c2d2
JA
6306 /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
6307 vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0';
d3a24ed2
CR
6308 if (vtype == VT_POSPARMS && varname[0] == '*')
6309 vtype |= VT_STARSUB;
ccc6cda3
JA
6310 *varp = (SHELL_VAR *)NULL;
6311
6312#if defined (ARRAY_VARS)
6313 if (valid_array_reference (varname))
6314 {
6315 v = array_variable_part (varname, &temp, (int *)0);
5f8cde23
CR
6316 /* If we want to signal array_value to use an already-computed index,
6317 set LIND to that index */
6318 lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0;
fdf670ea 6319 if (v && (array_p (v) || assoc_p (v)))
f73dda09
JA
6320 { /* [ */
6321 if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
ccc6cda3 6322 {
dd4f3dd8 6323 /* Callers have to differentiate betwen indexed and associative */
ccc6cda3 6324 vtype = VT_ARRAYVAR;
d3a24ed2
CR
6325 if (temp[0] == '*')
6326 vtype |= VT_STARSUB;
fdf670ea 6327 *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
ccc6cda3
JA
6328 }
6329 else
6330 {
d166f048 6331 vtype = VT_ARRAYMEMBER;
5f8cde23 6332 *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
ccc6cda3
JA
6333 }
6334 *varp = v;
6335 }
8fed3589
CR
6336 else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']'))
6337 {
6338 vtype = VT_VARIABLE;
6339 *varp = v;
6340 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6341 *valp = dequote_string (value);
6342 else
6343 *valp = dequote_escapes (value);
6344 }
ccc6cda3 6345 else
fdf670ea
CR
6346 {
6347 vtype = VT_ARRAYMEMBER;
6348 *varp = v;
5f8cde23 6349 *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
fdf670ea 6350 }
ccc6cda3 6351 }
fdf670ea 6352 else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
ccc6cda3 6353 {
7117c2d2 6354 vtype = VT_ARRAYMEMBER;
ccc6cda3 6355 *varp = v;
fdf670ea 6356 *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
ccc6cda3
JA
6357 }
6358 else
6359#endif
762a763b
CR
6360 {
6361 if (value && vtype == VT_VARIABLE)
6362 {
6363 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6364 *valp = dequote_string (value);
6365 else
6366 *valp = dequote_escapes (value);
6367 }
6368 else
6369 *valp = value;
6370 }
ccc6cda3
JA
6371
6372 return vtype;
6373}
6374
cce855bc
JA
6375/******************************************************/
6376/* */
6377/* Functions to extract substrings of variable values */
6378/* */
6379/******************************************************/
6380
545f34cf
CR
6381#if defined (HANDLE_MULTIBYTE)
6382/* Character-oriented rather than strictly byte-oriented substrings. S and
6383 E, rather being strict indices into STRING, indicate character (possibly
6384 multibyte character) positions that require calculation.
6385 Used by the ${param:offset[:length]} expansion. */
6386static char *
6387mb_substring (string, s, e)
6388 char *string;
6389 int s, e;
6390{
6391 char *tt;
6392 int start, stop, i, slen;
6393 DECLARE_MBSTATE;
6394
6395 start = 0;
da713c23
CR
6396 /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
6397 slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
545f34cf
CR
6398
6399 i = s;
6400 while (string[start] && i--)
6401 ADVANCE_CHAR (string, slen, start);
6402 stop = start;
6403 i = e - s;
6404 while (string[stop] && i--)
6405 ADVANCE_CHAR (string, slen, stop);
6406 tt = substring (string, start, stop);
6407 return tt;
6408}
6409#endif
6410
ccc6cda3
JA
6411/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
6412 is `@', use the positional parameters; otherwise, use the value of
6413 VARNAME. If VARNAME is an array variable, use the array elements. */
6414
6415static char *
5f8cde23
CR
6416parameter_brace_substring (varname, value, ind, substr, quoted, flags)
6417 char *varname, *value;
6418 int ind;
6419 char *substr;
6420 int quoted, flags;
ccc6cda3 6421{
7117c2d2 6422 intmax_t e1, e2;
d3a24ed2 6423 int vtype, r, starsub;
d3ad40de 6424 char *temp, *val, *tt, *oname;
ccc6cda3
JA
6425 SHELL_VAR *v;
6426
6427 if (value == 0)
6428 return ((char *)NULL);
6429
d3ad40de 6430 oname = this_command_name;
ccc6cda3
JA
6431 this_command_name = varname;
6432
5f8cde23 6433 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
ccc6cda3 6434 if (vtype == -1)
d3ad40de
CR
6435 {
6436 this_command_name = oname;
6437 return ((char *)NULL);
6438 }
ccc6cda3 6439
d3a24ed2
CR
6440 starsub = vtype & VT_STARSUB;
6441 vtype &= ~VT_STARSUB;
6442
09767ff0 6443 r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
d3ad40de 6444 this_command_name = oname;
e8ce775d 6445 if (r <= 0)
631b20c6
CR
6446 {
6447 if (vtype == VT_VARIABLE)
6448 FREE (val);
6449 return ((r == 0) ? &expand_param_error : (char *)NULL);
6450 }
ccc6cda3
JA
6451
6452 switch (vtype)
6453 {
6454 case VT_VARIABLE:
d166f048 6455 case VT_ARRAYMEMBER:
545f34cf
CR
6456#if defined (HANDLE_MULTIBYTE)
6457 if (MB_CUR_MAX > 1)
6458 tt = mb_substring (val, e1, e2);
6459 else
6460#endif
7117c2d2 6461 tt = substring (val, e1, e2);
545f34cf 6462
7117c2d2
JA
6463 if (vtype == VT_VARIABLE)
6464 FREE (val);
6465 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6466 temp = quote_string (tt);
6467 else
6468 temp = tt ? quote_escapes (tt) : (char *)NULL;
6469 FREE (tt);
ccc6cda3
JA
6470 break;
6471 case VT_POSPARMS:
7117c2d2
JA
6472 tt = pos_params (varname, e1, e2, quoted);
6473 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
6474 {
6475 temp = tt ? quote_escapes (tt) : (char *)NULL;
6476 FREE (tt);
6477 }
6478 else
6479 temp = tt;
ccc6cda3
JA
6480 break;
6481#if defined (ARRAY_VARS)
6482 case VT_ARRAYVAR:
fdf670ea 6483 if (assoc_p (v))
09767ff0
CR
6484 /* we convert to list and take first e2 elements starting at e1th
6485 element -- officially undefined for now */
6486 temp = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted);
fdf670ea 6487 else
5e13499c 6488 /* We want E2 to be the number of elements desired (arrays can be sparse,
704a1a2a
CR
6489 so verify_substring_values just returns the numbers specified and we
6490 rely on array_subrange to understand how to deal with them). */
fdf670ea 6491 temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
d3ad40de
CR
6492 /* array_subrange now calls array_quote_escapes as appropriate, so the
6493 caller no longer needs to. */
ccc6cda3
JA
6494 break;
6495#endif
f73dda09
JA
6496 default:
6497 temp = (char *)NULL;
ccc6cda3
JA
6498 }
6499
6500 return temp;
6501}
6502
cce855bc
JA
6503/****************************************************************/
6504/* */
6505/* Functions to perform pattern substitution on variable values */
6506/* */
6507/****************************************************************/
6508
ee56a865
CR
6509static int
6510shouldexp_replacement (s)
6511 char *s;
6512{
6513 register char *p;
6514
6515 for (p = s; p && *p; p++)
6516 {
6517 if (*p == '\\')
6518 p++;
6519 else if (*p == '&')
6520 return 1;
6521 }
6522 return 0;
6523}
6524
ccc6cda3
JA
6525char *
6526pat_subst (string, pat, rep, mflags)
6527 char *string, *pat, *rep;
6528 int mflags;
6529{
ee56a865
CR
6530 char *ret, *s, *e, *str, *rstr, *mstr;
6531 int rsize, rptr, l, replen, mtype, rxpand, rslen, mlen;
ccc6cda3 6532
5f8cde23
CR
6533 if (string == 0)
6534 return (savestring (""));
6535
b72432fd
JA
6536 mtype = mflags & MATCH_TYPEMASK;
6537
e054386f 6538#if 0 /* bash-4.2 ? */
ee56a865 6539 rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0;
e054386f
CR
6540#else
6541 rxpand = 0;
6542#endif
ee56a865 6543
b72432fd
JA
6544 /* Special cases:
6545 * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
6546 * with REP and return the result.
6547 * 2. A null pattern with mtype == MATCH_END means to append REP to
6548 * STRING and return the result.
ee56a865 6549 * These don't understand or process `&' in the replacement string.
b72432fd
JA
6550 */
6551 if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
6552 {
6553 replen = STRLEN (rep);
5f8cde23 6554 l = STRLEN (string);
f73dda09 6555 ret = (char *)xmalloc (replen + l + 2);
bb70624e
JA
6556 if (replen == 0)
6557 strcpy (ret, string);
6558 else if (mtype == MATCH_BEG)
b72432fd
JA
6559 {
6560 strcpy (ret, rep);
6561 strcpy (ret + replen, string);
6562 }
6563 else
6564 {
6565 strcpy (ret, string);
6566 strcpy (ret + l, rep);
6567 }
6568 return (ret);
6569 }
6570
f73dda09 6571 ret = (char *)xmalloc (rsize = 64);
ccc6cda3
JA
6572 ret[0] = '\0';
6573
ccc6cda3
JA
6574 for (replen = STRLEN (rep), rptr = 0, str = string;;)
6575 {
6576 if (match_pattern (str, pat, mtype, &s, &e) == 0)
6577 break;
6578 l = s - str;
ee56a865
CR
6579
6580 if (rxpand)
6581 {
6582 int x;
6583 mlen = e - s;
6584 mstr = xmalloc (mlen + 1);
6585 for (x = 0; x < mlen; x++)
6586 mstr[x] = s[x];
6587 mstr[mlen] = '\0';
6588 rstr = strcreplace (rep, '&', mstr, 0);
6589 rslen = strlen (rstr);
6590 }
6591 else
6592 {
6593 rstr = rep;
6594 rslen = replen;
6595 }
6596
6597 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
ccc6cda3
JA
6598
6599 /* OK, now copy the leading unmatched portion of the string (from
6600 str to s) to ret starting at rptr (the current offset). Then copy
28ef6c31
JA
6601 the replacement string at ret + rptr + (s - str). Increment
6602 rptr (if necessary) and str and go on. */
ccc6cda3
JA
6603 if (l)
6604 {
6605 strncpy (ret + rptr, str, l);
6606 rptr += l;
6607 }
6608 if (replen)
6609 {
ee56a865
CR
6610 strncpy (ret + rptr, rstr, rslen);
6611 rptr += rslen;
ccc6cda3
JA
6612 }
6613 str = e; /* e == end of match */
d3a24ed2 6614
ee56a865
CR
6615 if (rstr != rep)
6616 free (rstr);
6617
ccc6cda3 6618 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
28ef6c31 6619 break;
d3a24ed2
CR
6620
6621 if (s == e)
5ccad779
CR
6622 {
6623 /* On a zero-length match, make sure we copy one character, since
6624 we increment one character to avoid infinite recursion. */
6625 RESIZE_MALLOCED_BUFFER (ret, rptr, 1, rsize, 64);
6626 ret[rptr++] = *str++;
6627 e++; /* avoid infinite recursion on zero-length match */
6628 }
ccc6cda3
JA
6629 }
6630
6631 /* Now copy the unmatched portion of the input string */
5f8cde23 6632 if (str && *str)
d166f048
JA
6633 {
6634 RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
6635 strcpy (ret + rptr, str);
6636 }
ccc6cda3
JA
6637 else
6638 ret[rptr] = '\0';
6639
6640 return ret;
6641}
6642
6643/* Do pattern match and replacement on the positional parameters. */
6644static char *
6645pos_params_pat_subst (string, pat, rep, mflags)
6646 char *string, *pat, *rep;
6647 int mflags;
6648{
6649 WORD_LIST *save, *params;
6650 WORD_DESC *w;
d3ad40de 6651 char *ret;
e33f2203 6652 int pchar, qflags;
ccc6cda3
JA
6653
6654 save = params = list_rest_of_args ();
6655 if (save == 0)
6656 return ((char *)NULL);
6657
6658 for ( ; params; params = params->next)
6659 {
6660 ret = pat_subst (params->word->word, pat, rep, mflags);
227f982e
CR
6661 w = alloc_word_desc ();
6662 w->word = ret ? ret : savestring ("");
ccc6cda3
JA
6663 dispose_word (params->word);
6664 params->word = w;
ccc6cda3
JA
6665 }
6666
e33f2203
CR
6667 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6668 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6669
e33f2203 6670 ret = string_list_pos_params (pchar, save, qflags);
e33f2203 6671
ccc6cda3
JA
6672 dispose_words (save);
6673
6674 return (ret);
6675}
6676
cce855bc
JA
6677/* Perform pattern substitution on VALUE, which is the expansion of
6678 VARNAME. PATSUB is an expression supplying the pattern to match
6679 and the string to substitute. QUOTED is a flags word containing
6680 the type of quoting currently in effect. */
ccc6cda3 6681static char *
5f8cde23
CR
6682parameter_brace_patsub (varname, value, ind, patsub, quoted, flags)
6683 char *varname, *value;
6684 int ind;
6685 char *patsub;
6686 int quoted, flags;
ccc6cda3 6687{
c2a47ea9 6688 int vtype, mflags, starsub, delim;
7117c2d2 6689 char *val, *temp, *pat, *rep, *p, *lpatsub, *tt;
ccc6cda3
JA
6690 SHELL_VAR *v;
6691
6692 if (value == 0)
6693 return ((char *)NULL);
6694
6695 this_command_name = varname;
6696
5f8cde23 6697 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
ccc6cda3
JA
6698 if (vtype == -1)
6699 return ((char *)NULL);
6700
d3a24ed2
CR
6701 starsub = vtype & VT_STARSUB;
6702 vtype &= ~VT_STARSUB;
6703
ccc6cda3 6704 mflags = 0;
77638cbf
CR
6705 /* PATSUB is never NULL when this is called. */
6706 if (*patsub == '/')
d3ad40de
CR
6707 {
6708 mflags |= MATCH_GLOBREP;
6709 patsub++;
6710 }
7117c2d2
JA
6711
6712 /* Malloc this because expand_string_if_necessary or one of the expansion
6713 functions in its call chain may free it on a substitution error. */
bb70624e 6714 lpatsub = savestring (patsub);
ccc6cda3
JA
6715
6716 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6717 mflags |= MATCH_QUOTED;
6718
d3a24ed2
CR
6719 if (starsub)
6720 mflags |= MATCH_STARSUB;
6721
dc8fbaf9
CR
6722 /* If the pattern starts with a `/', make sure we skip over it when looking
6723 for the replacement delimiter. */
4d8d005b 6724 delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
c2a47ea9
CR
6725 if (lpatsub[delim] == '/')
6726 {
6727 lpatsub[delim] = 0;
6728 rep = lpatsub + delim + 1;
6729 }
6730 else
6731 rep = (char *)NULL;
ccc6cda3
JA
6732
6733 if (rep && *rep == '\0')
6734 rep = (char *)NULL;
6735
5e13499c
CR
6736 /* Perform the same expansions on the pattern as performed by the
6737 pattern removal expansions. */
6738 pat = getpattern (lpatsub, quoted, 1);
bb70624e 6739
ccc6cda3 6740 if (rep)
7175a77f
CR
6741 {
6742 /* We want to perform quote removal on the expanded replacement even if
6743 the entire expansion is double-quoted because the parser and string
6744 extraction functions treated quotes in the replacement string as
6745 special. THIS IS NOT BACKWARDS COMPATIBLE WITH BASH-4.2. */
6746 if (shell_compatibility_level > 42)
6747 rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
6748 /* This is the bash-4.2 code. */
6749 else if ((mflags & MATCH_QUOTED) == 0)
6750 rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
6751 else
6752 rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
6753 }
ccc6cda3 6754
dc8fbaf9 6755 /* ksh93 doesn't allow the match specifier to be a part of the expanded
d3ad40de
CR
6756 pattern. This is an extension. Make sure we don't anchor the pattern
6757 at the beginning or end of the string if we're doing global replacement,
6758 though. */
ccc6cda3 6759 p = pat;
d3ad40de
CR
6760 if (mflags & MATCH_GLOBREP)
6761 mflags |= MATCH_ANY;
dc8fbaf9 6762 else if (pat && pat[0] == '#')
ccc6cda3
JA
6763 {
6764 mflags |= MATCH_BEG;
6765 p++;
6766 }
d166f048 6767 else if (pat && pat[0] == '%')
ccc6cda3
JA
6768 {
6769 mflags |= MATCH_END;
6770 p++;
6771 }
6772 else
6773 mflags |= MATCH_ANY;
6774
cce855bc
JA
6775 /* OK, we now want to substitute REP for PAT in VAL. If
6776 flags & MATCH_GLOBREP is non-zero, the substitution is done
6777 everywhere, otherwise only the first occurrence of PAT is
7117c2d2
JA
6778 replaced. The pattern matching code doesn't understand
6779 CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
6780 values passed in (VT_VARIABLE) so the pattern substitution
6781 code works right. We need to requote special chars after
6782 we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
6783 other cases if QUOTED == 0, since the posparams and arrays
6784 indexed by * or @ do special things when QUOTED != 0. */
6785
ccc6cda3
JA
6786 switch (vtype)
6787 {
6788 case VT_VARIABLE:
d166f048 6789 case VT_ARRAYMEMBER:
ccc6cda3 6790 temp = pat_subst (val, p, rep, mflags);
7117c2d2
JA
6791 if (vtype == VT_VARIABLE)
6792 FREE (val);
6793 if (temp)
6794 {
e6598ba4 6795 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
7117c2d2
JA
6796 free (temp);
6797 temp = tt;
6798 }
ccc6cda3
JA
6799 break;
6800 case VT_POSPARMS:
6801 temp = pos_params_pat_subst (val, p, rep, mflags);
7117c2d2
JA
6802 if (temp && (mflags & MATCH_QUOTED) == 0)
6803 {
6804 tt = quote_escapes (temp);
6805 free (temp);
6806 temp = tt;
6807 }
ccc6cda3
JA
6808 break;
6809#if defined (ARRAY_VARS)
6810 case VT_ARRAYVAR:
fdf670ea
CR
6811 temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags)
6812 : array_patsub (array_cell (v), p, rep, mflags);
e6598ba4
CR
6813 /* Don't call quote_escapes anymore; array_patsub calls
6814 array_quote_escapes as appropriate before adding the
fdf670ea 6815 space separators; ditto for assoc_patsub. */
ccc6cda3
JA
6816 break;
6817#endif
6818 }
6819
6820 FREE (pat);
6821 FREE (rep);
bb70624e 6822 free (lpatsub);
ccc6cda3
JA
6823
6824 return temp;
6825}
6826
09767ff0
CR
6827/****************************************************************/
6828/* */
6829/* Functions to perform case modification on variable values */
6830/* */
6831/****************************************************************/
6832
6833/* Do case modification on the positional parameters. */
6834
6835static char *
6836pos_params_modcase (string, pat, modop, mflags)
6837 char *string, *pat;
6838 int modop;
6839 int mflags;
6840{
6841 WORD_LIST *save, *params;
6842 WORD_DESC *w;
6843 char *ret;
6844 int pchar, qflags;
6845
6846 save = params = list_rest_of_args ();
6847 if (save == 0)
6848 return ((char *)NULL);
6849
6850 for ( ; params; params = params->next)
6851 {
6852 ret = sh_modcase (params->word->word, pat, modop);
6853 w = alloc_word_desc ();
6854 w->word = ret ? ret : savestring ("");
6855 dispose_word (params->word);
6856 params->word = w;
6857 }
6858
6859 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6860 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6861
6862 ret = string_list_pos_params (pchar, save, qflags);
6863 dispose_words (save);
6864
6865 return (ret);
6866}
6867
6868/* Perform case modification on VALUE, which is the expansion of
6869 VARNAME. MODSPEC is an expression supplying the type of modification
6870 to perform. QUOTED is a flags word containing the type of quoting
6871 currently in effect. */
6872static char *
5f8cde23 6873parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, flags)
09767ff0 6874 char *varname, *value;
5f8cde23 6875 int ind, modspec;
09767ff0 6876 char *patspec;
5f8cde23 6877 int quoted, flags;
09767ff0
CR
6878{
6879 int vtype, starsub, modop, mflags, x;
6880 char *val, *temp, *pat, *p, *lpat, *tt;
6881 SHELL_VAR *v;
6882
6883 if (value == 0)
6884 return ((char *)NULL);
6885
6886 this_command_name = varname;
6887
5f8cde23 6888 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
09767ff0
CR
6889 if (vtype == -1)
6890 return ((char *)NULL);
6891
6892 starsub = vtype & VT_STARSUB;
6893 vtype &= ~VT_STARSUB;
6894
6895 modop = 0;
6896 mflags = 0;
6897 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6898 mflags |= MATCH_QUOTED;
6899 if (starsub)
6900 mflags |= MATCH_STARSUB;
6901
6902 p = patspec;
6903 if (modspec == '^')
6904 {
6905 x = p && p[0] == modspec;
e141c35a 6906 modop = x ? CASE_UPPER : CASE_UPFIRST;
09767ff0
CR
6907 p += x;
6908 }
6909 else if (modspec == ',')
6910 {
6911 x = p && p[0] == modspec;
e141c35a 6912 modop = x ? CASE_LOWER : CASE_LOWFIRST;
09767ff0
CR
6913 p += x;
6914 }
6915 else if (modspec == '~')
6916 {
6917 x = p && p[0] == modspec;
6918 modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
6919 p += x;
6920 }
6921
6922 lpat = p ? savestring (p) : 0;
6923 /* Perform the same expansions on the pattern as performed by the
6924 pattern removal expansions. FOR LATER */
6925 pat = lpat ? getpattern (lpat, quoted, 1) : 0;
6926
6927 /* OK, now we do the case modification. */
6928 switch (vtype)
6929 {
6930 case VT_VARIABLE:
6931 case VT_ARRAYMEMBER:
6932 temp = sh_modcase (val, pat, modop);
6933 if (vtype == VT_VARIABLE)
6934 FREE (val);
6935 if (temp)
6936 {
6937 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
6938 free (temp);
6939 temp = tt;
6940 }
6941 break;
6942
6943 case VT_POSPARMS:
6944 temp = pos_params_modcase (val, pat, modop, mflags);
6945 if (temp && (mflags & MATCH_QUOTED) == 0)
6946 {
6947 tt = quote_escapes (temp);
6948 free (temp);
6949 temp = tt;
6950 }
6951 break;
6952
6953#if defined (ARRAY_VARS)
6954 case VT_ARRAYVAR:
6955 temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
6956 : array_modcase (array_cell (v), pat, modop, mflags);
6957 /* Don't call quote_escapes; array_modcase calls array_quote_escapes
6958 as appropriate before adding the space separators; ditto for
6959 assoc_modcase. */
6960 break;
6961#endif
6962 }
6963
6964 FREE (pat);
6965 free (lpat);
6966
6967 return temp;
6968}
6969
d3ad40de
CR
6970/* Check for unbalanced parens in S, which is the contents of $(( ... )). If
6971 any occur, this must be a nested command substitution, so return 0.
6972 Otherwise, return 1. A valid arithmetic expression must always have a
6973 ( before a matching ), so any cases where there are more right parens
6974 means that this must not be an arithmetic expression, though the parser
6975 will not accept it without a balanced total number of parens. */
6976static int
6977chk_arithsub (s, len)
6978 const char *s;
6979 int len;
6980{
6981 int i, count;
6982 DECLARE_MBSTATE;
6983
6984 i = count = 0;
6985 while (i < len)
6986 {
176b12ee 6987 if (s[i] == LPAREN)
d3ad40de 6988 count++;
176b12ee 6989 else if (s[i] == RPAREN)
d3ad40de
CR
6990 {
6991 count--;
6992 if (count < 0)
6993 return 0;
6994 }
6995
6996 switch (s[i])
6997 {
6998 default:
6999 ADVANCE_CHAR (s, len, i);
7000 break;
7001
7002 case '\\':
7003 i++;
7004 if (s[i])
7005 ADVANCE_CHAR (s, len, i);
7006 break;
7007
7008 case '\'':
7009 i = skip_single_quoted (s, len, ++i);
7010 break;
7011
7012 case '"':
7013 i = skip_double_quoted ((char *)s, len, ++i);
7014 break;
7015 }
7016 }
7017
7018 return (count == 0);
7019}
7020
cce855bc
JA
7021/****************************************************************/
7022/* */
7023/* Functions to perform parameter expansion on a string */
7024/* */
7025/****************************************************************/
7026
09767ff0 7027/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
227f982e 7028static WORD_DESC *
e1e48bba 7029parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
ccc6cda3 7030 char *string;
e1e48bba 7031 int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at, pflags;
ccc6cda3
JA
7032{
7033 int check_nullness, var_is_set, var_is_null, var_is_special;
09767ff0 7034 int want_substring, want_indir, want_patsub, want_casemod;
ccc6cda3 7035 char *name, *value, *temp, *temp1;
227f982e 7036 WORD_DESC *tdesc, *ret;
09767ff0 7037 int t_index, sindex, c, tflag, modspec;
7117c2d2 7038 intmax_t number;
5f8cde23 7039 arrayind_t ind;
ccc6cda3 7040
c40a57dd 7041 temp = temp1 = value = (char *)NULL;
ccc6cda3 7042 var_is_set = var_is_null = var_is_special = check_nullness = 0;
09767ff0 7043 want_substring = want_indir = want_patsub = want_casemod = 0;
ccc6cda3 7044
cce855bc
JA
7045 sindex = *indexp;
7046 t_index = ++sindex;
11a6f9a9
CR
7047 /* ${#var} doesn't have any of the other parameter expansions on it. */
7048 if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
e6598ba4 7049 name = string_extract (string, &t_index, "}", SX_VARNAME);
11a6f9a9 7050 else
09767ff0
CR
7051#if defined (CASEMOD_EXPANSIONS)
7052 /* To enable case-toggling expansions using the `~' operator character
7053 change the 1 to 0. */
7054# if defined (CASEMOD_CAPCASE)
7055 name = string_extract (string, &t_index, "#%^,~:-=?+/}", SX_VARNAME);
7056# else
7057 name = string_extract (string, &t_index, "#%^,:-=?+/}", SX_VARNAME);
7058# endif /* CASEMOD_CAPCASE */
7059#else
e6598ba4 7060 name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME);
09767ff0 7061#endif /* CASEMOD_EXPANSIONS */
cce855bc 7062
227f982e
CR
7063 ret = 0;
7064 tflag = 0;
7065
5f8cde23
CR
7066 ind = INTMAX_MIN;
7067
cce855bc
JA
7068 /* If the name really consists of a special variable, then make sure
7069 that we have the entire name. We don't allow indirect references
7070 to special variables except `#', `?', `@' and `*'. */
e05be32d
CR
7071 if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
7072 (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
ccc6cda3
JA
7073 {
7074 t_index++;
ccc6cda3 7075 temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
631b20c6 7076 name = (char *)xrealloc (name, 3 + (strlen (temp1)));
ccc6cda3
JA
7077 *name = string[sindex];
7078 if (string[sindex] == '!')
7079 {
28ef6c31
JA
7080 /* indirect reference of $#, $?, $@, or $* */
7081 name[1] = string[sindex + 1];
7082 strcpy (name + 2, temp1);
ccc6cda3 7083 }
cce855bc 7084 else
ccc6cda3
JA
7085 strcpy (name + 1, temp1);
7086 free (temp1);
7087 }
7088 sindex = t_index;
7089
7090 /* Find out what character ended the variable name. Then
7091 do the appropriate thing. */
7092 if (c = string[sindex])
7093 sindex++;
7094
7095 /* If c is followed by one of the valid parameter expansion
7096 characters, move past it as normal. If not, assume that
7097 a substring specification is being given, and do not move
7098 past it. */
28ef6c31 7099 if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
ccc6cda3
JA
7100 {
7101 check_nullness++;
7102 if (c = string[sindex])
7103 sindex++;
7104 }
cce855bc 7105 else if (c == ':' && string[sindex] != RBRACE)
ccc6cda3 7106 want_substring = 1;
77638cbf 7107 else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */
ccc6cda3 7108 want_patsub = 1;
09767ff0
CR
7109#if defined (CASEMOD_EXPANSIONS)
7110 else if (c == '^' || c == ',' || c == '~')
7111 {
7112 modspec = c;
7113 want_casemod = 1;
7114 }
7115#endif
ccc6cda3 7116
cce855bc
JA
7117 /* Catch the valid and invalid brace expressions that made it through the
7118 tests above. */
7119 /* ${#-} is a valid expansion and means to take the length of $-.
7120 Similarly for ${#?} and ${##}... */
7121 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
28ef6c31 7122 VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
cce855bc 7123 {
f73dda09 7124 name = (char *)xrealloc (name, 3);
cce855bc
JA
7125 name[1] = c;
7126 name[2] = '\0';
7127 c = string[sindex++];
7128 }
7129
7130 /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
7131 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
7132 member (c, "%:=+/") && string[sindex] == RBRACE)
7133 {
7134 temp = (char *)NULL;
7135 goto bad_substitution;
7136 }
e33f2203 7137
cce855bc
JA
7138 /* Indirect expansion begins with a `!'. A valid indirect expansion is
7139 either a variable name, one of the positional parameters or a special
7140 variable that expands to one of the positional parameters. */
7141 want_indir = *name == '!' &&
f73dda09 7142 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
7117c2d2 7143 || VALID_INDIR_PARAM (name[1]));
ccc6cda3
JA
7144
7145 /* Determine the value of this variable. */
7146
cce855bc 7147 /* Check for special variables, directly referenced. */
bb70624e 7148 if (SPECIAL_VAR (name, want_indir))
ccc6cda3
JA
7149 var_is_special++;
7150
cce855bc
JA
7151 /* Check for special expansion things, like the length of a parameter */
7152 if (*name == '#' && name[1])
ccc6cda3 7153 {
cce855bc 7154 /* If we are not pointing at the character just after the
28ef6c31
JA
7155 closing brace, then we haven't gotten all of the name.
7156 Since it begins with a special character, this is a bad
7157 substitution. Also check NAME for validity before trying
7158 to go on. */
cce855bc 7159 if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
ccc6cda3
JA
7160 {
7161 temp = (char *)NULL;
7162 goto bad_substitution;
7163 }
7164
7165 number = parameter_brace_expand_length (name);
e05be32d
CR
7166 if (number == INTMAX_MIN && unbound_vars_is_error)
7167 {
7168 last_command_exit_value = EXECUTION_FAILURE;
7169 err_unboundvar (name+1);
7170 free (name);
7171 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7172 }
ccc6cda3
JA
7173 free (name);
7174
7175 *indexp = sindex;
227f982e
CR
7176 if (number < 0)
7177 return (&expand_wdesc_error);
7178 else
7179 {
7180 ret = alloc_word_desc ();
7181 ret->word = itos (number);
7182 return ret;
7183 }
ccc6cda3
JA
7184 }
7185
7186 /* ${@} is identical to $@. */
7187 if (name[0] == '@' && name[1] == '\0')
7188 {
7189 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7190 *quoted_dollar_atp = 1;
7191
7192 if (contains_dollar_at)
7193 *contains_dollar_at = 1;
348a457e
CR
7194
7195 tflag |= W_DOLLARAT;
ccc6cda3
JA
7196 }
7197
d3a24ed2 7198 /* Process ${!PREFIX*} expansion. */
bb70624e
JA
7199 if (want_indir && string[sindex - 1] == RBRACE &&
7200 (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
f73dda09 7201 legal_variable_starter ((unsigned char) name[1]))
bb70624e
JA
7202 {
7203 char **x;
7204 WORD_LIST *xlist;
7205
7206 temp1 = savestring (name + 1);
7207 number = strlen (temp1);
7208 temp1[number - 1] = '\0';
7209 x = all_variables_matching_prefix (temp1);
7117c2d2 7210 xlist = strvec_to_word_list (x, 0, 0);
28ef6c31
JA
7211 if (string[sindex - 2] == '*')
7212 temp = string_list_dollar_star (xlist);
7213 else
7214 {
7215 temp = string_list_dollar_at (xlist, quoted);
7216 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7217 *quoted_dollar_atp = 1;
7218 if (contains_dollar_at)
7219 *contains_dollar_at = 1;
348a457e
CR
7220
7221 tflag |= W_DOLLARAT;
28ef6c31 7222 }
bb70624e 7223 free (x);
af98a2a6 7224 dispose_words (xlist);
bb70624e
JA
7225 free (temp1);
7226 *indexp = sindex;
227f982e 7227
631b20c6
CR
7228 free (name);
7229
227f982e
CR
7230 ret = alloc_word_desc ();
7231 ret->word = temp;
348a457e 7232 ret->flags = tflag; /* XXX */
227f982e 7233 return ret;
bb70624e 7234 }
d3a24ed2
CR
7235
7236#if defined (ARRAY_VARS)
5e13499c
CR
7237 /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */
7238 if (want_indir && string[sindex - 1] == RBRACE &&
7239 string[sindex - 2] == ']' && valid_array_reference (name+1))
d3a24ed2
CR
7240 {
7241 char *x, *x1;
7242
7243 temp1 = savestring (name + 1);
7244 x = array_variable_name (temp1, &x1, (int *)0); /* [ */
7245 FREE (x);
7246 if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']')
7247 {
fdf670ea 7248 temp = array_keys (temp1, quoted); /* handles assoc vars too */
d3a24ed2
CR
7249 if (x1[0] == '@')
7250 {
7251 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7252 *quoted_dollar_atp = 1;
7253 if (contains_dollar_at)
7254 *contains_dollar_at = 1;
348a457e
CR
7255
7256 tflag |= W_DOLLARAT;
d3a24ed2
CR
7257 }
7258
7259 free (temp1);
7260 *indexp = sindex;
227f982e
CR
7261
7262 ret = alloc_word_desc ();
7263 ret->word = temp;
348a457e 7264 ret->flags = tflag; /* XXX */
227f982e 7265 return ret;
d3a24ed2
CR
7266 }
7267
7268 free (temp1);
7269 }
7270#endif /* ARRAY_VARS */
bb70624e 7271
ccc6cda3
JA
7272 /* Make sure that NAME is valid before trying to go on. */
7273 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
7274 var_is_special) == 0)
7275 {
7276 temp = (char *)NULL;
7277 goto bad_substitution;
7278 }
7279
7280 if (want_indir)
227f982e 7281 tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
ccc6cda3 7282 else
208fdb50 7283 tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS)), &ind);
227f982e
CR
7284
7285 if (tdesc)
7286 {
7287 temp = tdesc->word;
7288 tflag = tdesc->flags;
7289 dispose_word_desc (tdesc);
7290 }
7291 else
7292 temp = (char *)0;
ccc6cda3 7293
15623760
CR
7294 if (temp == &expand_param_error || temp == &expand_param_fatal)
7295 {
7296 FREE (name);
7297 FREE (value);
7298 return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
7299 }
7300
ccc6cda3 7301#if defined (ARRAY_VARS)
cce855bc 7302 if (valid_array_reference (name))
d3a24ed2 7303 chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at);
ccc6cda3
JA
7304#endif
7305
7306 var_is_set = temp != (char *)0;
7307 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
0500de0b
CR
7308 /* XXX - this may not need to be restricted to special variables */
7309 if (check_nullness)
3087e51c 7310 var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp);
ccc6cda3
JA
7311
7312 /* Get the rest of the stuff inside the braces. */
cce855bc 7313 if (c && c != RBRACE)
ccc6cda3
JA
7314 {
7315 /* Extract the contents of the ${ ... } expansion
28ef6c31 7316 according to the Posix.2 rules. */
e192f341 7317 value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
cce855bc 7318 if (string[sindex] == RBRACE)
28ef6c31 7319 sindex++;
ccc6cda3
JA
7320 else
7321 goto bad_substitution;
7322 }
7323 else
7324 value = (char *)NULL;
726f6388 7325
ccc6cda3
JA
7326 *indexp = sindex;
7327
e05be32d
CR
7328 /* All the cases where an expansion can possibly generate an unbound
7329 variable error. */
7330 if (want_substring || want_patsub || want_casemod || c == '#' || c == '%' || c == RBRACE)
7331 {
7332 if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
7333 {
7334 last_command_exit_value = EXECUTION_FAILURE;
7335 err_unboundvar (name);
7336 FREE (value);
7337 FREE (temp);
7338 free (name);
7339 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7340 }
7341 }
7342
ccc6cda3
JA
7343 /* If this is a substring spec, process it and add the result. */
7344 if (want_substring)
726f6388 7345 {
5f8cde23 7346 temp1 = parameter_brace_substring (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
ccc6cda3
JA
7347 FREE (name);
7348 FREE (value);
7349 FREE (temp);
227f982e
CR
7350
7351 if (temp1 == &expand_param_error)
7352 return (&expand_wdesc_error);
7353 else if (temp1 == &expand_param_fatal)
7354 return (&expand_wdesc_fatal);
7355
7356 ret = alloc_word_desc ();
7357 ret->word = temp1;
d3ad40de
CR
7358 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7359 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
227f982e 7360 return ret;
726f6388 7361 }
ccc6cda3 7362 else if (want_patsub)
726f6388 7363 {
5f8cde23 7364 temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
ccc6cda3
JA
7365 FREE (name);
7366 FREE (value);
7367 FREE (temp);
227f982e
CR
7368
7369 if (temp1 == &expand_param_error)
7370 return (&expand_wdesc_error);
7371 else if (temp1 == &expand_param_fatal)
7372 return (&expand_wdesc_fatal);
7373
40c8fbee
CR
7374 ret = alloc_word_desc ();
7375 ret->word = temp1;
7376 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7377 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
227f982e 7378 return ret;
ccc6cda3 7379 }
09767ff0
CR
7380#if defined (CASEMOD_EXPANSIONS)
7381 else if (want_casemod)
7382 {
5f8cde23 7383 temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
09767ff0
CR
7384 FREE (name);
7385 FREE (value);
7386 FREE (temp);
7387
7388 if (temp1 == &expand_param_error)
7389 return (&expand_wdesc_error);
7390 else if (temp1 == &expand_param_fatal)
7391 return (&expand_wdesc_fatal);
7392
7393 ret = alloc_word_desc ();
7394 ret->word = temp1;
40c8fbee
CR
7395 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7396 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
09767ff0
CR
7397 return ret;
7398 }
7399#endif
726f6388 7400
ccc6cda3
JA
7401 /* Do the right thing based on which character ended the variable name. */
7402 switch (c)
7403 {
7404 default:
7405 case '\0':
7406 bad_substitution:
7f947b68 7407 last_command_exit_value = EXECUTION_FAILURE;
5e13499c 7408 report_error (_("%s: bad substitution"), string ? string : "??");
ccc6cda3
JA
7409 FREE (value);
7410 FREE (temp);
7411 free (name);
227f982e 7412 return &expand_wdesc_error;
ccc6cda3 7413
cce855bc 7414 case RBRACE:
ccc6cda3 7415 break;
726f6388 7416
ccc6cda3
JA
7417 case '#': /* ${param#[#]pattern} */
7418 case '%': /* ${param%[%]pattern} */
7419 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
28ef6c31
JA
7420 {
7421 FREE (value);
ccc6cda3 7422 break;
28ef6c31 7423 }
5f8cde23 7424 temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
ccc6cda3
JA
7425 free (temp);
7426 free (value);
3d35553a 7427 free (name);
40c8fbee
CR
7428
7429 ret = alloc_word_desc ();
7430 ret->word = temp1;
7431 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7432 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7433 return ret;
ccc6cda3
JA
7434
7435 case '-':
7436 case '=':
7437 case '?':
7438 case '+':
7439 if (var_is_set && var_is_null == 0)
28ef6c31
JA
7440 {
7441 /* If the operator is `+', we don't want the value of the named
7442 variable for anything, just the value of the right hand side. */
ccc6cda3
JA
7443 if (c == '+')
7444 {
28ef6c31
JA
7445 /* XXX -- if we're double-quoted and the named variable is "$@",
7446 we want to turn off any special handling of "$@" --
7447 we're not using it, so whatever is on the rhs applies. */
7448 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7449 *quoted_dollar_atp = 0;
7450 if (contains_dollar_at)
7451 *contains_dollar_at = 0;
7452
ccc6cda3
JA
7453 FREE (temp);
7454 if (value)
28ef6c31 7455 {
6faad625
CR
7456 /* From Posix discussion on austin-group list. Issue 221
7457 requires that backslashes escaping `}' inside
7458 double-quoted ${...} be removed. */
64419627
CR
7459 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7460 quoted |= Q_DOLBRACE;
227f982e
CR
7461 ret = parameter_brace_expand_rhs (name, value, c,
7462 quoted,
7463 quoted_dollar_atp,
7464 contains_dollar_at);
7465 /* XXX - fix up later, esp. noting presence of
7466 W_HASQUOTEDNULL in ret->flags */
ccc6cda3
JA
7467 free (value);
7468 }
7469 else
28ef6c31 7470 temp = (char *)NULL;
ccc6cda3
JA
7471 }
7472 else
7473 {
7474 FREE (value);
7475 }
7476 /* Otherwise do nothing; just use the value in TEMP. */
726f6388 7477 }
ccc6cda3 7478 else /* VAR not set or VAR is NULL. */
28ef6c31 7479 {
ccc6cda3
JA
7480 FREE (temp);
7481 temp = (char *)NULL;
7482 if (c == '=' && var_is_special)
7483 {
7f947b68 7484 last_command_exit_value = EXECUTION_FAILURE;
5e13499c 7485 report_error (_("$%s: cannot assign in this way"), name);
ccc6cda3
JA
7486 free (name);
7487 free (value);
227f982e 7488 return &expand_wdesc_error;
ccc6cda3
JA
7489 }
7490 else if (c == '?')
7491 {
7492 parameter_brace_expand_error (name, value);
227f982e 7493 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
ccc6cda3
JA
7494 }
7495 else if (c != '+')
28ef6c31
JA
7496 {
7497 /* XXX -- if we're double-quoted and the named variable is "$@",
7498 we want to turn off any special handling of "$@" --
7499 we're not using it, so whatever is on the rhs applies. */
7500 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7501 *quoted_dollar_atp = 0;
7502 if (contains_dollar_at)
7503 *contains_dollar_at = 0;
7504
6faad625
CR
7505 /* From Posix discussion on austin-group list. Issue 221 requires
7506 that backslashes escaping `}' inside double-quoted ${...} be
7507 removed. */
64419627
CR
7508 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7509 quoted |= Q_DOLBRACE;
227f982e
CR
7510 ret = parameter_brace_expand_rhs (name, value, c, quoted,
7511 quoted_dollar_atp,
7512 contains_dollar_at);
7513 /* XXX - fix up later, esp. noting presence of
7514 W_HASQUOTEDNULL in tdesc->flags */
28ef6c31 7515 }
ccc6cda3 7516 free (value);
726f6388 7517 }
28ef6c31 7518
ccc6cda3 7519 break;
726f6388 7520 }
ccc6cda3 7521 free (name);
227f982e
CR
7522
7523 if (ret == 0)
7524 {
7525 ret = alloc_word_desc ();
7526 ret->flags = tflag;
7527 ret->word = temp;
7528 }
7529 return (ret);
726f6388
JA
7530}
7531
cce855bc
JA
7532/* Expand a single ${xxx} expansion. The braces are optional. When
7533 the braces are used, parameter_brace_expand() does the work,
7534 possibly calling param_expand recursively. */
227f982e 7535static WORD_DESC *
cce855bc
JA
7536param_expand (string, sindex, quoted, expanded_something,
7537 contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
7538 pflags)
7539 char *string;
7540 int *sindex, quoted, *expanded_something, *contains_dollar_at;
7541 int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
7542{
7117c2d2 7543 char *temp, *temp1, uerror[3];
f73dda09
JA
7544 int zindex, t_index, expok;
7545 unsigned char c;
7117c2d2 7546 intmax_t number;
cce855bc 7547 SHELL_VAR *var;
f73dda09 7548 WORD_LIST *list;
227f982e
CR
7549 WORD_DESC *tdesc, *ret;
7550 int tflag;
cce855bc
JA
7551
7552 zindex = *sindex;
7553 c = string[++zindex];
7554
7555 temp = (char *)NULL;
227f982e
CR
7556 ret = tdesc = (WORD_DESC *)NULL;
7557 tflag = 0;
cce855bc
JA
7558
7559 /* Do simple cases first. Switch on what follows '$'. */
7560 switch (c)
7561 {
7562 /* $0 .. $9? */
7563 case '0':
7564 case '1':
7565 case '2':
7566 case '3':
7567 case '4':
7568 case '5':
7569 case '6':
7570 case '7':
7571 case '8':
7572 case '9':
f73dda09 7573 temp1 = dollar_vars[TODIGIT (c)];
cce855bc
JA
7574 if (unbound_vars_is_error && temp1 == (char *)NULL)
7575 {
7117c2d2
JA
7576 uerror[0] = '$';
7577 uerror[1] = c;
7578 uerror[2] = '\0';
cce855bc 7579 last_command_exit_value = EXECUTION_FAILURE;
0d8616ff 7580 err_unboundvar (uerror);
227f982e 7581 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
cce855bc 7582 }
5ba8ff6e 7583 if (temp1)
762a763b 7584 temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
5ba8ff6e
CR
7585 ? quote_string (temp1)
7586 : quote_escapes (temp1);
7587 else
7588 temp = (char *)NULL;
227f982e 7589
cce855bc
JA
7590 break;
7591
7592 /* $$ -- pid of the invoking shell. */
7593 case '$':
7594 temp = itos (dollar_dollar_pid);
7595 break;
7596
7597 /* $# -- number of positional parameters. */
7598 case '#':
7599 temp = itos (number_of_args ());
7600 break;
7601
7602 /* $? -- return value of the last synchronous command. */
7603 case '?':
7604 temp = itos (last_command_exit_value);
7605 break;
7606
7607 /* $- -- flags supplied to the shell on invocation or by `set'. */
7608 case '-':
7609 temp = which_set_flags ();
7610 break;
7611
7612 /* $! -- Pid of the last asynchronous command. */
7613 case '!':
7614 /* If no asynchronous pids have been created, expand to nothing.
7615 If `set -u' has been executed, and no async processes have
7616 been created, this is an expansion error. */
7617 if (last_asynchronous_pid == NO_PID)
7618 {
7619 if (expanded_something)
7620 *expanded_something = 0;
7621 temp = (char *)NULL;
7622 if (unbound_vars_is_error)
7623 {
7117c2d2
JA
7624 uerror[0] = '$';
7625 uerror[1] = c;
7626 uerror[2] = '\0';
cce855bc 7627 last_command_exit_value = EXECUTION_FAILURE;
0d8616ff 7628 err_unboundvar (uerror);
227f982e 7629 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
cce855bc
JA
7630 }
7631 }
7632 else
f73dda09 7633 temp = itos (last_asynchronous_pid);
cce855bc
JA
7634 break;
7635
7636 /* The only difference between this and $@ is when the arg is quoted. */
7637 case '*': /* `$*' */
7638 list = list_rest_of_args ();
7639
12ae1612
CR
7640#if 0
7641 /* According to austin-group posix proposal by Geoff Clare in
7642 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
7643
7644 "The shell shall write a message to standard error and
7645 immediately exit when it tries to expand an unset parameter
7646 other than the '@' and '*' special parameters."
7647 */
7648
1231ac47 7649 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
57a3f689
CR
7650 {
7651 uerror[0] = '$';
7652 uerror[1] = '*';
7653 uerror[2] = '\0';
57a3f689 7654 last_command_exit_value = EXECUTION_FAILURE;
0d8616ff 7655 err_unboundvar (uerror);
57a3f689
CR
7656 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7657 }
12ae1612 7658#endif
57a3f689 7659
cce855bc
JA
7660 /* If there are no command-line arguments, this should just
7661 disappear if there are other characters in the expansion,
7662 even if it's quoted. */
7663 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
7664 temp = (char *)NULL;
1231ac47 7665 else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
cce855bc
JA
7666 {
7667 /* If we have "$*" we want to make a string of the positional
7668 parameters, separated by the first character of $IFS, and
7669 quote the whole string, including the separators. If IFS
7670 is unset, the parameters are separated by ' '; if $IFS is
7671 null, the parameters are concatenated. */
1231ac47 7672 temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list) : string_list (list);
adc6cff5
CR
7673 if (temp)
7674 {
7675 temp1 = quote_string (temp);
7676 if (*temp == 0)
7677 tflag |= W_HASQUOTEDNULL;
7678 free (temp);
7679 temp = temp1;
7680 }
cce855bc
JA
7681 }
7682 else
28ef6c31 7683 {
227f982e
CR
7684 /* We check whether or not we're eventually going to split $* here,
7685 for example when IFS is empty and we are processing the rhs of
7686 an assignment statement. In that case, we don't separate the
7687 arguments at all. Otherwise, if the $* is not quoted it is
7688 identical to $@ */
227f982e
CR
7689# if defined (HANDLE_MULTIBYTE)
7690 if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
7691# else
7692 if (expand_no_split_dollar_star && ifs_firstc == 0)
7693# endif
7694 temp = string_list_dollar_star (list);
7695 else
f0c4de40
CR
7696 {
7697 temp = string_list_dollar_at (list, quoted);
1a81420a 7698 if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null))
f0c4de40 7699 tflag |= W_SPLITSPACE;
f0c4de40
CR
7700 }
7701
28ef6c31
JA
7702 if (expand_no_split_dollar_star == 0 && contains_dollar_at)
7703 *contains_dollar_at = 1;
7704 }
cce855bc
JA
7705
7706 dispose_words (list);
7707 break;
7708
7709 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
7710 means that we have to turn quoting off after we split into
7711 the individually quoted arguments so that the final split
7712 on the first character of $IFS is still done. */
7713 case '@': /* `$@' */
7714 list = list_rest_of_args ();
7715
12ae1612
CR
7716#if 0
7717 /* According to austin-group posix proposal by Geoff Clare in
7718 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
7719
7720 "The shell shall write a message to standard error and
7721 immediately exit when it tries to expand an unset parameter
7722 other than the '@' and '*' special parameters."
7723 */
7724
1231ac47 7725 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
57a3f689
CR
7726 {
7727 uerror[0] = '$';
7728 uerror[1] = '@';
7729 uerror[2] = '\0';
57a3f689 7730 last_command_exit_value = EXECUTION_FAILURE;
0d8616ff 7731 err_unboundvar (uerror);
57a3f689
CR
7732 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7733 }
12ae1612 7734#endif
57a3f689 7735
cce855bc
JA
7736 /* We want to flag the fact that we saw this. We can't turn
7737 off quoting entirely, because other characters in the
7738 string might need it (consider "\"$@\""), but we need some
7739 way to signal that the final split on the first character
7740 of $IFS should be done, even though QUOTED is 1. */
1231ac47 7741 /* XXX - should this test include Q_PATQUOTE? */
cce855bc
JA
7742 if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7743 *quoted_dollar_at_p = 1;
7744 if (contains_dollar_at)
7745 *contains_dollar_at = 1;
7746
7747 /* We want to separate the positional parameters with the first
7748 character of $IFS in case $IFS is something other than a space.
7749 We also want to make sure that splitting is done no matter what --
7750 according to POSIX.2, this expands to a list of the positional
7751 parameters no matter what IFS is set to. */
40647963 7752 temp = string_list_dollar_at (list, (pflags & PF_ASSIGNRHS) ? (quoted|Q_DOUBLE_QUOTES) : quoted);
cce855bc 7753
348a457e 7754 tflag |= W_DOLLARAT;
cce855bc
JA
7755 dispose_words (list);
7756 break;
7757
7758 case LBRACE:
e1e48bba 7759 tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
227f982e
CR
7760 quoted_dollar_at_p,
7761 contains_dollar_at);
7762
227f982e
CR
7763 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
7764 return (tdesc);
7765 temp = tdesc ? tdesc->word : (char *)0;
cce855bc
JA
7766
7767 /* XXX */
bb70624e 7768 /* Quoted nulls should be removed if there is anything else
cce855bc
JA
7769 in the string. */
7770 /* Note that we saw the quoted null so we can add one back at
7771 the end of this function if there are no other characters
28ef6c31
JA
7772 in the string, discard TEMP, and go on. The exception to
7773 this is when we have "${@}" and $1 is '', since $@ needs
7774 special handling. */
227f982e 7775 if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
cce855bc
JA
7776 {
7777 if (had_quoted_null_p)
7778 *had_quoted_null_p = 1;
28ef6c31
JA
7779 if (*quoted_dollar_at_p == 0)
7780 {
7781 free (temp);
227f982e 7782 tdesc->word = temp = (char *)NULL;
28ef6c31
JA
7783 }
7784
cce855bc
JA
7785 }
7786
227f982e 7787 ret = tdesc;
cce855bc
JA
7788 goto return0;
7789
7790 /* Do command or arithmetic substitution. */
7791 case LPAREN:
7792 /* We have to extract the contents of this paren substitution. */
7793 t_index = zindex + 1;
e33f2203 7794 temp = extract_command_subst (string, &t_index, 0);
cce855bc
JA
7795 zindex = t_index;
7796
7797 /* For Posix.2-style `$(( ))' arithmetic substitution,
28ef6c31 7798 extract the expression and pass it to the evaluator. */
cce855bc
JA
7799 if (temp && *temp == LPAREN)
7800 {
7801 char *temp2;
7802 temp1 = temp + 1;
7803 temp2 = savestring (temp1);
7804 t_index = strlen (temp2) - 1;
7805
7806 if (temp2[t_index] != RPAREN)
7807 {
7808 free (temp2);
7809 goto comsub;
7810 }
7811
7812 /* Cut off ending `)' */
7813 temp2[t_index] = '\0';
7814
d3ad40de
CR
7815 if (chk_arithsub (temp2, t_index) == 0)
7816 {
7817 free (temp2);
984a1947 7818#if 0
ecf57862 7819 internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
984a1947 7820#endif
d3ad40de
CR
7821 goto comsub;
7822 }
7823
cce855bc 7824 /* Expand variables found inside the expression. */
d3ad40de 7825 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
cce855bc
JA
7826 free (temp2);
7827
7828arithsub:
7829 /* No error messages. */
7830 this_command_name = (char *)NULL;
7831 number = evalexp (temp1, &expok);
7832 free (temp);
7833 free (temp1);
7834 if (expok == 0)
7835 {
7836 if (interactive_shell == 0 && posixly_correct)
7837 {
7838 last_command_exit_value = EXECUTION_FAILURE;
227f982e 7839 return (&expand_wdesc_fatal);
cce855bc
JA
7840 }
7841 else
227f982e 7842 return (&expand_wdesc_error);
cce855bc
JA
7843 }
7844 temp = itos (number);
7845 break;
7846 }
7847
7848comsub:
d3a24ed2
CR
7849 if (pflags & PF_NOCOMSUB)
7850 /* we need zindex+1 because string[zindex] == RPAREN */
7851 temp1 = substring (string, *sindex, zindex+1);
7852 else
d3ad40de
CR
7853 {
7854 tdesc = command_substitute (temp, quoted);
7855 temp1 = tdesc ? tdesc->word : (char *)NULL;
e33f2203
CR
7856 if (tdesc)
7857 dispose_word_desc (tdesc);
d3ad40de 7858 }
cce855bc
JA
7859 FREE (temp);
7860 temp = temp1;
7861 break;
7862
7863 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
7864 away in a future bash release. */
7865 case '[':
bb70624e 7866 /* Extract the contents of this arithmetic substitution. */
cce855bc
JA
7867 t_index = zindex + 1;
7868 temp = extract_arithmetic_subst (string, &t_index);
7869 zindex = t_index;
35bb237e
CR
7870 if (temp == 0)
7871 {
7872 temp = savestring (string);
7873 if (expanded_something)
7874 *expanded_something = 0;
7875 goto return0;
7876 }
cce855bc
JA
7877
7878 /* Do initial variable expansion. */
d3ad40de 7879 temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES);
cce855bc
JA
7880
7881 goto arithsub;
7882
7883 default:
7884 /* Find the variable in VARIABLE_LIST. */
7885 temp = (char *)NULL;
7886
7887 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
7888 ;
7889 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
7890
7891 /* If this isn't a variable name, then just output the `$'. */
7892 if (temp1 == 0 || *temp1 == '\0')
7893 {
7894 FREE (temp1);
f73dda09 7895 temp = (char *)xmalloc (2);
cce855bc
JA
7896 temp[0] = '$';
7897 temp[1] = '\0';
7898 if (expanded_something)
7899 *expanded_something = 0;
7900 goto return0;
7901 }
7902
7903 /* If the variable exists, return its value cell. */
7904 var = find_variable (temp1);
7905
7117c2d2 7906 if (var && invisible_p (var) == 0 && var_isset (var))
cce855bc
JA
7907 {
7908#if defined (ARRAY_VARS)
fdf670ea 7909 if (assoc_p (var) || array_p (var))
cce855bc 7910 {
fdf670ea
CR
7911 temp = array_p (var) ? array_reference (array_cell (var), 0)
7912 : assoc_reference (assoc_cell (var), "0");
cce855bc 7913 if (temp)
762a763b 7914 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
5ba8ff6e
CR
7915 ? quote_string (temp)
7916 : quote_escapes (temp);
5565fb1a
CR
7917 else if (unbound_vars_is_error)
7918 goto unbound_variable;
cce855bc
JA
7919 }
7920 else
7921#endif
762a763b
CR
7922 {
7923 temp = value_cell (var);
7924
7925 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7926 ? quote_string (temp)
7927 : quote_escapes (temp);
7928 }
5ba8ff6e 7929
cce855bc 7930 free (temp1);
7117c2d2 7931
cce855bc
JA
7932 goto return0;
7933 }
d42cb8c1
CR
7934 else if (var = find_variable_last_nameref (temp1))
7935 {
7936 temp = nameref_cell (var);
15623760 7937#if defined (ARRAY_VARS)
d42cb8c1
CR
7938 if (temp && *temp && valid_array_reference (temp))
7939 {
f14388d3 7940 tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (arrayind_t *)NULL);
d42cb8c1
CR
7941 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
7942 return (tdesc);
7943 ret = tdesc;
7944 goto return0;
7945 }
7946 else
15623760
CR
7947#endif
7948 /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */
7949 if (temp && *temp && legal_identifier (temp) == 0)
7950 {
7951 last_command_exit_value = EXECUTION_FAILURE;
7952 report_error (_("%s: invalid variable name for name reference"), temp);
7953 return (&expand_wdesc_error); /* XXX */
7954 }
7955 else
d42cb8c1
CR
7956 temp = (char *)NULL;
7957 }
cce855bc
JA
7958
7959 temp = (char *)NULL;
7960
5565fb1a 7961unbound_variable:
cce855bc 7962 if (unbound_vars_is_error)
0d8616ff
CR
7963 {
7964 last_command_exit_value = EXECUTION_FAILURE;
7965 err_unboundvar (temp1);
7966 }
cce855bc
JA
7967 else
7968 {
7969 free (temp1);
7970 goto return0;
7971 }
7972
7973 free (temp1);
7974 last_command_exit_value = EXECUTION_FAILURE;
7975 return ((unbound_vars_is_error && interactive_shell == 0)
227f982e
CR
7976 ? &expand_wdesc_fatal
7977 : &expand_wdesc_error);
cce855bc
JA
7978 }
7979
7980 if (string[zindex])
7981 zindex++;
7982
7983return0:
7984 *sindex = zindex;
227f982e
CR
7985
7986 if (ret == 0)
7987 {
7988 ret = alloc_word_desc ();
7989 ret->flags = tflag; /* XXX */
7990 ret->word = temp;
7991 }
7992 return ret;
cce855bc
JA
7993}
7994
7995/* Make a word list which is the result of parameter and variable
7996 expansion, command substitution, arithmetic substitution, and
7997 quote removal of WORD. Return a pointer to a WORD_LIST which is
7998 the result of the expansion. If WORD contains a null word, the
7999 word list returned is also null.
726f6388 8000
ccc6cda3
JA
8001 QUOTED contains flag values defined in shell.h.
8002
b72432fd
JA
8003 ISEXP is used to tell expand_word_internal that the word should be
8004 treated as the result of an expansion. This has implications for
8005 how IFS characters in the word are treated.
8006
726f6388
JA
8007 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
8008 they point to an integer value which receives information about expansion.
8009 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
8010 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
8011 else zero.
8012
8013 This only does word splitting in the case of $@ expansion. In that
8014 case, we split on ' '. */
8015
8016/* Values for the local variable quoted_state. */
8017#define UNQUOTED 0
8018#define PARTIALLY_QUOTED 1
8019#define WHOLLY_QUOTED 2
8020
8021static WORD_LIST *
b72432fd 8022expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
726f6388 8023 WORD_DESC *word;
b72432fd 8024 int quoted, isexp;
726f6388
JA
8025 int *contains_dollar_at;
8026 int *expanded_something;
8027{
ccc6cda3
JA
8028 WORD_LIST *list;
8029 WORD_DESC *tword;
726f6388
JA
8030
8031 /* The intermediate string that we build while expanding. */
ccc6cda3 8032 char *istring;
726f6388
JA
8033
8034 /* The current size of the above object. */
ccc6cda3 8035 int istring_size;
726f6388
JA
8036
8037 /* Index into ISTRING. */
ccc6cda3 8038 int istring_index;
726f6388
JA
8039
8040 /* Temporary string storage. */
ccc6cda3 8041 char *temp, *temp1;
726f6388
JA
8042
8043 /* The text of WORD. */
ccc6cda3 8044 register char *string;
726f6388 8045
7117c2d2
JA
8046 /* The size of STRING. */
8047 size_t string_size;
8048
726f6388 8049 /* The index into STRING. */
ccc6cda3 8050 int sindex;
726f6388
JA
8051
8052 /* This gets 1 if we see a $@ while quoted. */
ccc6cda3 8053 int quoted_dollar_at;
726f6388
JA
8054
8055 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
8056 whether WORD contains no quoting characters, a partially quoted
8057 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
ccc6cda3
JA
8058 int quoted_state;
8059
22e63b05 8060 /* State flags */
ccc6cda3 8061 int had_quoted_null;
348a457e 8062 int has_dollar_at, temp_has_dollar_at;
f0c4de40 8063 int split_on_spaces;
28ef6c31 8064 int tflag;
e1e48bba 8065 int pflags; /* flags passed to param_expand */
726f6388 8066
22e63b05
CR
8067 int assignoff; /* If assignment, offset of `=' */
8068
f73dda09 8069 register unsigned char c; /* Current character. */
726f6388 8070 int t_index; /* For calls to string_extract_xxx. */
726f6388 8071
bb70624e 8072 char twochars[2];
b72432fd 8073
7117c2d2
JA
8074 DECLARE_MBSTATE;
8075
f73dda09 8076 istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
ccc6cda3 8077 istring[istring_index = 0] = '\0';
cce855bc 8078 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
f0c4de40 8079 split_on_spaces = 0;
ccc6cda3
JA
8080 quoted_state = UNQUOTED;
8081
8082 string = word->word;
8083 if (string == 0)
8084 goto finished_with_string;
da713c23
CR
8085 /* Don't need the string length for the SADD... and COPY_ macros unless
8086 multibyte characters are possible. */
8087 string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1;
726f6388
JA
8088
8089 if (contains_dollar_at)
8090 *contains_dollar_at = 0;
8091
22e63b05
CR
8092 assignoff = -1;
8093
726f6388
JA
8094 /* Begin the expansion. */
8095
ccc6cda3 8096 for (sindex = 0; ;)
726f6388
JA
8097 {
8098 c = string[sindex];
8099
8100 /* Case on toplevel character. */
8101 switch (c)
8102 {
8103 case '\0':
8104 goto finished_with_string;
8105
8106 case CTLESC:
7117c2d2
JA
8107 sindex++;
8108#if HANDLE_MULTIBYTE
8109 if (MB_CUR_MAX > 1 && string[sindex])
8110 {
545f34cf 8111 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7117c2d2
JA
8112 }
8113 else
8114#endif
8115 {
8116 temp = (char *)xmalloc (3);
8117 temp[0] = CTLESC;
8118 temp[1] = c = string[sindex];
8119 temp[2] = '\0';
8120 }
726f6388 8121
cce855bc 8122dollar_add_string:
726f6388
JA
8123 if (string[sindex])
8124 sindex++;
8125
cce855bc
JA
8126add_string:
8127 if (temp)
8128 {
8129 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
8130 temp = (char *)0;
8131 }
8132
8133 break;
726f6388
JA
8134
8135#if defined (PROCESS_SUBSTITUTION)
8136 /* Process substitution. */
8137 case '<':
8138 case '>':
8139 {
dc8fbaf9 8140 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || posixly_correct)
726f6388 8141 {
bb70624e 8142 sindex--; /* add_character: label increments sindex */
726f6388
JA
8143 goto add_character;
8144 }
8145 else
cce855bc 8146 t_index = sindex + 1; /* skip past both '<' and LPAREN */
726f6388 8147
cce855bc 8148 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/
ccc6cda3 8149 sindex = t_index;
726f6388
JA
8150
8151 /* If the process substitution specification is `<()', we want to
8152 open the pipe for writing in the child and produce output; if
8153 it is `>()', we want to open the pipe for reading in the child
8154 and consume input. */
ccc6cda3 8155 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
726f6388
JA
8156
8157 FREE (temp1);
8158
8159 goto dollar_add_string;
8160 }
8161#endif /* PROCESS_SUBSTITUTION */
8162
22e63b05
CR
8163 case '=':
8164 /* Posix.2 section 3.6.1 says that tildes following `=' in words
8165 which are not assignment statements are not expanded. If the
8166 shell isn't in posix mode, though, we perform tilde expansion
8167 on `likely candidate' unquoted assignment statements (flags
8168 include W_ASSIGNMENT but not W_QUOTED). A likely candidate
8169 contains an unquoted :~ or =~. Something to think about: we
8170 now have a flag that says to perform tilde expansion on arguments
8171 to `assignment builtins' like declare and export that look like
8172 assignment statements. We now do tilde expansion on such words
8173 even in POSIX mode. */
8174 if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
c1d39fb8 8175 {
e1e48bba 8176 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
c1d39fb8
CR
8177 goto add_ifs_character;
8178 else
8179 goto add_character;
8180 }
22e63b05
CR
8181 /* If we're not in posix mode or forcing assignment-statement tilde
8182 expansion, note where the `=' appears in the word and prepare to
8183 do tilde expansion following the first `='. */
8184 if ((word->flags & W_ASSIGNMENT) &&
8185 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
8186 assignoff == -1 && sindex > 0)
8187 assignoff = sindex;
8188 if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
8189 word->flags |= W_ITILDE;
d90269dd 8190#if 0
22e63b05
CR
8191 else if ((word->flags & W_ASSIGNMENT) &&
8192 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
8193 string[sindex+1] == '~')
8194 word->flags |= W_ITILDE;
d90269dd 8195#endif
e1e48bba 8196 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
c1d39fb8
CR
8197 goto add_ifs_character;
8198 else
8199 goto add_character;
22e63b05
CR
8200
8201 case ':':
8202 if (word->flags & W_NOTILDE)
c1d39fb8 8203 {
e1e48bba 8204 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
c1d39fb8
CR
8205 goto add_ifs_character;
8206 else
8207 goto add_character;
8208 }
cdb32d45
CR
8209
8210 if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) &&
22e63b05
CR
8211 string[sindex+1] == '~')
8212 word->flags |= W_ITILDE;
c1d39fb8 8213
e1e48bba 8214 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
c1d39fb8
CR
8215 goto add_ifs_character;
8216 else
8217 goto add_character;
22e63b05
CR
8218
8219 case '~':
8220 /* If the word isn't supposed to be tilde expanded, or we're not
8221 at the start of a word or after an unquoted : or = in an
8222 assignment statement, we don't do tilde expansion. */
da719982 8223 if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
22e63b05
CR
8224 (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
8225 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8226 {
8227 word->flags &= ~W_ITILDE;
e1e48bba 8228 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
c1d39fb8
CR
8229 goto add_ifs_character;
8230 else
8231 goto add_character;
22e63b05
CR
8232 }
8233
8234 if (word->flags & W_ASSIGNRHS)
8235 tflag = 2;
cdb32d45 8236 else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
22e63b05
CR
8237 tflag = 1;
8238 else
8239 tflag = 0;
8240
8241 temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
8242
8243 word->flags &= ~W_ITILDE;
8244
8245 if (temp && *temp && t_index > 0)
8246 {
8247 temp1 = bash_tilde_expand (temp, tflag);
dc8fbaf9
CR
8248 if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
8249 {
8250 FREE (temp);
8251 FREE (temp1);
8252 goto add_character; /* tilde expansion failed */
8253 }
22e63b05
CR
8254 free (temp);
8255 temp = temp1;
8256 sindex += t_index;
866961ad 8257 goto add_quoted_string; /* XXX was add_string */
22e63b05
CR
8258 }
8259 else
8260 {
8261 FREE (temp);
8262 goto add_character;
8263 }
8264
726f6388 8265 case '$':
726f6388
JA
8266 if (expanded_something)
8267 *expanded_something = 1;
8268
348a457e 8269 temp_has_dollar_at = 0;
e1e48bba
CR
8270 pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
8271 if (word->flags & W_NOSPLIT2)
8272 pflags |= PF_NOSPLIT2;
40647963
CR
8273 if (word->flags & W_ASSIGNRHS)
8274 pflags |= PF_ASSIGNRHS;
227f982e 8275 tword = param_expand (string, &sindex, quoted, expanded_something,
348a457e 8276 &temp_has_dollar_at, &quoted_dollar_at,
e1e48bba 8277 &had_quoted_null, pflags);
348a457e 8278 has_dollar_at += temp_has_dollar_at;
f0c4de40 8279 split_on_spaces += (tword->flags & W_SPLITSPACE);
f0c4de40 8280
227f982e 8281 if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
726f6388 8282 {
cce855bc
JA
8283 free (string);
8284 free (istring);
227f982e
CR
8285 return ((tword == &expand_wdesc_error) ? &expand_word_error
8286 : &expand_word_fatal);
cce855bc
JA
8287 }
8288 if (contains_dollar_at && has_dollar_at)
8289 *contains_dollar_at = 1;
227f982e
CR
8290
8291 if (tword && (tword->flags & W_HASQUOTEDNULL))
8292 had_quoted_null = 1;
8293
77638cbf 8294 temp = tword ? tword->word : (char *)NULL;
227f982e
CR
8295 dispose_word_desc (tword);
8296
efc2f955
CR
8297 /* Kill quoted nulls; we will add them back at the end of
8298 expand_word_internal if nothing else in the string */
8299 if (had_quoted_null && temp && QUOTED_NULL (temp))
8300 {
8301 FREE (temp);
8302 temp = (char *)NULL;
8303 }
8304
cce855bc
JA
8305 goto add_string;
8306 break;
726f6388 8307
cce855bc
JA
8308 case '`': /* Backquoted command substitution. */
8309 {
d3a24ed2 8310 t_index = sindex++;
726f6388 8311
e6598ba4 8312 temp = string_extract (string, &sindex, "`", SX_REQMATCH);
bc7bed50
CR
8313 /* The test of sindex against t_index is to allow bare instances of
8314 ` to pass through, for backwards compatibility. */
7027abcb
CR
8315 if (temp == &extract_string_error || temp == &extract_string_fatal)
8316 {
bc7bed50
CR
8317 if (sindex - 1 == t_index)
8318 {
8319 sindex = t_index;
8320 goto add_character;
8321 }
7f947b68 8322 last_command_exit_value = EXECUTION_FAILURE;
d3ad40de 8323 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
7027abcb
CR
8324 free (string);
8325 free (istring);
8326 return ((temp == &extract_string_error) ? &expand_word_error
8327 : &expand_word_fatal);
8328 }
8329
bc7bed50
CR
8330 if (expanded_something)
8331 *expanded_something = 1;
8332
d3a24ed2
CR
8333 if (word->flags & W_NOCOMSUB)
8334 /* sindex + 1 because string[sindex] == '`' */
8335 temp1 = substring (string, t_index, sindex + 1);
8336 else
8337 {
8338 de_backslash (temp);
d3ad40de
CR
8339 tword = command_substitute (temp, quoted);
8340 temp1 = tword ? tword->word : (char *)NULL;
e33f2203
CR
8341 if (tword)
8342 dispose_word_desc (tword);
d3a24ed2 8343 }
cce855bc
JA
8344 FREE (temp);
8345 temp = temp1;
8346 goto dollar_add_string;
8347 }
ccc6cda3 8348
cce855bc
JA
8349 case '\\':
8350 if (string[sindex + 1] == '\n')
8351 {
8352 sindex += 2;
8353 continue;
8354 }
726f6388 8355
cce855bc 8356 c = string[++sindex];
726f6388 8357
cce855bc 8358 if (quoted & Q_HERE_DOCUMENT)
28ef6c31 8359 tflag = CBSHDOC;
cce855bc 8360 else if (quoted & Q_DOUBLE_QUOTES)
28ef6c31 8361 tflag = CBSDQUOTE;
cce855bc 8362 else
28ef6c31
JA
8363 tflag = 0;
8364
64419627 8365 /* From Posix discussion on austin-group list: Backslash escaping
9e51a74d
CR
8366 a } in ${...} is removed. Issue 0000221 */
8367 if ((quoted & Q_DOLBRACE) && c == RBRACE)
64419627 8368 {
ad4aef08
CR
8369 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
8370 }
8371 /* This is the fix for " $@\ " */
8372 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) & isexp == 0 && isifs (c))
8373 {
8374 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
8375 DEFAULT_ARRAY_SIZE);
8376 istring[istring_index++] = CTLESC;
8377 istring[istring_index++] = '\\';
8378 istring[istring_index] = '\0';
8379
64419627
CR
8380 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
8381 }
8382 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
cce855bc 8383 {
7117c2d2 8384 SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
bb70624e
JA
8385 }
8386 else if (c == 0)
8387 {
8388 c = CTLNUL;
8389 sindex--; /* add_character: label increments sindex */
8390 goto add_character;
cce855bc
JA
8391 }
8392 else
bb70624e 8393 {
7117c2d2 8394 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
bb70624e 8395 }
726f6388 8396
bb70624e
JA
8397 sindex++;
8398add_twochars:
8399 /* BEFORE jumping here, we need to increment sindex if appropriate */
8400 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
8401 DEFAULT_ARRAY_SIZE);
8402 istring[istring_index++] = twochars[0];
8403 istring[istring_index++] = twochars[1];
8404 istring[istring_index] = '\0';
8405
8406 break;
726f6388 8407
cce855bc 8408 case '"':
da719982 8409 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
cce855bc 8410 goto add_character;
ccc6cda3
JA
8411
8412 t_index = ++sindex;
8413 temp = string_extract_double_quoted (string, &sindex, 0);
8414
8415 /* If the quotes surrounded the entire string, then the
8416 whole word was quoted. */
8417 quoted_state = (t_index == 1 && string[sindex] == '\0')
8418 ? WHOLLY_QUOTED
7117c2d2 8419 : PARTIALLY_QUOTED;
ccc6cda3
JA
8420
8421 if (temp && *temp)
726f6388 8422 {
227f982e
CR
8423 tword = alloc_word_desc ();
8424 tword->word = temp;
8425
ccc6cda3
JA
8426 temp = (char *)NULL;
8427
348a457e 8428 temp_has_dollar_at = 0; /* XXX */
227f982e 8429 /* Need to get W_HASQUOTEDNULL flag through this function. */
348a457e
CR
8430 list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL);
8431 has_dollar_at += temp_has_dollar_at;
726f6388 8432
ccc6cda3
JA
8433 if (list == &expand_word_error || list == &expand_word_fatal)
8434 {
8435 free (istring);
8436 free (string);
8437 /* expand_word_internal has already freed temp_word->word
8438 for us because of the way it prints error messages. */
8439 tword->word = (char *)NULL;
8440 dispose_word (tword);
8441 return list;
8442 }
726f6388 8443
ccc6cda3 8444 dispose_word (tword);
726f6388 8445
ccc6cda3
JA
8446 /* "$@" (a double-quoted dollar-at) expands into nothing,
8447 not even a NULL word, when there are no positional
8448 parameters. */
cce855bc 8449 if (list == 0 && has_dollar_at)
726f6388 8450 {
ccc6cda3
JA
8451 quoted_dollar_at++;
8452 break;
8453 }
8454
8455 /* If we get "$@", we know we have expanded something, so we
8456 need to remember it for the final split on $IFS. This is
8457 a special case; it's the only case where a quoted string
8458 can expand into more than one word. It's going to come back
8459 from the above call to expand_word_internal as a list with
8460 a single word, in which all characters are quoted and
8461 separated by blanks. What we want to do is to turn it back
8462 into a list for the next piece of code. */
8463 if (list)
8464 dequote_list (list);
8465
227f982e 8466 if (list && list->word && (list->word->flags & W_HASQUOTEDNULL))
efc2f955 8467 had_quoted_null = 1; /* XXX */
227f982e 8468
cce855bc 8469 if (has_dollar_at)
ccc6cda3
JA
8470 {
8471 quoted_dollar_at++;
8472 if (contains_dollar_at)
8473 *contains_dollar_at = 1;
8474 if (expanded_something)
8475 *expanded_something = 1;
8476 }
8477 }
8478 else
8479 {
8480 /* What we have is "". This is a minor optimization. */
f73dda09 8481 FREE (temp);
ccc6cda3
JA
8482 list = (WORD_LIST *)NULL;
8483 }
8484
8485 /* The code above *might* return a list (consider the case of "$@",
8486 where it returns "$1", "$2", etc.). We can't throw away the
8487 rest of the list, and we have to make sure each word gets added
8488 as quoted. We test on tresult->next: if it is non-NULL, we
8489 quote the whole list, save it to a string with string_list, and
8490 add that string. We don't need to quote the results of this
8491 (and it would be wrong, since that would quote the separators
8492 as well), so we go directly to add_string. */
8493 if (list)
8494 {
8495 if (list->next)
8496 {
bc4cd23c
JA
8497 /* Testing quoted_dollar_at makes sure that "$@" is
8498 split correctly when $IFS does not contain a space. */
8499 temp = quoted_dollar_at
8500 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES)
8501 : string_list (quote_list (list));
ccc6cda3 8502 dispose_words (list);
726f6388
JA
8503 goto add_string;
8504 }
8505 else
8506 {
ccc6cda3 8507 temp = savestring (list->word->word);
227f982e 8508 tflag = list->word->flags;
ccc6cda3 8509 dispose_words (list);
227f982e 8510
cce855bc
JA
8511 /* If the string is not a quoted null string, we want
8512 to remove any embedded unquoted CTLNUL characters.
8513 We do not want to turn quoted null strings back into
8514 the empty string, though. We do this because we
8515 want to remove any quoted nulls from expansions that
8516 contain other characters. For example, if we have
8517 x"$*"y or "x$*y" and there are no positional parameters,
7117c2d2 8518 the $* should expand into nothing. */
227f982e
CR
8519 /* We use the W_HASQUOTEDNULL flag to differentiate the
8520 cases: a quoted null character as above and when
8521 CTLNUL is contained in the (non-null) expansion
8522 of some variable. We use the had_quoted_null flag to
10590446 8523 pass the value through this function to its caller. */
227f982e 8524 if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
cce855bc 8525 remove_quoted_nulls (temp); /* XXX */
726f6388
JA
8526 }
8527 }
ccc6cda3
JA
8528 else
8529 temp = (char *)NULL;
726f6388 8530
ccc6cda3 8531 /* We do not want to add quoted nulls to strings that are only
efc2f955 8532 partially quoted; we can throw them away. The exception to
f4f5e1c2
CR
8533 this is when we are going to be performing word splitting,
8534 since we have to preserve a null argument if the next character
8535 will cause word splitting. */
adc6cff5 8536 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
cce855bc 8537 continue;
726f6388 8538
ccc6cda3 8539 add_quoted_string:
726f6388 8540
ccc6cda3
JA
8541 if (temp)
8542 {
8543 temp1 = temp;
8544 temp = quote_string (temp);
8545 free (temp1);
bb70624e 8546 goto add_string;
ccc6cda3
JA
8547 }
8548 else
8549 {
8550 /* Add NULL arg. */
bb70624e
JA
8551 c = CTLNUL;
8552 sindex--; /* add_character: label increments sindex */
8553 goto add_character;
ccc6cda3 8554 }
bb70624e 8555
ccc6cda3 8556 /* break; */
726f6388 8557
ccc6cda3 8558 case '\'':
da719982 8559 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
ccc6cda3 8560 goto add_character;
726f6388 8561
ccc6cda3
JA
8562 t_index = ++sindex;
8563 temp = string_extract_single_quoted (string, &sindex);
726f6388 8564
ccc6cda3
JA
8565 /* If the entire STRING was surrounded by single quotes,
8566 then the string is wholly quoted. */
8567 quoted_state = (t_index == 1 && string[sindex] == '\0')
8568 ? WHOLLY_QUOTED
7117c2d2 8569 : PARTIALLY_QUOTED;
726f6388 8570
ccc6cda3
JA
8571 /* If all we had was '', it is a null expansion. */
8572 if (*temp == '\0')
8573 {
8574 free (temp);
8575 temp = (char *)NULL;
8576 }
8577 else
7117c2d2 8578 remove_quoted_escapes (temp); /* ??? */
726f6388 8579
ccc6cda3
JA
8580 /* We do not want to add quoted nulls to strings that are only
8581 partially quoted; such nulls are discarded. */
8582 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
8583 continue;
726f6388 8584
bb70624e
JA
8585 /* If we have a quoted null expansion, add a quoted NULL to istring. */
8586 if (temp == 0)
8587 {
8588 c = CTLNUL;
8589 sindex--; /* add_character: label increments sindex */
8590 goto add_character;
8591 }
8592 else
8593 goto add_quoted_string;
8594
ccc6cda3 8595 /* break; */
726f6388
JA
8596
8597 default:
726f6388 8598 /* This is the fix for " $@ " */
c1d39fb8 8599 add_ifs_character:
7117c2d2 8600 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c)))
726f6388 8601 {
bb70624e
JA
8602 if (string[sindex]) /* from old goto dollar_add_string */
8603 sindex++;
8604 if (c == 0)
8605 {
8606 c = CTLNUL;
8607 goto add_character;
8608 }
8609 else
8610 {
7117c2d2 8611#if HANDLE_MULTIBYTE
545f34cf
CR
8612 if (MB_CUR_MAX > 1)
8613 sindex--;
8614
7117c2d2
JA
8615 if (MB_CUR_MAX > 1)
8616 {
545f34cf 8617 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7117c2d2
JA
8618 }
8619 else
8620#endif
8621 {
8622 twochars[0] = CTLESC;
8623 twochars[1] = c;
8624 goto add_twochars;
8625 }
bb70624e 8626 }
726f6388
JA
8627 }
8628
7117c2d2
JA
8629 SADD_MBCHAR (temp, string, sindex, string_size);
8630
726f6388 8631 add_character:
ccc6cda3
JA
8632 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
8633 DEFAULT_ARRAY_SIZE);
726f6388
JA
8634 istring[istring_index++] = c;
8635 istring[istring_index] = '\0';
8636
8637 /* Next character. */
8638 sindex++;
8639 }
8640 }
8641
8642finished_with_string:
726f6388
JA
8643 /* OK, we're ready to return. If we have a quoted string, and
8644 quoted_dollar_at is not set, we do no splitting at all; otherwise
8645 we split on ' '. The routines that call this will handle what to
8646 do if nothing has been expanded. */
ccc6cda3
JA
8647
8648 /* Partially and wholly quoted strings which expand to the empty
8649 string are retained as an empty arguments. Unquoted strings
8650 which expand to the empty string are discarded. The single
8651 exception is the case of expanding "$@" when there are no
8652 positional parameters. In that case, we discard the expansion. */
8653
8654 /* Because of how the code that handles "" and '' in partially
8655 quoted strings works, we need to make ISTRING into a QUOTED_NULL
8656 if we saw quoting characters, but the expansion was empty.
8657 "" and '' are tossed away before we get to this point when
8658 processing partially quoted strings. This makes "" and $xxx""
8659 equivalent when xxx is unset. We also look to see whether we
8660 saw a quoted null from a ${} expansion and add one back if we
8661 need to. */
8662
8663 /* If we expand to nothing and there were no single or double quotes
8664 in the word, we throw it away. Otherwise, we return a NULL word.
8665 The single exception is for $@ surrounded by double quotes when
8666 there are no positional parameters. In that case, we also throw
8667 the word away. */
8668
8669 if (*istring == '\0')
8670 {
8671 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
726f6388 8672 {
726f6388
JA
8673 istring[0] = CTLNUL;
8674 istring[1] = '\0';
ccc6cda3 8675 tword = make_bare_word (istring);
227f982e 8676 tword->flags |= W_HASQUOTEDNULL; /* XXX */
ccc6cda3
JA
8677 list = make_word_list (tword, (WORD_LIST *)NULL);
8678 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8679 tword->flags |= W_QUOTED;
726f6388 8680 }
ccc6cda3
JA
8681 /* According to sh, ksh, and Posix.2, if a word expands into nothing
8682 and a double-quoted "$@" appears anywhere in it, then the entire
8683 word is removed. */
8684 else if (quoted_state == UNQUOTED || quoted_dollar_at)
8685 list = (WORD_LIST *)NULL;
8686#if 0
8687 else
726f6388 8688 {
ccc6cda3 8689 tword = make_bare_word (istring);
ccc6cda3
JA
8690 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8691 tword->flags |= W_QUOTED;
227f982e 8692 list = make_word_list (tword, (WORD_LIST *)NULL);
726f6388 8693 }
f73dda09
JA
8694#else
8695 else
8696 list = (WORD_LIST *)NULL;
ccc6cda3
JA
8697#endif
8698 }
8699 else if (word->flags & W_NOSPLIT)
8700 {
8701 tword = make_bare_word (istring);
ccc6cda3
JA
8702 if (word->flags & W_ASSIGNMENT)
8703 tword->flags |= W_ASSIGNMENT; /* XXX */
43df7bbb
CR
8704 if (word->flags & W_COMPASSIGN)
8705 tword->flags |= W_COMPASSIGN; /* XXX */
b72432fd
JA
8706 if (word->flags & W_NOGLOB)
8707 tword->flags |= W_NOGLOB; /* XXX */
df0e4bfe
CR
8708 if (word->flags & W_NOBRACE)
8709 tword->flags |= W_NOBRACE; /* XXX */
43df7bbb
CR
8710 if (word->flags & W_NOEXPAND)
8711 tword->flags |= W_NOEXPAND; /* XXX */
ccc6cda3 8712 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
28ef6c31 8713 tword->flags |= W_QUOTED;
efc2f955 8714 if (had_quoted_null && QUOTED_NULL (istring))
227f982e
CR
8715 tword->flags |= W_HASQUOTEDNULL;
8716 list = make_word_list (tword, (WORD_LIST *)NULL);
ccc6cda3
JA
8717 }
8718 else
8719 {
8720 char *ifs_chars;
8721
7117c2d2 8722 ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
726f6388 8723
cce855bc
JA
8724 /* If we have $@, we need to split the results no matter what. If
8725 IFS is unset or NULL, string_list_dollar_at has separated the
8726 positional parameters with a space, so we split on space (we have
8727 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
8728 string_list_dollar_at has separated the positional parameters
1a81420a
CR
8729 with the first character of $IFS, so we split on $IFS. If
8730 SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
8731 unset or null, and we want to make sure that we split on spaces
8732 regardless of what else has happened to IFS since the expansion. */
8733 if (split_on_spaces)
8734 list = list_string (istring, " ", 1); /* XXX quoted == 1? */
8735 else if (has_dollar_at && ifs_chars)
cce855bc 8736 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
ccc6cda3
JA
8737 else
8738 {
8739 tword = make_bare_word (istring);
ccc6cda3
JA
8740 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
8741 tword->flags |= W_QUOTED;
8742 if (word->flags & W_ASSIGNMENT)
8743 tword->flags |= W_ASSIGNMENT;
43df7bbb
CR
8744 if (word->flags & W_COMPASSIGN)
8745 tword->flags |= W_COMPASSIGN;
b72432fd
JA
8746 if (word->flags & W_NOGLOB)
8747 tword->flags |= W_NOGLOB;
df0e4bfe
CR
8748 if (word->flags & W_NOBRACE)
8749 tword->flags |= W_NOBRACE;
43df7bbb
CR
8750 if (word->flags & W_NOEXPAND)
8751 tword->flags |= W_NOEXPAND;
efc2f955 8752 if (had_quoted_null && QUOTED_NULL (istring))
227f982e
CR
8753 tword->flags |= W_HASQUOTEDNULL; /* XXX */
8754 list = make_word_list (tword, (WORD_LIST *)NULL);
726f6388 8755 }
726f6388 8756 }
726f6388 8757
ccc6cda3
JA
8758 free (istring);
8759 return (list);
726f6388
JA
8760}
8761
8762/* **************************************************************** */
8763/* */
8764/* Functions for Quote Removal */
8765/* */
8766/* **************************************************************** */
8767
8768/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
7117c2d2 8769 backslash quoting rules for within double quotes or a here document. */
726f6388
JA
8770char *
8771string_quote_removal (string, quoted)
8772 char *string;
8773 int quoted;
8774{
7117c2d2
JA
8775 size_t slen;
8776 char *r, *result_string, *temp, *send;
f73dda09
JA
8777 int sindex, tindex, dquote;
8778 unsigned char c;
7117c2d2 8779 DECLARE_MBSTATE;
726f6388
JA
8780
8781 /* The result can be no longer than the original string. */
7117c2d2
JA
8782 slen = strlen (string);
8783 send = string + slen;
8784
8785 r = result_string = (char *)xmalloc (slen + 1);
726f6388 8786
ccc6cda3 8787 for (dquote = sindex = 0; c = string[sindex];)
726f6388
JA
8788 {
8789 switch (c)
8790 {
8791 case '\\':
8792 c = string[++sindex];
33fe8777
CR
8793 if (c == 0)
8794 {
8795 *r++ = '\\';
8796 break;
8797 }
28ef6c31 8798 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
726f6388 8799 *r++ = '\\';
ccc6cda3 8800 /* FALLTHROUGH */
726f6388
JA
8801
8802 default:
7117c2d2 8803 SCOPY_CHAR_M (r, string, send, sindex);
726f6388
JA
8804 break;
8805
8806 case '\'':
ccc6cda3 8807 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
726f6388
JA
8808 {
8809 *r++ = c;
8810 sindex++;
ccc6cda3 8811 break;
726f6388 8812 }
ccc6cda3
JA
8813 tindex = sindex + 1;
8814 temp = string_extract_single_quoted (string, &tindex);
8815 if (temp)
726f6388 8816 {
ccc6cda3
JA
8817 strcpy (r, temp);
8818 r += strlen (r);
8819 free (temp);
726f6388 8820 }
ccc6cda3 8821 sindex = tindex;
726f6388
JA
8822 break;
8823
8824 case '"':
8825 dquote = 1 - dquote;
8826 sindex++;
8827 break;
8828 }
8829 }
8830 *r = '\0';
8831 return (result_string);
8832}
8833
ccc6cda3
JA
8834#if 0
8835/* UNUSED */
726f6388
JA
8836/* Perform quote removal on word WORD. This allocates and returns a new
8837 WORD_DESC *. */
8838WORD_DESC *
8839word_quote_removal (word, quoted)
8840 WORD_DESC *word;
8841 int quoted;
8842{
8843 WORD_DESC *w;
8844 char *t;
8845
8846 t = string_quote_removal (word->word, quoted);
227f982e
CR
8847 w = alloc_word_desc ();
8848 w->word = t ? t : savestring ("");
726f6388
JA
8849 return (w);
8850}
8851
8852/* Perform quote removal on all words in LIST. If QUOTED is non-zero,
8853 the members of the list are treated as if they are surrounded by
8854 double quotes. Return a new list, or NULL if LIST is NULL. */
8855WORD_LIST *
8856word_list_quote_removal (list, quoted)
8857 WORD_LIST *list;
8858 int quoted;
8859{
227f982e 8860 WORD_LIST *result, *t, *tresult, *e;
726f6388 8861
ccc6cda3 8862 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
726f6388 8863 {
7117c2d2 8864 tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
227f982e 8865#if 0
726f6388 8866 result = (WORD_LIST *) list_append (result, tresult);
227f982e
CR
8867#else
8868 if (result == 0)
8869 result = e = tresult;
8870 else
8871 {
8872 e->next = tresult;
8873 while (e->next)
8874 e = e->next;
8875 }
8876#endif
726f6388
JA
8877 }
8878 return (result);
8879}
ccc6cda3 8880#endif
726f6388 8881
726f6388
JA
8882/*******************************************
8883 * *
8884 * Functions to perform word splitting *
8885 * *
8886 *******************************************/
8887
7117c2d2
JA
8888void
8889setifs (v)
8890 SHELL_VAR *v;
b72432fd 8891{
7117c2d2
JA
8892 char *t;
8893 unsigned char uc;
8894
8895 ifs_var = v;
cdb32d45 8896 ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
b72432fd 8897
f0c4de40
CR
8898 ifs_is_set = ifs_var != 0;
8899 ifs_is_null = ifs_is_set && (*ifs_value == 0);
8900
633e5c6d
CR
8901 /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
8902 handle multibyte chars in IFS */
7117c2d2
JA
8903 memset (ifs_cmap, '\0', sizeof (ifs_cmap));
8904 for (t = ifs_value ; t && *t; t++)
8905 {
8906 uc = *t;
8907 ifs_cmap[uc] = 1;
8908 }
8909
633e5c6d
CR
8910#if defined (HANDLE_MULTIBYTE)
8911 if (ifs_value == 0)
8912 {
8913 ifs_firstc[0] = '\0';
8914 ifs_firstc_len = 1;
8915 }
8916 else
8917 {
8918 size_t ifs_len;
8919 ifs_len = strnlen (ifs_value, MB_CUR_MAX);
8920 ifs_firstc_len = MBLEN (ifs_value, ifs_len);
22e63b05 8921 if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
633e5c6d
CR
8922 {
8923 ifs_firstc[0] = ifs_value[0];
8924 ifs_firstc[1] = '\0';
8925 ifs_firstc_len = 1;
8926 }
8927 else
8928 memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
8929 }
8930#else
7117c2d2 8931 ifs_firstc = ifs_value ? *ifs_value : 0;
633e5c6d 8932#endif
7117c2d2
JA
8933}
8934
8935char *
8936getifs ()
8937{
8938 return ifs_value;
b72432fd
JA
8939}
8940
726f6388
JA
8941/* This splits a single word into a WORD LIST on $IFS, but only if the word
8942 is not quoted. list_string () performs quote removal for us, even if we
8943 don't do any splitting. */
8944WORD_LIST *
7117c2d2 8945word_split (w, ifs_chars)
726f6388 8946 WORD_DESC *w;
7117c2d2 8947 char *ifs_chars;
726f6388
JA
8948{
8949 WORD_LIST *result;
8950
8951 if (w)
8952 {
7117c2d2 8953 char *xifs;
726f6388 8954
7117c2d2
JA
8955 xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
8956 result = list_string (w->word, xifs, w->flags & W_QUOTED);
726f6388
JA
8957 }
8958 else
8959 result = (WORD_LIST *)NULL;
ccc6cda3 8960
726f6388
JA
8961 return (result);
8962}
8963
8964/* Perform word splitting on LIST and return the RESULT. It is possible
8965 to return (WORD_LIST *)NULL. */
8966static WORD_LIST *
8967word_list_split (list)
8968 WORD_LIST *list;
8969{
37c41ab1 8970 WORD_LIST *result, *t, *tresult, *e;
726f6388 8971
ccc6cda3 8972 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
726f6388 8973 {
7117c2d2 8974 tresult = word_split (t->word, ifs_value);
37c41ab1
CR
8975 if (result == 0)
8976 result = e = tresult;
8977 else
8978 {
8979 e->next = tresult;
8980 while (e->next)
8981 e = e->next;
8982 }
726f6388
JA
8983 }
8984 return (result);
8985}
8986
8987/**************************************************
8988 * *
cce855bc 8989 * Functions to expand an entire WORD_LIST *
726f6388
JA
8990 * *
8991 **************************************************/
8992
d3a24ed2
CR
8993/* Do any word-expansion-specific cleanup and jump to top_level */
8994static void
8995exp_jump_to_top_level (v)
8996 int v;
8997{
f11997f8
CR
8998 set_pipestatus_from_exit (last_command_exit_value);
8999
d3a24ed2
CR
9000 /* Cleanup code goes here. */
9001 expand_no_split_dollar_star = 0; /* XXX */
9002 expanding_redir = 0;
d7f49990 9003 assigning_in_environment = 0;
d3a24ed2 9004
2e4498b3
CR
9005 if (parse_and_execute_level == 0)
9006 top_level_cleanup (); /* from sig.c */
9007
d3a24ed2
CR
9008 jump_to_top_level (v);
9009}
9010
cce855bc
JA
9011/* Put NLIST (which is a WORD_LIST * of only one element) at the front of
9012 ELIST, and set ELIST to the new list. */
9013#define PREPEND_LIST(nlist, elist) \
9014 do { nlist->next = elist; elist = nlist; } while (0)
9015
726f6388
JA
9016/* Separate out any initial variable assignments from TLIST. If set -k has
9017 been executed, remove all assignment statements from TLIST. Initial
9018 variable assignments and other environment assignments are placed
bb70624e 9019 on SUBST_ASSIGN_VARLIST. */
726f6388
JA
9020static WORD_LIST *
9021separate_out_assignments (tlist)
9022 WORD_LIST *tlist;
9023{
9024 register WORD_LIST *vp, *lp;
9025
0527c903 9026 if (tlist == 0)
726f6388
JA
9027 return ((WORD_LIST *)NULL);
9028
bb70624e
JA
9029 if (subst_assign_varlist)
9030 dispose_words (subst_assign_varlist); /* Clean up after previous error */
b72432fd 9031
bb70624e 9032 subst_assign_varlist = (WORD_LIST *)NULL;
726f6388
JA
9033 vp = lp = tlist;
9034
9035 /* Separate out variable assignments at the start of the command.
9036 Loop invariant: vp->next == lp
9037 Loop postcondition:
7117c2d2
JA
9038 lp = list of words left after assignment statements skipped
9039 tlist = original list of words
726f6388 9040 */
ccc6cda3 9041 while (lp && (lp->word->flags & W_ASSIGNMENT))
726f6388
JA
9042 {
9043 vp = lp;
9044 lp = lp->next;
9045 }
9046
bb70624e
JA
9047 /* If lp != tlist, we have some initial assignment statements.
9048 We make SUBST_ASSIGN_VARLIST point to the list of assignment
9049 words and TLIST point to the remaining words. */
726f6388
JA
9050 if (lp != tlist)
9051 {
bb70624e 9052 subst_assign_varlist = tlist;
726f6388
JA
9053 /* ASSERT(vp->next == lp); */
9054 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
9055 tlist = lp; /* remainder of word list */
9056 }
9057
9058 /* vp == end of variable list */
9059 /* tlist == remainder of original word list without variable assignments */
9060 if (!tlist)
9061 /* All the words in tlist were assignment statements */
9062 return ((WORD_LIST *)NULL);
9063
9064 /* ASSERT(tlist != NULL); */
ccc6cda3 9065 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
726f6388
JA
9066
9067 /* If the -k option is in effect, we need to go through the remaining
bb70624e
JA
9068 words, separate out the assignment words, and place them on
9069 SUBST_ASSIGN_VARLIST. */
726f6388
JA
9070 if (place_keywords_in_env)
9071 {
9072 WORD_LIST *tp; /* tp == running pointer into tlist */
9073
9074 tp = tlist;
9075 lp = tlist->next;
9076
9077 /* Loop Invariant: tp->next == lp */
9078 /* Loop postcondition: tlist == word list without assignment statements */
9079 while (lp)
9080 {
ccc6cda3 9081 if (lp->word->flags & W_ASSIGNMENT)
726f6388
JA
9082 {
9083 /* Found an assignment statement, add this word to end of
bb70624e
JA
9084 subst_assign_varlist (vp). */
9085 if (!subst_assign_varlist)
9086 subst_assign_varlist = vp = lp;
726f6388
JA
9087 else
9088 {
9089 vp->next = lp;
9090 vp = lp;
9091 }
9092
9093 /* Remove the word pointed to by LP from TLIST. */
9094 tp->next = lp->next;
9095 /* ASSERT(vp == lp); */
9096 lp->next = (WORD_LIST *)NULL;
9097 lp = tp->next;
9098 }
9099 else
9100 {
9101 tp = lp;
9102 lp = lp->next;
9103 }
9104 }
9105 }
9106 return (tlist);
9107}
9108
cce855bc
JA
9109#define WEXP_VARASSIGN 0x001
9110#define WEXP_BRACEEXP 0x002
9111#define WEXP_TILDEEXP 0x004
9112#define WEXP_PARAMEXP 0x008
9113#define WEXP_PATHEXP 0x010
9114
9115/* All of the expansions, including variable assignments at the start of
9116 the list. */
9117#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
9118
9119/* All of the expansions except variable assignments at the start of
9120 the list. */
9121#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
9122
9123/* All of the `shell expansions': brace expansion, tilde expansion, parameter
9124 expansion, command substitution, arithmetic expansion, word splitting, and
9125 quote removal. */
9126#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
9127
726f6388
JA
9128/* Take the list of words in LIST and do the various substitutions. Return
9129 a new list of words which is the expanded list, and without things like
9130 variable assignments. */
9131
9132WORD_LIST *
9133expand_words (list)
9134 WORD_LIST *list;
9135{
cce855bc 9136 return (expand_word_list_internal (list, WEXP_ALL));
726f6388
JA
9137}
9138
9139/* Same as expand_words (), but doesn't hack variable or environment
9140 variables. */
9141WORD_LIST *
9142expand_words_no_vars (list)
9143 WORD_LIST *list;
9144{
cce855bc 9145 return (expand_word_list_internal (list, WEXP_NOVARS));
726f6388
JA
9146}
9147
cce855bc
JA
9148WORD_LIST *
9149expand_words_shellexp (list)
726f6388 9150 WORD_LIST *list;
726f6388 9151{
cce855bc
JA
9152 return (expand_word_list_internal (list, WEXP_SHELLEXP));
9153}
726f6388 9154
cce855bc
JA
9155static WORD_LIST *
9156glob_expand_word_list (tlist, eflags)
9157 WORD_LIST *tlist;
9158 int eflags;
9159{
9160 char **glob_array, *temp_string;
9161 register int glob_index;
9162 WORD_LIST *glob_list, *output_list, *disposables, *next;
9163 WORD_DESC *tword;
726f6388 9164
cce855bc
JA
9165 output_list = disposables = (WORD_LIST *)NULL;
9166 glob_array = (char **)NULL;
9167 while (tlist)
9168 {
9169 /* For each word, either globbing is attempted or the word is
9170 added to orig_list. If globbing succeeds, the results are
9171 added to orig_list and the word (tlist) is added to the list
9172 of disposable words. If globbing fails and failed glob
9173 expansions are left unchanged (the shell default), the
9174 original word is added to orig_list. If globbing fails and
9175 failed glob expansions are removed, the original word is
9176 added to the list of disposable words. orig_list ends up
7117c2d2 9177 in reverse order and requires a call to REVERSE_LIST to
cce855bc
JA
9178 be set right. After all words are examined, the disposable
9179 words are freed. */
9180 next = tlist->next;
726f6388 9181
cce855bc 9182 /* If the word isn't an assignment and contains an unquoted
28ef6c31 9183 pattern matching character, then glob it. */
b72432fd 9184 if ((tlist->word->flags & W_NOGLOB) == 0 &&
cce855bc 9185 unquoted_glob_pattern_p (tlist->word->word))
726f6388 9186 {
cce855bc
JA
9187 glob_array = shell_glob_filename (tlist->word->word);
9188
9189 /* Handle error cases.
9190 I don't think we should report errors like "No such file
9191 or directory". However, I would like to report errors
9192 like "Read failed". */
9193
d3a24ed2 9194 if (glob_array == 0 || GLOB_FAILED (glob_array))
726f6388 9195 {
bb70624e 9196 glob_array = (char **)xmalloc (sizeof (char *));
cce855bc
JA
9197 glob_array[0] = (char *)NULL;
9198 }
9199
9200 /* Dequote the current word in case we have to use it. */
9201 if (glob_array[0] == NULL)
9202 {
9203 temp_string = dequote_string (tlist->word->word);
9204 free (tlist->word->word);
9205 tlist->word->word = temp_string;
9206 }
9207
9208 /* Make the array into a word list. */
9209 glob_list = (WORD_LIST *)NULL;
9210 for (glob_index = 0; glob_array[glob_index]; glob_index++)
9211 {
9212 tword = make_bare_word (glob_array[glob_index]);
cce855bc
JA
9213 glob_list = make_word_list (tword, glob_list);
9214 }
9215
9216 if (glob_list)
9217 {
9218 output_list = (WORD_LIST *)list_append (glob_list, output_list);
9219 PREPEND_LIST (tlist, disposables);
9220 }
d3a24ed2
CR
9221 else if (fail_glob_expansion != 0)
9222 {
7f947b68 9223 last_command_exit_value = EXECUTION_FAILURE;
5e13499c 9224 report_error (_("no match: %s"), tlist->word->word);
c184f645 9225 exp_jump_to_top_level (DISCARD);
d3a24ed2 9226 }
cce855bc
JA
9227 else if (allow_null_glob_expansion == 0)
9228 {
9229 /* Failed glob expressions are left unchanged. */
9230 PREPEND_LIST (tlist, output_list);
9231 }
9232 else
9233 {
9234 /* Failed glob expressions are removed. */
9235 PREPEND_LIST (tlist, disposables);
726f6388 9236 }
726f6388 9237 }
cce855bc
JA
9238 else
9239 {
9240 /* Dequote the string. */
9241 temp_string = dequote_string (tlist->word->word);
9242 free (tlist->word->word);
9243 tlist->word->word = temp_string;
9244 PREPEND_LIST (tlist, output_list);
9245 }
9246
7117c2d2 9247 strvec_dispose (glob_array);
cce855bc
JA
9248 glob_array = (char **)NULL;
9249
9250 tlist = next;
726f6388
JA
9251 }
9252
cce855bc
JA
9253 if (disposables)
9254 dispose_words (disposables);
9255
9256 if (output_list)
9257 output_list = REVERSE_LIST (output_list, WORD_LIST *);
9258
9259 return (output_list);
9260}
726f6388
JA
9261
9262#if defined (BRACE_EXPANSION)
cce855bc
JA
9263static WORD_LIST *
9264brace_expand_word_list (tlist, eflags)
9265 WORD_LIST *tlist;
9266 int eflags;
9267{
9268 register char **expansions;
9269 char *temp_string;
9270 WORD_LIST *disposables, *output_list, *next;
9271 WORD_DESC *w;
9272 int eindex;
9273
9274 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
726f6388 9275 {
cce855bc 9276 next = tlist->next;
726f6388 9277
df0e4bfe
CR
9278 if (tlist->word->flags & W_NOBRACE)
9279 {
3087e51c 9280/*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/
df0e4bfe
CR
9281 PREPEND_LIST (tlist, output_list);
9282 continue;
9283 }
9284
6669f0e5
CR
9285 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
9286 {
9287/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
9288 PREPEND_LIST (tlist, output_list);
9289 continue;
9290 }
df0e4bfe 9291
cce855bc
JA
9292 /* Only do brace expansion if the word has a brace character. If
9293 not, just add the word list element to BRACES and continue. In
9294 the common case, at least when running shell scripts, this will
d0ca3503 9295 degenerate to a bunch of calls to `mbschr', and then what is
cce855bc 9296 basically a reversal of TLIST into BRACES, which is corrected
7117c2d2 9297 by a call to REVERSE_LIST () on BRACES when the end of TLIST
cce855bc 9298 is reached. */
d0ca3503 9299 if (mbschr (tlist->word->word, LBRACE))
726f6388 9300 {
cce855bc 9301 expansions = brace_expand (tlist->word->word);
726f6388 9302
cce855bc 9303 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
726f6388 9304 {
51f7ea36
CR
9305 w = alloc_word_desc ();
9306 w->word = temp_string;
9307
cce855bc
JA
9308 /* If brace expansion didn't change the word, preserve
9309 the flags. We may want to preserve the flags
9310 unconditionally someday -- XXX */
9311 if (STREQ (temp_string, tlist->word->word))
9312 w->flags = tlist->word->flags;
51f7ea36
CR
9313 else
9314 w = make_word_flags (w, temp_string);
9315
cce855bc 9316 output_list = make_word_list (w, output_list);
726f6388 9317 }
cce855bc 9318 free (expansions);
726f6388 9319
cce855bc
JA
9320 /* Add TLIST to the list of words to be freed after brace
9321 expansion has been performed. */
9322 PREPEND_LIST (tlist, disposables);
9323 }
9324 else
9325 PREPEND_LIST (tlist, output_list);
726f6388 9326 }
cce855bc
JA
9327
9328 if (disposables)
9329 dispose_words (disposables);
9330
9331 if (output_list)
9332 output_list = REVERSE_LIST (output_list, WORD_LIST *);
9333
9334 return (output_list);
9335}
9336#endif
9337
fdf670ea
CR
9338#if defined (ARRAY_VARS)
9339/* Take WORD, a compound associative array assignment, and internally run
9340 'declare -A w', where W is the variable name portion of WORD. */
9341static int
9342make_internal_declare (word, option)
9343 char *word;
9344 char *option;
9345{
9346 int t;
9347 WORD_LIST *wl;
9348 WORD_DESC *w;
9349
9350 w = make_word (word);
9351
9352 t = assignment (w->word, 0);
9353 w->word[t] = '\0';
9354
9355 wl = make_word_list (w, (WORD_LIST *)NULL);
9356 wl = make_word_list (make_word (option), wl);
9357
9358 return (declare_builtin (wl));
9359}
9360#endif
9361
cce855bc
JA
9362static WORD_LIST *
9363shell_expand_word_list (tlist, eflags)
9364 WORD_LIST *tlist;
9365 int eflags;
9366{
9367 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list;
9368 int expanded_something, has_dollar_at;
9369 char *temp_string;
726f6388 9370
726f6388 9371 /* We do tilde expansion all the time. This is what 1003.2 says. */
cce855bc
JA
9372 new_list = (WORD_LIST *)NULL;
9373 for (orig_list = tlist; tlist; tlist = next)
726f6388 9374 {
ccc6cda3 9375 temp_string = tlist->word->word;
726f6388
JA
9376
9377 next = tlist->next;
9378
43df7bbb
CR
9379#if defined (ARRAY_VARS)
9380 /* If this is a compound array assignment to a builtin that accepts
9381 such assignments (e.g., `declare'), take the assignment and perform
9382 it separately, handling the semantics of declarations inside shell
9383 functions. This avoids the double-evaluation of such arguments,
9384 because `declare' does some evaluation of compound assignments on
9385 its own. */
9386 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
9387 {
9388 int t;
9389
3087e51c
CR
9390 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
9391 make_internal_declare (tlist->word->word, "-gA");
9392 else if (tlist->word->flags & W_ASSIGNASSOC)
fdf670ea 9393 make_internal_declare (tlist->word->word, "-A");
1a81420a 9394 else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
36eb585c
CR
9395 make_internal_declare (tlist->word->word, "-ga");
9396 else if (tlist->word->flags & W_ASSIGNARRAY)
9397 make_internal_declare (tlist->word->word, "-a");
3087e51c
CR
9398 else if (tlist->word->flags & W_ASSNGLOBAL)
9399 make_internal_declare (tlist->word->word, "-g");
fdf670ea 9400
adc6cff5 9401 t = do_word_assignment (tlist->word, 0);
43df7bbb
CR
9402 if (t == 0)
9403 {
9404 last_command_exit_value = EXECUTION_FAILURE;
9405 exp_jump_to_top_level (DISCARD);
9406 }
9407
9408 /* Now transform the word as ksh93 appears to do and go on */
9409 t = assignment (tlist->word->word, 0);
9410 tlist->word->word[t] = '\0';
36eb585c 9411 tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
43df7bbb
CR
9412 }
9413#endif
9414
ccc6cda3 9415 expanded_something = 0;
726f6388 9416 expanded = expand_word_internal
b72432fd 9417 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
726f6388
JA
9418
9419 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
9420 {
9421 /* By convention, each time this error is returned,
9422 tlist->word->word has already been freed. */
9423 tlist->word->word = (char *)NULL;
ccc6cda3 9424
726f6388
JA
9425 /* Dispose our copy of the original list. */
9426 dispose_words (orig_list);
d166f048 9427 /* Dispose the new list we're building. */
726f6388
JA
9428 dispose_words (new_list);
9429
28ef6c31 9430 last_command_exit_value = EXECUTION_FAILURE;
726f6388 9431 if (expanded == &expand_word_error)
d3a24ed2 9432 exp_jump_to_top_level (DISCARD);
726f6388 9433 else
d3a24ed2 9434 exp_jump_to_top_level (FORCE_EOF);
726f6388
JA
9435 }
9436
ccc6cda3
JA
9437 /* Don't split words marked W_NOSPLIT. */
9438 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
726f6388 9439 {
ccc6cda3 9440 temp_list = word_list_split (expanded);
726f6388
JA
9441 dispose_words (expanded);
9442 }
9443 else
9444 {
9445 /* If no parameter expansion, command substitution, process
9446 substitution, or arithmetic substitution took place, then
9447 do not do word splitting. We still have to remove quoted
9448 null characters from the result. */
9449 word_list_remove_quoted_nulls (expanded);
ccc6cda3 9450 temp_list = expanded;
726f6388
JA
9451 }
9452
ccc6cda3
JA
9453 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
9454 new_list = (WORD_LIST *)list_append (expanded, new_list);
726f6388
JA
9455 }
9456
cce855bc
JA
9457 if (orig_list)
9458 dispose_words (orig_list);
726f6388 9459
726f6388 9460 if (new_list)
cce855bc 9461 new_list = REVERSE_LIST (new_list, WORD_LIST *);
726f6388 9462
cce855bc
JA
9463 return (new_list);
9464}
726f6388 9465
cce855bc
JA
9466/* The workhorse for expand_words () and expand_words_no_vars ().
9467 First arg is LIST, a WORD_LIST of words.
b72432fd
JA
9468 Second arg EFLAGS is a flags word controlling which expansions are
9469 performed.
726f6388 9470
cce855bc
JA
9471 This does all of the substitutions: brace expansion, tilde expansion,
9472 parameter expansion, command substitution, arithmetic expansion,
9473 process substitution, word splitting, and pathname expansion, according
9474 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
9475 set, or for which no expansion is done, do not undergo word splitting.
df0e4bfe
CR
9476 Words with the W_NOGLOB bit set do not undergo pathname expansion; words
9477 with W_NOBRACE set do not undergo brace expansion (see
9478 brace_expand_word_list above). */
cce855bc
JA
9479static WORD_LIST *
9480expand_word_list_internal (list, eflags)
9481 WORD_LIST *list;
9482 int eflags;
9483{
9484 WORD_LIST *new_list, *temp_list;
9485 int tint;
726f6388 9486
f0c4de40 9487 tempenv_assign_error = 0;
cce855bc
JA
9488 if (list == 0)
9489 return ((WORD_LIST *)NULL);
726f6388 9490
bb70624e 9491 garglist = new_list = copy_word_list (list);
cce855bc
JA
9492 if (eflags & WEXP_VARASSIGN)
9493 {
bb70624e 9494 garglist = new_list = separate_out_assignments (new_list);
cce855bc
JA
9495 if (new_list == 0)
9496 {
bb70624e 9497 if (subst_assign_varlist)
cce855bc
JA
9498 {
9499 /* All the words were variable assignments, so they are placed
9500 into the shell's environment. */
bb70624e 9501 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
cce855bc
JA
9502 {
9503 this_command_name = (char *)NULL; /* no arithmetic errors */
adc6cff5 9504 tint = do_word_assignment (temp_list->word, 0);
cce855bc
JA
9505 /* Variable assignment errors in non-interactive shells
9506 running in Posix.2 mode cause the shell to exit. */
28ef6c31 9507 if (tint == 0)
ccc6cda3 9508 {
cce855bc 9509 last_command_exit_value = EXECUTION_FAILURE;
28ef6c31 9510 if (interactive_shell == 0 && posixly_correct)
d3a24ed2 9511 exp_jump_to_top_level (FORCE_EOF);
28ef6c31 9512 else
d3a24ed2 9513 exp_jump_to_top_level (DISCARD);
ccc6cda3 9514 }
726f6388 9515 }
bb70624e
JA
9516 dispose_words (subst_assign_varlist);
9517 subst_assign_varlist = (WORD_LIST *)NULL;
cce855bc
JA
9518 }
9519 return ((WORD_LIST *)NULL);
9520 }
9521 }
726f6388 9522
cce855bc
JA
9523 /* Begin expanding the words that remain. The expansions take place on
9524 things that aren't really variable assignments. */
726f6388 9525
cce855bc
JA
9526#if defined (BRACE_EXPANSION)
9527 /* Do brace expansion on this word if there are any brace characters
9528 in the string. */
9529 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
9530 new_list = brace_expand_word_list (new_list, eflags);
9531#endif /* BRACE_EXPANSION */
726f6388 9532
cce855bc
JA
9533 /* Perform the `normal' shell expansions: tilde expansion, parameter and
9534 variable substitution, command substitution, arithmetic expansion,
9535 and word splitting. */
9536 new_list = shell_expand_word_list (new_list, eflags);
726f6388 9537
cce855bc
JA
9538 /* Okay, we're almost done. Now let's just do some filename
9539 globbing. */
9540 if (new_list)
9541 {
9542 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
9543 /* Glob expand the word list unless globbing has been disabled. */
9544 new_list = glob_expand_word_list (new_list, eflags);
726f6388 9545 else
cce855bc
JA
9546 /* Dequote the words, because we're not performing globbing. */
9547 new_list = dequote_list (new_list);
726f6388
JA
9548 }
9549
bb70624e 9550 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
726f6388 9551 {
43df7bbb 9552 sh_wassign_func_t *assign_func;
adc6cff5 9553 int is_special_builtin, is_builtin_or_func;
726f6388
JA
9554
9555 /* If the remainder of the words expand to nothing, Posix.2 requires
9556 that the variable and environment assignments affect the shell's
9557 environment. */
43df7bbb 9558 assign_func = new_list ? assign_in_env : do_word_assignment;
56299fa5 9559 tempenv_assign_error = 0;
726f6388 9560
adc6cff5 9561 is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
e05be32d
CR
9562 /* Posix says that special builtins exit if a variable assignment error
9563 occurs in an assignment preceding it. */
adc6cff5 9564 is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
e05be32d 9565
bb70624e 9566 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
726f6388 9567 {
ccc6cda3 9568 this_command_name = (char *)NULL;
d7f49990 9569 assigning_in_environment = (assign_func == assign_in_env);
adc6cff5 9570 tint = (*assign_func) (temp_list->word, is_builtin_or_func);
d7f49990 9571 assigning_in_environment = 0;
ccc6cda3
JA
9572 /* Variable assignment errors in non-interactive shells running
9573 in Posix.2 mode cause the shell to exit. */
56299fa5 9574 if (tint == 0)
ccc6cda3 9575 {
43df7bbb 9576 if (assign_func == do_word_assignment)
56299fa5
CR
9577 {
9578 last_command_exit_value = EXECUTION_FAILURE;
e05be32d 9579 if (interactive_shell == 0 && posixly_correct && is_special_builtin)
56299fa5
CR
9580 exp_jump_to_top_level (FORCE_EOF);
9581 else
9582 exp_jump_to_top_level (DISCARD);
9583 }
28ef6c31 9584 else
56299fa5 9585 tempenv_assign_error++;
ccc6cda3 9586 }
726f6388 9587 }
726f6388 9588
bb70624e
JA
9589 dispose_words (subst_assign_varlist);
9590 subst_assign_varlist = (WORD_LIST *)NULL;
726f6388
JA
9591 }
9592
cce855bc 9593 return (new_list);
ccc6cda3 9594}