]> git.ipfire.org Git - thirdparty/bash.git/blame - subst.c
commit bash-20091223 snapshot
[thirdparty/bash.git] / subst.c
CommitLineData
cc87ba64
CR
1/* subst.c -- The part of the shell that does parameter, command, arithmetic,
2 and globbing substitutions. */
726f6388 3
bb70624e
JA
4/* ``Have a little faith, there's magic in the night. You ain't a
5 beauty, but, hey, you're alright.'' */
6
012bac39 7/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
726f6388
JA
8
9 This file is part of GNU Bash, the Bourne Again SHell.
10
2e4498b3
CR
11 Bash is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 Bash is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with Bash. If not, see <http://www.gnu.org/licenses/>.
23*/
726f6388 24
ccc6cda3
JA
25#include "config.h"
26
726f6388
JA
27#include "bashtypes.h"
28#include <stdio.h>
f73dda09 29#include "chartypes.h"
e77a3058
CR
30#if defined (HAVE_PWD_H)
31# include <pwd.h>
32#endif
726f6388
JA
33#include <signal.h>
34#include <errno.h>
ccc6cda3
JA
35
36#if defined (HAVE_UNISTD_H)
37# include <unistd.h>
38#endif
726f6388
JA
39
40#include "bashansi.h"
41#include "posixstat.h"
5e13499c 42#include "bashintl.h"
726f6388
JA
43
44#include "shell.h"
45#include "flags.h"
46#include "jobs.h"
47#include "execute_cmd.h"
48#include "filecntl.h"
ccc6cda3
JA
49#include "trap.h"
50#include "pathexp.h"
51#include "mailcheck.h"
52
7117c2d2
JA
53#include "shmbutil.h"
54
ccc6cda3
JA
55#include "builtins/getopt.h"
56#include "builtins/common.h"
726f6388 57
48ff5447
CR
58#include "builtins/builtext.h"
59
cce855bc 60#include <tilde/tilde.h>
f73dda09 61#include <glob/strmatch.h>
ccc6cda3
JA
62
63#if !defined (errno)
64extern int errno;
65#endif /* !errno */
726f6388
JA
66
67/* The size that strings change by. */
d166f048 68#define DEFAULT_INITIAL_ARRAY_SIZE 112
ccc6cda3
JA
69#define DEFAULT_ARRAY_SIZE 128
70
71/* Variable types. */
72#define VT_VARIABLE 0
73#define VT_POSPARMS 1
74#define VT_ARRAYVAR 2
d166f048 75#define VT_ARRAYMEMBER 3
e33f2203 76#define VT_ASSOCVAR 4
726f6388 77
d3a24ed2
CR
78#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
79
ccc6cda3
JA
80/* Flags for quoted_strchr */
81#define ST_BACKSL 0x01
82#define ST_CTLESC 0x02
7117c2d2
JA
83#define ST_SQUOTE 0x04 /* unused yet */
84#define ST_DQUOTE 0x08 /* unused yet */
85
d3a24ed2
CR
86/* Flags for the `pflags' argument to param_expand() */
87#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
1231ac47 88#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */
e1e48bba 89#define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 */
d3a24ed2 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
176b12ee
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];
633e5c6d
CR
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;
633e5c6d 141#endif
7117c2d2 142
0527c903
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. */
d7f49990
CR
146int assigning_in_environment;
147
0527c903
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. */
d3a24ed2 154extern int last_command_exit_value, last_command_exit_signal;
f486d0a1
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;
d3a24ed2 164extern int expanding_redir;
56299fa5 165extern int tempenv_assign_error;
726f6388 166
d3ad40de
CR
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
d3a24ed2
CR
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;
227f982e 188static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
726f6388 189static char expand_param_error, expand_param_fatal;
7027abcb 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
43df7bbb
CR
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
d3ad40de 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 *));
d3ad40de 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));
6932f7f5 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
545f34cf
CR
239static unsigned char *mb_getcharlens __P((char *, int));
240
704a1a2a 241static char *remove_upattern __P((char *, char *, int));
d3ad40de 242#if defined (HANDLE_MULTIBYTE)
704a1a2a
CR
243static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int));
244#endif
f73dda09 245static char *remove_pattern __P((char *, char *, int));
704a1a2a 246
f73dda09 247static int match_pattern_char __P((char *, char *));
704a1a2a
CR
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
fdf670ea 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
d3ad40de 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));
d3a24ed2 273static int chk_atstar __P((char *, int, int *, int *));
d3ad40de 274static int chk_arithsub __P((const char *, int));
d3a24ed2 275
1231ac47 276static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int));
227f982e
CR
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));
09767ff0 285static int verify_substring_values __P((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
762a763b 286static int get_var_and_type __P((char *, char *, int, SHELL_VAR **, char **));
545f34cf 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
09767ff0
CR
294static char *pos_params_casemod __P((char *, char *, int, int));
295static char *parameter_brace_casemod __P((char *, char *, int, char *, int));
296
e1e48bba 297static WORD_DESC *parameter_brace_expand __P((char *, int *, int, int, int *, int *));
227f982e 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
d3a24ed2
CR
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
fdf670ea
CR
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
9dd88db7
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.
e6598ba4 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.
e6598ba4
CR
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
7027abcb 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;
7027abcb 704 int found;
7117c2d2 705 size_t slen;
726f6388 706 char *temp;
7117c2d2 707 DECLARE_MBSTATE;
726f6388 708
da713c23 709 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
7117c2d2 710 i = *sindex;
7027abcb 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)
e6598ba4 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. */
3eb2d94a 726 ni = skipsubscript (string, i, 0);
ccc6cda3
JA
727 if (string[ni] == ']')
728 i = ni;
729 }
730#endif
731 else if (MEMBER (c, charlist))
7027abcb
CR
732 {
733 found = 1;
726f6388 734 break;
7027abcb 735 }
7117c2d2
JA
736
737 ADVANCE_CHAR (string, slen, i);
726f6388 738 }
bb70624e 739
7027abcb
CR
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. */
e6598ba4 742 if ((flags & SX_REQMATCH) && found == 0)
7027abcb
CR
743 {
744 *sindex = i;
745 return (&extract_string_error);
746 }
747
e6598ba4 748 temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
726f6388 749 *sindex = i;
7027abcb 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 {
61deeb13
CR
855 int free_ret = 1;
856
ccc6cda3 857 si = i + 2;
cce855bc 858 if (string[i + 1] == LPAREN)
e33f2203 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
61deeb13
CR
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];
56299fa5
CR
876 temp[j] = string[si];
877
878 if (string[si])
879 {
880 j++;
881 i = si + 1;
882 }
883 else
884 i = si;
726f6388 885
61deeb13
CR
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)
e33f2203 961 ret = extract_command_subst (string, &si, SX_NOALLOC);
ccc6cda3 962 else
8e1a6eaa 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
da713c23
CR
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)
d3ad40de 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 *
d3ad40de 1033string_extract_verbatim (string, slen, sindex, charlist, flags)
f73dda09 1034 char *string;
da713c23 1035 size_t slen;
ccc6cda3 1036 int *sindex;
f73dda09 1037 char *charlist;
d3ad40de 1038 int flags;
ccc6cda3 1039{
824dfe68 1040 register int i;
633e5c6d
CR
1041#if defined (HANDLE_MULTIBYTE)
1042 size_t clen;
1043 wchar_t *wcharlist;
1044#endif
ccc6cda3
JA
1045 int c;
1046 char *temp;
633e5c6d 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
633e5c6d 1056 i = *sindex;
da713c23
CR
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
633e5c6d
CR
1062#if defined (HANDLE_MULTIBYTE)
1063 clen = strlen (charlist);
1064 wcharlist = 0;
1065#endif
1066 while (c = string[i])
ccc6cda3 1067 {
633e5c6d
CR
1068#if defined (HANDLE_MULTIBYTE)
1069 size_t mblength;
1070#endif
e6598ba4
CR
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 {
633e5c6d 1081 i += 2;
ccc6cda3
JA
1082 continue;
1083 }
e33f2203 1084
633e5c6d 1085#if defined (HANDLE_MULTIBYTE)
da713c23 1086 mblength = MBLEN (string + i, slen - i);
633e5c6d
CR
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;
d3ad40de
CR
1104 wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
1105 mbstowcs (wcharlist, charlist, len + 1);
633e5c6d
CR
1106 }
1107
1108 if (wcschr (wcharlist, wc))
1109 break;
1110 }
1111 }
1112 else
1113#endif
ccc6cda3
JA
1114 if (MEMBER (c, charlist))
1115 break;
633e5c6d
CR
1116
1117 ADVANCE_CHAR (string, slen, i);
ccc6cda3
JA
1118 }
1119
633e5c6d
CR
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 "$(".
e33f2203 1132 Make (SINDEX) get the position of the matching ")". )
ecf57862 1133 XFLAGS is additional flags to pass to other extraction functions. */
ccc6cda3 1134char *
e33f2203 1135extract_command_subst (string, sindex, xflags)
726f6388
JA
1136 char *string;
1137 int *sindex;
e33f2203 1138 int xflags;
726f6388 1139{
176b12ee 1140 if (string[*sindex] == LPAREN)
e33f2203
CR
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)
43df7bbb
CR
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{
43df7bbb
CR
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 }
e225d5a9 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;
d3ad40de 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
d3ad40de 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
d3ad40de
CR
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
d3ad40de 1251 /* Not exactly right yet; should handle shell metacharacters and
602bb739 1252 multibyte characters, too. See COMMENT_BEGIN define in parse.y */
e33f2203 1253 if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
d3ad40de
CR
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
ecf57862
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;
e6598ba4 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;
e6598ba4 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;
e6598ba4 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
d3a24ed2 1329 if (c == 0 && nesting_level)
726f6388 1330 {
d3a24ed2
CR
1331 if (no_longjmp_on_fatal_error == 0)
1332 {
5e13499c 1333 report_error (_("bad substitution: no closing `%s' in %s"), closer, string);
d3a24ed2
CR
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;
e6598ba4 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;
e6598ba4 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;
e33f2203 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
d3a24ed2 1450 if (c == 0 && nesting_level)
cce855bc 1451 {
d3a24ed2
CR
1452 if (no_longjmp_on_fatal_error == 0)
1453 { /* { */
d3ad40de 1454 report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
d3a24ed2
CR
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
e6598ba4 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)
704a1a2a 1493 do string[j++] = string[prev_i++]; while (prev_i < i);
7117c2d2 1494 else
704a1a2a 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
4d8d005b
CR
1527#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
1528
6932f7f5 1529/* This function assumes s[i] == open; returns with s[ret] == close; used to
3eb2d94a
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()). */
6932f7f5
CR
1534static int
1535skip_matched_pair (string, start, open, close, flags)
76af2125 1536 const char *string;
6932f7f5 1537 int start, open, close, flags;
76af2125
CR
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 }
3eb2d94a 1574 else if ((flags & 1) == 0 && c == '`')
76af2125
CR
1575 {
1576 backq = 1;
1577 i++;
1578 continue;
1579 }
3eb2d94a 1580 else if ((flags & 1) == 0 && c == open)
76af2125
CR
1581 {
1582 count++;
1583 i++;
1584 continue;
1585 }
6932f7f5 1586 else if (c == close)
76af2125
CR
1587 {
1588 count--;
1589 if (count == 0)
1590 break;
1591 i++;
1592 continue;
1593 }
3eb2d94a 1594 else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
76af2125
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 }
3eb2d94a 1600 else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
76af2125
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
6932f7f5
CR
1623#if defined (ARRAY_VARS)
1624int
3eb2d94a 1625skipsubscript (string, start, flags)
6932f7f5 1626 const char *string;
3eb2d94a 1627 int start, flags;
6932f7f5 1628{
3eb2d94a 1629 return (skip_matched_pair (string, start, '[', ']', flags));
6932f7f5
CR
1630}
1631#endif
1632
c2a47ea9
CR
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
4d8d005b 1640skip_to_delim (string, start, delims, flags)
c2a47ea9
CR
1641 char *string;
1642 int start;
1643 char *delims;
4d8d005b 1644 int flags;
c2a47ea9 1645{
176b12ee 1646 int i, pass_next, backq, si, c, invert, skipquote, skipcmd;
c2a47ea9
CR
1647 size_t slen;
1648 char *temp;
1649 DECLARE_MBSTATE;
1650
1651 slen = strlen (string + start) + start;
4d8d005b
CR
1652 if (flags & SD_NOJMP)
1653 no_longjmp_on_fatal_error = 1;
8c2fef19 1654 invert = (flags & SD_INVERT);
176b12ee 1655 skipcmd = (flags & SD_NOSKIPCMD) == 0;
8c2fef19 1656
c2a47ea9
CR
1657 i = start;
1658 pass_next = backq = 0;
1659 while (c = string[i])
1660 {
a8fd3f3e
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 =='"'));
c2a47ea9
CR
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 }
a8fd3f3e 1693 else if (skipquote == 0 && invert == 0 && member (c, delims))
8c2fef19 1694 break;
c2a47ea9
CR
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 }
176b12ee 1701 else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
c2a47ea9
CR
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 }
176b12ee
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 */
a8fd3f3e 1731 else if ((skipquote || invert) && (member (c, delims) == 0))
c2a47ea9
CR
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
d3a24ed2
CR
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 *
a8fd3f3e 1849split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
bb70624e
JA
1850 char *string;
1851 int slen;
1852 char *delims;
a8fd3f3e 1853 int sentinel, flags;
bb70624e
JA
1854 int *nwp, *cwp;
1855{
a8fd3f3e 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;
d3a24ed2 1870 ifs_split = delims == 0;
bb70624e
JA
1871
1872 /* Make d2 the non-whitespace characters in delims */
1873 d2 = 0;
1874 if (delims)
1875 {
633e5c6d
CR
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 {
633e5c6d 1887#if defined (HANDLE_MULTIBYTE)
d3ad40de
CR
1888 mbstate_t state_bak;
1889 state_bak = state;
633e5c6d
CR
1890 mblength = MBRLEN (delims + i, slength, &state);
1891 if (MB_INVALIDCH (mblength))
1892 state = state_bak;
22e63b05 1893 else if (mblength > 1)
633e5c6d
CR
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];
633e5c6d
CR
1904
1905 i++;
1906 slength--;
bb70624e
JA
1907 }
1908 d2[ts] = '\0';
1909 }
1910
1911 ret = (WORD_LIST *)NULL;
1912
dfc21851 1913 /* Remove sequences of whitespace characters at the start of the string, as
d3a24ed2
CR
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;
a8fd3f3e 1923 dflags = flags|SD_NOJMP;
bb70624e
JA
1924 while (1)
1925 {
a8fd3f3e 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;
d3a24ed2
CR
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
d3a24ed2
CR
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
dfc21851
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
5e13499c 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
12d937f9
CR
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
c2a47ea9
CR
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{
dc8fbaf9 2138 char *ret;
633e5c6d 2139#if defined (HANDLE_MULTIBYTE)
dc8fbaf9 2140# if defined (__GNUC__)
633e5c6d 2141 char sep[MB_CUR_MAX + 1];
dc8fbaf9
CR
2142# else
2143 char *sep = 0;
2144# endif
633e5c6d 2145#else
7117c2d2 2146 char sep[2];
633e5c6d
CR
2147#endif
2148
633e5c6d 2149#if defined (HANDLE_MULTIBYTE)
dc8fbaf9
CR
2150# if !defined (__GNUC__)
2151 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2152# endif /* !__GNUC__ */
633e5c6d
CR
2153 if (ifs_firstc_len == 1)
2154 {
2155 sep[0] = ifs_firstc[0];
2156 sep[1] = '\0';
2157 }
2158 else
da713c23
CR
2159 {
2160 memcpy (sep, ifs_firstc, ifs_firstc_len);
2161 sep[ifs_firstc_len] = '\0';
2162 }
633e5c6d 2163#else
7117c2d2 2164 sep[0] = ifs_firstc;
726f6388 2165 sep[1] = '\0';
633e5c6d 2166#endif
726f6388 2167
dc8fbaf9
CR
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{
227f982e 2189 char *ifs, *ret;
633e5c6d 2190#if defined (HANDLE_MULTIBYTE)
dc8fbaf9 2191# if defined (__GNUC__)
633e5c6d 2192 char sep[MB_CUR_MAX + 1];
dc8fbaf9
CR
2193# else
2194 char *sep = 0;
2195# endif /* !__GNUC__ */
633e5c6d
CR
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
633e5c6d 2204#if defined (HANDLE_MULTIBYTE)
dc8fbaf9
CR
2205# if !defined (__GNUC__)
2206 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2207# endif /* !__GNUC__ */
633e5c6d
CR
2208 if (ifs && *ifs)
2209 {
227f982e 2210 if (ifs_firstc_len == 1)
633e5c6d 2211 {
227f982e 2212 sep[0] = ifs_firstc[0];
633e5c6d
CR
2213 sep[1] = '\0';
2214 }
2215 else
2216 {
227f982e
CR
2217 memcpy (sep, ifs_firstc, ifs_firstc_len);
2218 sep[ifs_firstc_len] = '\0';
633e5c6d
CR
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';
633e5c6d 2229#endif
cce855bc 2230
d3ad40de
CR
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))
d3ad40de 2235#else
1231ac47 2236 tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
d3ad40de 2237#endif
cce855bc
JA
2238 ? quote_list (list)
2239 : list_quote_escapes (list);
dc8fbaf9
CR
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
e33f2203
CR
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. */
d3a24ed2
CR
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;
e6598ba4 2337 int sindex, sh_style_split, whitesep, xflags;
633e5c6d 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';
e6598ba4
CR
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
633e5c6d 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. */
da713c23 2372 slen = (MB_CUR_MAX > 1) ? strlen (string) : 1;
ccc6cda3 2373 for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
726f6388 2374 {
da713c23
CR
2375 /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
2376 unless multibyte chars are possible. */
e6598ba4 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 {
227f982e 2387 t = alloc_word_desc ();
726f6388 2388 t->word = make_quoted_char ('\0');
227f982e 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);
227f982e 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 {
227f982e 2407 t = alloc_word_desc ();
ccc6cda3 2408 t->word = make_quoted_char ('\0');
227f982e 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])
633e5c6d
CR
2420 {
2421 DECLARE_MBSTATE;
633e5c6d
CR
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]))
9d2b70f0
CR
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) */
d3ad40de 2439 while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex]))
9d2b70f0
CR
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;
e6598ba4 2459 int sindex, sh_style_split, whitesep, xflags;
633e5c6d 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';
e6598ba4
CR
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
e6598ba4 2475 s = *stringp;
633e5c6d
CR
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;
da713c23
CR
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;
e6598ba4 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])
633e5c6d
CR
2515 {
2516 DECLARE_MBSTATE;
633e5c6d
CR
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]))
9d2b70f0
CR
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
43df7bbb
CR
2624#if defined (ARRAY_VARS)
2625static SHELL_VAR *
d11b8b46 2626do_compound_assignment (name, value, flags)
43df7bbb 2627 char *name, *value;
d11b8b46 2628 int flags;
43df7bbb
CR
2629{
2630 SHELL_VAR *v;
09767ff0 2631 int mklocal, mkassoc;
d3ad40de 2632 WORD_LIST *list;
d11b8b46
CR
2633
2634 mklocal = flags & ASS_MKLOCAL;
09767ff0 2635 mkassoc = flags & ASS_MKASSOC;
43df7bbb
CR
2636
2637 if (mklocal && variable_context)
2638 {
2639 v = find_variable (name);
fdf670ea 2640 list = expand_compound_array_assignment (v, value, flags);
09767ff0
CR
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)
43df7bbb 2644 v = make_local_array_variable (name);
d3ad40de 2645 assign_compound_array_list (v, list, flags);
43df7bbb
CR
2646 }
2647 else
d11b8b46 2648 v = assign_array_from_string (name, value, flags);
43df7bbb
CR
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
43df7bbb
CR
2660do_assignment_internal (word, expand)
2661 const WORD_DESC *word;
726f6388
JA
2662 int expand;
2663{
cb603128 2664 int offset, tlen, appendop, assign_list, aflags, retval;
d3ad40de 2665 char *name, *value;
ccc6cda3
JA
2666 SHELL_VAR *entry;
2667#if defined (ARRAY_VARS)
2668 char *t;
1d7ecd77 2669 int ni;
ccc6cda3 2670#endif
43df7bbb 2671 const char *string;
ccc6cda3 2672
43df7bbb
CR
2673 if (word == 0 || word->word == 0)
2674 return 0;
2675
d11b8b46 2676 appendop = assign_list = aflags = 0;
43df7bbb 2677 string = word->word;
5e13499c 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
d11b8b46
CR
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;
43df7bbb 2694 tlen = STRLEN (temp);
726f6388 2695
ccc6cda3 2696#if defined (ARRAY_VARS)
43df7bbb 2697 if (expand && (word->flags & W_COMPASSIGN))
726f6388 2698 {
ccc6cda3 2699 assign_list = ni = 1;
43df7bbb 2700 value = extract_array_assignment_list (temp, &ni);
ccc6cda3
JA
2701 }
2702 else
2703#endif
ccc6cda3 2704 if (expand && temp[0])
22e63b05 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)
d11b8b46
CR
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
d11b8b46
CR
2727 if (appendop)
2728 aflags |= ASS_APPEND;
2729
ccc6cda3 2730#if defined (ARRAY_VARS)
d0ca3503 2731 if (t = mbschr (name, '[')) /*]*/
ccc6cda3
JA
2732 {
2733 if (assign_list)
2734 {
5e13499c 2735 report_error (_("%s: cannot assign list to array member"), name);
ccc6cda3
JA
2736 ASSIGN_RETURN (0);
2737 }
d11b8b46 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)
d11b8b46
CR
2743 {
2744 if (word->flags & W_ASSIGNARG)
2745 aflags |= ASS_MKLOCAL;
09767ff0
CR
2746 if (word->flags & W_ASSIGNASSOC)
2747 aflags |= ASS_MKASSOC;
d11b8b46
CR
2748 entry = do_compound_assignment (name, value, aflags);
2749 }
ccc6cda3
JA
2750 else
2751#endif /* ARRAY_VARS */
d11b8b46 2752 entry = bind_variable (name, value, aflags);
ccc6cda3 2753
726f6388
JA
2754 stupidly_hack_special_variables (name);
2755
cb603128
CR
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;
cb603128 2767
09767ff0 2768 if (entry && retval != 0 && noassign_p (entry) == 0)
cb603128 2769 VUNSETATTR (entry, att_invisible);
09767ff0
CR
2770
2771 ASSIGN_RETURN (retval);
cb603128 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);
cb603128 2777#endif
726f6388
JA
2778}
2779
2780/* Perform the assignment statement in STRING, and expand the
43df7bbb 2781 right side by doing tilde, command and parameter expansion. */
ccc6cda3 2782int
726f6388 2783do_assignment (string)
43df7bbb 2784 char *string;
726f6388 2785{
43df7bbb
CR
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
43df7bbb
CR
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)
43df7bbb 2806 char *string;
726f6388 2807{
43df7bbb
CR
2808 WORD_DESC td;
2809
2810 td.flags = W_ASSIGNMENT;
2811 td.word = string;
2812
e225d5a9 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
d3ad40de
CR
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
0527c903 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;
e33f2203
CR
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)
22e63b05 2944#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~')
cce855bc 2945#else
22e63b05 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
da713c23
CR
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
43df7bbb
CR
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
dc8fbaf9 3043char *
d3ad40de 3044expand_arith_string (string, quoted)
dc8fbaf9 3045 char *string;
48ff5447 3046 int quoted;
dc8fbaf9 3047{
d3ad40de 3048 return (expand_string_if_necessary (string, quoted, expand_string));
dc8fbaf9
CR
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
d3ad40de 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
d3ad40de
CR
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;
d3ad40de 3087 int qflags;
cce855bc
JA
3088
3089 if (w->word == 0 || w->word[0] == '\0')
3090 return ((char *)NULL);
3091
e1e48bba 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 {
d3ad40de
CR
3103 qflags = QGLOB_CVTNULL;
3104 if (special == 2)
3105 qflags |= QGLOB_REGEXP;
28ef6c31 3106 p = string_list (l);
d3ad40de 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;
d3a24ed2 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)
227f982e
CR
3189 {
3190 remove_quoted_nulls (value->word->word);
3191 value->word->flags &= ~W_HASQUOTEDNULL;
3192 }
726f6388
JA
3193 dequote_list (value);
3194 }
3195 return (value);
3196}
3197
22e63b05
CR
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)
227f982e
CR
3222 {
3223 remove_quoted_nulls (value->word->word);
3224 value->word->flags &= ~W_HASQUOTEDNULL;
3225 }
22e63b05
CR
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 *
4d8d005b 3237expand_prompt_string (string, quoted, wflags)
bb70624e
JA
3238 char *string;
3239 int quoted;
4d8d005b 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
4d8d005b 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)
227f982e
CR
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
e6598ba4
CR
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;
e6598ba4 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
d3ad40de 3372 quote_spaces = (ifs_value && *ifs_value == 0);
e6598ba4
CR
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 {
e6598ba4 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. */
09767ff0 3417char *
cce855bc
JA
3418dequote_escapes (string)
3419 char *string;
3420{
e6598ba4 3421 register char *s, *t, *s1;
7117c2d2
JA
3422 size_t slen;
3423 char *result, *send;
d3ad40de 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)
e6598ba4 3436 return (strcpy (result, string));
7117c2d2 3437
d3ad40de 3438 quote_spaces = (ifs_value && *ifs_value == 0);
e6598ba4
CR
3439
3440 s = string;
7117c2d2 3441 while (*s)
cce855bc 3442 {
d3ad40de 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
d3ad40de
CR
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
d3ad40de
CR
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
d3ad40de 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);
e33f2203
CR
3569 if (*t == 0)
3570 w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
ccc6cda3 3571 w->word->flags |= W_QUOTED;
e33f2203 3572 free (t);
726f6388 3573 }
ccc6cda3 3574 return list;
726f6388
JA
3575}
3576
d3ad40de
CR
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);
e33f2203
CR
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. */
b0c16657 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. */
09767ff0 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)
704a1a2a 3636 {
d3a24ed2
CR
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;
704a1a2a
CR
3642 if (i == slen)
3643 break;
3644 }
7117c2d2 3645 else if (string[i] == CTLNUL)
704a1a2a 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)
227f982e
CR
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
545f34cf 3683#if defined (HANDLE_MULTIBYTE)
704a1a2a 3684#if 0 /* Currently unused */
545f34cf
CR
3685static unsigned char *
3686mb_getcharlens (string, len)
3687 char *string;
3688 int len;
3689{
704a1a2a
CR
3690 int i, offset, last;
3691 unsigned char *ret;
545f34cf
CR
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
704a1a2a 3708#endif
545f34cf 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 *
704a1a2a 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 3730 register char *p, *ret, c;
726f6388 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 */
704a1a2a 3738 for (p = end; p >= param; p--)
726f6388
JA
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;
545f34cf 3747
726f6388
JA
3748 }
3749 break;
3750
3751 case RP_SHORT_LEFT: /* remove shortest match at start */
704a1a2a 3752 for (p = param; p <= end; p++)
726f6388
JA
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 3764 case RP_LONG_RIGHT: /* remove longest match at end */
704a1a2a 3765 for (p = param; p <= end; p++)
ccc6cda3 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 */
704a1a2a 3778 for (p = end; p >= param; p--)
ccc6cda3 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 }
704a1a2a
CR
3787 }
3788 break;
3789 }
3790
3791 return (savestring (param)); /* no match, return original string */
3792}
3793
3794#if defined (HANDLE_MULTIBYTE)
704a1a2a
CR
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{
d3ad40de
CR
3802 wchar_t wc, *ret;
3803 int n;
545f34cf 3804
704a1a2a
CR
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)
545f34cf 3812 {
704a1a2a
CR
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);
545f34cf 3855 }
ccc6cda3
JA
3856 }
3857 break;
3858 }
545f34cf 3859
704a1a2a
CR
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);
dc8fbaf9 3898 xret = (char *)xmalloc (n + 1);
704a1a2a
CR
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));
ccc6cda3
JA
3908}
3909
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
704a1a2a 3947match_upattern (string, pat, mtype, sp, ep)
ccc6cda3
JA
3948 char *string, *pat;
3949 int mtype;
3950 char **sp, **ep;
3951{
5e13499c 3952 int c, len;
233564d2 3953 register char *p, *p1, *npat;
ccc6cda3 3954 char *end;
ccc6cda3 3955
233564d2
CR
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);
176b12ee 3965 if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
233564d2 3966 {
dc8fbaf9 3967 p = npat = (char *)xmalloc (len + 3);
233564d2 3968 p1 = pat;
176b12ee 3969 if (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))
233564d2
CR
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
5e13499c
CR
3985 len = STRLEN (string);
3986 end = string + len;
ccc6cda3
JA
3987
3988 switch (mtype)
3989 {
3990 case MATCH_ANY:
704a1a2a 3991 for (p = string; p <= end; p++)
ccc6cda3
JA
3992 {
3993 if (match_pattern_char (pat, p))
3994 {
704a1a2a 3995 for (p1 = end; p1 >= p; p1--)
ccc6cda3
JA
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 }
545f34cf 4009
ccc6cda3
JA
4010 return (0);
4011
4012 case MATCH_BEG:
4013 if (match_pattern_char (pat, string) == 0)
28ef6c31 4014 return (0);
545f34cf 4015
704a1a2a 4016 for (p = end; p >= string; p--)
ccc6cda3
JA
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 }
545f34cf 4028
ccc6cda3 4029 return (0);
726f6388 4030
ccc6cda3 4031 case MATCH_END:
704a1a2a 4032 for (p = string; p <= end; p++)
545f34cf
CR
4033 {
4034 if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
4035 {
4036 *sp = p;
4037 *ep = end;
4038 return 1;
4039 }
4040
704a1a2a
CR
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{
233564d2 4092 wchar_t wc, *wp, *nwpat, *wp1;
704a1a2a
CR
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
233564d2
CR
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);
176b12ee 4109 if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
233564d2 4110 {
dc8fbaf9 4111 wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
233564d2 4112 wp1 = wpat;
176b12ee 4113 if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
233564d2
CR
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
704a1a2a
CR
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)
545f34cf 4176 {
704a1a2a
CR
4177 *sp = indices[n];
4178 *ep = indices[wstrlen];
4179 return 1;
545f34cf 4180 }
545f34cf 4181 }
704a1a2a 4182
ccc6cda3 4183 return (0);
726f6388 4184 }
ccc6cda3
JA
4185
4186 return (0);
726f6388 4187}
704a1a2a
CR
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;
d3ad40de 4257#if 0
cce855bc 4258 int i;
d3ad40de 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. */
22e63b05 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);
227f982e
CR
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 *);
e33f2203 4327 tword = string_list_pos_params (itype, l, quoted);
cce855bc 4328 dispose_words (l);
e33f2203 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 *
fdf670ea
CR
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{
fdf670ea
CR
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
fdf670ea
CR
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{
d3a24ed2 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
762a763b 4397 vtype = get_var_and_type (varname, value, quoted, &v, &val);
7117c2d2 4398 if (vtype == -1)
cce855bc
JA
4399 return ((char *)NULL);
4400
d3a24ed2
CR
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
c40a57dd
CR
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 {
e6598ba4
CR
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:
fdf670ea 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;
1231ac47
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
1231ac47
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{
1231ac47
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;
e1e48bba 4520 word->flags |= W_NOSPLIT2;
1231ac47
CR
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
d3ad40de
CR
4603int
4604fifos_pending ()
4605{
4606 return nfifo;
4607}
4608
726f6388
JA
4609static char *
4610make_named_pipe ()
4611{
4612 char *tname;
4613
d3ad40de 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;
626d0694 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
d3ad40de
CR
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
e141c35a 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 {
5e13499c 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
36211029 4768 if (pathname == 0)
726f6388 4769 {
5e13499c 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 */
d3a24ed2 4786 free_pushed_string_input ();
726f6388
JA
4787 /* Cancel traps, in trap.c. */
4788 restore_original_signals ();
4789 setup_async_signals ();
d3ad40de 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 ();
866961ad 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 {
5e13499c 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 {
5e13499c
CR
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 {
d3ad40de 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 {
5e13499c 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 *
d3ad40de 4910read_comsub (fd, quoted, rflag)
d166f048 4911 int fd, quoted;
d3ad40de 4912 int *rflag;
d166f048 4913{
e6598ba4
CR
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;
d3ad40de 4919 istring_index = istring_size = bufn = tflag = 0;
d166f048 4920
e6598ba4
CR
4921 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
4922 skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
4923
28ef6c31
JA
4924#ifdef __CYGWIN__
4925 setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */
4926#endif
4927
d3ad40de
CR
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
d3ad40de
CR
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. */
e6598ba4 4960 else if (skip_ctlesc == 0 && c == CTLESC)
d3ad40de
CR
4961 {
4962 tflag |= W_HASCTLESC;
4963 istring[istring_index++] = CTLESC;
4964 }
e6598ba4 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);
d3ad40de
CR
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
d3ad40de
CR
5015 if (rflag)
5016 *rflag = tflag;
d166f048
JA
5017 return istring;
5018}
5019
d3ad40de
CR
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{
cac4cdbf 5027 pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
ccc6cda3 5028 char *istring;
d3ad40de
CR
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]))
d3ad40de 5037 return ((WORD_DESC *)NULL);
726f6388 5038
cce855bc
JA
5039 if (wordexp_only && read_but_dont_execute)
5040 {
3eb2d94a 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
d3a24ed2 5057 /* Flags to pass to parse_and_execute() */
f486d0a1 5058 pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
d3a24ed2 5059
726f6388
JA
5060 /* Pipe the output of executing STRING into the current shell. */
5061 if (pipe (fildes) < 0)
5062 {
5e13499c 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 ();
da719982 5074#endif /* JOB_CONTROL */
726f6388 5075
cac4cdbf 5076 old_async_pid = last_asynchronous_pid;
cac4cdbf 5077 pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC);
cac4cdbf
CR
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)
525739ba 5086 /* XXX DO THIS ONLY IN PARENT ? XXX */
ccc6cda3
JA
5087 set_sigchld_handler ();
5088 stop_making_children ();
525739ba 5089 if (pid != 0)
525739ba 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 {
5e13499c 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]);
d3ad40de 5103 return ((WORD_DESC *)NULL);
726f6388
JA
5104 }
5105
5106 if (pid == 0)
5107 {
5108 set_sigint_handler (); /* XXX */
28ef6c31 5109
d3a24ed2
CR
5110 free_pushed_string_input ();
5111
726f6388
JA
5112 if (dup2 (fildes[1], 1) < 0)
5113 {
5e13499c 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
d3a24ed2 5160 if (result == ERREXIT)
5e13499c 5161 rc = last_command_exit_value;
d3a24ed2 5162 else if (result == EXITPROG)
5e13499c 5163 rc = last_command_exit_value;
726f6388 5164 else if (result)
5e13499c 5165 rc = EXECUTION_FAILURE;
bb70624e 5166 else if (function_value)
5e13499c 5167 rc = return_catch_value;
726f6388 5168 else
d3a24ed2
CR
5169 {
5170 subshell_level++;
5171 rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
5172 subshell_level--;
d3a24ed2 5173 }
5e13499c
CR
5174
5175 last_command_exit_value = rc;
5176 rc = run_exit_trap ();
d3ad40de
CR
5177#if defined (PROCESS_SUBSTITUTION)
5178 unlink_fifo_list ();
5179#endif
5e13499c 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
d3ad40de
CR
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. */
d3a24ed2 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
d3ad40de
CR
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;
fdf670ea 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. */
fdf670ea 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';
0d8616ff 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 {
fdf670ea
CR
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
fdf670ea
CR
5280 if (assoc_p (var))
5281 {
5282 t[len - 1] = '\0';
09767ff0 5283 akey = expand_assignment_string_to_string (t, 0); /* [ */
fdf670ea
CR
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
fdf670ea
CR
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
30915f17 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
d3a24ed2
CR
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 {
d0ca3503 5367 temp1 = mbschr (name, '[');
d3a24ed2
CR
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. */
227f982e 5394static WORD_DESC *
1231ac47 5395parameter_brace_expand_word (name, var_is_special, quoted, pflags)
726f6388 5396 char *name;
1231ac47 5397 int var_is_special, quoted, pflags;
726f6388 5398{
227f982e 5399 WORD_DESC *ret;
ccc6cda3 5400 char *temp, *tt;
7117c2d2 5401 intmax_t arg_index;
ccc6cda3 5402 SHELL_VAR *var;
b1a26c01 5403 int atype, rflags;
726f6388 5404
227f982e
CR
5405 ret = 0;
5406 temp = 0;
b1a26c01 5407 rflags = 0;
227f982e
CR
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);
762a763b
CR
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
227f982e 5428 ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
1231ac47 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)
762a763b
CR
5437 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5438 ? quote_string (temp)
5439 : quote_escapes (temp);
b1a26c01
CR
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)
fdf670ea
CR
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)
762a763b
CR
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
227f982e
CR
5470 if (ret == 0)
5471 {
5472 ret = alloc_word_desc ();
5473 ret->word = temp;
b1a26c01 5474 ret->flags |= rflags;
227f982e
CR
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. */
227f982e 5481static WORD_DESC *
d3a24ed2 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;
d3a24ed2 5485 int *quoted_dollar_atp, *contains_dollar_at;
ccc6cda3
JA
5486{
5487 char *temp, *t;
227f982e 5488 WORD_DESC *w;
ccc6cda3 5489
1231ac47 5490 w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND);
227f982e 5491 t = w->word;
762a763b
CR
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 }
227f982e
CR
5501 dispose_word_desc (w);
5502
d3a24ed2 5503 chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at);
ccc6cda3 5504 if (t == 0)
227f982e
CR
5505 return (WORD_DESC *)NULL;
5506
1231ac47 5507 w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0);
ccc6cda3 5508 free (t);
227f982e
CR
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. */
227f982e 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{
227f982e 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
d3ad40de 5529 embedded unescaped double quotes (for sh backwards compatibility). */
22e63b05 5530 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
726f6388 5531 {
ccc6cda3 5532 hasdol = 0;
22e63b05 5533 temp = string_extract_double_quoted (value, &hasdol, 1);
726f6388 5534 }
22e63b05
CR
5535 else
5536 temp = value;
ccc6cda3 5537
227f982e 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);
22e63b05
CR
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
12d937f9
CR
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. */
12d937f9 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. */
d3ad40de 5569 temp = make_quoted_char ('\0');
227f982e 5570 w->flags |= W_HASQUOTEDNULL;
726f6388
JA
5571 }
5572 else
5573 temp = (char *)NULL;
5574
5575 if (c == '-' || c == '+')
227f982e
CR
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);
d3a24ed2
CR
5585#if defined (ARRAY_VARS)
5586 if (valid_array_reference (name))
d11b8b46 5587 assign_array_element (name, t1, 0);
d3a24ed2
CR
5588 else
5589#endif /* ARRAY_VARS */
d11b8b46 5590 bind_variable (name, t1, 0);
726f6388 5591 free (t1);
227f982e
CR
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 {
22e63b05 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
5e13499c 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
898cc92e
CR
5640#if defined (HANDLE_MULTIBYTE)
5641size_t
5642mbstrlen (s)
5643 const char *s;
5644{
5645 size_t clen, nc;
a82a04b3 5646 mbstate_t mbs, mbsbak;
898cc92e
CR
5647
5648 nc = 0;
5649 memset (&mbs, 0, sizeof (mbs));
a82a04b3
CR
5650 mbsbak = mbs;
5651 while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0)
898cc92e 5652 {
a82a04b3
CR
5653 if (MB_INVALIDCH(clen))
5654 {
5655 clen = 1; /* assume single byte */
5656 mbs = mbsbak;
5657 }
5658
898cc92e
CR
5659 s += clen;
5660 nc++;
a82a04b3 5661 mbsbak = mbs;
898cc92e
CR
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);
898cc92e 5723 number = MB_STRLEN (t);
ccc6cda3
JA
5724 FREE (t);
5725 }
5726#if defined (ARRAY_VARS)
fdf670ea 5727 else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
ccc6cda3 5728 {
fdf670ea
CR
5729 if (assoc_p (var))
5730 t = assoc_reference (assoc_cell (var), "0");
5731 else
5732 t = array_reference (array_cell (var), 0);
898cc92e 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
898cc92e 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
09767ff0
CR
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;
09767ff0 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
d3ad40de 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:
898cc92e 5853 len = MB_STRLEN (value);
ccc6cda3
JA
5854 break;
5855 case VT_POSPARMS:
5856 len = number_of_args () + 1;
d3ad40de
CR
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:
301e2142 5862 /* For arrays, the first value deals with array indices. Negative
09767ff0
CR
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
8ed8525c 5885 if (*e1p > len || *e1p < 0)
e8ce775d 5886 return (-1);
d166f048 5887
5e13499c
CR
5888#if defined (ARRAY_VARS)
5889 /* For arrays, the second offset deals with the number of elements. */
5890 if (vtype == VT_ARRAYVAR)
dd4f3dd8 5891 len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
5e13499c
CR
5892#endif
5893
ccc6cda3
JA
5894 if (t)
5895 {
5896 t++;
bb70624e 5897 temp2 = savestring (t);
d3ad40de 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 {
5e13499c 5907 internal_error (_("%s: substring expression < 0"), t);
ccc6cda3 5908 return (0);
28ef6c31 5909 }
5e13499c
CR
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
762a763b 5935get_var_and_type (varname, value, quoted, varp, valp)
ccc6cda3 5936 char *varname, *value;
762a763b 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';
d3a24ed2
CR
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);
fdf670ea 5957 if (v && (array_p (v) || assoc_p (v)))
f73dda09
JA
5958 { /* [ */
5959 if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
ccc6cda3 5960 {
dd4f3dd8 5961 /* Callers have to differentiate betwen indexed and associative */
ccc6cda3 5962 vtype = VT_ARRAYVAR;
d3a24ed2
CR
5963 if (temp[0] == '*')
5964 vtype |= VT_STARSUB;
fdf670ea 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 }
8fed3589
CR
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
fdf670ea
CR
5984 {
5985 vtype = VT_ARRAYMEMBER;
5986 *varp = v;
5987 *valp = array_value (varname, 1, (int *)NULL);
5988 }
ccc6cda3 5989 }
fdf670ea 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;
fdf670ea 5994 *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
ccc6cda3
JA
5995 }
5996 else
5997#endif
762a763b
CR
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
545f34cf
CR
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;
da713c23
CR
6034 /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
6035 slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
545f34cf
CR
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;
d3a24ed2 6059 int vtype, r, starsub;
d3ad40de 6060 char *temp, *val, *tt, *oname;
ccc6cda3
JA
6061 SHELL_VAR *v;
6062
6063 if (value == 0)
6064 return ((char *)NULL);
6065
d3ad40de 6066 oname = this_command_name;
ccc6cda3
JA
6067 this_command_name = varname;
6068
762a763b 6069 vtype = get_var_and_type (varname, value, quoted, &v, &val);
ccc6cda3 6070 if (vtype == -1)
d3ad40de
CR
6071 {
6072 this_command_name = oname;
6073 return ((char *)NULL);
6074 }
ccc6cda3 6075
d3a24ed2
CR
6076 starsub = vtype & VT_STARSUB;
6077 vtype &= ~VT_STARSUB;
6078
09767ff0 6079 r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
d3ad40de 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:
545f34cf
CR
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);
545f34cf 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:
fdf670ea 6115 if (assoc_p (v))
09767ff0
CR
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);
fdf670ea 6119 else
5e13499c 6120 /* We want E2 to be the number of elements desired (arrays can be sparse,
704a1a2a
CR
6121 so verify_substring_values just returns the numbers specified and we
6122 rely on array_subrange to understand how to deal with them). */
fdf670ea 6123 temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
d3ad40de
CR
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 */
d3a24ed2 6202
ccc6cda3 6203 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
28ef6c31 6204 break;
d3a24ed2
CR
6205
6206 if (s == e)
5ccad779
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;
d3ad40de 6236 char *ret;
e33f2203 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);
227f982e
CR
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
e33f2203
CR
6252 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6253 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6254
6255#if 0
d3a24ed2
CR
6256 if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
6257 ret = string_list_dollar_star (quote_list (save));
e33f2203
CR
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);
d3a24ed2 6262 else
e33f2203
CR
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{
c2a47ea9 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
762a763b 6291 vtype = get_var_and_type (varname, value, quoted, &v, &val);
ccc6cda3
JA
6292 if (vtype == -1)
6293 return ((char *)NULL);
6294
d3a24ed2
CR
6295 starsub = vtype & VT_STARSUB;
6296 vtype &= ~VT_STARSUB;
6297
ccc6cda3 6298 mflags = 0;
d3ad40de
CR
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
d3a24ed2
CR
6312 if (starsub)
6313 mflags |= MATCH_STARSUB;
6314
dc8fbaf9
CR
6315 /* If the pattern starts with a `/', make sure we skip over it when looking
6316 for the replacement delimiter. */
c2a47ea9 6317#if 0
dc8fbaf9 6318 if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL))
ccc6cda3
JA
6319 *rep++ = '\0';
6320 else
6321 rep = (char *)NULL;
c2a47ea9 6322#else
4d8d005b 6323 delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
c2a47ea9
CR
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
5e13499c
CR
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
dc8fbaf9 6348 /* ksh93 doesn't allow the match specifier to be a part of the expanded
d3ad40de
CR
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;
d3ad40de
CR
6353 if (mflags & MATCH_GLOBREP)
6354 mflags |= MATCH_ANY;
dc8fbaf9 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 {
e6598ba4 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:
fdf670ea
CR
6404 temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags)
6405 : array_patsub (array_cell (v), p, rep, mflags);
e6598ba4
CR
6406 /* Don't call quote_escapes anymore; array_patsub calls
6407 array_quote_escapes as appropriate before adding the
fdf670ea 6408 space separators; ditto for assoc_patsub. */
ccc6cda3
JA
6409 break;
6410#endif
6411 }
6412
6413 FREE (pat);
6414 FREE (rep);
bb70624e 6415 free (lpatsub);
ccc6cda3
JA
6416
6417 return temp;
6418}
6419
09767ff0
CR
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;
e141c35a 6499 modop = x ? CASE_UPPER : CASE_UPFIRST;
09767ff0
CR
6500 p += x;
6501 }
6502 else if (modspec == ',')
6503 {
6504 x = p && p[0] == modspec;
e141c35a 6505 modop = x ? CASE_LOWER : CASE_LOWFIRST;
09767ff0
CR
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)
6539 {
6540 tt = quote_escapes (temp);
6541 free (temp);
6542 temp = tt;
6543 }
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. */
6553 break;
6554#endif
6555 }
6556
6557 FREE (pat);
6558 free (lpat);
6559
6560 return temp;
6561}
6562
d3ad40de
CR
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 {
176b12ee 6580 if (s[i] == LPAREN)
d3ad40de 6581 count++;
176b12ee 6582 else if (s[i] == RPAREN)
d3ad40de
CR
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
09767ff0 6620/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
227f982e 6621static WORD_DESC *
e1e48bba 6622parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
ccc6cda3 6623 char *string;
e1e48bba 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;
09767ff0 6627 int want_substring, want_indir, want_patsub, want_casemod;
ccc6cda3 6628 char *name, *value, *temp, *temp1;
227f982e 6629 WORD_DESC *tdesc, *ret;
09767ff0 6630 int t_index, sindex, c, tflag, modspec;
7117c2d2 6631 intmax_t number;
ccc6cda3 6632
c40a57dd 6633 temp = temp1 = value = (char *)NULL;
ccc6cda3 6634 var_is_set = var_is_null = var_is_special = check_nullness = 0;
09767ff0 6635 want_substring = want_indir = want_patsub = want_casemod = 0;
ccc6cda3 6636
cce855bc
JA
6637 sindex = *indexp;
6638 t_index = ++sindex;
11a6f9a9
CR
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])) /* {{ */
e6598ba4 6641 name = string_extract (string, &t_index, "}", SX_VARNAME);
11a6f9a9 6642 else
09767ff0
CR
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
e6598ba4 6652 name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME);
09767ff0 6653#endif /* CASEMOD_EXPANSIONS */
cce855bc 6654
227f982e
CR
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;
09767ff0
CR
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 }
e33f2203 6735
cce855bc
JA
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;
227f982e
CR
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
d3a24ed2 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);
af98a2a6 6811 dispose_words (xlist);
bb70624e
JA
6812 free (temp1);
6813 *indexp = sindex;
227f982e
CR
6814
6815 ret = alloc_word_desc ();
6816 ret->word = temp;
6817 return ret;
bb70624e 6818 }
d3a24ed2
CR
6819
6820#if defined (ARRAY_VARS)
5e13499c
CR
6821 /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */
6822 if (want_indir && string[sindex - 1] == RBRACE &&
6823 string[sindex - 2] == ']' && valid_array_reference (name+1))
d3a24ed2
CR
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 {
fdf670ea 6832 temp = array_keys (temp1, quoted); /* handles assoc vars too */
d3a24ed2
CR
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;
227f982e
CR
6843
6844 ret = alloc_word_desc ();
6845 ret->word = temp;
6846 return ret;
d3a24ed2
CR
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)
227f982e 6862 tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
ccc6cda3 6863 else
e1e48bba 6864 tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&PF_NOSPLIT2));
227f982e
CR
6865
6866 if (tdesc)
6867 {
6868 temp = tdesc->word;
6869 tflag = tdesc->flags;
6870 dispose_word_desc (tdesc);
6871 }
6872 else
6873 temp = (char *)0;
ccc6cda3
JA
6874
6875#if defined (ARRAY_VARS)
cce855bc 6876 if (valid_array_reference (name))
d3a24ed2 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);
227f982e
CR
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;
d3ad40de
CR
6914 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
6915 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
227f982e 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);
227f982e
CR
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;
40c8fbee
CR
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;
227f982e 6936 return ret;
ccc6cda3 6937 }
09767ff0
CR
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;
40c8fbee
CR
6953 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
6954 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
09767ff0
CR
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:
5e13499c 6965 report_error (_("%s: bad substitution"), string ? string : "??");
ccc6cda3
JA
6966 FREE (value);
6967 FREE (temp);
6968 free (name);
227f982e 6969 return &expand_wdesc_error;
ccc6cda3 6970
cce855bc 6971 case RBRACE:
2c471a92 6972 if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
28ef6c31 6973 {
0d8616ff 6974 last_command_exit_value = EXECUTION_FAILURE;
7117c2d2 6975 err_unboundvar (name);
ccc6cda3
JA
6976 FREE (value);
6977 FREE (temp);
6978 free (name);
227f982e 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);
40c8fbee
CR
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 {
227f982e
CR
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 {
5e13499c 7045 report_error (_("$%s: cannot assign in this way"), name);
ccc6cda3
JA
7046 free (name);
7047 free (value);
227f982e 7048 return &expand_wdesc_error;
ccc6cda3
JA
7049 }
7050 else if (c == '?')
7051 {
7052 parameter_brace_expand_error (name, value);
227f982e 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
227f982e
CR
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);
227f982e
CR
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. */
227f982e 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;
227f982e
CR
7104 WORD_DESC *tdesc, *ret;
7105 int tflag;
cce855bc
JA
7106
7107 zindex = *sindex;
7108 c = string[++zindex];
7109
7110 temp = (char *)NULL;
227f982e
CR
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;
0d8616ff 7135 err_unboundvar (uerror);
227f982e 7136 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
cce855bc 7137 }
5ba8ff6e 7138 if (temp1)
762a763b 7139 temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
5ba8ff6e
CR
7140 ? quote_string (temp1)
7141 : quote_escapes (temp1);
7142 else
7143 temp = (char *)NULL;
227f982e 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;
0d8616ff 7183 err_unboundvar (uerror);
227f982e 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
12ae1612
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
1231ac47 7204 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
57a3f689
CR
7205 {
7206 uerror[0] = '$';
7207 uerror[1] = '*';
7208 uerror[2] = '\0';
57a3f689 7209 last_command_exit_value = EXECUTION_FAILURE;
0d8616ff 7210 err_unboundvar (uerror);
57a3f689
CR
7211 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7212 }
12ae1612 7213#endif
57a3f689 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;
1231ac47 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. */
1231ac47 7227 temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list) : string_list (list);
cce855bc 7228 temp1 = quote_string (temp);
227f982e
CR
7229 if (*temp == 0)
7230 tflag |= W_HASQUOTEDNULL;
cce855bc
JA
7231 free (temp);
7232 temp = temp1;
7233 }
7234 else
28ef6c31 7235 {
227f982e
CR
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);
227f982e 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
12ae1612
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
1231ac47 7276 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
57a3f689
CR
7277 {
7278 uerror[0] = '$';
7279 uerror[1] = '@';
7280 uerror[2] = '\0';
57a3f689 7281 last_command_exit_value = EXECUTION_FAILURE;
0d8616ff 7282 err_unboundvar (uerror);
57a3f689
CR
7283 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7284 }
12ae1612 7285#endif
57a3f689 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. */
1231ac47 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
e1e48bba
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:
e1e48bba 7314 tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
227f982e
CR
7315 quoted_dollar_at_p,
7316 contains_dollar_at);
7317
227f982e
CR
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. */
227f982e 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);
227f982e 7337 tdesc->word = temp = (char *)NULL;
28ef6c31
JA
7338 }
7339
cce855bc
JA
7340 }
7341
227f982e 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;
e33f2203 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
d3ad40de
CR
7370 if (chk_arithsub (temp2, t_index) == 0)
7371 {
7372 free (temp2);
ecf57862 7373 internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
d3ad40de
CR
7374 goto comsub;
7375 }
7376
cce855bc 7377 /* Expand variables found inside the expression. */
d3ad40de 7378 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
cce855bc
JA
7379 free (temp2);
7380
7381arithsub:
7382 /* No error messages. */
7383 this_command_name = (char *)NULL;
7384 number = evalexp (temp1, &expok);
7385 free (temp);
7386 free (temp1);
7387 if (expok == 0)
7388 {
7389 if (interactive_shell == 0 && posixly_correct)
7390 {
7391 last_command_exit_value = EXECUTION_FAILURE;
227f982e 7392 return (&expand_wdesc_fatal);
cce855bc
JA
7393 }
7394 else
227f982e 7395 return (&expand_wdesc_error);
cce855bc
JA
7396 }
7397 temp = itos (number);
7398 break;
7399 }
7400
7401comsub:
d3a24ed2
CR
7402 if (pflags & PF_NOCOMSUB)
7403 /* we need zindex+1 because string[zindex] == RPAREN */
7404 temp1 = substring (string, *sindex, zindex+1);
7405 else
d3ad40de
CR
7406 {
7407 tdesc = command_substitute (temp, quoted);
7408 temp1 = tdesc ? tdesc->word : (char *)NULL;
e33f2203
CR
7409 if (tdesc)
7410 dispose_word_desc (tdesc);
d3ad40de 7411 }
cce855bc
JA
7412 FREE (temp);
7413 temp = temp1;
7414 break;
7415
7416 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
7417 away in a future bash release. */
7418 case '[':
bb70624e 7419 /* Extract the contents of this arithmetic substitution. */
cce855bc
JA
7420 t_index = zindex + 1;
7421 temp = extract_arithmetic_subst (string, &t_index);
7422 zindex = t_index;
35bb237e
CR
7423 if (temp == 0)
7424 {
7425 temp = savestring (string);
7426 if (expanded_something)
7427 *expanded_something = 0;
7428 goto return0;
7429 }
cce855bc
JA
7430
7431 /* Do initial variable expansion. */
d3ad40de 7432 temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES);
cce855bc
JA
7433
7434 goto arithsub;
7435
7436 default:
7437 /* Find the variable in VARIABLE_LIST. */
7438 temp = (char *)NULL;
7439
7440 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
7441 ;
7442 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
7443
7444 /* If this isn't a variable name, then just output the `$'. */
7445 if (temp1 == 0 || *temp1 == '\0')
7446 {
7447 FREE (temp1);
f73dda09 7448 temp = (char *)xmalloc (2);
cce855bc
JA
7449 temp[0] = '$';
7450 temp[1] = '\0';
7451 if (expanded_something)
7452 *expanded_something = 0;
7453 goto return0;
7454 }
7455
7456 /* If the variable exists, return its value cell. */
7457 var = find_variable (temp1);
7458
7117c2d2 7459 if (var && invisible_p (var) == 0 && var_isset (var))
cce855bc
JA
7460 {
7461#if defined (ARRAY_VARS)
fdf670ea 7462 if (assoc_p (var) || array_p (var))
cce855bc 7463 {
fdf670ea
CR
7464 temp = array_p (var) ? array_reference (array_cell (var), 0)
7465 : assoc_reference (assoc_cell (var), "0");
cce855bc 7466 if (temp)
762a763b 7467 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
5ba8ff6e
CR
7468 ? quote_string (temp)
7469 : quote_escapes (temp);
5565fb1a
CR
7470 else if (unbound_vars_is_error)
7471 goto unbound_variable;
cce855bc
JA
7472 }
7473 else
7474#endif
762a763b
CR
7475 {
7476 temp = value_cell (var);
7477
7478 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7479 ? quote_string (temp)
7480 : quote_escapes (temp);
7481 }
5ba8ff6e 7482
cce855bc 7483 free (temp1);
7117c2d2 7484
cce855bc
JA
7485 goto return0;
7486 }
7487
7488 temp = (char *)NULL;
7489
5565fb1a 7490unbound_variable:
cce855bc 7491 if (unbound_vars_is_error)
0d8616ff
CR
7492 {
7493 last_command_exit_value = EXECUTION_FAILURE;
7494 err_unboundvar (temp1);
7495 }
cce855bc
JA
7496 else
7497 {
7498 free (temp1);
7499 goto return0;
7500 }
7501
7502 free (temp1);
7503 last_command_exit_value = EXECUTION_FAILURE;
7504 return ((unbound_vars_is_error && interactive_shell == 0)
227f982e
CR
7505 ? &expand_wdesc_fatal
7506 : &expand_wdesc_error);
cce855bc
JA
7507 }
7508
7509 if (string[zindex])
7510 zindex++;
7511
7512return0:
7513 *sindex = zindex;
227f982e
CR
7514
7515 if (ret == 0)
7516 {
7517 ret = alloc_word_desc ();
7518 ret->flags = tflag; /* XXX */
7519 ret->word = temp;
7520 }
7521 return ret;
cce855bc
JA
7522}
7523
7524/* Make a word list which is the result of parameter and variable
7525 expansion, command substitution, arithmetic substitution, and
7526 quote removal of WORD. Return a pointer to a WORD_LIST which is
7527 the result of the expansion. If WORD contains a null word, the
7528 word list returned is also null.
726f6388 7529
ccc6cda3
JA
7530 QUOTED contains flag values defined in shell.h.
7531
b72432fd
JA
7532 ISEXP is used to tell expand_word_internal that the word should be
7533 treated as the result of an expansion. This has implications for
7534 how IFS characters in the word are treated.
7535
726f6388
JA
7536 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
7537 they point to an integer value which receives information about expansion.
7538 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
7539 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
7540 else zero.
7541
7542 This only does word splitting in the case of $@ expansion. In that
7543 case, we split on ' '. */
7544
7545/* Values for the local variable quoted_state. */
7546#define UNQUOTED 0
7547#define PARTIALLY_QUOTED 1
7548#define WHOLLY_QUOTED 2
7549
7550static WORD_LIST *
b72432fd 7551expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
726f6388 7552 WORD_DESC *word;
b72432fd 7553 int quoted, isexp;
726f6388
JA
7554 int *contains_dollar_at;
7555 int *expanded_something;
7556{
ccc6cda3
JA
7557 WORD_LIST *list;
7558 WORD_DESC *tword;
726f6388
JA
7559
7560 /* The intermediate string that we build while expanding. */
ccc6cda3 7561 char *istring;
726f6388
JA
7562
7563 /* The current size of the above object. */
ccc6cda3 7564 int istring_size;
726f6388
JA
7565
7566 /* Index into ISTRING. */
ccc6cda3 7567 int istring_index;
726f6388
JA
7568
7569 /* Temporary string storage. */
ccc6cda3 7570 char *temp, *temp1;
726f6388
JA
7571
7572 /* The text of WORD. */
ccc6cda3 7573 register char *string;
726f6388 7574
7117c2d2
JA
7575 /* The size of STRING. */
7576 size_t string_size;
7577
726f6388 7578 /* The index into STRING. */
ccc6cda3 7579 int sindex;
726f6388
JA
7580
7581 /* This gets 1 if we see a $@ while quoted. */
ccc6cda3 7582 int quoted_dollar_at;
726f6388
JA
7583
7584 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
7585 whether WORD contains no quoting characters, a partially quoted
7586 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
ccc6cda3
JA
7587 int quoted_state;
7588
22e63b05 7589 /* State flags */
ccc6cda3 7590 int had_quoted_null;
cce855bc 7591 int has_dollar_at;
28ef6c31 7592 int tflag;
e1e48bba 7593 int pflags; /* flags passed to param_expand */
726f6388 7594
22e63b05
CR
7595 int assignoff; /* If assignment, offset of `=' */
7596
f73dda09 7597 register unsigned char c; /* Current character. */
726f6388 7598 int t_index; /* For calls to string_extract_xxx. */
726f6388 7599
bb70624e 7600 char twochars[2];
b72432fd 7601
7117c2d2
JA
7602 DECLARE_MBSTATE;
7603
f73dda09 7604 istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
ccc6cda3 7605 istring[istring_index = 0] = '\0';
cce855bc 7606 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
ccc6cda3
JA
7607 quoted_state = UNQUOTED;
7608
7609 string = word->word;
7610 if (string == 0)
7611 goto finished_with_string;
da713c23
CR
7612 /* Don't need the string length for the SADD... and COPY_ macros unless
7613 multibyte characters are possible. */
7614 string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1;
726f6388
JA
7615
7616 if (contains_dollar_at)
7617 *contains_dollar_at = 0;
7618
22e63b05
CR
7619 assignoff = -1;
7620
726f6388
JA
7621 /* Begin the expansion. */
7622
ccc6cda3 7623 for (sindex = 0; ;)
726f6388
JA
7624 {
7625 c = string[sindex];
7626
7627 /* Case on toplevel character. */
7628 switch (c)
7629 {
7630 case '\0':
7631 goto finished_with_string;
7632
7633 case CTLESC:
7117c2d2
JA
7634 sindex++;
7635#if HANDLE_MULTIBYTE
7636 if (MB_CUR_MAX > 1 && string[sindex])
7637 {
545f34cf 7638 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7117c2d2
JA
7639 }
7640 else
7641#endif
7642 {
7643 temp = (char *)xmalloc (3);
7644 temp[0] = CTLESC;
7645 temp[1] = c = string[sindex];
7646 temp[2] = '\0';
7647 }
726f6388 7648
cce855bc 7649dollar_add_string:
726f6388
JA
7650 if (string[sindex])
7651 sindex++;
7652
cce855bc
JA
7653add_string:
7654 if (temp)
7655 {
7656 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
7657 temp = (char *)0;
7658 }
7659
7660 break;
726f6388
JA
7661
7662#if defined (PROCESS_SUBSTITUTION)
7663 /* Process substitution. */
7664 case '<':
7665 case '>':
7666 {
dc8fbaf9 7667 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || posixly_correct)
726f6388 7668 {
bb70624e 7669 sindex--; /* add_character: label increments sindex */
726f6388
JA
7670 goto add_character;
7671 }
7672 else
cce855bc 7673 t_index = sindex + 1; /* skip past both '<' and LPAREN */
726f6388 7674
cce855bc 7675 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/
ccc6cda3 7676 sindex = t_index;
726f6388
JA
7677
7678 /* If the process substitution specification is `<()', we want to
7679 open the pipe for writing in the child and produce output; if
7680 it is `>()', we want to open the pipe for reading in the child
7681 and consume input. */
ccc6cda3 7682 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
726f6388
JA
7683
7684 FREE (temp1);
7685
7686 goto dollar_add_string;
7687 }
7688#endif /* PROCESS_SUBSTITUTION */
7689
22e63b05
CR
7690 case '=':
7691 /* Posix.2 section 3.6.1 says that tildes following `=' in words
7692 which are not assignment statements are not expanded. If the
7693 shell isn't in posix mode, though, we perform tilde expansion
7694 on `likely candidate' unquoted assignment statements (flags
7695 include W_ASSIGNMENT but not W_QUOTED). A likely candidate
7696 contains an unquoted :~ or =~. Something to think about: we
7697 now have a flag that says to perform tilde expansion on arguments
7698 to `assignment builtins' like declare and export that look like
7699 assignment statements. We now do tilde expansion on such words
7700 even in POSIX mode. */
7701 if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
c1d39fb8 7702 {
e1e48bba 7703 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
c1d39fb8
CR
7704 goto add_ifs_character;
7705 else
7706 goto add_character;
7707 }
22e63b05
CR
7708 /* If we're not in posix mode or forcing assignment-statement tilde
7709 expansion, note where the `=' appears in the word and prepare to
7710 do tilde expansion following the first `='. */
7711 if ((word->flags & W_ASSIGNMENT) &&
7712 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
7713 assignoff == -1 && sindex > 0)
7714 assignoff = sindex;
7715 if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
7716 word->flags |= W_ITILDE;
d90269dd 7717#if 0
22e63b05
CR
7718 else if ((word->flags & W_ASSIGNMENT) &&
7719 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
7720 string[sindex+1] == '~')
7721 word->flags |= W_ITILDE;
d90269dd 7722#endif
e1e48bba 7723 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
c1d39fb8
CR
7724 goto add_ifs_character;
7725 else
7726 goto add_character;
22e63b05
CR
7727
7728 case ':':
7729 if (word->flags & W_NOTILDE)
c1d39fb8 7730 {
e1e48bba 7731 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
c1d39fb8
CR
7732 goto add_ifs_character;
7733 else
7734 goto add_character;
7735 }
cdb32d45
CR
7736
7737 if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) &&
22e63b05
CR
7738 string[sindex+1] == '~')
7739 word->flags |= W_ITILDE;
c1d39fb8 7740
e1e48bba 7741 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
c1d39fb8
CR
7742 goto add_ifs_character;
7743 else
7744 goto add_character;
22e63b05
CR
7745
7746 case '~':
7747 /* If the word isn't supposed to be tilde expanded, or we're not
7748 at the start of a word or after an unquoted : or = in an
7749 assignment statement, we don't do tilde expansion. */
da719982 7750 if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
22e63b05
CR
7751 (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
7752 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7753 {
7754 word->flags &= ~W_ITILDE;
e1e48bba 7755 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
c1d39fb8
CR
7756 goto add_ifs_character;
7757 else
7758 goto add_character;
22e63b05
CR
7759 }
7760
7761 if (word->flags & W_ASSIGNRHS)
7762 tflag = 2;
cdb32d45 7763 else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
22e63b05
CR
7764 tflag = 1;
7765 else
7766 tflag = 0;
7767
7768 temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
7769
7770 word->flags &= ~W_ITILDE;
7771
7772 if (temp && *temp && t_index > 0)
7773 {
7774 temp1 = bash_tilde_expand (temp, tflag);
dc8fbaf9
CR
7775 if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
7776 {
7777 FREE (temp);
7778 FREE (temp1);
7779 goto add_character; /* tilde expansion failed */
7780 }
22e63b05
CR
7781 free (temp);
7782 temp = temp1;
7783 sindex += t_index;
866961ad 7784 goto add_quoted_string; /* XXX was add_string */
22e63b05
CR
7785 }
7786 else
7787 {
7788 FREE (temp);
7789 goto add_character;
7790 }
7791
726f6388 7792 case '$':
726f6388
JA
7793 if (expanded_something)
7794 *expanded_something = 1;
7795
cce855bc 7796 has_dollar_at = 0;
e1e48bba
CR
7797 pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
7798 if (word->flags & W_NOSPLIT2)
7799 pflags |= PF_NOSPLIT2;
227f982e 7800 tword = param_expand (string, &sindex, quoted, expanded_something,
cce855bc 7801 &has_dollar_at, &quoted_dollar_at,
e1e48bba 7802 &had_quoted_null, pflags);
726f6388 7803
227f982e 7804 if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
726f6388 7805 {
cce855bc
JA
7806 free (string);
7807 free (istring);
227f982e
CR
7808 return ((tword == &expand_wdesc_error) ? &expand_word_error
7809 : &expand_word_fatal);
cce855bc
JA
7810 }
7811 if (contains_dollar_at && has_dollar_at)
7812 *contains_dollar_at = 1;
227f982e
CR
7813
7814 if (tword && (tword->flags & W_HASQUOTEDNULL))
7815 had_quoted_null = 1;
7816
7817 temp = tword->word;
7818 dispose_word_desc (tword);
7819
cce855bc
JA
7820 goto add_string;
7821 break;
726f6388 7822
cce855bc
JA
7823 case '`': /* Backquoted command substitution. */
7824 {
d3a24ed2 7825 t_index = sindex++;
726f6388 7826
e6598ba4 7827 temp = string_extract (string, &sindex, "`", SX_REQMATCH);
bc7bed50
CR
7828 /* The test of sindex against t_index is to allow bare instances of
7829 ` to pass through, for backwards compatibility. */
7027abcb
CR
7830 if (temp == &extract_string_error || temp == &extract_string_fatal)
7831 {
bc7bed50
CR
7832 if (sindex - 1 == t_index)
7833 {
7834 sindex = t_index;
7835 goto add_character;
7836 }
d3ad40de 7837 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
7027abcb
CR
7838 free (string);
7839 free (istring);
7840 return ((temp == &extract_string_error) ? &expand_word_error
7841 : &expand_word_fatal);
7842 }
7843
bc7bed50
CR
7844 if (expanded_something)
7845 *expanded_something = 1;
7846
d3a24ed2
CR
7847 if (word->flags & W_NOCOMSUB)
7848 /* sindex + 1 because string[sindex] == '`' */
7849 temp1 = substring (string, t_index, sindex + 1);
7850 else
7851 {
7852 de_backslash (temp);
d3ad40de
CR
7853 tword = command_substitute (temp, quoted);
7854 temp1 = tword ? tword->word : (char *)NULL;
e33f2203
CR
7855 if (tword)
7856 dispose_word_desc (tword);
d3a24ed2 7857 }
cce855bc
JA
7858 FREE (temp);
7859 temp = temp1;
7860 goto dollar_add_string;
7861 }
ccc6cda3 7862
cce855bc
JA
7863 case '\\':
7864 if (string[sindex + 1] == '\n')
7865 {
7866 sindex += 2;
7867 continue;
7868 }
726f6388 7869
cce855bc 7870 c = string[++sindex];
726f6388 7871
cce855bc 7872 if (quoted & Q_HERE_DOCUMENT)
28ef6c31 7873 tflag = CBSHDOC;
cce855bc 7874 else if (quoted & Q_DOUBLE_QUOTES)
28ef6c31 7875 tflag = CBSDQUOTE;
cce855bc 7876 else
28ef6c31
JA
7877 tflag = 0;
7878
28ef6c31 7879 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
cce855bc 7880 {
7117c2d2 7881 SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
bb70624e
JA
7882 }
7883 else if (c == 0)
7884 {
7885 c = CTLNUL;
7886 sindex--; /* add_character: label increments sindex */
7887 goto add_character;
cce855bc
JA
7888 }
7889 else
bb70624e 7890 {
7117c2d2 7891 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
bb70624e 7892 }
726f6388 7893
bb70624e
JA
7894 sindex++;
7895add_twochars:
7896 /* BEFORE jumping here, we need to increment sindex if appropriate */
7897 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
7898 DEFAULT_ARRAY_SIZE);
7899 istring[istring_index++] = twochars[0];
7900 istring[istring_index++] = twochars[1];
7901 istring[istring_index] = '\0';
7902
7903 break;
726f6388 7904
cce855bc 7905 case '"':
da719982
CR
7906#if 0
7907 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
7908#else
7909 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7910#endif
cce855bc 7911 goto add_character;
ccc6cda3
JA
7912
7913 t_index = ++sindex;
7914 temp = string_extract_double_quoted (string, &sindex, 0);
7915
7916 /* If the quotes surrounded the entire string, then the
7917 whole word was quoted. */
7918 quoted_state = (t_index == 1 && string[sindex] == '\0')
7919 ? WHOLLY_QUOTED
7117c2d2 7920 : PARTIALLY_QUOTED;
ccc6cda3
JA
7921
7922 if (temp && *temp)
726f6388 7923 {
227f982e
CR
7924 tword = alloc_word_desc ();
7925 tword->word = temp;
7926
ccc6cda3
JA
7927 temp = (char *)NULL;
7928
cce855bc 7929 has_dollar_at = 0;
227f982e 7930 /* Need to get W_HASQUOTEDNULL flag through this function. */
b72432fd 7931 list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL);
726f6388 7932
ccc6cda3
JA
7933 if (list == &expand_word_error || list == &expand_word_fatal)
7934 {
7935 free (istring);
7936 free (string);
7937 /* expand_word_internal has already freed temp_word->word
7938 for us because of the way it prints error messages. */
7939 tword->word = (char *)NULL;
7940 dispose_word (tword);
7941 return list;
7942 }
726f6388 7943
ccc6cda3 7944 dispose_word (tword);
726f6388 7945
ccc6cda3
JA
7946 /* "$@" (a double-quoted dollar-at) expands into nothing,
7947 not even a NULL word, when there are no positional
7948 parameters. */
cce855bc 7949 if (list == 0 && has_dollar_at)
726f6388 7950 {
ccc6cda3
JA
7951 quoted_dollar_at++;
7952 break;
7953 }
7954
7955 /* If we get "$@", we know we have expanded something, so we
7956 need to remember it for the final split on $IFS. This is
7957 a special case; it's the only case where a quoted string
7958 can expand into more than one word. It's going to come back
7959 from the above call to expand_word_internal as a list with
7960 a single word, in which all characters are quoted and
7961 separated by blanks. What we want to do is to turn it back
7962 into a list for the next piece of code. */
7963 if (list)
7964 dequote_list (list);
7965
227f982e
CR
7966 if (list && list->word && (list->word->flags & W_HASQUOTEDNULL))
7967 had_quoted_null = 1;
7968
cce855bc 7969 if (has_dollar_at)
ccc6cda3
JA
7970 {
7971 quoted_dollar_at++;
7972 if (contains_dollar_at)
7973 *contains_dollar_at = 1;
7974 if (expanded_something)
7975 *expanded_something = 1;
7976 }
7977 }
7978 else
7979 {
7980 /* What we have is "". This is a minor optimization. */
f73dda09 7981 FREE (temp);
ccc6cda3
JA
7982 list = (WORD_LIST *)NULL;
7983 }
7984
7985 /* The code above *might* return a list (consider the case of "$@",
7986 where it returns "$1", "$2", etc.). We can't throw away the
7987 rest of the list, and we have to make sure each word gets added
7988 as quoted. We test on tresult->next: if it is non-NULL, we
7989 quote the whole list, save it to a string with string_list, and
7990 add that string. We don't need to quote the results of this
7991 (and it would be wrong, since that would quote the separators
7992 as well), so we go directly to add_string. */
7993 if (list)
7994 {
7995 if (list->next)
7996 {
e1e48bba
CR
7997#if 0
7998 if (quoted_dollar_at && word->flags & W_NOSPLIT2)
7999 temp = string_list_internal (quote_list (list), " ");
8000 else
8001#endif
bc4cd23c
JA
8002 /* Testing quoted_dollar_at makes sure that "$@" is
8003 split correctly when $IFS does not contain a space. */
8004 temp = quoted_dollar_at
8005 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES)
8006 : string_list (quote_list (list));
ccc6cda3 8007 dispose_words (list);
726f6388
JA
8008 goto add_string;
8009 }
8010 else
8011 {
ccc6cda3 8012 temp = savestring (list->word->word);
227f982e 8013 tflag = list->word->flags;
ccc6cda3 8014 dispose_words (list);
227f982e 8015
cce855bc
JA
8016 /* If the string is not a quoted null string, we want
8017 to remove any embedded unquoted CTLNUL characters.
8018 We do not want to turn quoted null strings back into
8019 the empty string, though. We do this because we
8020 want to remove any quoted nulls from expansions that
8021 contain other characters. For example, if we have
8022 x"$*"y or "x$*y" and there are no positional parameters,
7117c2d2 8023 the $* should expand into nothing. */
227f982e
CR
8024 /* We use the W_HASQUOTEDNULL flag to differentiate the
8025 cases: a quoted null character as above and when
8026 CTLNUL is contained in the (non-null) expansion
8027 of some variable. We use the had_quoted_null flag to
10590446 8028 pass the value through this function to its caller. */
227f982e 8029 if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
cce855bc 8030 remove_quoted_nulls (temp); /* XXX */
726f6388
JA
8031 }
8032 }
ccc6cda3
JA
8033 else
8034 temp = (char *)NULL;
726f6388 8035
ccc6cda3
JA
8036 /* We do not want to add quoted nulls to strings that are only
8037 partially quoted; we can throw them away. */
8038 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
cce855bc 8039 continue;
726f6388 8040
ccc6cda3 8041 add_quoted_string:
726f6388 8042
ccc6cda3
JA
8043 if (temp)
8044 {
8045 temp1 = temp;
8046 temp = quote_string (temp);
8047 free (temp1);
bb70624e 8048 goto add_string;
ccc6cda3
JA
8049 }
8050 else
8051 {
8052 /* Add NULL arg. */
bb70624e
JA
8053 c = CTLNUL;
8054 sindex--; /* add_character: label increments sindex */
8055 goto add_character;
ccc6cda3 8056 }
bb70624e 8057
ccc6cda3 8058 /* break; */
726f6388 8059
ccc6cda3 8060 case '\'':
da719982
CR
8061#if 0
8062 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
8063#else
8064 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8065#endif
ccc6cda3 8066 goto add_character;
726f6388 8067
ccc6cda3
JA
8068 t_index = ++sindex;
8069 temp = string_extract_single_quoted (string, &sindex);
726f6388 8070
ccc6cda3
JA
8071 /* If the entire STRING was surrounded by single quotes,
8072 then the string is wholly quoted. */
8073 quoted_state = (t_index == 1 && string[sindex] == '\0')
8074 ? WHOLLY_QUOTED
7117c2d2 8075 : PARTIALLY_QUOTED;
726f6388 8076
ccc6cda3
JA
8077 /* If all we had was '', it is a null expansion. */
8078 if (*temp == '\0')
8079 {
8080 free (temp);
8081 temp = (char *)NULL;
8082 }
8083 else
7117c2d2 8084 remove_quoted_escapes (temp); /* ??? */
726f6388 8085
ccc6cda3
JA
8086 /* We do not want to add quoted nulls to strings that are only
8087 partially quoted; such nulls are discarded. */
8088 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
8089 continue;
726f6388 8090
bb70624e
JA
8091 /* If we have a quoted null expansion, add a quoted NULL to istring. */
8092 if (temp == 0)
8093 {
8094 c = CTLNUL;
8095 sindex--; /* add_character: label increments sindex */
8096 goto add_character;
8097 }
8098 else
8099 goto add_quoted_string;
8100
ccc6cda3 8101 /* break; */
726f6388
JA
8102
8103 default:
726f6388 8104 /* This is the fix for " $@ " */
c1d39fb8 8105 add_ifs_character:
7117c2d2 8106 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c)))
726f6388 8107 {
bb70624e
JA
8108 if (string[sindex]) /* from old goto dollar_add_string */
8109 sindex++;
8110 if (c == 0)
8111 {
8112 c = CTLNUL;
8113 goto add_character;
8114 }
8115 else
8116 {
7117c2d2 8117#if HANDLE_MULTIBYTE
545f34cf
CR
8118 if (MB_CUR_MAX > 1)
8119 sindex--;
8120
7117c2d2
JA
8121 if (MB_CUR_MAX > 1)
8122 {
545f34cf 8123 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7117c2d2
JA
8124 }
8125 else
8126#endif
8127 {
8128 twochars[0] = CTLESC;
8129 twochars[1] = c;
8130 goto add_twochars;
8131 }
bb70624e 8132 }
726f6388
JA
8133 }
8134
7117c2d2
JA
8135 SADD_MBCHAR (temp, string, sindex, string_size);
8136
726f6388 8137 add_character:
ccc6cda3
JA
8138 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
8139 DEFAULT_ARRAY_SIZE);
726f6388
JA
8140 istring[istring_index++] = c;
8141 istring[istring_index] = '\0';
8142
8143 /* Next character. */
8144 sindex++;
8145 }
8146 }
8147
8148finished_with_string:
726f6388
JA
8149 /* OK, we're ready to return. If we have a quoted string, and
8150 quoted_dollar_at is not set, we do no splitting at all; otherwise
8151 we split on ' '. The routines that call this will handle what to
8152 do if nothing has been expanded. */
ccc6cda3
JA
8153
8154 /* Partially and wholly quoted strings which expand to the empty
8155 string are retained as an empty arguments. Unquoted strings
8156 which expand to the empty string are discarded. The single
8157 exception is the case of expanding "$@" when there are no
8158 positional parameters. In that case, we discard the expansion. */
8159
8160 /* Because of how the code that handles "" and '' in partially
8161 quoted strings works, we need to make ISTRING into a QUOTED_NULL
8162 if we saw quoting characters, but the expansion was empty.
8163 "" and '' are tossed away before we get to this point when
8164 processing partially quoted strings. This makes "" and $xxx""
8165 equivalent when xxx is unset. We also look to see whether we
8166 saw a quoted null from a ${} expansion and add one back if we
8167 need to. */
8168
8169 /* If we expand to nothing and there were no single or double quotes
8170 in the word, we throw it away. Otherwise, we return a NULL word.
8171 The single exception is for $@ surrounded by double quotes when
8172 there are no positional parameters. In that case, we also throw
8173 the word away. */
8174
8175 if (*istring == '\0')
8176 {
8177 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
726f6388 8178 {
726f6388
JA
8179 istring[0] = CTLNUL;
8180 istring[1] = '\0';
ccc6cda3 8181 tword = make_bare_word (istring);
227f982e 8182 tword->flags |= W_HASQUOTEDNULL; /* XXX */
ccc6cda3
JA
8183 list = make_word_list (tword, (WORD_LIST *)NULL);
8184 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8185 tword->flags |= W_QUOTED;
726f6388 8186 }
ccc6cda3
JA
8187 /* According to sh, ksh, and Posix.2, if a word expands into nothing
8188 and a double-quoted "$@" appears anywhere in it, then the entire
8189 word is removed. */
8190 else if (quoted_state == UNQUOTED || quoted_dollar_at)
8191 list = (WORD_LIST *)NULL;
8192#if 0
8193 else
726f6388 8194 {
ccc6cda3 8195 tword = make_bare_word (istring);
ccc6cda3
JA
8196 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8197 tword->flags |= W_QUOTED;
227f982e 8198 list = make_word_list (tword, (WORD_LIST *)NULL);
726f6388 8199 }
f73dda09
JA
8200#else
8201 else
8202 list = (WORD_LIST *)NULL;
ccc6cda3
JA
8203#endif
8204 }
8205 else if (word->flags & W_NOSPLIT)
8206 {
8207 tword = make_bare_word (istring);
ccc6cda3
JA
8208 if (word->flags & W_ASSIGNMENT)
8209 tword->flags |= W_ASSIGNMENT; /* XXX */
43df7bbb
CR
8210 if (word->flags & W_COMPASSIGN)
8211 tword->flags |= W_COMPASSIGN; /* XXX */
b72432fd
JA
8212 if (word->flags & W_NOGLOB)
8213 tword->flags |= W_NOGLOB; /* XXX */
43df7bbb
CR
8214 if (word->flags & W_NOEXPAND)
8215 tword->flags |= W_NOEXPAND; /* XXX */
ccc6cda3 8216 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
28ef6c31 8217 tword->flags |= W_QUOTED;
227f982e
CR
8218 if (had_quoted_null)
8219 tword->flags |= W_HASQUOTEDNULL;
8220 list = make_word_list (tword, (WORD_LIST *)NULL);
ccc6cda3
JA
8221 }
8222 else
8223 {
8224 char *ifs_chars;
8225
7117c2d2 8226 ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
726f6388 8227
cce855bc
JA
8228 /* If we have $@, we need to split the results no matter what. If
8229 IFS is unset or NULL, string_list_dollar_at has separated the
8230 positional parameters with a space, so we split on space (we have
8231 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
8232 string_list_dollar_at has separated the positional parameters
8233 with the first character of $IFS, so we split on $IFS. */
8234 if (has_dollar_at && ifs_chars)
8235 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
ccc6cda3
JA
8236 else
8237 {
8238 tword = make_bare_word (istring);
ccc6cda3
JA
8239 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
8240 tword->flags |= W_QUOTED;
8241 if (word->flags & W_ASSIGNMENT)
8242 tword->flags |= W_ASSIGNMENT;
43df7bbb
CR
8243 if (word->flags & W_COMPASSIGN)
8244 tword->flags |= W_COMPASSIGN;
b72432fd
JA
8245 if (word->flags & W_NOGLOB)
8246 tword->flags |= W_NOGLOB;
43df7bbb
CR
8247 if (word->flags & W_NOEXPAND)
8248 tword->flags |= W_NOEXPAND;
227f982e
CR
8249 if (had_quoted_null)
8250 tword->flags |= W_HASQUOTEDNULL; /* XXX */
8251 list = make_word_list (tword, (WORD_LIST *)NULL);
726f6388 8252 }
726f6388 8253 }
726f6388 8254
ccc6cda3
JA
8255 free (istring);
8256 return (list);
726f6388
JA
8257}
8258
8259/* **************************************************************** */
8260/* */
8261/* Functions for Quote Removal */
8262/* */
8263/* **************************************************************** */
8264
8265/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
7117c2d2 8266 backslash quoting rules for within double quotes or a here document. */
726f6388
JA
8267char *
8268string_quote_removal (string, quoted)
8269 char *string;
8270 int quoted;
8271{
7117c2d2
JA
8272 size_t slen;
8273 char *r, *result_string, *temp, *send;
f73dda09
JA
8274 int sindex, tindex, dquote;
8275 unsigned char c;
7117c2d2 8276 DECLARE_MBSTATE;
726f6388
JA
8277
8278 /* The result can be no longer than the original string. */
7117c2d2
JA
8279 slen = strlen (string);
8280 send = string + slen;
8281
8282 r = result_string = (char *)xmalloc (slen + 1);
726f6388 8283
ccc6cda3 8284 for (dquote = sindex = 0; c = string[sindex];)
726f6388
JA
8285 {
8286 switch (c)
8287 {
8288 case '\\':
8289 c = string[++sindex];
33fe8777
CR
8290 if (c == 0)
8291 {
8292 *r++ = '\\';
8293 break;
8294 }
28ef6c31 8295 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
726f6388 8296 *r++ = '\\';
ccc6cda3 8297 /* FALLTHROUGH */
726f6388
JA
8298
8299 default:
7117c2d2 8300 SCOPY_CHAR_M (r, string, send, sindex);
726f6388
JA
8301 break;
8302
8303 case '\'':
ccc6cda3 8304 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
726f6388
JA
8305 {
8306 *r++ = c;
8307 sindex++;
ccc6cda3 8308 break;
726f6388 8309 }
ccc6cda3
JA
8310 tindex = sindex + 1;
8311 temp = string_extract_single_quoted (string, &tindex);
8312 if (temp)
726f6388 8313 {
ccc6cda3
JA
8314 strcpy (r, temp);
8315 r += strlen (r);
8316 free (temp);
726f6388 8317 }
ccc6cda3 8318 sindex = tindex;
726f6388
JA
8319 break;
8320
8321 case '"':
8322 dquote = 1 - dquote;
8323 sindex++;
8324 break;
8325 }
8326 }
8327 *r = '\0';
8328 return (result_string);
8329}
8330
ccc6cda3
JA
8331#if 0
8332/* UNUSED */
726f6388
JA
8333/* Perform quote removal on word WORD. This allocates and returns a new
8334 WORD_DESC *. */
8335WORD_DESC *
8336word_quote_removal (word, quoted)
8337 WORD_DESC *word;
8338 int quoted;
8339{
8340 WORD_DESC *w;
8341 char *t;
8342
8343 t = string_quote_removal (word->word, quoted);
227f982e
CR
8344 w = alloc_word_desc ();
8345 w->word = t ? t : savestring ("");
726f6388
JA
8346 return (w);
8347}
8348
8349/* Perform quote removal on all words in LIST. If QUOTED is non-zero,
8350 the members of the list are treated as if they are surrounded by
8351 double quotes. Return a new list, or NULL if LIST is NULL. */
8352WORD_LIST *
8353word_list_quote_removal (list, quoted)
8354 WORD_LIST *list;
8355 int quoted;
8356{
227f982e 8357 WORD_LIST *result, *t, *tresult, *e;
726f6388 8358
ccc6cda3 8359 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
726f6388 8360 {
7117c2d2 8361 tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
227f982e 8362#if 0
726f6388 8363 result = (WORD_LIST *) list_append (result, tresult);
227f982e
CR
8364#else
8365 if (result == 0)
8366 result = e = tresult;
8367 else
8368 {
8369 e->next = tresult;
8370 while (e->next)
8371 e = e->next;
8372 }
8373#endif
726f6388
JA
8374 }
8375 return (result);
8376}
ccc6cda3 8377#endif
726f6388 8378
726f6388
JA
8379/*******************************************
8380 * *
8381 * Functions to perform word splitting *
8382 * *
8383 *******************************************/
8384
7117c2d2
JA
8385void
8386setifs (v)
8387 SHELL_VAR *v;
b72432fd 8388{
7117c2d2
JA
8389 char *t;
8390 unsigned char uc;
8391
8392 ifs_var = v;
cdb32d45 8393 ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
b72432fd 8394
633e5c6d
CR
8395 /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
8396 handle multibyte chars in IFS */
7117c2d2
JA
8397 memset (ifs_cmap, '\0', sizeof (ifs_cmap));
8398 for (t = ifs_value ; t && *t; t++)
8399 {
8400 uc = *t;
8401 ifs_cmap[uc] = 1;
8402 }
8403
633e5c6d
CR
8404#if defined (HANDLE_MULTIBYTE)
8405 if (ifs_value == 0)
8406 {
8407 ifs_firstc[0] = '\0';
8408 ifs_firstc_len = 1;
8409 }
8410 else
8411 {
8412 size_t ifs_len;
8413 ifs_len = strnlen (ifs_value, MB_CUR_MAX);
8414 ifs_firstc_len = MBLEN (ifs_value, ifs_len);
22e63b05 8415 if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
633e5c6d
CR
8416 {
8417 ifs_firstc[0] = ifs_value[0];
8418 ifs_firstc[1] = '\0';
8419 ifs_firstc_len = 1;
8420 }
8421 else
8422 memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
8423 }
8424#else
7117c2d2 8425 ifs_firstc = ifs_value ? *ifs_value : 0;
633e5c6d 8426#endif
7117c2d2
JA
8427}
8428
8429char *
8430getifs ()
8431{
8432 return ifs_value;
b72432fd
JA
8433}
8434
726f6388
JA
8435/* This splits a single word into a WORD LIST on $IFS, but only if the word
8436 is not quoted. list_string () performs quote removal for us, even if we
8437 don't do any splitting. */
8438WORD_LIST *
7117c2d2 8439word_split (w, ifs_chars)
726f6388 8440 WORD_DESC *w;
7117c2d2 8441 char *ifs_chars;
726f6388
JA
8442{
8443 WORD_LIST *result;
8444
8445 if (w)
8446 {
7117c2d2 8447 char *xifs;
726f6388 8448
7117c2d2
JA
8449 xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
8450 result = list_string (w->word, xifs, w->flags & W_QUOTED);
726f6388
JA
8451 }
8452 else
8453 result = (WORD_LIST *)NULL;
ccc6cda3 8454
726f6388
JA
8455 return (result);
8456}
8457
8458/* Perform word splitting on LIST and return the RESULT. It is possible
8459 to return (WORD_LIST *)NULL. */
8460static WORD_LIST *
8461word_list_split (list)
8462 WORD_LIST *list;
8463{
37c41ab1 8464 WORD_LIST *result, *t, *tresult, *e;
726f6388 8465
ccc6cda3 8466 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
726f6388 8467 {
7117c2d2 8468 tresult = word_split (t->word, ifs_value);
37c41ab1
CR
8469 if (result == 0)
8470 result = e = tresult;
8471 else
8472 {
8473 e->next = tresult;
8474 while (e->next)
8475 e = e->next;
8476 }
726f6388
JA
8477 }
8478 return (result);
8479}
8480
8481/**************************************************
8482 * *
cce855bc 8483 * Functions to expand an entire WORD_LIST *
726f6388
JA
8484 * *
8485 **************************************************/
8486
d3a24ed2
CR
8487/* Do any word-expansion-specific cleanup and jump to top_level */
8488static void
8489exp_jump_to_top_level (v)
8490 int v;
8491{
f11997f8
CR
8492 set_pipestatus_from_exit (last_command_exit_value);
8493
d3a24ed2
CR
8494 /* Cleanup code goes here. */
8495 expand_no_split_dollar_star = 0; /* XXX */
8496 expanding_redir = 0;
d7f49990 8497 assigning_in_environment = 0;
d3a24ed2 8498
2e4498b3
CR
8499 if (parse_and_execute_level == 0)
8500 top_level_cleanup (); /* from sig.c */
8501
d3a24ed2
CR
8502 jump_to_top_level (v);
8503}
8504
cce855bc
JA
8505/* Put NLIST (which is a WORD_LIST * of only one element) at the front of
8506 ELIST, and set ELIST to the new list. */
8507#define PREPEND_LIST(nlist, elist) \
8508 do { nlist->next = elist; elist = nlist; } while (0)
8509
726f6388
JA
8510/* Separate out any initial variable assignments from TLIST. If set -k has
8511 been executed, remove all assignment statements from TLIST. Initial
8512 variable assignments and other environment assignments are placed
bb70624e 8513 on SUBST_ASSIGN_VARLIST. */
726f6388
JA
8514static WORD_LIST *
8515separate_out_assignments (tlist)
8516 WORD_LIST *tlist;
8517{
8518 register WORD_LIST *vp, *lp;
8519
0527c903 8520 if (tlist == 0)
726f6388
JA
8521 return ((WORD_LIST *)NULL);
8522
bb70624e
JA
8523 if (subst_assign_varlist)
8524 dispose_words (subst_assign_varlist); /* Clean up after previous error */
b72432fd 8525
bb70624e 8526 subst_assign_varlist = (WORD_LIST *)NULL;
726f6388
JA
8527 vp = lp = tlist;
8528
8529 /* Separate out variable assignments at the start of the command.
8530 Loop invariant: vp->next == lp
8531 Loop postcondition:
7117c2d2
JA
8532 lp = list of words left after assignment statements skipped
8533 tlist = original list of words
726f6388 8534 */
ccc6cda3 8535 while (lp && (lp->word->flags & W_ASSIGNMENT))
726f6388
JA
8536 {
8537 vp = lp;
8538 lp = lp->next;
8539 }
8540
bb70624e
JA
8541 /* If lp != tlist, we have some initial assignment statements.
8542 We make SUBST_ASSIGN_VARLIST point to the list of assignment
8543 words and TLIST point to the remaining words. */
726f6388
JA
8544 if (lp != tlist)
8545 {
bb70624e 8546 subst_assign_varlist = tlist;
726f6388
JA
8547 /* ASSERT(vp->next == lp); */
8548 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
8549 tlist = lp; /* remainder of word list */
8550 }
8551
8552 /* vp == end of variable list */
8553 /* tlist == remainder of original word list without variable assignments */
8554 if (!tlist)
8555 /* All the words in tlist were assignment statements */
8556 return ((WORD_LIST *)NULL);
8557
8558 /* ASSERT(tlist != NULL); */
ccc6cda3 8559 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
726f6388
JA
8560
8561 /* If the -k option is in effect, we need to go through the remaining
bb70624e
JA
8562 words, separate out the assignment words, and place them on
8563 SUBST_ASSIGN_VARLIST. */
726f6388
JA
8564 if (place_keywords_in_env)
8565 {
8566 WORD_LIST *tp; /* tp == running pointer into tlist */
8567
8568 tp = tlist;
8569 lp = tlist->next;
8570
8571 /* Loop Invariant: tp->next == lp */
8572 /* Loop postcondition: tlist == word list without assignment statements */
8573 while (lp)
8574 {
ccc6cda3 8575 if (lp->word->flags & W_ASSIGNMENT)
726f6388
JA
8576 {
8577 /* Found an assignment statement, add this word to end of
bb70624e
JA
8578 subst_assign_varlist (vp). */
8579 if (!subst_assign_varlist)
8580 subst_assign_varlist = vp = lp;
726f6388
JA
8581 else
8582 {
8583 vp->next = lp;
8584 vp = lp;
8585 }
8586
8587 /* Remove the word pointed to by LP from TLIST. */
8588 tp->next = lp->next;
8589 /* ASSERT(vp == lp); */
8590 lp->next = (WORD_LIST *)NULL;
8591 lp = tp->next;
8592 }
8593 else
8594 {
8595 tp = lp;
8596 lp = lp->next;
8597 }
8598 }
8599 }
8600 return (tlist);
8601}
8602
cce855bc
JA
8603#define WEXP_VARASSIGN 0x001
8604#define WEXP_BRACEEXP 0x002
8605#define WEXP_TILDEEXP 0x004
8606#define WEXP_PARAMEXP 0x008
8607#define WEXP_PATHEXP 0x010
8608
8609/* All of the expansions, including variable assignments at the start of
8610 the list. */
8611#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
8612
8613/* All of the expansions except variable assignments at the start of
8614 the list. */
8615#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
8616
8617/* All of the `shell expansions': brace expansion, tilde expansion, parameter
8618 expansion, command substitution, arithmetic expansion, word splitting, and
8619 quote removal. */
8620#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
8621
726f6388
JA
8622/* Take the list of words in LIST and do the various substitutions. Return
8623 a new list of words which is the expanded list, and without things like
8624 variable assignments. */
8625
8626WORD_LIST *
8627expand_words (list)
8628 WORD_LIST *list;
8629{
cce855bc 8630 return (expand_word_list_internal (list, WEXP_ALL));
726f6388
JA
8631}
8632
8633/* Same as expand_words (), but doesn't hack variable or environment
8634 variables. */
8635WORD_LIST *
8636expand_words_no_vars (list)
8637 WORD_LIST *list;
8638{
cce855bc 8639 return (expand_word_list_internal (list, WEXP_NOVARS));
726f6388
JA
8640}
8641
cce855bc
JA
8642WORD_LIST *
8643expand_words_shellexp (list)
726f6388 8644 WORD_LIST *list;
726f6388 8645{
cce855bc
JA
8646 return (expand_word_list_internal (list, WEXP_SHELLEXP));
8647}
726f6388 8648
cce855bc
JA
8649static WORD_LIST *
8650glob_expand_word_list (tlist, eflags)
8651 WORD_LIST *tlist;
8652 int eflags;
8653{
8654 char **glob_array, *temp_string;
8655 register int glob_index;
8656 WORD_LIST *glob_list, *output_list, *disposables, *next;
8657 WORD_DESC *tword;
726f6388 8658
cce855bc
JA
8659 output_list = disposables = (WORD_LIST *)NULL;
8660 glob_array = (char **)NULL;
8661 while (tlist)
8662 {
8663 /* For each word, either globbing is attempted or the word is
8664 added to orig_list. If globbing succeeds, the results are
8665 added to orig_list and the word (tlist) is added to the list
8666 of disposable words. If globbing fails and failed glob
8667 expansions are left unchanged (the shell default), the
8668 original word is added to orig_list. If globbing fails and
8669 failed glob expansions are removed, the original word is
8670 added to the list of disposable words. orig_list ends up
7117c2d2 8671 in reverse order and requires a call to REVERSE_LIST to
cce855bc
JA
8672 be set right. After all words are examined, the disposable
8673 words are freed. */
8674 next = tlist->next;
726f6388 8675
cce855bc 8676 /* If the word isn't an assignment and contains an unquoted
28ef6c31 8677 pattern matching character, then glob it. */
b72432fd 8678 if ((tlist->word->flags & W_NOGLOB) == 0 &&
cce855bc 8679 unquoted_glob_pattern_p (tlist->word->word))
726f6388 8680 {
cce855bc
JA
8681 glob_array = shell_glob_filename (tlist->word->word);
8682
8683 /* Handle error cases.
8684 I don't think we should report errors like "No such file
8685 or directory". However, I would like to report errors
8686 like "Read failed". */
8687
d3a24ed2 8688 if (glob_array == 0 || GLOB_FAILED (glob_array))
726f6388 8689 {
bb70624e 8690 glob_array = (char **)xmalloc (sizeof (char *));
cce855bc
JA
8691 glob_array[0] = (char *)NULL;
8692 }
8693
8694 /* Dequote the current word in case we have to use it. */
8695 if (glob_array[0] == NULL)
8696 {
8697 temp_string = dequote_string (tlist->word->word);
8698 free (tlist->word->word);
8699 tlist->word->word = temp_string;
8700 }
8701
8702 /* Make the array into a word list. */
8703 glob_list = (WORD_LIST *)NULL;
8704 for (glob_index = 0; glob_array[glob_index]; glob_index++)
8705 {
8706 tword = make_bare_word (glob_array[glob_index]);
8707 tword->flags |= W_GLOBEXP; /* XXX */
8708 glob_list = make_word_list (tword, glob_list);
8709 }
8710
8711 if (glob_list)
8712 {
8713 output_list = (WORD_LIST *)list_append (glob_list, output_list);
8714 PREPEND_LIST (tlist, disposables);
8715 }
d3a24ed2
CR
8716 else if (fail_glob_expansion != 0)
8717 {
5e13499c 8718 report_error (_("no match: %s"), tlist->word->word);
c184f645 8719 exp_jump_to_top_level (DISCARD);
d3a24ed2 8720 }
cce855bc
JA
8721 else if (allow_null_glob_expansion == 0)
8722 {
8723 /* Failed glob expressions are left unchanged. */
8724 PREPEND_LIST (tlist, output_list);
8725 }
8726 else
8727 {
8728 /* Failed glob expressions are removed. */
8729 PREPEND_LIST (tlist, disposables);
726f6388 8730 }
726f6388 8731 }
cce855bc
JA
8732 else
8733 {
8734 /* Dequote the string. */
8735 temp_string = dequote_string (tlist->word->word);
8736 free (tlist->word->word);
8737 tlist->word->word = temp_string;
8738 PREPEND_LIST (tlist, output_list);
8739 }
8740
7117c2d2 8741 strvec_dispose (glob_array);
cce855bc
JA
8742 glob_array = (char **)NULL;
8743
8744 tlist = next;
726f6388
JA
8745 }
8746
cce855bc
JA
8747 if (disposables)
8748 dispose_words (disposables);
8749
8750 if (output_list)
8751 output_list = REVERSE_LIST (output_list, WORD_LIST *);
8752
8753 return (output_list);
8754}
726f6388
JA
8755
8756#if defined (BRACE_EXPANSION)
cce855bc
JA
8757static WORD_LIST *
8758brace_expand_word_list (tlist, eflags)
8759 WORD_LIST *tlist;
8760 int eflags;
8761{
8762 register char **expansions;
8763 char *temp_string;
8764 WORD_LIST *disposables, *output_list, *next;
8765 WORD_DESC *w;
8766 int eindex;
8767
8768 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
726f6388 8769 {
cce855bc 8770 next = tlist->next;
726f6388 8771
6669f0e5
CR
8772 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
8773 {
8774/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
8775 PREPEND_LIST (tlist, output_list);
8776 continue;
8777 }
8778
cce855bc
JA
8779 /* Only do brace expansion if the word has a brace character. If
8780 not, just add the word list element to BRACES and continue. In
8781 the common case, at least when running shell scripts, this will
d0ca3503 8782 degenerate to a bunch of calls to `mbschr', and then what is
cce855bc 8783 basically a reversal of TLIST into BRACES, which is corrected
7117c2d2 8784 by a call to REVERSE_LIST () on BRACES when the end of TLIST
cce855bc 8785 is reached. */
d0ca3503 8786 if (mbschr (tlist->word->word, LBRACE))
726f6388 8787 {
cce855bc 8788 expansions = brace_expand (tlist->word->word);
726f6388 8789
cce855bc 8790 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
726f6388 8791 {
cce855bc
JA
8792 w = make_word (temp_string);
8793 /* If brace expansion didn't change the word, preserve
8794 the flags. We may want to preserve the flags
8795 unconditionally someday -- XXX */
8796 if (STREQ (temp_string, tlist->word->word))
8797 w->flags = tlist->word->flags;
8798 output_list = make_word_list (w, output_list);
8799 free (expansions[eindex]);
726f6388 8800 }
cce855bc 8801 free (expansions);
726f6388 8802
cce855bc
JA
8803 /* Add TLIST to the list of words to be freed after brace
8804 expansion has been performed. */
8805 PREPEND_LIST (tlist, disposables);
8806 }
8807 else
8808 PREPEND_LIST (tlist, output_list);
726f6388 8809 }
cce855bc
JA
8810
8811 if (disposables)
8812 dispose_words (disposables);
8813
8814 if (output_list)
8815 output_list = REVERSE_LIST (output_list, WORD_LIST *);
8816
8817 return (output_list);
8818}
8819#endif
8820
fdf670ea
CR
8821#if defined (ARRAY_VARS)
8822/* Take WORD, a compound associative array assignment, and internally run
8823 'declare -A w', where W is the variable name portion of WORD. */
8824static int
8825make_internal_declare (word, option)
8826 char *word;
8827 char *option;
8828{
8829 int t;
8830 WORD_LIST *wl;
8831 WORD_DESC *w;
8832
8833 w = make_word (word);
8834
8835 t = assignment (w->word, 0);
8836 w->word[t] = '\0';
8837
8838 wl = make_word_list (w, (WORD_LIST *)NULL);
8839 wl = make_word_list (make_word (option), wl);
8840
8841 return (declare_builtin (wl));
8842}
8843#endif
8844
cce855bc
JA
8845static WORD_LIST *
8846shell_expand_word_list (tlist, eflags)
8847 WORD_LIST *tlist;
8848 int eflags;
8849{
8850 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list;
8851 int expanded_something, has_dollar_at;
8852 char *temp_string;
726f6388 8853
726f6388 8854 /* We do tilde expansion all the time. This is what 1003.2 says. */
cce855bc
JA
8855 new_list = (WORD_LIST *)NULL;
8856 for (orig_list = tlist; tlist; tlist = next)
726f6388 8857 {
ccc6cda3 8858 temp_string = tlist->word->word;
726f6388
JA
8859
8860 next = tlist->next;
8861
43df7bbb
CR
8862#if defined (ARRAY_VARS)
8863 /* If this is a compound array assignment to a builtin that accepts
8864 such assignments (e.g., `declare'), take the assignment and perform
8865 it separately, handling the semantics of declarations inside shell
8866 functions. This avoids the double-evaluation of such arguments,
8867 because `declare' does some evaluation of compound assignments on
8868 its own. */
8869 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
8870 {
8871 int t;
8872
fdf670ea
CR
8873 if (tlist->word->flags & W_ASSIGNASSOC)
8874 make_internal_declare (tlist->word->word, "-A");
8875
43df7bbb
CR
8876 t = do_word_assignment (tlist->word);
8877 if (t == 0)
8878 {
8879 last_command_exit_value = EXECUTION_FAILURE;
8880 exp_jump_to_top_level (DISCARD);
8881 }
8882
8883 /* Now transform the word as ksh93 appears to do and go on */
8884 t = assignment (tlist->word->word, 0);
8885 tlist->word->word[t] = '\0';
fdf670ea 8886 tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC);
43df7bbb
CR
8887 }
8888#endif
8889
ccc6cda3 8890 expanded_something = 0;
726f6388 8891 expanded = expand_word_internal
b72432fd 8892 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
726f6388
JA
8893
8894 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
8895 {
8896 /* By convention, each time this error is returned,
8897 tlist->word->word has already been freed. */
8898 tlist->word->word = (char *)NULL;
ccc6cda3 8899
726f6388
JA
8900 /* Dispose our copy of the original list. */
8901 dispose_words (orig_list);
d166f048 8902 /* Dispose the new list we're building. */
726f6388
JA
8903 dispose_words (new_list);
8904
28ef6c31 8905 last_command_exit_value = EXECUTION_FAILURE;
726f6388 8906 if (expanded == &expand_word_error)
d3a24ed2 8907 exp_jump_to_top_level (DISCARD);
726f6388 8908 else
d3a24ed2 8909 exp_jump_to_top_level (FORCE_EOF);
726f6388
JA
8910 }
8911
ccc6cda3
JA
8912 /* Don't split words marked W_NOSPLIT. */
8913 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
726f6388 8914 {
ccc6cda3 8915 temp_list = word_list_split (expanded);
726f6388
JA
8916 dispose_words (expanded);
8917 }
8918 else
8919 {
8920 /* If no parameter expansion, command substitution, process
8921 substitution, or arithmetic substitution took place, then
8922 do not do word splitting. We still have to remove quoted
8923 null characters from the result. */
8924 word_list_remove_quoted_nulls (expanded);
ccc6cda3 8925 temp_list = expanded;
726f6388
JA
8926 }
8927
ccc6cda3
JA
8928 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
8929 new_list = (WORD_LIST *)list_append (expanded, new_list);
726f6388
JA
8930 }
8931
cce855bc
JA
8932 if (orig_list)
8933 dispose_words (orig_list);
726f6388 8934
726f6388 8935 if (new_list)
cce855bc 8936 new_list = REVERSE_LIST (new_list, WORD_LIST *);
726f6388 8937
cce855bc
JA
8938 return (new_list);
8939}
726f6388 8940
cce855bc
JA
8941/* The workhorse for expand_words () and expand_words_no_vars ().
8942 First arg is LIST, a WORD_LIST of words.
b72432fd
JA
8943 Second arg EFLAGS is a flags word controlling which expansions are
8944 performed.
726f6388 8945
cce855bc
JA
8946 This does all of the substitutions: brace expansion, tilde expansion,
8947 parameter expansion, command substitution, arithmetic expansion,
8948 process substitution, word splitting, and pathname expansion, according
8949 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
8950 set, or for which no expansion is done, do not undergo word splitting.
b72432fd 8951 Words with the W_NOGLOB bit set do not undergo pathname expansion. */
cce855bc
JA
8952static WORD_LIST *
8953expand_word_list_internal (list, eflags)
8954 WORD_LIST *list;
8955 int eflags;
8956{
8957 WORD_LIST *new_list, *temp_list;
8958 int tint;
726f6388 8959
cce855bc
JA
8960 if (list == 0)
8961 return ((WORD_LIST *)NULL);
726f6388 8962
bb70624e 8963 garglist = new_list = copy_word_list (list);
cce855bc
JA
8964 if (eflags & WEXP_VARASSIGN)
8965 {
bb70624e 8966 garglist = new_list = separate_out_assignments (new_list);
cce855bc
JA
8967 if (new_list == 0)
8968 {
bb70624e 8969 if (subst_assign_varlist)
cce855bc
JA
8970 {
8971 /* All the words were variable assignments, so they are placed
8972 into the shell's environment. */
bb70624e 8973 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
cce855bc
JA
8974 {
8975 this_command_name = (char *)NULL; /* no arithmetic errors */
43df7bbb 8976 tint = do_word_assignment (temp_list->word);
cce855bc
JA
8977 /* Variable assignment errors in non-interactive shells
8978 running in Posix.2 mode cause the shell to exit. */
28ef6c31 8979 if (tint == 0)
ccc6cda3 8980 {
cce855bc 8981 last_command_exit_value = EXECUTION_FAILURE;
28ef6c31 8982 if (interactive_shell == 0 && posixly_correct)
d3a24ed2 8983 exp_jump_to_top_level (FORCE_EOF);
28ef6c31 8984 else
d3a24ed2 8985 exp_jump_to_top_level (DISCARD);
ccc6cda3 8986 }
726f6388 8987 }
bb70624e
JA
8988 dispose_words (subst_assign_varlist);
8989 subst_assign_varlist = (WORD_LIST *)NULL;
cce855bc
JA
8990 }
8991 return ((WORD_LIST *)NULL);
8992 }
8993 }
726f6388 8994
cce855bc
JA
8995 /* Begin expanding the words that remain. The expansions take place on
8996 things that aren't really variable assignments. */
726f6388 8997
cce855bc
JA
8998#if defined (BRACE_EXPANSION)
8999 /* Do brace expansion on this word if there are any brace characters
9000 in the string. */
9001 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
9002 new_list = brace_expand_word_list (new_list, eflags);
9003#endif /* BRACE_EXPANSION */
726f6388 9004
cce855bc
JA
9005 /* Perform the `normal' shell expansions: tilde expansion, parameter and
9006 variable substitution, command substitution, arithmetic expansion,
9007 and word splitting. */
9008 new_list = shell_expand_word_list (new_list, eflags);
726f6388 9009
cce855bc
JA
9010 /* Okay, we're almost done. Now let's just do some filename
9011 globbing. */
9012 if (new_list)
9013 {
9014 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
9015 /* Glob expand the word list unless globbing has been disabled. */
9016 new_list = glob_expand_word_list (new_list, eflags);
726f6388 9017 else
cce855bc
JA
9018 /* Dequote the words, because we're not performing globbing. */
9019 new_list = dequote_list (new_list);
726f6388
JA
9020 }
9021
bb70624e 9022 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
726f6388 9023 {
43df7bbb 9024 sh_wassign_func_t *assign_func;
726f6388
JA
9025
9026 /* If the remainder of the words expand to nothing, Posix.2 requires
9027 that the variable and environment assignments affect the shell's
9028 environment. */
43df7bbb 9029 assign_func = new_list ? assign_in_env : do_word_assignment;
56299fa5 9030 tempenv_assign_error = 0;
726f6388 9031
bb70624e 9032 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
726f6388 9033 {
ccc6cda3 9034 this_command_name = (char *)NULL;
d7f49990 9035 assigning_in_environment = (assign_func == assign_in_env);
43df7bbb 9036 tint = (*assign_func) (temp_list->word);
d7f49990 9037 assigning_in_environment = 0;
ccc6cda3
JA
9038 /* Variable assignment errors in non-interactive shells running
9039 in Posix.2 mode cause the shell to exit. */
56299fa5 9040 if (tint == 0)
ccc6cda3 9041 {
43df7bbb 9042 if (assign_func == do_word_assignment)
56299fa5
CR
9043 {
9044 last_command_exit_value = EXECUTION_FAILURE;
9045 if (interactive_shell == 0 && posixly_correct)
9046 exp_jump_to_top_level (FORCE_EOF);
9047 else
9048 exp_jump_to_top_level (DISCARD);
9049 }
28ef6c31 9050 else
56299fa5 9051 tempenv_assign_error++;
ccc6cda3 9052 }
726f6388 9053 }
726f6388 9054
bb70624e
JA
9055 dispose_words (subst_assign_varlist);
9056 subst_assign_varlist = (WORD_LIST *)NULL;
726f6388
JA
9057 }
9058
cce855bc 9059#if 0
ccc6cda3
JA
9060 tint = list_length (new_list) + 1;
9061 RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
cce855bc
JA
9062 for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next)
9063 glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0';
ccc6cda3 9064 glob_argv_flags[tint] = '\0';
ccc6cda3 9065#endif
726f6388 9066
cce855bc 9067 return (new_list);
ccc6cda3 9068}