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