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