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