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