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