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