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