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