]> git.ipfire.org Git - thirdparty/bash.git/blame - subst.c
Imported from ../bash-2.04.tar.gz.
[thirdparty/bash.git] / subst.c
CommitLineData
726f6388
JA
1/* subst.c -- The part of the shell that does parameter, command, and
2 globbing substitutions. */
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
726f6388
JA
7/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
8
9 This file is part of GNU Bash, the Bourne Again SHell.
10
11 Bash is free software; you can redistribute it and/or modify it under
12 the terms of the GNU General Public License as published by the Free
13 Software Foundation; either version 2, or (at your option) any later
14 version.
15
16 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
17 WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 for more details.
20
21 You should have received a copy of the GNU General Public License along
22 with Bash; see the file COPYING. If not, write to the Free Software
bb70624e 23 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
726f6388 24
ccc6cda3
JA
25#include "config.h"
26
726f6388
JA
27#include "bashtypes.h"
28#include <stdio.h>
29#include <pwd.h>
30#include <signal.h>
31#include <errno.h>
ccc6cda3
JA
32
33#if defined (HAVE_UNISTD_H)
34# include <unistd.h>
35#endif
726f6388
JA
36
37#include "bashansi.h"
38#include "posixstat.h"
39
40#include "shell.h"
41#include "flags.h"
42#include "jobs.h"
43#include "execute_cmd.h"
44#include "filecntl.h"
ccc6cda3
JA
45#include "trap.h"
46#include "pathexp.h"
47#include "mailcheck.h"
48
d166f048
JA
49#if !defined (HAVE_RESTARTABLE_SYSCALLS) /* for getc_with_restart */
50#include "input.h"
51#endif
52
ccc6cda3
JA
53#include "builtins/getopt.h"
54#include "builtins/common.h"
726f6388 55
cce855bc 56#include <tilde/tilde.h>
726f6388 57#include <glob/fnmatch.h>
ccc6cda3
JA
58
59#if !defined (errno)
60extern int errno;
61#endif /* !errno */
726f6388
JA
62
63/* The size that strings change by. */
d166f048 64#define DEFAULT_INITIAL_ARRAY_SIZE 112
ccc6cda3
JA
65#define DEFAULT_ARRAY_SIZE 128
66
67/* Variable types. */
68#define VT_VARIABLE 0
69#define VT_POSPARMS 1
70#define VT_ARRAYVAR 2
d166f048 71#define VT_ARRAYMEMBER 3
726f6388 72
ccc6cda3
JA
73/* Flags for quoted_strchr */
74#define ST_BACKSL 0x01
75#define ST_CTLESC 0x02
76
cce855bc
JA
77/* These defs make it easier to use the editor. */
78#define LBRACE '{'
79#define RBRACE '}'
80#define LPAREN '('
81#define RPAREN ')'
726f6388 82
bb70624e
JA
83/* Evaluates to 1 if this is one of the shell's special variables. */
84#define SPECIAL_VAR(name, wi) \
85 ((digit (*name) && all_digits (name)) || \
86 (name[1] == '\0' && member (*name, "#-?$!@*")) || \
87 (wi && name[2] == '\0' && member (name[1], "#?@*")))
88
726f6388
JA
89/* Process ID of the last command executed within command substitution. */
90pid_t last_command_subst_pid = NO_PID;
b72432fd 91pid_t current_command_subst_pid = NO_PID;
726f6388
JA
92
93/* Extern functions and variables from different files. */
94extern int last_command_exit_value, interactive, interactive_shell;
ccc6cda3 95extern int subshell_environment, startup_state;
bb70624e 96extern int return_catch_flag, return_catch_value;
ccc6cda3 97extern int dollar_dollar_pid;
726f6388 98extern int posixly_correct;
726f6388 99extern char *this_command_name;
ccc6cda3 100extern struct fd_bitmap *current_fds_to_close;
cce855bc 101extern int wordexp_only;
726f6388 102
ccc6cda3
JA
103extern void getopts_reset ();
104
105/* Non-zero means to allow unmatched globbed filenames to expand to
106 a null file. */
107int allow_null_glob_expansion;
108
109/* Variables to keep track of which words in an expanded word list (the
110 output of expand_word_list_internal) are the result of globbing
111 expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c. */
112char *glob_argv_flags;
113static int glob_argv_flags_size;
726f6388
JA
114
115static WORD_LIST expand_word_error, expand_word_fatal;
116static char expand_param_error, expand_param_fatal;
117
b72432fd 118static int doing_completion = 0;
bb70624e
JA
119static int doing_prompt_expansion = 0;
120
121/* Used to hold a list of variable assignments preceding a command. Global
122 so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
123 SIGCHLD trap. */
124WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
125/* A WORD_LIST of words to be expanded by expand_word_list_internal,
126 without any leading variable assignments. */
127static WORD_LIST *garglist = (WORD_LIST *)NULL;
b72432fd 128
cce855bc
JA
129static char *make_quoted_char ();
130static void remove_quoted_nulls ();
131static char *param_expand ();
132static char *maybe_expand_string ();
133static WORD_LIST *call_expand_word_internal ();
726f6388 134static WORD_LIST *expand_string_internal ();
ccc6cda3 135static WORD_LIST *expand_word_internal (), *expand_word_list_internal ();
726f6388 136static WORD_LIST *expand_string_leave_quoted ();
ccc6cda3 137static WORD_LIST *expand_string_for_rhs ();
b72432fd 138static char *getifs ();
726f6388 139static WORD_LIST *word_list_split ();
ccc6cda3 140static WORD_LIST *quote_list (), *dequote_list ();
cce855bc
JA
141static char *quote_escapes ();
142static WORD_LIST *list_quote_escapes ();
726f6388 143static int unquoted_substring (), unquoted_member ();
726f6388
JA
144static int do_assignment_internal ();
145static char *string_extract_verbatim (), *string_extract ();
146static char *string_extract_double_quoted (), *string_extract_single_quoted ();
cce855bc
JA
147static char *string_list_dollar_at (), *string_list_dollar_star ();
148static inline int skip_single_quoted (), skip_double_quoted ();
726f6388
JA
149static char *extract_delimited_string ();
150static char *extract_dollar_brace_string ();
151
152/* **************************************************************** */
153/* */
154/* Utility Functions */
155/* */
156/* **************************************************************** */
157
158/* Cons a new string from STRING starting at START and ending at END,
159 not including END. */
160char *
161substring (string, start, end)
162 char *string;
163 int start, end;
164{
ccc6cda3
JA
165 register int len;
166 register char *result;
726f6388 167
ccc6cda3
JA
168 len = end - start;
169 result = xmalloc (len + 1);
726f6388
JA
170 strncpy (result, string + start, len);
171 result[len] = '\0';
172 return (result);
173}
174
ccc6cda3
JA
175static char *
176quoted_substring (string, start, end)
177 char *string;
178 int start, end;
179{
180 register int len, l;
181 register char *result, *s, *r;
182
183 len = end - start;
184
185 /* Move to string[start], skipping quoted characters. */
186 for (s = string, l = 0; *s && l < start; )
187 {
188 if (*s == CTLESC)
189 {
190 s++;
191 continue;
192 }
193 l++;
194 if (*s == 0)
195 break;
196 }
197
198 r = result = xmalloc (2*len + 1); /* save room for quotes */
199
200 /* Copy LEN characters, including quote characters. */
201 s = string + l;
202 for (l = 0; l < len; s++)
203 {
204 if (*s == CTLESC)
205 *r++ = *s++;
206 *r++ = *s;
207 l++;
208 if (*s == 0)
209 break;
210 }
211 *r = '\0';
212 return result;
213}
214
215/* Find the first occurrence of character C in string S, obeying shell
216 quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
217 characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters
218 escaped with CTLESC are skipped. */
219static inline char *
220quoted_strchr (s, c, flags)
221 char *s;
222 int c, flags;
223{
224 register char *p;
225
226 for (p = s; *p; p++)
227 {
228 if (((flags & ST_BACKSL) && *p == '\\')
229 || ((flags & ST_CTLESC) && *p == CTLESC))
230 {
231 p++;
232 if (*p == '\0')
233 return ((char *)NULL);
234 continue;
235 }
236 else if (*p == c)
237 return p;
238 }
239 return ((char *)NULL);
240}
241
cce855bc
JA
242/* Return 1 if CHARACTER appears in an unquoted portion of
243 STRING. Return 0 otherwise. */
244static int
245unquoted_member (character, string)
246 int character;
726f6388
JA
247 char *string;
248{
cce855bc 249 int sindex, c;
726f6388 250
cce855bc 251 for (sindex = 0; c = string[sindex]; )
726f6388 252 {
cce855bc
JA
253 if (c == character)
254 return (1);
255
256 switch (c)
ccc6cda3 257 {
cce855bc
JA
258 default:
259 sindex++;
260 break;
261
262 case '\\':
263 sindex++;
264 if (string[sindex])
265 sindex++;
266 break;
267
268 case '\'':
269 sindex = skip_single_quoted (string, ++sindex);
270 break;
271
272 case '"':
273 sindex = skip_double_quoted (string, ++sindex);
274 break;
ccc6cda3 275 }
726f6388 276 }
cce855bc 277 return (0);
726f6388
JA
278}
279
cce855bc
JA
280/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
281static int
282unquoted_substring (substr, string)
283 char *substr, *string;
726f6388 284{
cce855bc 285 int sindex, c, sublen;
726f6388 286
cce855bc
JA
287 if (substr == 0 || *substr == '\0')
288 return (0);
289
290 sublen = strlen (substr);
291 for (sindex = 0; c = string[sindex]; )
726f6388 292 {
cce855bc
JA
293 if (STREQN (string + sindex, substr, sublen))
294 return (1);
295
296 switch (c)
297 {
298 case '\\':
299 sindex++;
300
301 if (string[sindex])
302 sindex++;
303 break;
304
305 case '\'':
306 sindex = skip_single_quoted (string, ++sindex);
307 break;
308
309 case '"':
310 sindex = skip_double_quoted (string, ++sindex);
311 break;
312
313 default:
314 sindex++;
315 break;
316 }
726f6388 317 }
cce855bc 318 return (0);
ccc6cda3 319}
726f6388 320
cce855bc
JA
321/* Most of the substitutions must be done in parallel. In order
322 to avoid using tons of unclear goto's, I have some functions
323 for manipulating malloc'ed strings. They all take INDX, a
324 pointer to an integer which is the offset into the string
325 where manipulation is taking place. They also take SIZE, a
326 pointer to an integer which is the current length of the
327 character array for this string. */
726f6388 328
cce855bc
JA
329/* Append SOURCE to TARGET at INDEX. SIZE is the current amount
330 of space allocated to TARGET. SOURCE can be NULL, in which
331 case nothing happens. Gets rid of SOURCE by freeing it.
332 Returns TARGET in case the location has changed. */
333inline char *
334sub_append_string (source, target, indx, size)
335 char *source, *target;
336 int *indx, *size;
337{
338 if (source)
726f6388 339 {
cce855bc
JA
340 int srclen, n;
341
342 srclen = STRLEN (source);
343 if (srclen >= (int)(*size - *indx))
726f6388 344 {
cce855bc
JA
345 n = srclen + *indx;
346 n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
347 target = xrealloc (target, (*size = n));
726f6388 348 }
cce855bc
JA
349
350 FASTCOPY (source, target + *indx, srclen);
351 *indx += srclen;
352 target[*indx] = '\0';
353
354 free (source);
726f6388 355 }
cce855bc
JA
356 return (target);
357}
358
359#if 0
360/* UNUSED */
361/* Append the textual representation of NUMBER to TARGET.
362 INDX and SIZE are as in SUB_APPEND_STRING. */
363char *
364sub_append_number (number, target, indx, size)
365 int number, *indx, *size;
366 char *target;
367{
368 char *temp;
369
370 temp = itos (number);
371 return (sub_append_string (temp, target, indx, size));
726f6388 372}
d166f048 373#endif
726f6388
JA
374
375/* Extract a substring from STRING, starting at SINDEX and ending with
376 one of the characters in CHARLIST. Don't make the ending character
377 part of the string. Leave SINDEX pointing at the ending character.
ccc6cda3
JA
378 Understand about backslashes in the string. If VARNAME is non-zero,
379 and array variables have been compiled into the shell, everything
380 between a `[' and a corresponding `]' is skipped over. */
726f6388 381static char *
ccc6cda3 382string_extract (string, sindex, charlist, varname)
726f6388 383 char *string, *charlist;
ccc6cda3 384 int *sindex, varname;
726f6388 385{
ccc6cda3 386 register int c, i;
726f6388
JA
387 char *temp;
388
ccc6cda3 389 for (i = *sindex; c = string[i]; i++)
726f6388
JA
390 {
391 if (c == '\\')
392 if (string[i + 1])
393 i++;
394 else
395 break;
ccc6cda3
JA
396#if defined (ARRAY_VARS)
397 else if (varname && c == '[')
398 {
399 int ni;
400 /* If this is an array subscript, skip over it and continue. */
401 ni = skipsubscript (string, i);
402 if (string[ni] == ']')
403 i = ni;
404 }
405#endif
406 else if (MEMBER (c, charlist))
726f6388 407 break;
726f6388 408 }
bb70624e
JA
409
410 temp = substring (string, *sindex, i);
726f6388
JA
411 *sindex = i;
412 return (temp);
413}
414
ccc6cda3
JA
415/* Extract the contents of STRING as if it is enclosed in double quotes.
416 SINDEX, when passed in, is the offset of the character immediately
417 following the opening double quote; on exit, SINDEX is left pointing after
418 the closing double quote. If STRIPDQ is non-zero, unquoted double
419 quotes are stripped and the string is terminated by a null byte.
420 Backslashes between the embedded double quotes are processed. If STRIPDQ
421 is zero, an unquoted `"' terminates the string. */
422static inline char *
423string_extract_double_quoted (string, sindex, stripdq)
726f6388 424 char *string;
ccc6cda3 425 int *sindex, stripdq;
726f6388 426{
ccc6cda3
JA
427 int c, j, i, t;
428 char *temp, *ret; /* The new string we return. */
429 int pass_next, backquote, si; /* State variables for the machine. */
430 int dquote;
726f6388 431
ccc6cda3
JA
432 pass_next = backquote = dquote = 0;
433 temp = xmalloc (1 + strlen (string) - *sindex);
726f6388 434
ccc6cda3 435 for (j = 0, i = *sindex; c = string[i]; i++)
726f6388 436 {
ccc6cda3
JA
437 /* Process a character that was quoted by a backslash. */
438 if (pass_next)
726f6388 439 {
ccc6cda3 440 /* Posix.2 sez:
726f6388 441
ccc6cda3
JA
442 ``The backslash shall retain its special meaning as an escape
443 character only when followed by one of the characters:
444 $ ` " \ <newline>''.
726f6388 445
ccc6cda3
JA
446 If STRIPDQ is zero, we handle the double quotes here and let
447 expand_word_internal handle the rest. If STRIPDQ is non-zero,
448 we have already been through one round of backslash stripping,
449 and want to strip these backslashes only if DQUOTE is non-zero,
450 indicating that we are inside an embedded double-quoted string. */
451
452 /* If we are in an embedded quoted string, then don't strip
453 backslashes before characters for which the backslash
454 retains its special meaning, but remove backslashes in
455 front of other characters. If we are not in an
456 embedded quoted string, don't strip backslashes at all.
457 This mess is necessary because the string was already
458 surrounded by double quotes (and sh has some really weird
459 quoting rules).
460 The returned string will be run through expansion as if
461 it were double-quoted. */
462 if ((stripdq == 0 && c != '"') ||
463 (stripdq && ((dquote && strchr (slashify_in_quotes, c)) || dquote == 0)))
464 temp[j++] = '\\';
465 temp[j++] = c;
466 pass_next = 0;
467 continue;
468 }
726f6388 469
ccc6cda3
JA
470 /* A backslash protects the next character. The code just above
471 handles preserving the backslash in front of any character but
472 a double quote. */
473 if (c == '\\')
726f6388 474 {
ccc6cda3 475 pass_next++;
726f6388
JA
476 continue;
477 }
478
ccc6cda3
JA
479 /* Inside backquotes, ``the portion of the quoted string from the
480 initial backquote and the characters up to the next backquote
481 that is not preceded by a backslash, having escape characters
482 removed, defines that command''. */
483 if (backquote)
726f6388 484 {
ccc6cda3
JA
485 if (c == '`')
486 backquote = 0;
487 temp[j++] = c;
726f6388
JA
488 continue;
489 }
490
ccc6cda3 491 if (c == '`')
726f6388 492 {
ccc6cda3
JA
493 temp[j++] = c;
494 backquote++;
495 continue;
726f6388
JA
496 }
497
ccc6cda3
JA
498 /* Pass everything between `$(' and the matching `)' or a quoted
499 ${ ... } pair through according to the Posix.2 specification. */
cce855bc 500 if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
726f6388 501 {
ccc6cda3 502 si = i + 2;
cce855bc
JA
503 if (string[i + 1] == LPAREN)
504 ret = extract_delimited_string (string, &si, "$(", "(", ")"); /*)*/
ccc6cda3
JA
505 else
506 ret = extract_dollar_brace_string (string, &si, 1);
726f6388 507
ccc6cda3
JA
508 temp[j++] = '$';
509 temp[j++] = string[i + 1];
726f6388 510
ccc6cda3
JA
511 for (t = 0; ret[t]; t++, j++)
512 temp[j] = ret[t];
513 temp[j++] = string[si];
726f6388 514
ccc6cda3
JA
515 i = si;
516 free (ret);
517 continue;
726f6388
JA
518 }
519
ccc6cda3
JA
520 /* Add any character but a double quote to the quoted string we're
521 accumulating. */
522 if (c != '"')
726f6388 523 {
ccc6cda3 524 temp[j++] = c;
726f6388
JA
525 continue;
526 }
ccc6cda3
JA
527
528 /* c == '"' */
529 if (stripdq)
726f6388 530 {
ccc6cda3
JA
531 dquote ^= 1;
532 continue;
726f6388 533 }
ccc6cda3
JA
534
535 break;
726f6388 536 }
ccc6cda3 537 temp[j] = '\0';
726f6388 538
ccc6cda3
JA
539 /* Point to after the closing quote. */
540 if (c)
541 i++;
726f6388
JA
542 *sindex = i;
543
ccc6cda3
JA
544 return (temp);
545}
546
547/* This should really be another option to string_extract_double_quoted. */
548static inline int
549skip_double_quoted (string, sind)
550 char *string;
551 int sind;
552{
553 int c, j, i;
554 char *ret;
555 int pass_next, backquote, si;
556
557 pass_next = backquote = 0;
558
559 for (j = 0, i = sind; c = string[i]; i++)
726f6388 560 {
ccc6cda3
JA
561 if (pass_next)
562 {
563 pass_next = 0;
564 continue;
565 }
566 else if (c == '\\')
567 {
568 pass_next++;
569 continue;
570 }
571 else if (backquote)
572 {
573 if (c == '`')
574 backquote = 0;
575 continue;
576 }
577 else if (c == '`')
578 {
579 backquote++;
580 continue;
581 }
cce855bc 582 else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
ccc6cda3
JA
583 {
584 si = i + 2;
cce855bc 585 if (string[i + 1] == LPAREN)
ccc6cda3
JA
586 ret = extract_delimited_string (string, &si, "$(", "(", ")");
587 else
588 ret = extract_dollar_brace_string (string, &si, 0);
589
590 i = si;
591 free (ret);
592 continue;
593 }
594 else if (c != '"')
595 continue;
596 else
597 break;
726f6388 598 }
ccc6cda3
JA
599
600 if (c)
601 i++;
602
603 return (i);
726f6388
JA
604}
605
ccc6cda3
JA
606/* Extract the contents of STRING as if it is enclosed in single quotes.
607 SINDEX, when passed in, is the offset of the character immediately
608 following the opening single quote; on exit, SINDEX is left pointing after
609 the closing single quote. */
610static inline char *
611string_extract_single_quoted (string, sindex)
612 char *string;
613 int *sindex;
614{
615 register int i, j;
616 char *t;
617
618 for (i = *sindex; string[i] && string[i] != '\''; i++)
619 ;
620
bb70624e 621 t = substring (string, *sindex, i);
ccc6cda3
JA
622
623 if (string[i])
624 i++;
625 *sindex = i;
626
627 return (t);
628}
629
630static inline int
631skip_single_quoted (string, sind)
632 char *string;
633 int sind;
634{
635 register int i;
636
637 for (i = sind; string[i] && string[i] != '\''; i++)
638 ;
639 if (string[i])
640 i++;
641 return i;
642}
643
644/* Just like string_extract, but doesn't hack backslashes or any of
bb70624e 645 that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */
726f6388 646static char *
ccc6cda3
JA
647string_extract_verbatim (string, sindex, charlist)
648 char *string, *charlist;
649 int *sindex;
650{
651 register int i = *sindex;
652 int c;
653 char *temp;
654
655 if (charlist[0] == '\'' && charlist[1] == '\0')
656 {
657 temp = string_extract_single_quoted (string, sindex);
658 --*sindex; /* leave *sindex at separator character */
659 return temp;
660 }
661
662 for (i = *sindex; c = string[i]; i++)
663 {
664 if (c == CTLESC)
665 {
666 i++;
667 continue;
668 }
669
670 if (MEMBER (c, charlist))
671 break;
672 }
673
bb70624e 674 temp = substring (string, *sindex, i);
ccc6cda3
JA
675 *sindex = i;
676
677 return (temp);
678}
679
680/* Extract the $( construct in STRING, and return a new string.
681 Start extracting at (SINDEX) as if we had just seen "$(".
682 Make (SINDEX) get the position of the matching ")". */
683char *
684extract_command_subst (string, sindex)
726f6388
JA
685 char *string;
686 int *sindex;
687{
ccc6cda3
JA
688 return (extract_delimited_string (string, sindex, "$(", "(", ")"));
689}
690
691/* Extract the $[ construct in STRING, and return a new string.
692 Start extracting at (SINDEX) as if we had just seen "$[".
693 Make (SINDEX) get the position of the matching "]". */
694char *
695extract_arithmetic_subst (string, sindex)
696 char *string;
697 int *sindex;
698{
699 return (extract_delimited_string (string, sindex, "$[", "[", "]"));
700}
701
702#if defined (PROCESS_SUBSTITUTION)
703/* Extract the <( or >( construct in STRING, and return a new string.
704 Start extracting at (SINDEX) as if we had just seen "<(".
cce855bc 705 Make (SINDEX) get the position of the matching ")". */ /*))*/
ccc6cda3
JA
706char *
707extract_process_subst (string, starter, sindex)
708 char *string;
709 char *starter;
710 int *sindex;
711{
712 return (extract_delimited_string (string, sindex, starter, "(", ")"));
713}
714#endif /* PROCESS_SUBSTITUTION */
715
716#if defined (ARRAY_VARS)
717char *
718extract_array_assignment_list (string, sindex)
719 char *string;
720 int *sindex;
721{
722 return (extract_delimited_string (string, sindex, "(", (char *)NULL, ")"));
723}
724#endif
725
726/* Extract and create a new string from the contents of STRING, a
727 character string delimited with OPENER and CLOSER. SINDEX is
728 the address of an int describing the current offset in STRING;
729 it should point to just after the first OPENER found. On exit,
730 SINDEX gets the position of the last character of the matching CLOSER.
731 If OPENER is more than a single character, ALT_OPENER, if non-null,
732 contains a character string that can also match CLOSER and thus
733 needs to be skipped. */
734static char *
735extract_delimited_string (string, sindex, opener, alt_opener, closer)
736 char *string;
737 int *sindex;
738 char *opener, *alt_opener, *closer;
739{
740 int i, c, si;
741 char *t, *result;
726f6388 742 int pass_character, nesting_level;
ccc6cda3
JA
743 int len_closer, len_opener, len_alt_opener;
744
745 len_opener = STRLEN (opener);
746 len_alt_opener = STRLEN (alt_opener);
747 len_closer = STRLEN (closer);
726f6388 748
ccc6cda3 749 pass_character = 0;
726f6388
JA
750
751 nesting_level = 1;
ccc6cda3 752 i = *sindex;
726f6388 753
ccc6cda3 754 while (nesting_level)
726f6388 755 {
ccc6cda3
JA
756 c = string[i];
757
758 if (c == 0)
759 break;
760
761 if (pass_character) /* previous char was backslash */
726f6388
JA
762 {
763 pass_character = 0;
ccc6cda3 764 i++;
726f6388
JA
765 continue;
766 }
767
768 if (c == CTLESC)
769 {
770 pass_character++;
ccc6cda3 771 i++;
726f6388
JA
772 continue;
773 }
774
ccc6cda3
JA
775#if 0
776 if (c == '\\' && delimiter == '"' &&
777 (member (string[i], slashify_in_quotes)))
778#else
726f6388 779 if (c == '\\')
ccc6cda3 780#endif
726f6388 781 {
ccc6cda3
JA
782 pass_character++;
783 i++;
784 continue;
726f6388
JA
785 }
786
ccc6cda3
JA
787 /* Process a nested OPENER. */
788 if (STREQN (string + i, opener, len_opener))
726f6388 789 {
ccc6cda3
JA
790 si = i + len_opener;
791 t = extract_delimited_string (string, &si, opener, alt_opener, closer);
792 i = si + 1;
793 FREE (t);
794 continue;
726f6388
JA
795 }
796
ccc6cda3
JA
797 /* Process a nested ALT_OPENER */
798 if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
726f6388 799 {
ccc6cda3
JA
800 si = i + len_alt_opener;
801 t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer);
802 i = si + 1;
803 FREE (t);
726f6388
JA
804 continue;
805 }
ccc6cda3
JA
806
807 /* If the current substring terminates the delimited string, decrement
808 the nesting level. */
809 if (STREQN (string + i, closer, len_closer))
726f6388 810 {
ccc6cda3
JA
811 i += len_closer - 1; /* move to last char of the closer */
812 nesting_level--;
813 if (nesting_level == 0)
814 break;
726f6388 815 }
ccc6cda3
JA
816
817 /* Pass old-style command substitution through verbatim. */
818 if (c == '`')
819 {
820 si = i + 1;
821 t = string_extract (string, &si, "`", 0);
822 i = si + 1;
823 FREE (t);
824 continue;
825 }
826
827 /* Pass single-quoted strings through verbatim. */
828 if (c == '\'')
829 {
830 si = i + 1;
831 i = skip_single_quoted (string, si);
832 continue;
833 }
834
835 /* Pass embedded double-quoted strings through verbatim as well. */
836 if (c == '"')
837 {
838 si = i + 1;
839 i = skip_double_quoted (string, si);
840 continue;
841 }
842
843 i++; /* move past this character, which was not special. */
726f6388
JA
844 }
845
bb70624e 846#if 0
ccc6cda3 847 if (c == 0 && nesting_level)
bb70624e
JA
848#else
849 if (c == 0 && nesting_level && doing_completion == 0)
850#endif
726f6388 851 {
ccc6cda3 852 report_error ("bad substitution: no `%s' in %s", closer, string);
ccc6cda3 853 jump_to_top_level (DISCARD);
726f6388 854 }
ccc6cda3 855
cce855bc
JA
856 si = i - *sindex - len_closer + 1;
857 result = xmalloc (1 + si);
858 strncpy (result, string + *sindex, si);
859 result[si] = '\0';
860 *sindex = i;
861
726f6388
JA
862 return (result);
863}
864
ccc6cda3
JA
865/* Extract a parameter expansion expression within ${ and } from STRING.
866 Obey the Posix.2 rules for finding the ending `}': count braces while
867 skipping over enclosed quoted strings and command substitutions.
868 SINDEX is the address of an int describing the current offset in STRING;
869 it should point to just after the first `{' found. On exit, SINDEX
870 gets the position of the matching `}'. QUOTED is non-zero if this
871 occurs inside double quotes. */
872/* XXX -- this is very similar to extract_delimited_string -- XXX */
726f6388 873static char *
ccc6cda3 874extract_dollar_brace_string (string, sindex, quoted)
726f6388 875 char *string;
ccc6cda3 876 int *sindex, quoted;
726f6388 877{
ccc6cda3
JA
878 register int i, c, l;
879 int pass_character, nesting_level, si;
880 char *result, *t;
726f6388 881
ccc6cda3 882 pass_character = 0;
726f6388 883
ccc6cda3
JA
884 nesting_level = 1;
885
886 for (i = *sindex; (c = string[i]); i++)
726f6388 887 {
ccc6cda3 888 if (pass_character)
726f6388 889 {
ccc6cda3
JA
890 pass_character = 0;
891 continue;
892 }
726f6388 893
cce855bc
JA
894 /* CTLESCs and backslashes quote the next character. */
895 if (c == CTLESC || c == '\\')
726f6388 896 {
ccc6cda3 897 pass_character++;
726f6388
JA
898 continue;
899 }
900
cce855bc 901 if (string[i] == '$' && string[i+1] == LBRACE)
726f6388 902 {
ccc6cda3
JA
903 nesting_level++;
904 i++;
726f6388
JA
905 continue;
906 }
907
cce855bc 908 if (c == RBRACE)
726f6388 909 {
ccc6cda3
JA
910 nesting_level--;
911 if (nesting_level == 0)
912 break;
726f6388
JA
913 continue;
914 }
915
ccc6cda3
JA
916 /* Pass the contents of old-style command substitutions through
917 verbatim. */
918 if (c == '`')
726f6388 919 {
ccc6cda3
JA
920 si = i + 1;
921 t = string_extract (string, &si, "`", 0);
922 i = si;
923 free (t);
924 continue;
925 }
726f6388 926
cce855bc
JA
927 /* Pass the contents of new-style command substitutions and
928 arithmetic substitutions through verbatim. */
929 if (string[i] == '$' && string[i+1] == LPAREN)
ccc6cda3 930 {
726f6388 931 si = i + 2;
cce855bc 932 t = extract_delimited_string (string, &si, "$(", "(", ")"); /*)*/
726f6388 933 i = si;
ccc6cda3 934 free (t);
726f6388
JA
935 continue;
936 }
937
cce855bc
JA
938 /* Pass the contents of single-quoted and double-quoted strings
939 through verbatim. */
940 if (c == '\'' || c == '"')
ccc6cda3
JA
941 {
942 si = i + 1;
cce855bc
JA
943 i = (c == '\'') ? skip_single_quoted (string, si)
944 : skip_double_quoted (string, si);
945 /* skip_XXX_quoted leaves index one past close quote */
ccc6cda3
JA
946 i--;
947 continue;
948 }
cce855bc 949 }
726f6388 950
b72432fd 951 if (c == 0 && nesting_level && doing_completion == 0)
cce855bc
JA
952 {
953 report_error ("bad substitution: no ending `}' in %s", string);
954 jump_to_top_level (DISCARD);
726f6388 955 }
726f6388 956
bb70624e 957 result = substring (string, *sindex, i);
726f6388
JA
958 *sindex = i;
959
ccc6cda3 960 return (result);
726f6388
JA
961}
962
ccc6cda3
JA
963/* Remove backslashes which are quoting backquotes from STRING. Modifies
964 STRING, and returns a pointer to it. */
965char *
966de_backslash (string)
726f6388 967 char *string;
ccc6cda3
JA
968{
969 register int i, l;
726f6388 970
ccc6cda3
JA
971 for (i = 0, l = strlen (string); i < l; i++)
972 if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
973 string[i + 1] == '$'))
974 strcpy (string + i, string + i + 1); /* XXX - should be memmove */
975 return (string);
976}
726f6388 977
ccc6cda3 978#if 0
cce855bc 979/*UNUSED*/
ccc6cda3
JA
980/* Replace instances of \! in a string with !. */
981void
982unquote_bang (string)
983 char *string;
984{
985 register int i, j;
986 register char *temp;
726f6388 987
ccc6cda3 988 temp = xmalloc (1 + strlen (string));
726f6388 989
ccc6cda3
JA
990 for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
991 {
992 if (string[i] == '\\' && string[i + 1] == '!')
993 {
994 temp[j] = '!';
995 i++;
996 }
997 }
998 strcpy (string, temp);
999 free (temp);
726f6388 1000}
ccc6cda3 1001#endif
726f6388 1002
ccc6cda3 1003#if defined (READLINE)
726f6388
JA
1004/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
1005 an unclosed quoted string), or if the character at EINDEX is quoted
b72432fd
JA
1006 by a backslash. DOING_COMPLETION is used to flag that the various
1007 single and double-quoted string parsing functions should not return an
1008 error if there are unclosed quotes or braces. */
1009
1010#define CQ_RETURN(x) do { doing_completion = 0; return (x); } while (0)
1011
726f6388
JA
1012int
1013char_is_quoted (string, eindex)
1014 char *string;
1015 int eindex;
1016{
1017 int i, pass_next, quoted;
726f6388 1018
b72432fd 1019 doing_completion = 1;
726f6388
JA
1020 for (i = pass_next = quoted = 0; i <= eindex; i++)
1021 {
1022 if (pass_next)
1023 {
1024 pass_next = 0;
1025 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
b72432fd 1026 CQ_RETURN(1);
726f6388
JA
1027 continue;
1028 }
ccc6cda3
JA
1029 else if (string[i] == '\'' || string[i] == '"')
1030 {
1031 i = (string[i] == '\'') ? skip_single_quoted (string, ++i)
1032 : skip_double_quoted (string, ++i);
1033 if (i > eindex)
b72432fd 1034 CQ_RETURN(1);
ccc6cda3
JA
1035 i--; /* the skip functions increment past the closing quote. */
1036 }
726f6388 1037 else if (string[i] == '\\')
ccc6cda3
JA
1038 {
1039 pass_next = 1;
1040 continue;
1041 }
726f6388 1042 }
b72432fd 1043 CQ_RETURN(0);
726f6388
JA
1044}
1045
726f6388
JA
1046int
1047unclosed_pair (string, eindex, openstr)
1048 char *string;
1049 int eindex;
1050 char *openstr;
1051{
ccc6cda3 1052 int i, pass_next, openc, olen;
726f6388
JA
1053
1054 olen = strlen (openstr);
1055 for (i = pass_next = openc = 0; i <= eindex; i++)
1056 {
1057 if (pass_next)
1058 {
1059 pass_next = 0;
1060 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
1061 return 0;
1062 continue;
1063 }
1064 else if (STREQN (string + i, openstr, olen))
1065 {
1066 openc = 1 - openc;
1067 i += olen - 1;
1068 }
ccc6cda3 1069 else if (string[i] == '\'' || string[i] == '"')
726f6388 1070 {
ccc6cda3
JA
1071 i = (string[i] == '\'') ? skip_single_quoted (string, i)
1072 : skip_double_quoted (string, i);
726f6388
JA
1073 if (i > eindex)
1074 return 0;
1075 }
1076 else if (string[i] == '\\')
1077 {
1078 pass_next = 1;
1079 continue;
1080 }
1081 }
1082 return (openc);
1083}
bb70624e
JA
1084
1085/* Skip characters in STRING until we find a character in DELIMS, and return
1086 the index of that character. START is the index into string at which we
1087 begin. This is similar in spirit to strpbrk, but it returns an index into
1088 STRING and takes a starting index. This little piece of code knows quite
1089 a lot of shell syntax. It's very similar to skip_double_quoted and other
1090 functions of that ilk. */
1091int
1092skip_to_delim (string, start, delims)
1093 char *string;
1094 int start;
1095 char *delims;
1096{
1097 int i, pass_next, backq, si;
1098 char *temp;
1099
1100 doing_completion = 1;
1101 for (i = start, pass_next = backq = 0; string[i]; i++)
1102 {
1103 if (pass_next)
1104 {
1105 pass_next = 0;
1106 if (string[i] == 0)
1107 CQ_RETURN(i);
1108 continue;
1109 }
1110 else if (string[i] == '\\')
1111 {
1112 pass_next = 1;
1113 continue;
1114 }
1115 else if (backq)
1116 {
1117 if (string[i] == '`')
1118 backq = 0;
1119 continue;
1120 }
1121 else if (string[i] == '`')
1122 {
1123 backq = 1;
1124 continue;
1125 }
1126 else if (string[i] == '\'' || string[i] == '"')
1127 {
1128 i = (string[i] == '\'') ? skip_single_quoted (string, ++i)
1129 : skip_double_quoted (string, ++i);
1130 i--; /* the skip functions increment past the closing quote. */
1131 }
1132 else if (string[i] == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
1133 {
1134 si = i + 2;
1135 if (string[si] == '\0')
1136 break;
1137 if (string[i+1] == LPAREN)
1138 temp = extract_delimited_string (string, &si, "$(", "(", ")"); /* ) */
1139 else
1140 temp = extract_dollar_brace_string (string, &si, 0);
1141 i = si;
1142 free (temp);
1143 continue;
1144 }
1145 else if (member (string[i], delims))
1146 break;
1147 }
1148 CQ_RETURN(i);
1149}
1150
1151/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
1152 individual words. If DELIMS is NULL, the current value of $IFS is used
1153 to split the string. SENTINEL is an index to look for. NWP, if non-NULL
1154 gets the number of words in the returned list. CWP, if non-NULL, gets
1155 the index of the word containing SENTINEL. Non-whitespace chars in
1156 DELIMS delimit separate fields. */
1157WORD_LIST *
1158split_at_delims (string, slen, delims, sentinel, nwp, cwp)
1159 char *string;
1160 int slen;
1161 char *delims;
1162 int sentinel;
1163 int *nwp, *cwp;
1164{
1165 int ts, te, i, nw, cw, peekc;
1166 char *token, *s, *d, *d2;
1167 WORD_LIST *ret, *tl;
1168
1169 if (string == 0 || *string == '\0')
1170 {
1171 if (nwp)
1172 *nwp = 0;
1173 if (cwp)
1174 *cwp = 0;
1175 return ((WORD_LIST *)NULL);
1176 }
1177
1178 d = (delims == 0) ? getifs () : delims;
1179
1180 /* Make d2 the non-whitespace characters in delims */
1181 d2 = 0;
1182 if (delims)
1183 {
1184 d2 = xmalloc (strlen (delims) + 1);
1185 for (i = ts = 0; delims[i]; i++)
1186 {
1187 if (whitespace(delims[i]) == 0)
1188 d2[ts++] = delims[i];
1189 }
1190 d2[ts] = '\0';
1191 }
1192
1193 ret = (WORD_LIST *)NULL;
1194
1195 for (i = 0; member (string[i], d) && whitespace(string[i]); i++)
1196 ;
1197 if (string[i] == '\0')
1198 return (ret);
1199
1200 ts = i;
1201 nw = 0;
1202 cw = -1;
1203 while (1)
1204 {
1205 te = skip_to_delim (string, ts, d);
1206
1207 /* If we have a non-whitespace delimiter character, use it to make a
1208 separate field. This is just about what $IFS splitting does and
1209 is closer to the behavior of the shell parser. */
1210 if (ts == te && member(string[ts], d2))
1211 {
1212 te = ts + 1;
1213 while (member(string[te], d2))
1214 te++;
1215 }
1216
1217 token = substring (string, ts, te);
1218
1219 ret = add_string_to_list (token, ret);
1220 free (token);
1221 nw++;
1222
1223 if (sentinel >= ts && sentinel <= te)
1224 cw = nw;
1225
1226 /* If the cursor is at whitespace just before word start, set the
1227 sentinel word to the current word. */
1228 if (cwp && cw == -1 && sentinel == ts-1)
1229 cw = nw;
1230
1231 /* If the cursor is at whitespace between two words, make a new, empty
1232 word, add it before (well, after, since the list is in reverse order)
1233 the word we just added, and set the current word to that one. */
1234 if (cwp && cw == -1 && sentinel < ts)
1235 {
1236 tl = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
1237 tl->word = make_word ("");
1238 tl->next = ret->next;
1239 ret->next = tl;
1240 cw = nw;
1241 nw++;
1242 }
1243
1244 if (string[te] == 0)
1245 break;
1246
1247 i = te + member(string[te], d);
1248 while (member (string[i], d) && whitespace(string[i]))
1249 i++;
1250
1251 if (string[i])
1252 ts = i;
1253 else
1254 break;
1255 }
1256
1257 /* Special case for SENTINEL at the end of STRING. If we haven't found
1258 the word containing SENTINEL yet, and the index we're looking for is at
1259 the end of STRING, add an additional null argument and set the current
1260 word pointer to that. */
1261 if (cwp && cw == -1 && sentinel >= slen)
1262 {
1263 if (whitespace (string[sentinel - 1]))
1264 {
1265 token = "";
1266 ret = add_string_to_list (token, ret);
1267 nw++;
1268 }
1269 cw = nw;
1270 }
1271
1272 if (nwp)
1273 *nwp = nw;
1274 if (cwp)
1275 *cwp = cw;
1276
1277 return (REVERSE_LIST (ret, WORD_LIST *));
1278}
726f6388
JA
1279#endif /* READLINE */
1280
ccc6cda3
JA
1281#if 0
1282/* UNUSED */
726f6388
JA
1283/* Extract the name of the variable to bind to from the assignment string. */
1284char *
1285assignment_name (string)
1286 char *string;
1287{
ccc6cda3 1288 int offset;
726f6388
JA
1289 char *temp;
1290
ccc6cda3
JA
1291 offset = assignment (string);
1292 if (offset == 0)
726f6388 1293 return (char *)NULL;
bb70624e 1294 temp = substring (string, 0, offset);
726f6388
JA
1295 return (temp);
1296}
ccc6cda3 1297#endif
726f6388 1298
cce855bc
JA
1299/* **************************************************************** */
1300/* */
1301/* Functions to convert strings to WORD_LISTs and vice versa */
1302/* */
1303/* **************************************************************** */
1304
726f6388
JA
1305/* Return a single string of all the words in LIST. SEP is the separator
1306 to put between individual elements of LIST in the output string. */
1307static char *
1308string_list_internal (list, sep)
1309 WORD_LIST *list;
1310 char *sep;
1311{
1312 register WORD_LIST *t;
1313 char *result, *r;
1314 int word_len, sep_len, result_size;
1315
ccc6cda3 1316 if (list == 0)
726f6388
JA
1317 return ((char *)NULL);
1318
1319 /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
1320 sep_len = STRLEN (sep);
1321 result_size = 0;
1322
1323 for (t = list; t; t = t->next)
1324 {
1325 if (t != list)
1326 result_size += sep_len;
1327 result_size += strlen (t->word->word);
1328 }
1329
1330 r = result = xmalloc (result_size + 1);
1331
1332 for (t = list; t; t = t->next)
1333 {
1334 if (t != list && sep_len)
1335 {
ccc6cda3
JA
1336 if (sep_len > 1)
1337 {
1338 FASTCOPY (sep, r, sep_len);
1339 r += sep_len;
1340 }
1341 else
1342 *r++ = sep[0];
726f6388
JA
1343 }
1344
1345 word_len = strlen (t->word->word);
1346 FASTCOPY (t->word->word, r, word_len);
1347 r += word_len;
1348 }
1349
ccc6cda3 1350 *r = '\0';
726f6388
JA
1351 return (result);
1352}
1353
1354/* Return a single string of all the words present in LIST, separating
1355 each word with a space. */
1356char *
1357string_list (list)
1358 WORD_LIST *list;
1359{
1360 return (string_list_internal (list, " "));
1361}
1362
1363/* Return a single string of all the words present in LIST, obeying the
1364 quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
1365 expansion [of $*] appears within a double quoted string, it expands
1366 to a single field with the value of each parameter separated by the
1367 first character of the IFS variable, or by a <space> if IFS is unset." */
cce855bc 1368static char *
726f6388
JA
1369string_list_dollar_star (list)
1370 WORD_LIST *list;
1371{
ccc6cda3 1372 char *ifs, sep[2];
726f6388 1373
ccc6cda3 1374 ifs = get_string_value ("IFS");
726f6388 1375
cce855bc 1376 sep[0] = (ifs == 0) ? ' ' : *ifs;
726f6388
JA
1377 sep[1] = '\0';
1378
1379 return (string_list_internal (list, sep));
1380}
1381
cce855bc
JA
1382/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
1383 is non-zero, the $@ appears within double quotes, and we should quote
1384 the list before converting it into a string. If IFS is unset, and the
1385 word is not quoted, we just need to quote CTLESC and CTLNUL characters
1386 in the words in the list, because the default value of $IFS is
1387 <space><tab><newline>, IFS characters in the words in the list should
1388 also be split. If IFS is null, and the word is not quoted, we need
1389 to quote the words in the list to preserve the positional parameters
1390 exactly. */
1391static char *
1392string_list_dollar_at (list, quoted)
1393 WORD_LIST *list;
1394 int quoted;
1395{
1396 char *ifs, sep[2];
1397 WORD_LIST *tlist;
1398
1399 ifs = get_string_value ("IFS");
1400
1401 sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs;
1402 sep[1] = '\0';
1403
1404 tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0))
1405 ? quote_list (list)
1406 : list_quote_escapes (list);
1407 return (string_list_internal (tlist, sep));
1408}
1409
726f6388
JA
1410/* Return the list of words present in STRING. Separate the string into
1411 words at any of the characters found in SEPARATORS. If QUOTED is
1412 non-zero then word in the list will have its quoted flag set, otherwise
1413 the quoted flag is left as make_word () deemed fit.
1414
1415 This obeys the P1003.2 word splitting semantics. If `separators' is
1416 exactly <space><tab><newline>, then the splitting algorithm is that of
1417 the Bourne shell, which treats any sequence of characters from `separators'
1418 as a delimiter. If IFS is unset, which results in `separators' being set
1419 to "", no splitting occurs. If separators has some other value, the
1420 following rules are applied (`IFS white space' means zero or more
1421 occurrences of <space>, <tab>, or <newline>, as long as those characters
1422 are in `separators'):
1423
1424 1) IFS white space is ignored at the start and the end of the
1425 string.
1426 2) Each occurrence of a character in `separators' that is not
1427 IFS white space, along with any adjacent occurrences of
1428 IFS white space delimits a field.
1429 3) Any nonzero-length sequence of IFS white space delimits a field.
1430 */
1431
1432/* BEWARE! list_string strips null arguments. Don't call it twice and
1433 expect to have "" preserved! */
1434
726f6388
JA
1435/* This performs word splitting and quoted null character removal on
1436 STRING. */
726f6388
JA
1437#define issep(c) (member ((c), separators))
1438
1439WORD_LIST *
1440list_string (string, separators, quoted)
1441 register char *string, *separators;
1442 int quoted;
1443{
ccc6cda3
JA
1444 WORD_LIST *result;
1445 WORD_DESC *t;
1446 char *current_word, *s;
1447 int sindex, sh_style_split;
726f6388
JA
1448
1449 if (!string || !*string)
1450 return ((WORD_LIST *)NULL);
1451
1452 sh_style_split =
1453 separators && *separators && (STREQ (separators, " \t\n"));
1454
1455 /* Remove sequences of whitespace at the beginning of STRING, as
1456 long as those characters appear in IFS. Do not do this if
1457 STRING is quoted or if there are no separator characters. */
1458 if (!quoted || !separators || !*separators)
1459 {
1460 for (s = string; *s && spctabnl (*s) && issep (*s); s++);
1461
1462 if (!*s)
1463 return ((WORD_LIST *)NULL);
1464
1465 string = s;
1466 }
1467
1468 /* OK, now STRING points to a word that does not begin with white space.
1469 The splitting algorithm is:
1470 extract a word, stopping at a separator
1471 skip sequences of spc, tab, or nl as long as they are separators
1472 This obeys the field splitting rules in Posix.2. */
ccc6cda3 1473 for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
726f6388
JA
1474 {
1475 current_word = string_extract_verbatim (string, &sindex, separators);
ccc6cda3 1476 if (current_word == 0)
726f6388
JA
1477 break;
1478
1479 /* If we have a quoted empty string, add a quoted null argument. We
1480 want to preserve the quoted null character iff this is a quoted
1481 empty string; otherwise the quoted null characters are removed
1482 below. */
1483 if (QUOTED_NULL (current_word))
1484 {
ccc6cda3
JA
1485 t = make_bare_word ("");
1486 t->flags |= W_QUOTED;
726f6388
JA
1487 free (t->word);
1488 t->word = make_quoted_char ('\0');
1489 result = make_word_list (t, result);
1490 }
ccc6cda3 1491 else if (current_word[0] != '\0')
726f6388
JA
1492 {
1493 /* If we have something, then add it regardless. However,
1494 perform quoted null character removal on the current word. */
1495 remove_quoted_nulls (current_word);
cce855bc 1496 result = add_string_to_list (current_word, result);
ccc6cda3
JA
1497 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
1498 result->word->flags |= W_QUOTED;
726f6388
JA
1499 }
1500
1501 /* If we're not doing sequences of separators in the traditional
1502 Bourne shell style, then add a quoted null argument. */
726f6388
JA
1503 else if (!sh_style_split && !spctabnl (string[sindex]))
1504 {
ccc6cda3
JA
1505 t = make_bare_word ("");
1506 t->flags |= W_QUOTED;
1507 free (t->word);
1508 t->word = make_quoted_char ('\0');
1509 result = make_word_list (t, result);
726f6388
JA
1510 }
1511
1512 free (current_word);
1513
1514 /* Move past the current separator character. */
1515 if (string[sindex])
1516 sindex++;
1517
1518 /* Now skip sequences of space, tab, or newline characters if they are
1519 in the list of separators. */
1520 while (string[sindex] && spctabnl (string[sindex]) && issep (string[sindex]))
1521 sindex++;
726f6388
JA
1522 }
1523 return (REVERSE_LIST (result, WORD_LIST *));
1524}
1525
1526/* Parse a single word from STRING, using SEPARATORS to separate fields.
1527 ENDPTR is set to the first character after the word. This is used by
1528 the `read' builtin.
1529 XXX - this function is very similar to list_string; they should be
1530 combined - XXX */
1531char *
1532get_word_from_string (stringp, separators, endptr)
1533 char **stringp, *separators, **endptr;
1534{
1535 register char *s;
1536 char *current_word;
1537 int sindex, sh_style_split;
1538
1539 if (!stringp || !*stringp || !**stringp)
1540 return ((char *)NULL);
ccc6cda3 1541
726f6388
JA
1542 s = *stringp;
1543
1544 sh_style_split =
1545 separators && *separators && (STREQ (separators, " \t\n"));
1546
1547 /* Remove sequences of whitespace at the beginning of STRING, as
1548 long as those characters appear in IFS. */
1549 if (sh_style_split || !separators || !*separators)
1550 {
1551 for (; *s && spctabnl (*s) && issep (*s); s++);
1552
1553 /* If the string is nothing but whitespace, update it and return. */
1554 if (!*s)
1555 {
1556 *stringp = s;
1557 if (endptr)
1558 *endptr = s;
1559 return ((char *)NULL);
1560 }
1561 }
1562
1563 /* OK, S points to a word that does not begin with white space.
1564 Now extract a word, stopping at a separator, save a pointer to
1565 the first character after the word, then skip sequences of spc,
1566 tab, or nl as long as they are separators.
ccc6cda3 1567
726f6388
JA
1568 This obeys the field splitting rules in Posix.2. */
1569 sindex = 0;
1570 current_word = string_extract_verbatim (s, &sindex, separators);
1571
1572 /* Set ENDPTR to the first character after the end of the word. */
1573 if (endptr)
1574 *endptr = s + sindex;
1575
1576 /* Move past the current separator character. */
1577 if (s[sindex])
1578 sindex++;
1579
1580 /* Now skip sequences of space, tab, or newline characters if they are
1581 in the list of separators. */
1582 while (s[sindex] && spctabnl (s[sindex]) && issep (s[sindex]))
1583 sindex++;
1584
1585 /* Update STRING to point to the next field. */
1586 *stringp = s + sindex;
1587 return (current_word);
1588}
1589
1590/* Remove IFS white space at the end of STRING. Start at the end
1591 of the string and walk backwards until the beginning of the string
1592 or we find a character that's not IFS white space and not CTLESC.
1593 Only let CTLESC escape a white space character if SAW_ESCAPE is
1594 non-zero. */
1595char *
1596strip_trailing_ifs_whitespace (string, separators, saw_escape)
1597 char *string, *separators;
1598 int saw_escape;
1599{
1600 char *s;
ccc6cda3 1601
726f6388
JA
1602 s = string + STRLEN (string) - 1;
1603 while (s > string && ((spctabnl (*s) && issep (*s)) ||
1604 (saw_escape && *s == CTLESC && spctabnl (s[1]))))
1605 s--;
1606 *++s = '\0';
1607 return string;
1608}
1609
bb70624e
JA
1610#if 0
1611/* UNUSED */
1612/* Split STRING into words at whitespace. Obeys shell-style quoting with
1613 backslashes, single and double quotes. */
ccc6cda3
JA
1614WORD_LIST *
1615list_string_with_quotes (string)
1616 char *string;
1617{
1618 WORD_LIST *list;
1619 char *token, *s;
1620 int c, i, tokstart, len;
1621
1622 for (s = string; s && *s && spctabnl (*s); s++)
1623 ;
1624 if (s == 0 || *s == 0)
1625 return ((WORD_LIST *)NULL);
1626
1627 tokstart = i = 0;
1628 list = (WORD_LIST *)NULL;
1629 while (1)
1630 {
1631 c = s[i];
1632 if (c == '\\')
1633 {
1634 i++;
1635 if (s[i])
1636 i++;
1637 }
1638 else if (c == '\'')
1639 i = skip_single_quoted (s, ++i);
1640 else if (c == '"')
1641 i = skip_double_quoted (s, ++i);
1642 else if (c == 0 || spctabnl (c))
1643 {
1644 /* We have found the end of a token. Make a word out of it and
1645 add it to the word list. */
bb70624e 1646 token = substring (s, tokstart, i);
cce855bc 1647 list = add_string_to_list (token, list);
ccc6cda3
JA
1648 free (token);
1649 while (spctabnl (s[i]))
1650 i++;
1651 if (s[i])
1652 tokstart = i;
1653 else
1654 break;
1655 }
1656 else
1657 i++; /* normal character */
1658 }
1659 return (REVERSE_LIST (list, WORD_LIST *));
1660}
bb70624e 1661#endif
d166f048 1662
cce855bc
JA
1663/********************************************************/
1664/* */
1665/* Functions to perform assignment statements */
1666/* */
1667/********************************************************/
d166f048 1668
ccc6cda3
JA
1669#if defined (ARRAY_VARS)
1670SHELL_VAR *
1671do_array_element_assignment (name, value)
1672 char *name, *value;
1673{
1674 char *t;
1675 int ind, ni;
1676 SHELL_VAR *entry;
1677
1678 t = strchr (name, '[');
1679 if (t == 0)
1680 return ((SHELL_VAR *)NULL);
1681 ind = t - name;
1682 ni = skipsubscript (name, ind);
1683 if ((ALL_ELEMENT_SUB (t[1]) && t[2] == ']') || (ni <= ind + 1))
1684 {
1685 report_error ("%s: bad array subscript", name);
1686 return ((SHELL_VAR *)NULL);
1687 }
1688 *t++ = '\0';
1689 ind = array_expand_index (t, ni - ind);
1690 if (ind < 0)
1691 {
1692 t[-1] = '['; /* restore original name */
1693 report_error ("%s: bad array subscript", name);
1694 return ((SHELL_VAR *)NULL);
1695 }
1696 entry = bind_array_variable (name, ind, value);
1697 t[-1] = '['; /* restore original name */
1698 return (entry);
1699}
1700#endif /* ARRAY_VARS */
1701
726f6388
JA
1702/* Given STRING, an assignment string, get the value of the right side
1703 of the `=', and bind it to the left side. If EXPAND is true, then
1704 perform parameter expansion, command substitution, and arithmetic
1705 expansion on the right-hand side. Perform tilde expansion in any
1706 case. Do not perform word splitting on the result of expansion. */
1707static int
1708do_assignment_internal (string, expand)
1709 char *string;
1710 int expand;
1711{
ccc6cda3
JA
1712 int offset;
1713 char *name, *value;
1714 SHELL_VAR *entry;
1715#if defined (ARRAY_VARS)
1716 char *t;
1717 int ni, assign_list = 0;
1718#endif
1719
1720 offset = assignment (string);
1721 name = savestring (string);
1722 value = (char *)NULL;
726f6388
JA
1723
1724 if (name[offset] == '=')
1725 {
1726 char *temp;
1727
1728 name[offset] = 0;
1729 temp = name + offset + 1;
1730
ccc6cda3 1731#if defined (ARRAY_VARS)
cce855bc 1732 if (expand && temp[0] == LPAREN && strchr (temp, RPAREN))
726f6388 1733 {
ccc6cda3
JA
1734 assign_list = ni = 1;
1735 value = extract_delimited_string (temp, &ni, "(", (char *)NULL, ")");
1736 }
1737 else
1738#endif
1739
1740 /* Perform tilde expansion. */
1741 if (expand && temp[0])
1742 {
1743 temp = (strchr (temp, '~') && unquoted_member ('~', temp))
1744 ? bash_tilde_expand (temp)
1745 : savestring (temp);
726f6388
JA
1746
1747 value = maybe_expand_string (temp, 0, expand_string_unsplit);
1748 free (temp);
1749 }
1750 else
1751 value = savestring (temp);
1752 }
1753
1754 if (value == 0)
d166f048
JA
1755 {
1756 value = xmalloc (1);
1757 value[0] = '\0';
1758 }
726f6388 1759
726f6388 1760 if (echo_command_at_execute)
ccc6cda3
JA
1761#if defined (ARRAY_VARS)
1762 if (assign_list)
1763 fprintf (stderr, "%s%s=(%s)\n", indirection_level_string (), name, value);
1764 else
1765#endif
726f6388
JA
1766 fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value);
1767
d166f048 1768#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
ccc6cda3
JA
1769
1770#if defined (ARRAY_VARS)
1771 if (t = strchr (name, '['))
1772 {
1773 if (assign_list)
1774 {
1775 report_error ("%s: cannot assign list to array member", name);
1776 ASSIGN_RETURN (0);
1777 }
1778 entry = do_array_element_assignment (name, value);
1779 if (entry == 0)
1780 ASSIGN_RETURN (0);
1781 }
1782 else if (assign_list)
1783 entry = assign_array_from_string (name, value);
1784 else
1785#endif /* ARRAY_VARS */
1786 entry = bind_variable (name, value);
1787
726f6388
JA
1788 stupidly_hack_special_variables (name);
1789
1790 if (entry)
bb70624e 1791 VUNSETATTR (entry, att_invisible);
726f6388 1792
726f6388 1793 /* Return 1 if the assignment seems to have been performed correctly. */
bb70624e 1794 ASSIGN_RETURN (entry ? (readonly_p (entry) == 0) : 0);
726f6388
JA
1795}
1796
1797/* Perform the assignment statement in STRING, and expand the
1798 right side by doing command and parameter expansion. */
ccc6cda3 1799int
726f6388
JA
1800do_assignment (string)
1801 char *string;
1802{
1803 return do_assignment_internal (string, 1);
1804}
1805
1806/* Given STRING, an assignment string, get the value of the right side
1807 of the `=', and bind it to the left side. Do not do command and
1808 parameter substitution on the right hand side. */
ccc6cda3 1809int
726f6388
JA
1810do_assignment_no_expand (string)
1811 char *string;
1812{
1813 return do_assignment_internal (string, 0);
1814}
1815
cce855bc
JA
1816/***************************************************
1817 * *
1818 * Functions to manage the positional parameters *
1819 * *
1820 ***************************************************/
726f6388
JA
1821
1822/* Return the word list that corresponds to `$*'. */
1823WORD_LIST *
1824list_rest_of_args ()
1825{
ccc6cda3 1826 register WORD_LIST *list, *args;
726f6388
JA
1827 int i;
1828
1829 /* Break out of the loop as soon as one of the dollar variables is null. */
ccc6cda3
JA
1830 for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
1831 list = make_word_list (make_bare_word (dollar_vars[i]), list);
1832
1833 for (args = rest_of_args; args; args = args->next)
1834 list = make_word_list (make_bare_word (args->word->word), list);
726f6388 1835
726f6388
JA
1836 return (REVERSE_LIST (list, WORD_LIST *));
1837}
1838
ccc6cda3
JA
1839int
1840number_of_args ()
1841{
1842 register WORD_LIST *list;
1843 int n;
1844
1845 for (n = 0; n < 9 && dollar_vars[n+1]; n++)
1846 ;
1847 for (list = rest_of_args; list; list = list->next)
1848 n++;
1849 return n;
1850}
1851
cce855bc
JA
1852/* Return the value of a positional parameter. This handles values > 10. */
1853char *
1854get_dollar_var_value (ind)
1855 int ind;
1856{
1857 char *temp;
1858 WORD_LIST *p;
1859
1860 if (ind < 10)
1861 temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
1862 else /* We want something like ${11} */
1863 {
1864 ind -= 10;
1865 for (p = rest_of_args; p && ind--; p = p->next)
1866 ;
1867 temp = p ? savestring (p->word->word) : (char *)NULL;
1868 }
1869 return (temp);
1870}
1871
726f6388
JA
1872/* Make a single large string out of the dollar digit variables,
1873 and the rest_of_args. If DOLLAR_STAR is 1, then obey the special
1874 case of "$*" with respect to IFS. */
1875char *
1876string_rest_of_args (dollar_star)
1877 int dollar_star;
1878{
ccc6cda3 1879 register WORD_LIST *list;
726f6388
JA
1880 char *string;
1881
ccc6cda3 1882 list = list_rest_of_args ();
726f6388
JA
1883 string = dollar_star ? string_list_dollar_star (list) : string_list (list);
1884 dispose_words (list);
1885 return (string);
1886}
1887
cce855bc
JA
1888/* Return a string containing the positional parameters from START to
1889 END, inclusive. If STRING[0] == '*', we obey the rules for $*,
1890 which only makes a difference if QUOTED is non-zero. */
1891static char *
1892pos_params (string, start, end, quoted)
1893 char *string;
1894 int start, end, quoted;
726f6388 1895{
cce855bc
JA
1896 WORD_LIST *save, *params, *h, *t;
1897 char *ret;
1898 int i;
726f6388 1899
bb70624e
JA
1900 /* see if we can short-circuit. if start == end, we want 0 parameters. */
1901 if (start == end)
1902 return ((char *)NULL);
1903
cce855bc
JA
1904 save = params = list_rest_of_args ();
1905 if (save == 0)
1906 return ((char *)NULL);
1907
1908 for (i = 1; params && i < start; i++)
1909 params = params->next;
1910 if (params == 0)
1911 return ((char *)NULL);
1912 for (h = t = params; params && i < end; i++)
d166f048 1913 {
cce855bc
JA
1914 t = params;
1915 params = params->next;
d166f048 1916 }
726f6388 1917
cce855bc
JA
1918 t->next = (WORD_LIST *)NULL;
1919 if (string[0] == '*')
1920 ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (h) : string_list (h);
1921 else
1922 ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h);
bb70624e
JA
1923 if (t != params)
1924 t->next = params;
726f6388 1925
cce855bc
JA
1926 dispose_words (save);
1927 return (ret);
1928}
1929
1930/******************************************************************/
1931/* */
1932/* Functions to expand strings to strings or WORD_LISTs */
1933/* */
1934/******************************************************************/
1935
1936#if defined (PROCESS_SUBSTITUTION)
1937#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC)
1938#else
1939#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC)
1940#endif
1941
1942/* If there are any characters in STRING that require full expansion,
1943 then call FUNC to expand STRING; otherwise just perform quote
1944 removal if necessary. This returns a new string. */
1945static char *
1946maybe_expand_string (string, quoted, func)
1947 char *string;
1948 int quoted;
1949 WORD_LIST *(*func)();
1950{
1951 WORD_LIST *list;
1952 int i, saw_quote;
1953 char *ret;
1954
1955 for (i = saw_quote = 0; string[i]; i++)
1956 {
1957 if (EXP_CHAR (string[i]))
1958 break;
1959 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
1960 saw_quote = 1;
1961 }
1962
1963 if (string[i])
1964 {
1965 list = (*func) (string, quoted);
1966 if (list)
1967 {
1968 ret = string_list (list);
1969 dispose_words (list);
1970 }
1971 else
1972 ret = (char *)NULL;
1973 }
1974 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
1975 ret = string_quote_removal (string, quoted);
1976 else
1977 ret = savestring (string);
1978 return ret;
1979}
1980
1981static inline char *
1982expand_string_to_string (string, quoted, func)
1983 char *string;
1984 int quoted;
1985 WORD_LIST *(*func)();
1986{
1987 WORD_LIST *list;
1988 char *ret;
1989
1990 if (string == 0 || *string == '\0')
1991 return ((char *)NULL);
1992
1993 list = (*func) (string, quoted);
1994 if (list)
1995 {
1996 ret = string_list (list);
1997 dispose_words (list);
1998 }
1999 else
2000 ret = (char *)NULL;
2001
2002 return (ret);
2003}
2004
2005#if defined (COND_COMMAND)
2006/* Just remove backslashes in STRING. Returns a new string. */
2007char *
2008remove_backslashes (string)
2009 char *string;
2010{
2011 char *r, *ret, *s;
2012
2013 r = ret = xmalloc (strlen (string) + 1);
2014 for (s = string; s && *s; )
2015 {
2016 if (*s == '\\')
2017 s++;
2018 if (*s == 0)
2019 break;
2020 *r++ = *s++;
2021 }
2022 *r = '\0';
2023 return ret;
2024}
2025
2026/* This needs better error handling. */
2027/* Expand W for use as an argument to a unary or binary operator in a
2028 [[...]] expression. If SPECIAL is nonzero, this is the rhs argument
2029 to the != or == operator, and should be treated as a pattern. In
2030 this case, we quote the string specially for the globbing code. The
2031 caller is responsible for removing the backslashes if the unquoted
2032 words is needed later. */
2033char *
2034cond_expand_word (w, special)
2035 WORD_DESC *w;
2036 int special;
2037{
2038 char *r, *p;
2039 WORD_LIST *l;
2040
2041 if (w->word == 0 || w->word[0] == '\0')
2042 return ((char *)NULL);
2043
b72432fd 2044 l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
cce855bc
JA
2045 if (l)
2046 {
2047 if (special == 0)
2048 {
2049 dequote_list (l);
2050 r = string_list (l);
2051 }
2052 else
2053 {
2054 p = string_list (l);
2055 r = quote_string_for_globbing (p, QGLOB_CVTNULL);
2056 free (p);
2057 }
2058 dispose_words (l);
2059 }
2060 else
2061 r = (char *)NULL;
2062
2063 return r;
2064}
2065#endif
2066
2067/* Call expand_word_internal to expand W and handle error returns.
2068 A convenience function for functions that don't want to handle
2069 any errors or free any memory before aborting. */
2070static WORD_LIST *
b72432fd 2071call_expand_word_internal (w, q, i, c, e)
cce855bc 2072 WORD_DESC *w;
b72432fd 2073 int q, i, *c, *e;
cce855bc
JA
2074{
2075 WORD_LIST *result;
2076
b72432fd 2077 result = expand_word_internal (w, q, i, c, e);
bb70624e 2078 if (result == &expand_word_error || result == &expand_word_fatal)
cce855bc
JA
2079 {
2080 /* By convention, each time this error is returned, w->word has
bb70624e
JA
2081 already been freed (it sometimes may not be in the fatal case,
2082 but that doesn't result in a memory leak because we're going
2083 to exit in most cases). */
cce855bc 2084 w->word = (char *)NULL;
bb70624e 2085 jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
cce855bc
JA
2086 /* NOTREACHED */
2087 }
cce855bc
JA
2088 else
2089 return (result);
2090}
2091
2092/* Perform parameter expansion, command substitution, and arithmetic
2093 expansion on STRING, as if it were a word. Leave the result quoted. */
2094static WORD_LIST *
2095expand_string_internal (string, quoted)
2096 char *string;
2097 int quoted;
2098{
2099 WORD_DESC td;
2100 WORD_LIST *tresult;
2101
2102 if (string == 0 || *string == 0)
2103 return ((WORD_LIST *)NULL);
2104
2105 bzero ((char *)&td, sizeof (td));
2106 td.word = string;
b72432fd 2107 tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
cce855bc 2108 return (tresult);
726f6388
JA
2109}
2110
2111/* Expand STRING by performing parameter expansion, command substitution,
2112 and arithmetic expansion. Dequote the resulting WORD_LIST before
2113 returning it, but do not perform word splitting. The call to
2114 remove_quoted_nulls () is in here because word splitting normally
2115 takes care of quote removal. */
2116WORD_LIST *
2117expand_string_unsplit (string, quoted)
2118 char *string;
2119 int quoted;
2120{
2121 WORD_LIST *value;
2122
2123 if (!string || !*string)
2124 return ((WORD_LIST *)NULL);
2125
2126 value = expand_string_internal (string, quoted);
2127 if (value)
2128 {
2129 if (value->word)
2130 remove_quoted_nulls (value->word->word);
2131 dequote_list (value);
2132 }
2133 return (value);
2134}
2135
bb70624e
JA
2136
2137/* Expand one of the PS? prompt strings. This is a sort of combination of
2138 expand_string_unsplit and expand_string_internal, but returns the
2139 passed string when an error occurs. Might want to trap other calls
2140 to jump_to_top_level here so we don't endlessly loop. */
2141WORD_LIST *
2142expand_prompt_string (string, quoted)
2143 char *string;
2144 int quoted;
2145{
2146 WORD_LIST *value;
2147 WORD_DESC td;
2148
2149 if (string == 0 || *string == 0)
2150 return ((WORD_LIST *)NULL);
2151
2152 bzero ((char *)&td, sizeof (td));
2153 td.word = savestring (string);
2154 doing_prompt_expansion = 1;
2155 value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
2156 doing_prompt_expansion = 0;
2157 if (value == &expand_word_error || value == &expand_word_fatal)
2158 {
2159 value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
2160 return value;
2161 }
2162 FREE (td.word);
2163 if (value)
2164 {
2165 if (value->word)
2166 remove_quoted_nulls (value->word->word);
2167 dequote_list (value);
2168 }
2169 return (value);
2170}
2171
726f6388
JA
2172/* Expand STRING just as if you were expanding a word, but do not dequote
2173 the resultant WORD_LIST. This is called only from within this file,
2174 and is used to correctly preserve quoted characters when expanding
2175 things like ${1+"$@"}. This does parameter expansion, command
b72432fd 2176 substitution, arithmetic expansion, and word splitting. */
726f6388
JA
2177static WORD_LIST *
2178expand_string_leave_quoted (string, quoted)
2179 char *string;
2180 int quoted;
2181{
2182 WORD_LIST *tlist;
2183 WORD_LIST *tresult;
2184
ccc6cda3 2185 if (string == 0 || *string == '\0')
726f6388
JA
2186 return ((WORD_LIST *)NULL);
2187
2188 tlist = expand_string_internal (string, quoted);
2189
2190 if (tlist)
2191 {
2192 tresult = word_list_split (tlist);
2193 dispose_words (tlist);
2194 return (tresult);
2195 }
2196 return ((WORD_LIST *)NULL);
2197}
2198
ccc6cda3
JA
2199/* This does not perform word splitting or dequote the WORD_LIST
2200 it returns. */
2201static WORD_LIST *
2202expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at)
2203 char *string;
2204 int quoted, *dollar_at_p, *has_dollar_at;
2205{
2206 WORD_DESC td;
2207 WORD_LIST *tresult;
2208
2209 if (string == 0 || *string == '\0')
2210 return (WORD_LIST *)NULL;
2211
d166f048 2212 bzero ((char *)&td, sizeof (td));
ccc6cda3 2213 td.word = string;
b72432fd 2214 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at);
ccc6cda3
JA
2215 return (tresult);
2216}
2217
726f6388
JA
2218/* Expand STRING just as if you were expanding a word. This also returns
2219 a list of words. Note that filename globbing is *NOT* done for word
2220 or string expansion, just when the shell is expanding a command. This
2221 does parameter expansion, command substitution, arithmetic expansion,
2222 and word splitting. Dequote the resultant WORD_LIST before returning. */
2223WORD_LIST *
2224expand_string (string, quoted)
2225 char *string;
2226 int quoted;
2227{
2228 WORD_LIST *result;
2229
2230 if (!string || !*string)
2231 return ((WORD_LIST *)NULL);
2232
2233 result = expand_string_leave_quoted (string, quoted);
ccc6cda3 2234 return (result ? dequote_list (result) : result);
726f6388
JA
2235}
2236
2237/***************************************************
2238 * *
2239 * Functions to handle quoting chars *
2240 * *
2241 ***************************************************/
2242
cce855bc
JA
2243/* Conventions:
2244
2245 A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
2246 The parser passes CTLNUL as CTLESC CTLNUL. */
2247
2248/* The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
2249 This is necessary to make unquoted CTLESC and CTLNUL characters in the
2250 data stream pass through properly.
2251 Here we remove doubled CTLESC characters inside quoted strings before
2252 quoting the entire string, so we do not double the number of CTLESC
2253 characters. */
2254static char *
2255remove_quoted_escapes (string)
2256 char *string;
2257{
2258 register char *s;
2259 int docopy;
2260 char *t, *t1;
2261
2262 if (string == NULL)
2263 return (string);
2264
2265 t1 = t = xmalloc (strlen (string) + 1);
2266 for (docopy = 0, s = string; *s; s++, t1++)
2267 {
2268 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL))
2269 {
2270 s++;
2271 docopy = 1;
2272 }
2273 *t1 = *s;
2274 }
2275 *t1 = '\0';
2276 if (docopy)
2277 strcpy (string, t);
2278 free (t);
2279 return (string);
2280}
2281
2282/* Quote escape characters in string s, but no other characters. This is
2283 used to protect CTLESC and CTLNUL in variable values from the rest of
2284 the word expansion process after the variable is expanded. */
2285static char *
2286quote_escapes (string)
2287 char *string;
2288{
2289 register char *s, *t;
2290 char *result;
2291
2292 result = xmalloc ((strlen (string) * 2) + 1);
2293 for (s = string, t = result; *s; )
2294 {
2295 if (*s == CTLESC || *s == CTLNUL)
2296 *t++ = CTLESC;
2297 *t++ = *s++;
2298 }
2299 *t = '\0';
2300 return (result);
2301}
2302
2303static WORD_LIST *
2304list_quote_escapes (list)
2305 WORD_LIST *list;
2306{
2307 register WORD_LIST *w;
2308 char *t;
2309
2310 for (w = list; w; w = w->next)
2311 {
2312 t = w->word->word;
2313 w->word->word = quote_escapes (t);
2314 free (t);
2315 }
2316 return list;
2317}
2318
bb70624e
JA
2319#if 0
2320/* UNUSED */
cce855bc
JA
2321static char *
2322dequote_escapes (string)
2323 char *string;
2324{
2325 register char *s, *t;
2326 char *result;
2327
2328 result = xmalloc (strlen (string) + 1);
2329 for (s = string, t = result; *s; )
2330 {
2331 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL))
2332 {
2333 s++;
2334 if (*s == '\0')
2335 break;
2336 }
2337 *t++ = *s++;
2338 }
2339 *t = '\0';
2340 return result;
2341}
2342#endif
2343
ccc6cda3 2344static WORD_LIST *
726f6388 2345dequote_list (list)
ccc6cda3 2346 WORD_LIST *list;
726f6388
JA
2347{
2348 register char *s;
ccc6cda3 2349 register WORD_LIST *tlist;
726f6388 2350
ccc6cda3 2351 for (tlist = list; tlist; tlist = tlist->next)
726f6388 2352 {
ccc6cda3
JA
2353 s = dequote_string (tlist->word->word);
2354 free (tlist->word->word);
2355 tlist->word->word = s;
726f6388 2356 }
ccc6cda3 2357 return list;
726f6388
JA
2358}
2359
bb70624e 2360/* Return a new string with the quoted representation of character C. */
726f6388
JA
2361static char *
2362make_quoted_char (c)
2363 int c;
2364{
2365 char *temp;
2366
2367 temp = xmalloc (3);
2368 if (c == 0)
2369 {
2370 temp[0] = CTLNUL;
2371 temp[1] = '\0';
2372 }
2373 else
2374 {
2375 temp[0] = CTLESC;
2376 temp[1] = c;
2377 temp[2] = '\0';
2378 }
2379 return (temp);
2380}
2381
2382/* Quote STRING. Return a new string. */
ccc6cda3 2383char *
726f6388
JA
2384quote_string (string)
2385 char *string;
2386{
ccc6cda3 2387 register char *t;
726f6388
JA
2388 char *result;
2389
ccc6cda3 2390 if (*string == 0)
726f6388
JA
2391 {
2392 result = xmalloc (2);
2393 result[0] = CTLNUL;
2394 result[1] = '\0';
2395 }
2396 else
2397 {
726f6388
JA
2398 result = xmalloc ((strlen (string) * 2) + 1);
2399
ccc6cda3 2400 for (t = result; *string; )
726f6388
JA
2401 {
2402 *t++ = CTLESC;
2403 *t++ = *string++;
2404 }
2405 *t = '\0';
2406 }
2407 return (result);
2408}
2409
2410/* De-quoted quoted characters in STRING. */
2411char *
2412dequote_string (string)
2413 char *string;
2414{
2415 register char *t;
2416 char *result;
2417
2418 result = xmalloc (strlen (string) + 1);
2419
2420 if (QUOTED_NULL (string))
2421 {
2422 result[0] = '\0';
2423 return (result);
2424 }
2425
2426 /* If no character in the string can be quoted, don't bother examining
2427 each character. Just return a copy of the string passed to us. */
2428 if (strchr (string, CTLESC) == NULL) /* XXX */
2429 { /* XXX */
2430 strcpy (result, string); /* XXX */
2431 return (result); /* XXX */
2432 }
2433
ccc6cda3 2434 for (t = result; *string; string++, t++)
726f6388
JA
2435 {
2436 if (*string == CTLESC)
2437 {
2438 string++;
2439
2440 if (!*string)
2441 break;
2442 }
2443
ccc6cda3 2444 *t = *string;
726f6388
JA
2445 }
2446
2447 *t = '\0';
2448 return (result);
2449}
2450
2451/* Quote the entire WORD_LIST list. */
ccc6cda3 2452static WORD_LIST *
726f6388
JA
2453quote_list (list)
2454 WORD_LIST *list;
2455{
2456 register WORD_LIST *w;
ccc6cda3 2457 char *t;
726f6388
JA
2458
2459 for (w = list; w; w = w->next)
2460 {
ccc6cda3 2461 t = w->word->word;
726f6388
JA
2462 w->word->word = quote_string (t);
2463 free (t);
ccc6cda3 2464 w->word->flags |= W_QUOTED;
726f6388 2465 }
ccc6cda3 2466 return list;
726f6388
JA
2467}
2468
cce855bc
JA
2469/* Perform quoted null character removal on STRING. We don't allow any
2470 quoted null characters in the middle or at the ends of strings because
2471 of how expand_word_internal works. remove_quoted_nulls () turns
2472 STRING into an empty string iff it only consists of a quoted null,
2473 and removes all unquoted CTLNUL characters. */
2474/*
2475#define remove_quoted_nulls(string) \
2476 do { if (QUOTED_NULL (string)) string[0] ='\0'; } while (0)
2477*/
2478static void
2479remove_quoted_nulls (string)
2480 char *string;
2481{
2482 char *nstr, *s, *p;
2483
2484 nstr = savestring (string);
2485 nstr[0] = '\0';
2486 for (p = nstr, s = string; *s; s++)
2487 {
2488 if (*s == CTLESC)
2489 {
2490 *p++ = *s++; /* CTLESC */
2491 if (*s == 0)
2492 break;
2493 *p++ = *s; /* quoted char */
2494 continue;
2495 }
2496 if (*s == CTLNUL)
2497 continue;
2498 *p++ = *s;
2499 }
2500 *p = '\0';
2501 strcpy (string, nstr);
2502 free (nstr);
2503}
2504
2505/* Perform quoted null character removal on each element of LIST.
2506 This modifies LIST. */
2507void
2508word_list_remove_quoted_nulls (list)
2509 WORD_LIST *list;
2510{
2511 register WORD_LIST *t;
2512
2513 for (t = list; t; t = t->next)
2514 remove_quoted_nulls (t->word->word);
2515}
2516
2517/* **************************************************************** */
2518/* */
2519/* Functions for Matching and Removing Patterns */
2520/* */
2521/* **************************************************************** */
2522
2523/* Remove the portion of PARAM matched by PATTERN according to OP, where OP
2524 can have one of 4 values:
2525 RP_LONG_LEFT remove longest matching portion at start of PARAM
726f6388
JA
2526 RP_SHORT_LEFT remove shortest matching portion at start of PARAM
2527 RP_LONG_RIGHT remove longest matching portion at end of PARAM
2528 RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
2529*/
2530
2531#define RP_LONG_LEFT 1
2532#define RP_SHORT_LEFT 2
2533#define RP_LONG_RIGHT 3
2534#define RP_SHORT_RIGHT 4
2535
2536static char *
2537remove_pattern (param, pattern, op)
2538 char *param, *pattern;
2539 int op;
2540{
ccc6cda3
JA
2541 register int len;
2542 register char *end;
726f6388
JA
2543 register char *p, *ret, c;
2544
ccc6cda3
JA
2545 if (param == NULL || *param == '\0')
2546 return (param);
726f6388
JA
2547 if (pattern == NULL || *pattern == '\0') /* minor optimization */
2548 return (savestring (param));
2549
ccc6cda3
JA
2550 len = STRLEN (param);
2551 end = param + len;
726f6388
JA
2552
2553 switch (op)
2554 {
2555 case RP_LONG_LEFT: /* remove longest match at start */
2556 for (p = end; p >= param; p--)
2557 {
2558 c = *p; *p = '\0';
cce855bc 2559 if (fnmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
726f6388
JA
2560 {
2561 *p = c;
2562 return (savestring (p));
2563 }
2564 *p = c;
2565 }
2566 break;
2567
2568 case RP_SHORT_LEFT: /* remove shortest match at start */
2569 for (p = param; p <= end; p++)
2570 {
2571 c = *p; *p = '\0';
cce855bc 2572 if (fnmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
726f6388
JA
2573 {
2574 *p = c;
2575 return (savestring (p));
2576 }
2577 *p = c;
2578 }
2579 break;
2580
ccc6cda3
JA
2581 case RP_LONG_RIGHT: /* remove longest match at end */
2582 for (p = param; p <= end; p++)
2583 {
cce855bc 2584 if (fnmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
ccc6cda3
JA
2585 {
2586 c = *p; *p = '\0';
2587 ret = savestring (param);
2588 *p = c;
2589 return (ret);
2590 }
2591 }
2592 break;
2593
2594 case RP_SHORT_RIGHT: /* remove shortest match at end */
2595 for (p = end; p >= param; p--)
2596 {
cce855bc 2597 if (fnmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
ccc6cda3
JA
2598 {
2599 c = *p; *p = '\0';
2600 ret = savestring (param);
2601 *p = c;
2602 return (ret);
2603 }
2604 }
2605 break;
2606 }
2607 return (savestring (param)); /* no match, return original string */
2608}
2609
2610/* Return 1 of the first character of STRING could match the first
2611 character of pattern PAT. Used to avoid n2 calls to fnmatch(). */
2612static int
2613match_pattern_char (pat, string)
2614 char *pat, *string;
2615{
d166f048 2616 char c;
ccc6cda3
JA
2617
2618 if (*string == 0)
2619 return (0);
2620
2621 switch (c = *pat++)
2622 {
2623 default:
2624 return (*string == c);
2625 case '\\':
2626 return (*string == *pat);
2627 case '?':
cce855bc 2628 return (*string == LPAREN ? 1 : (*string != '\0'));
ccc6cda3
JA
2629 case '*':
2630 return (1);
cce855bc
JA
2631 case '+':
2632 case '!':
2633 case '@':
2634 return (*string == LPAREN ? 1 : (*string == c));
ccc6cda3 2635 case '[':
d166f048 2636 return (*string != '\0');
ccc6cda3
JA
2637 }
2638}
2639
2640/* Match PAT anywhere in STRING and return the match boundaries.
2641 This returns 1 in case of a successful match, 0 otherwise. SP
2642 and EP are pointers into the string where the match begins and
2643 ends, respectively. MTYPE controls what kind of match is attempted.
2644 MATCH_BEG and MATCH_END anchor the match at the beginning and end
2645 of the string, respectively. The longest match is returned. */
2646static int
2647match_pattern (string, pat, mtype, sp, ep)
2648 char *string, *pat;
2649 int mtype;
2650 char **sp, **ep;
2651{
2652 int c;
2653 register char *p, *p1;
2654 char *end;
2655
2656 if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
2657 return (0);
2658
2659 end = string + STRLEN (string);
2660
2661 switch (mtype)
2662 {
2663 case MATCH_ANY:
2664 for (p = string; p <= end; p++)
2665 {
2666 if (match_pattern_char (pat, p))
2667 {
2668 for (p1 = end; p1 >= p; p1--)
2669 {
2670 c = *p1; *p1 = '\0';
cce855bc 2671 if (fnmatch (pat, p, FNMATCH_EXTFLAG) == 0)
ccc6cda3
JA
2672 {
2673 *p1 = c;
2674 *sp = p;
2675 *ep = p1;
2676 return 1;
2677 }
2678 *p1 = c;
2679 }
2680 }
2681 }
2682 return (0);
2683
2684 case MATCH_BEG:
2685 if (match_pattern_char (pat, string) == 0)
2686 return (0);
2687 for (p = end; p >= string; p--)
2688 {
2689 c = *p; *p = '\0';
cce855bc 2690 if (fnmatch (pat, string, FNMATCH_EXTFLAG) == 0)
ccc6cda3
JA
2691 {
2692 *p = c;
2693 *sp = string;
2694 *ep = p;
2695 return 1;
2696 }
2697 *p = c;
2698 }
2699 return (0);
726f6388 2700
ccc6cda3
JA
2701 case MATCH_END:
2702 for (p = string; p <= end; p++)
cce855bc 2703 if (fnmatch (pat, p, FNMATCH_EXTFLAG) == 0)
726f6388 2704 {
ccc6cda3
JA
2705 *sp = p;
2706 *ep = end;
2707 return 1;
726f6388 2708 }
ccc6cda3 2709 return (0);
726f6388 2710 }
ccc6cda3
JA
2711
2712 return (0);
726f6388
JA
2713}
2714
cce855bc
JA
2715static int
2716getpatspec (c, value)
2717 int c;
2718 char *value;
2719{
2720 if (c == '#')
2721 return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
2722 else /* c == '%' */
2723 return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
2724}
2725
2726/* Posix.2 says that the WORD should be run through tilde expansion,
2727 parameter expansion, command substitution and arithmetic expansion.
2728 This leaves the result quoted, so quote_string_for_globbing () has
2729 to be called to fix it up for fnmatch (). If QUOTED is non-zero,
2730 it means that the entire expression was enclosed in double quotes.
2731 This means that quoting characters in the pattern do not make any
2732 special pattern characters quoted. For example, the `*' in the
2733 following retains its special meaning: "${foo#'*'}". */
2734static char *
2735getpattern (value, quoted, expandpat)
2736 char *value;
2737 int quoted, expandpat;
2738{
2739 char *pat, *tword;
2740 WORD_LIST *l;
2741 int i;
2742
2743 tword = strchr (value, '~') ? bash_tilde_expand (value) : savestring (value);
2744
2745 /* expand_string_internal () leaves WORD quoted and does not perform
2746 word splitting. */
2747 if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
2748 {
2749 i = 0;
2750 pat = string_extract_double_quoted (tword, &i, 1);
2751 free (tword);
2752 tword = pat;
2753 }
2754
2755 /* There is a problem here: how to handle single or double quotes in the
2756 pattern string when the whole expression is between double quotes? */
2757#if 0
2758 l = *tword ? expand_string_for_rhs (tword, quoted, (int *)NULL, (int *)NULL)
2759#else
2760 l = *tword ? expand_string_for_rhs (tword,
2761 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_NOQUOTE : quoted,
2762 (int *)NULL, (int *)NULL)
2763#endif
2764 : (WORD_LIST *)0;
2765 free (tword);
2766 pat = string_list (l);
2767 dispose_words (l);
2768 if (pat)
2769 {
2770 tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
2771 free (pat);
2772 pat = tword;
2773 }
2774 return (pat);
2775}
2776
2777/* Handle removing a pattern from a string as a result of ${name%[%]value}
2778 or ${name#[#]value}. */
2779static char *
2780parameter_brace_remove_pattern (value, temp, c, quoted)
2781 char *value, *temp;
2782 int c, quoted;
2783{
2784 int patspec;
2785 char *pattern, *tword;
2786
2787 patspec = getpatspec (c, value);
2788 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
2789 value++;
2790
2791 pattern = getpattern (value, quoted, 1);
2792
2793 tword = remove_pattern (temp, pattern, patspec);
2794
2795 FREE (pattern);
2796 return (tword);
2797}
2798
2799static char *
2800list_remove_pattern (list, pattern, patspec, type, quoted)
2801 WORD_LIST *list;
2802 char *pattern;
2803 int patspec, type, quoted;
2804{
2805 WORD_LIST *new, *l;
2806 WORD_DESC *w;
2807 char *tword;
2808
2809 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
2810 {
2811 tword = remove_pattern (l->word->word, pattern, patspec);
2812 w = make_bare_word (tword);
2813 free (tword);
2814 new = make_word_list (w, new);
2815 }
2816
2817 l = REVERSE_LIST (new, WORD_LIST *);
2818 if (type == '*')
2819 tword = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l);
2820 else
2821 tword = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l);
2822
2823 dispose_words (l);
2824 return (tword);
2825}
2826
2827static char *
2828parameter_list_remove_pattern (value, type, c, quoted)
2829 char *value;
2830 int type, c, quoted;
2831{
2832 int patspec;
2833 char *pattern, *ret;
2834 WORD_LIST *list;
2835
2836 patspec = getpatspec (c, value);
2837 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
2838 value++;
2839
2840 pattern = getpattern (value, quoted, 1);
2841
2842 list = list_rest_of_args ();
2843 ret = list_remove_pattern (list, pattern, patspec, type, quoted);
2844 dispose_words (list);
2845 FREE (pattern);
2846 return (ret);
2847}
2848
2849#if defined (ARRAY_VARS)
2850static char *
2851array_remove_pattern (value, aspec, aval, c, quoted)
2852 char *value, *aspec, *aval; /* AVAL == evaluated ASPEC */
2853 int c, quoted;
2854{
2855 SHELL_VAR *var;
2856 int len, patspec;
2857 char *ret, *t, *pattern;
2858 WORD_LIST *l;
2859
2860 var = array_variable_part (aspec, &t, &len);
2861 if (var == 0)
2862 return ((char *)NULL);
2863
2864 patspec = getpatspec (c, value);
2865 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
2866 value++;
2867
2868 pattern = getpattern (value, quoted, 1);
2869
2870 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
2871 {
2872 if (array_p (var) == 0)
2873 {
2874 report_error ("%s: bad array subscript", aspec);
2875 FREE (pattern);
2876 return ((char *)NULL);
2877 }
2878 l = array_to_word_list (array_cell (var));
2879 if (l == 0)
2880 return ((char *)NULL);
2881 ret = list_remove_pattern (l, pattern, patspec, t[0], quoted);
2882 dispose_words (l);
2883 }
2884 else
2885 {
2886 ret = remove_pattern (aval, pattern, patspec);
2887 if (ret)
2888 {
2889 t = quote_escapes (ret);
2890 free (ret);
2891 ret = t;
2892 }
2893 }
2894
2895 FREE (pattern);
2896 return ret;
2897}
2898#endif /* ARRAY_VARS */
2899
726f6388
JA
2900/*******************************************
2901 * *
2902 * Functions to expand WORD_DESCs *
2903 * *
2904 *******************************************/
2905
2906/* Expand WORD, performing word splitting on the result. This does
2907 parameter expansion, command substitution, arithmetic expansion,
2908 word splitting, and quote removal. */
2909
2910WORD_LIST *
2911expand_word (word, quoted)
2912 WORD_DESC *word;
2913 int quoted;
2914{
2915 WORD_LIST *result, *tresult;
2916
b72432fd 2917 tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
726f6388
JA
2918 result = word_list_split (tresult);
2919 dispose_words (tresult);
ccc6cda3 2920 return (result ? dequote_list (result) : result);
726f6388
JA
2921}
2922
2923/* Expand WORD, but do not perform word splitting on the result. This
2924 does parameter expansion, command substitution, arithmetic expansion,
2925 and quote removal. */
2926WORD_LIST *
2927expand_word_no_split (word, quoted)
2928 WORD_DESC *word;
2929 int quoted;
2930{
2931 WORD_LIST *result;
2932
b72432fd 2933 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
ccc6cda3 2934 return (result ? dequote_list (result) : result);
726f6388
JA
2935}
2936
2937/* Perform shell expansions on WORD, but do not perform word splitting or
2938 quote removal on the result. */
2939WORD_LIST *
2940expand_word_leave_quoted (word, quoted)
2941 WORD_DESC *word;
2942 int quoted;
2943{
b72432fd 2944 return (call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL));
726f6388
JA
2945}
2946
726f6388
JA
2947#if defined (PROCESS_SUBSTITUTION)
2948
cce855bc
JA
2949/*****************************************************************/
2950/* */
2951/* Hacking Process Substitution */
2952/* */
2953/*****************************************************************/
726f6388 2954
726f6388
JA
2955#if !defined (HAVE_DEV_FD)
2956/* Named pipes must be removed explicitly with `unlink'. This keeps a list
2957 of FIFOs the shell has open. unlink_fifo_list will walk the list and
2958 unlink all of them. add_fifo_list adds the name of an open FIFO to the
2959 list. NFIFO is a count of the number of FIFOs in the list. */
2960#define FIFO_INCR 20
ccc6cda3 2961extern char *mktemp ();
726f6388
JA
2962
2963static char **fifo_list = (char **)NULL;
ccc6cda3
JA
2964static int nfifo;
2965static int fifo_list_size;
726f6388
JA
2966
2967static void
2968add_fifo_list (pathname)
2969 char *pathname;
2970{
2971 if (nfifo >= fifo_list_size - 1)
2972 {
2973 fifo_list_size += FIFO_INCR;
2974 fifo_list = (char **)xrealloc (fifo_list,
2975 fifo_list_size * sizeof (char *));
2976 }
2977
2978 fifo_list[nfifo++] = savestring (pathname);
2979}
2980
2981void
2982unlink_fifo_list ()
2983{
ccc6cda3 2984 if (nfifo == 0)
726f6388
JA
2985 return;
2986
2987 while (nfifo--)
2988 {
2989 unlink (fifo_list[nfifo]);
2990 free (fifo_list[nfifo]);
2991 fifo_list[nfifo] = (char *)NULL;
2992 }
2993 nfifo = 0;
2994}
2995
2996static char *
2997make_named_pipe ()
2998{
2999 char *tname;
3000
3001 tname = mktemp (savestring ("/tmp/sh-np-XXXXXX"));
3002 if (mkfifo (tname, 0600) < 0)
3003 {
3004 free (tname);
3005 return ((char *)NULL);
3006 }
3007
3008 add_fifo_list (tname);
3009 return (tname);
3010}
3011
726f6388
JA
3012#else /* HAVE_DEV_FD */
3013
3014/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
3015 has open to children. NFDS is a count of the number of bits currently
3016 set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
3017 of open files. */
3018static char *dev_fd_list = (char *)NULL;
ccc6cda3 3019static int nfds;
726f6388
JA
3020static int totfds; /* The highest possible number of open files. */
3021
3022static void
3023add_fifo_list (fd)
3024 int fd;
3025{
3026 if (!dev_fd_list || fd >= totfds)
3027 {
3028 int ofds;
3029
3030 ofds = totfds;
3031 totfds = getdtablesize ();
3032 if (totfds < 0 || totfds > 256)
3033 totfds = 256;
3034 if (fd > totfds)
3035 totfds = fd + 2;
3036
3037 dev_fd_list = xrealloc (dev_fd_list, totfds);
3038 bzero (dev_fd_list + ofds, totfds - ofds);
3039 }
3040
3041 dev_fd_list[fd] = 1;
3042 nfds++;
3043}
3044
3045void
3046unlink_fifo_list ()
3047{
3048 register int i;
3049
ccc6cda3 3050 if (nfds == 0)
726f6388
JA
3051 return;
3052
3053 for (i = 0; nfds && i < totfds; i++)
3054 if (dev_fd_list[i])
3055 {
3056 close (i);
3057 dev_fd_list[i] = 0;
3058 nfds--;
3059 }
3060
3061 nfds = 0;
3062}
3063
3064#if defined (NOTDEF)
3065print_dev_fd_list ()
3066{
3067 register int i;
3068
3069 fprintf (stderr, "pid %d: dev_fd_list:", getpid ());
3070 fflush (stderr);
3071
3072 for (i = 0; i < totfds; i++)
3073 {
3074 if (dev_fd_list[i])
3075 fprintf (stderr, " %d", i);
3076 }
3077 fprintf (stderr, "\n");
3078}
3079#endif /* NOTDEF */
3080
3081static char *
3082make_dev_fd_filename (fd)
3083 int fd;
3084{
bb70624e 3085 char *ret, intbuf[16], *p;
726f6388 3086
d166f048 3087 ret = xmalloc (sizeof (DEV_FD_PREFIX) + 4);
bb70624e
JA
3088
3089 strcpy (ret, DEV_FD_PREFIX);
3090 p = inttostr (fd, intbuf, sizeof (intbuf));
3091 strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
3092
726f6388
JA
3093 add_fifo_list (fd);
3094 return (ret);
3095}
3096
3097#endif /* HAVE_DEV_FD */
3098
3099/* Return a filename that will open a connection to the process defined by
3100 executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
3101 a filename in /dev/fd corresponding to a descriptor that is one of the
3102 ends of the pipe. If not defined, we use named pipes on systems that have
3103 them. Systems without /dev/fd and named pipes are out of luck.
3104
3105 OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
3106 use the read end of the pipe and dup that file descriptor to fd 0 in
3107 the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
3108 writing or use the write end of the pipe in the child, and dup that
3109 file descriptor to fd 1 in the child. The parent does the opposite. */
3110
3111static char *
3112process_substitute (string, open_for_read_in_child)
3113 char *string;
3114 int open_for_read_in_child;
3115{
3116 char *pathname;
3117 int fd, result;
3118 pid_t old_pid, pid;
3119#if defined (HAVE_DEV_FD)
3120 int parent_pipe_fd, child_pipe_fd;
3121 int fildes[2];
3122#endif /* HAVE_DEV_FD */
3123#if defined (JOB_CONTROL)
3124 pid_t old_pipeline_pgrp;
ccc6cda3 3125#endif
726f6388 3126
cce855bc 3127 if (!string || !*string || wordexp_only)
726f6388
JA
3128 return ((char *)NULL);
3129
3130#if !defined (HAVE_DEV_FD)
3131 pathname = make_named_pipe ();
3132#else /* HAVE_DEV_FD */
3133 if (pipe (fildes) < 0)
3134 {
ccc6cda3 3135 sys_error ("cannot make pipe for process substitution");
726f6388
JA
3136 return ((char *)NULL);
3137 }
3138 /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
3139 the pipe in the parent, otherwise the read end. */
3140 parent_pipe_fd = fildes[open_for_read_in_child];
3141 child_pipe_fd = fildes[1 - open_for_read_in_child];
d166f048
JA
3142 /* Move the parent end of the pipe to some high file descriptor, to
3143 avoid clashes with FDs used by the script. */
3144 parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
3145
726f6388
JA
3146 pathname = make_dev_fd_filename (parent_pipe_fd);
3147#endif /* HAVE_DEV_FD */
3148
3149 if (!pathname)
3150 {
ccc6cda3 3151 sys_error ("cannot make pipe for process substitution");
726f6388
JA
3152 return ((char *)NULL);
3153 }
3154
3155 old_pid = last_made_pid;
3156
3157#if defined (JOB_CONTROL)
3158 old_pipeline_pgrp = pipeline_pgrp;
3159 pipeline_pgrp = shell_pgrp;
ccc6cda3 3160#if 0
726f6388 3161 cleanup_the_pipeline ();
ccc6cda3
JA
3162#else
3163 save_pipeline (1);
3164#endif
3165#endif /* JOB_CONTROL */
3166
726f6388
JA
3167 pid = make_child ((char *)NULL, 1);
3168 if (pid == 0)
3169 {
ccc6cda3 3170 reset_terminating_signals (); /* XXX */
726f6388
JA
3171 /* Cancel traps, in trap.c. */
3172 restore_original_signals ();
3173 setup_async_signals ();
ccc6cda3 3174 subshell_environment = SUBSHELL_COMSUB;
726f6388 3175 }
ccc6cda3
JA
3176
3177#if defined (JOB_CONTROL)
726f6388
JA
3178 set_sigchld_handler ();
3179 stop_making_children ();
3180 pipeline_pgrp = old_pipeline_pgrp;
ccc6cda3 3181#endif /* JOB_CONTROL */
726f6388
JA
3182
3183 if (pid < 0)
3184 {
ccc6cda3 3185 sys_error ("cannot make child for process substitution");
726f6388
JA
3186 free (pathname);
3187#if defined (HAVE_DEV_FD)
3188 close (parent_pipe_fd);
3189 close (child_pipe_fd);
3190#endif /* HAVE_DEV_FD */
3191 return ((char *)NULL);
3192 }
3193
3194 if (pid > 0)
3195 {
ccc6cda3
JA
3196#if defined (JOB_CONTROL)
3197 restore_pipeline (1);
3198#endif
3199
726f6388
JA
3200 last_made_pid = old_pid;
3201
3202#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
3203 close_pgrp_pipe ();
3204#endif /* JOB_CONTROL && PGRP_PIPE */
3205
3206#if defined (HAVE_DEV_FD)
3207 close (child_pipe_fd);
3208#endif /* HAVE_DEV_FD */
3209
3210 return (pathname);
3211 }
3212
3213 set_sigint_handler ();
3214
3215#if defined (JOB_CONTROL)
3216 set_job_control (0);
3217#endif /* JOB_CONTROL */
3218
3219#if !defined (HAVE_DEV_FD)
3220 /* Open the named pipe in the child. */
ccc6cda3 3221 fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY);
726f6388
JA
3222 if (fd < 0)
3223 {
ccc6cda3
JA
3224 sys_error ("cannot open named pipe %s for %s", pathname,
3225 open_for_read_in_child ? "reading" : "writing");
726f6388
JA
3226 exit (127);
3227 }
bb70624e
JA
3228 if (open_for_read_in_child)
3229 {
3230 if (unset_nodelay_mode (fd) < 0)
3231 {
3232 sys_error ("cannout reset nodelay mode for fd %d", fd);
3233 exit (127);
3234 }
3235 }
726f6388
JA
3236#else /* HAVE_DEV_FD */
3237 fd = child_pipe_fd;
3238#endif /* HAVE_DEV_FD */
3239
3240 if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
3241 {
ccc6cda3
JA
3242 sys_error ("cannot duplicate named pipe %s as fd %d", pathname,
3243 open_for_read_in_child ? 0 : 1);
726f6388
JA
3244 exit (127);
3245 }
3246
3247 close (fd);
3248
3249 /* Need to close any files that this process has open to pipes inherited
3250 from its parent. */
3251 if (current_fds_to_close)
3252 {
3253 close_fd_bitmap (current_fds_to_close);
3254 current_fds_to_close = (struct fd_bitmap *)NULL;
3255 }
3256
3257#if defined (HAVE_DEV_FD)
3258 /* Make sure we close the parent's end of the pipe and clear the slot
3259 in the fd list so it is not closed later, if reallocated by, for
3260 instance, pipe(2). */
3261 close (parent_pipe_fd);
3262 dev_fd_list[parent_pipe_fd] = 0;
3263#endif /* HAVE_DEV_FD */
3264
d166f048 3265 result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
726f6388
JA
3266
3267#if !defined (HAVE_DEV_FD)
3268 /* Make sure we close the named pipe in the child before we exit. */
3269 close (open_for_read_in_child ? 0 : 1);
3270#endif /* !HAVE_DEV_FD */
3271
3272 exit (result);
3273 /*NOTREACHED*/
3274}
3275#endif /* PROCESS_SUBSTITUTION */
3276
cce855bc
JA
3277/***********************************/
3278/* */
3279/* Command Substitution */
3280/* */
3281/***********************************/
3282
d166f048
JA
3283static char *
3284read_comsub (fd, quoted)
3285 int fd, quoted;
3286{
3287 char *istring, buf[128], *bufp;
3288 int bufn, istring_index, istring_size, c;
3289
3290 istring = (char *)NULL;
3291 istring_index = istring_size = bufn = 0;
3292
3293 /* Read the output of the command through the pipe. */
3294 while (1)
3295 {
3296 if (fd < 0)
3297 break;
3298 if (--bufn <= 0)
3299 {
bb70624e 3300 bufn = zread (fd, buf, sizeof (buf));
d166f048
JA
3301 if (bufn <= 0)
3302 break;
3303 bufp = buf;
3304 }
3305 c = *bufp++;
3306
3307 /* Add the character to ISTRING, possibly after resizing it. */
3308 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
3309
3310 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL)
3311 istring[istring_index++] = CTLESC;
3312
3313 istring[istring_index++] = c;
3314 }
3315
3316 if (istring)
3317 istring[istring_index] = '\0';
3318
3319 /* If we read no output, just return now and save ourselves some
3320 trouble. */
3321 if (istring_index == 0)
3322 {
3323 FREE (istring);
3324 return (char *)NULL;
3325 }
3326
3327 /* Strip trailing newlines from the output of the command. */
3328 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
3329 {
3330 while (istring_index > 0)
3331 {
3332 if (istring[istring_index - 1] == '\n')
3333 {
3334 --istring_index;
3335
3336 /* If the newline was quoted, remove the quoting char. */
3337 if (istring[istring_index - 1] == CTLESC)
3338 --istring_index;
3339 }
3340 else
3341 break;
3342 }
3343 istring[istring_index] = '\0';
3344 }
3345 else
3346 strip_trailing (istring, istring_index - 1, 1);
3347
3348 return istring;
3349}
3350
726f6388
JA
3351/* Perform command substitution on STRING. This returns a string,
3352 possibly quoted. */
bb70624e 3353char *
726f6388
JA
3354command_substitute (string, quoted)
3355 char *string;
3356 int quoted;
3357{
ccc6cda3
JA
3358 pid_t pid, old_pid, old_pipeline_pgrp;
3359 char *istring;
bb70624e 3360 int result, fildes[2], function_value;
726f6388 3361
ccc6cda3 3362 istring = (char *)NULL;
726f6388
JA
3363
3364 /* Don't fork () if there is no need to. In the case of no command to
3365 run, just return NULL. */
3366 if (!string || !*string || (string[0] == '\n' && !string[1]))
3367 return ((char *)NULL);
3368
cce855bc
JA
3369 if (wordexp_only && read_but_dont_execute)
3370 {
3371 last_command_exit_value = 125;
3372 jump_to_top_level (EXITPROG);
3373 }
3374
bb70624e
JA
3375 /* We're making the assumption here that the command substitution will
3376 eventually run a command from the file system. Since we'll run
3377 maybe_make_export_env in this subshell before executing that command,
3378 the parent shell and any other shells it starts will have to remake
3379 the environment. If we make it before we fork, other shells won't
3380 have to. Don't bother if we have any temporary variable assignments,
3381 though, because the export environment will be remade after this
3382 command completes anyway, but do it if all the words to be expanded
3383 are variable assignments. */
3384 if (subst_assign_varlist == 0 || garglist == 0)
3385 maybe_make_export_env (); /* XXX */
3386
726f6388
JA
3387 /* Pipe the output of executing STRING into the current shell. */
3388 if (pipe (fildes) < 0)
3389 {
ccc6cda3 3390 sys_error ("cannot make pipes for command substitution");
726f6388
JA
3391 goto error_exit;
3392 }
3393
3394 old_pid = last_made_pid;
3395#if defined (JOB_CONTROL)
ccc6cda3
JA
3396 old_pipeline_pgrp = pipeline_pgrp;
3397 pipeline_pgrp = shell_pgrp;
3398 cleanup_the_pipeline ();
3399#endif
726f6388 3400
ccc6cda3 3401 pid = make_child ((char *)NULL, 0);
726f6388
JA
3402 if (pid == 0)
3403 /* Reset the signal handlers in the child, but don't free the
3404 trap strings. */
3405 reset_signal_handlers ();
ccc6cda3
JA
3406
3407#if defined (JOB_CONTROL)
3408 set_sigchld_handler ();
3409 stop_making_children ();
3410 pipeline_pgrp = old_pipeline_pgrp;
3411#endif /* JOB_CONTROL */
726f6388
JA
3412
3413 if (pid < 0)
3414 {
ccc6cda3 3415 sys_error ("cannot make child for command substitution");
726f6388
JA
3416 error_exit:
3417
3418 FREE (istring);
3419 close (fildes[0]);
3420 close (fildes[1]);
3421 return ((char *)NULL);
3422 }
3423
3424 if (pid == 0)
3425 {
3426 set_sigint_handler (); /* XXX */
bb70624e 3427#if 0
726f6388
JA
3428#if defined (JOB_CONTROL)
3429 set_job_control (0);
bb70624e 3430#endif
726f6388
JA
3431#endif
3432 if (dup2 (fildes[1], 1) < 0)
3433 {
ccc6cda3 3434 sys_error ("command_substitute: cannot duplicate pipe as fd 1");
726f6388
JA
3435 exit (EXECUTION_FAILURE);
3436 }
3437
3438 /* If standard output is closed in the parent shell
3439 (such as after `exec >&-'), file descriptor 1 will be
3440 the lowest available file descriptor, and end up in
3441 fildes[0]. This can happen for stdin and stderr as well,
3442 but stdout is more important -- it will cause no output
3443 to be generated from this command. */
3444 if ((fildes[1] != fileno (stdin)) &&
3445 (fildes[1] != fileno (stdout)) &&
3446 (fildes[1] != fileno (stderr)))
3447 close (fildes[1]);
3448
3449 if ((fildes[0] != fileno (stdin)) &&
3450 (fildes[0] != fileno (stdout)) &&
3451 (fildes[0] != fileno (stderr)))
3452 close (fildes[0]);
3453
3454 /* The currently executing shell is not interactive. */
3455 interactive = 0;
3456
ccc6cda3
JA
3457 /* This is a subshell environment. */
3458 subshell_environment = SUBSHELL_COMSUB;
3459
726f6388
JA
3460 /* Command substitution does not inherit the -e flag. */
3461 exit_immediately_on_error = 0;
3462
3463 remove_quoted_escapes (string);
3464
ccc6cda3 3465 startup_state = 2; /* see if we can avoid a fork */
726f6388
JA
3466 /* Give command substitution a place to jump back to on failure,
3467 so we don't go back up to main (). */
3468 result = setjmp (top_level);
3469
bb70624e
JA
3470 /* If we're running a command substitution inside a shell function,
3471 trap `return' so we don't return from the function in the subshell
3472 and go off to never-never land. */
3473 if (result == 0 && return_catch_flag)
3474 function_value = setjmp (return_catch);
3475 else
3476 function_value = 0;
3477
726f6388
JA
3478 if (result == EXITPROG)
3479 exit (last_command_exit_value);
3480 else if (result)
3481 exit (EXECUTION_FAILURE);
bb70624e
JA
3482 else if (function_value)
3483 exit (return_catch_value);
726f6388 3484 else
d166f048 3485 exit (parse_and_execute (string, "command substitution", SEVAL_NOHIST));
726f6388
JA
3486 }
3487 else
3488 {
726f6388
JA
3489#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
3490 close_pgrp_pipe ();
3491#endif /* JOB_CONTROL && PGRP_PIPE */
3492
3493 close (fildes[1]);
3494
d166f048 3495 istring = read_comsub (fildes[0], quoted);
ccc6cda3 3496
726f6388
JA
3497 close (fildes[0]);
3498
b72432fd 3499 current_command_subst_pid = pid;
726f6388
JA
3500 last_command_exit_value = wait_for (pid);
3501 last_command_subst_pid = pid;
3502 last_made_pid = old_pid;
3503
3504#if defined (JOB_CONTROL)
3505 /* If last_command_exit_value > 128, then the substituted command
3506 was terminated by a signal. If that signal was SIGINT, then send
3507 SIGINT to ourselves. This will break out of loops, for instance. */
3508 if (last_command_exit_value == (128 + SIGINT))
3509 kill (getpid (), SIGINT);
3510
3511 /* wait_for gives the terminal back to shell_pgrp. If some other
cce855bc
JA
3512 process group should have it, give it away to that group here.
3513 pipeline_pgrp is non-zero only while we are constructing a
3514 pipline, so what we are concerned about is whether or not that
3515 pipeline was started in the background. A pipeline started in
3516 the background should never get the tty back here. */
3517#if 0
3518 if (interactive && pipeline_pgrp != (pid_t)0 && pipeline_pgrp != last_asynchronous_pid)
3519#else
3520 if (interactive && pipeline_pgrp != (pid_t)0 && subshell_environment != SUBSHELL_ASYNC)
3521#endif
726f6388
JA
3522 give_terminal_to (pipeline_pgrp);
3523#endif /* JOB_CONTROL */
3524
726f6388
JA
3525 return (istring);
3526 }
3527}
3528
3529/********************************************************
3530 * *
3531 * Utility functions for parameter expansion *
3532 * *
3533 ********************************************************/
3534
cce855bc 3535/* Utility functions to manage arrays and their contents for expansion */
ccc6cda3
JA
3536
3537#if defined (ARRAY_VARS)
ccc6cda3
JA
3538int
3539valid_array_reference (name)
3540 char *name;
3541{
3542 char *t;
3543 int r, len;
3544
3545 t = strchr (name, '[');
3546 if (t)
3547 {
3548 *t = '\0';
3549 r = legal_identifier (name);
3550 *t = '[';
3551 if (r == 0)
3552 return 0;
3553 /* Check for a properly-terminated non-blank subscript. */
3554 len = skipsubscript (t, 0);
3555 if (t[len] != ']' || len == 1)
3556 return 0;
3557 for (r = 1; r < len; r++)
3558 if (whitespace (t[r]) == 0)
3559 return 1;
3560 return 0;
3561 }
3562 return 0;
3563}
3564
3565/* Expand the array index beginning at S and extending LEN characters. */
3566int
3567array_expand_index (s, len)
3568 char *s;
3569 int len;
3570{
3571 char *exp, *t;
d166f048 3572 int val, expok;
ccc6cda3
JA
3573
3574 exp = xmalloc (len);
3575 strncpy (exp, s, len - 1);
3576 exp[len - 1] = '\0';
3577 t = maybe_expand_string (exp, 0, expand_string);
3578 this_command_name = (char *)NULL;
d166f048 3579 val = evalexp (t, &expok);
ccc6cda3
JA
3580 free (t);
3581 free (exp);
d166f048
JA
3582 if (expok == 0)
3583 jump_to_top_level (DISCARD);
ccc6cda3
JA
3584 return val;
3585}
3586
3587/* Return the variable specified by S without any subscript. If non-null,
3588 return the index of the start of the subscript in *SUBP. If non-null,
3589 the length of the subscript is returned in *LENP. */
3590SHELL_VAR *
3591array_variable_part (s, subp, lenp)
3592 char *s, **subp;
3593 int *lenp;
3594{
3595 char *t;
3596 int ind, ni;
3597 SHELL_VAR *var;
3598
3599 t = strchr (s, '[');
3600 ind = t - s;
3601 ni = skipsubscript (s, ind);
3602 if (ni <= ind + 1 || s[ni] != ']')
726f6388 3603 {
ccc6cda3
JA
3604 report_error ("%s: bad array subscript", s);
3605 return ((SHELL_VAR *)NULL);
3606 }
3607
3608 *t = '\0';
3609 var = find_variable (s);
3610 *t++ = '[';
3611
3612 if (subp)
3613 *subp = t;
3614 if (lenp)
3615 *lenp = ni - ind;
3616 return var;
3617}
3618
3619static char *
3620array_value_internal (s, quoted, allow_all)
3621 char *s;
3622 int quoted, allow_all;
3623{
3624 int len, ind;
cce855bc
JA
3625 char *retval, *t, *temp;
3626 WORD_LIST *l, *list;
ccc6cda3
JA
3627 SHELL_VAR *var;
3628
3629 var = array_variable_part (s, &t, &len);
3630
3631 if (var == 0)
3632 return (char *)NULL;
3633
3634 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
3635 {
3636 if (array_p (var) == 0 || allow_all == 0)
3637 {
3638 report_error ("%s: bad array subscript", s);
3639 return ((char *)NULL);
3640 }
3641 l = array_to_word_list (array_cell (var));
3642 if (l == (WORD_LIST *)NULL)
3643 return ((char *) NULL);
3644
cce855bc 3645#if 0
ccc6cda3
JA
3646 if (t[0] == '*') /* ${name[*]} */
3647 retval = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (l) : string_list (l);
3648 else /* ${name[@]} */
3649 retval = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (l) : l);
cce855bc
JA
3650#else
3651 if (t[0] == '*' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
3652 {
3653 temp = string_list_dollar_star (l);
3654 retval = quote_string (temp);
3655 free (temp);
3656 }
3657 else /* ${name[@]} or unquoted ${name[*]} */
3658 retval = string_list_dollar_at (l, quoted);
3659#endif
ccc6cda3
JA
3660
3661 dispose_words (l);
3662 }
3663 else
3664 {
3665 ind = array_expand_index (t, len);
3666 if (ind < 0)
726f6388 3667 {
ccc6cda3
JA
3668 report_error ("%s: bad array subscript", var->name);
3669 return ((char *)NULL);
726f6388 3670 }
ccc6cda3 3671 if (array_p (var) == 0)
d166f048 3672 return (ind == 0 ? savestring (value_cell (var)) : (char *)NULL);
ccc6cda3
JA
3673 retval = array_reference (array_cell (var), ind);
3674 if (retval)
3675 retval = quote_escapes (retval);
726f6388
JA
3676 }
3677
ccc6cda3
JA
3678 return retval;
3679}
726f6388 3680
ccc6cda3
JA
3681static char *
3682array_value (s, quoted)
3683 char *s;
3684 int quoted;
3685{
3686 return (array_value_internal (s, quoted, 1));
3687}
3688
3689/* Return the value of the array indexing expression S as a single string.
3690 If ALLOW_ALL is 0, do not allow `@' and `*' subscripts. This is used
3691 by other parts of the shell such as the arithmetic expression evaluator
3692 in expr.c. */
3693char *
3694get_array_value (s, allow_all)
3695 char *s;
3696 int allow_all;
3697{
3698 return (array_value_internal (s, 0, allow_all));
3699}
3700
3701static int
3702array_length_reference (s)
3703 char *s;
3704{
3705 int ind, len;
3706 char *t;
3707 ARRAY *array;
3708 SHELL_VAR *var;
3709
3710 var = array_variable_part (s, &t, &len);
726f6388 3711
ccc6cda3
JA
3712 /* If unbound variables should generate an error, report one and return
3713 failure. */
3714 if ((var == 0 || array_p (var) == 0) && unbound_vars_is_error)
726f6388 3715 {
ccc6cda3
JA
3716 ind = *--t;
3717 *t = '\0';
3718 report_error ("%s: unbound variable", s);
3719 *t++ = (char)ind;
3720 return (-1);
726f6388 3721 }
ccc6cda3
JA
3722 else if (var == 0)
3723 return 0;
3724 else if (array_p (var) == 0)
3725 return 1;
726f6388 3726
ccc6cda3 3727 array = array_cell (var);
726f6388 3728
ccc6cda3
JA
3729 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
3730 return (array_num_elements (array));
3731
3732 ind = array_expand_index (t, len);
3733 if (ind < 0)
3734 {
3735 report_error ("%s: bad array subscript", t);
3736 return (-1);
3737 }
3738 t = array_reference (array, ind);
3739 len = STRLEN (t);
3740
3741 return (len);
726f6388 3742}
ccc6cda3 3743#endif /* ARRAY_VARS */
726f6388
JA
3744
3745static int
3746valid_brace_expansion_word (name, var_is_special)
3747 char *name;
3748 int var_is_special;
3749{
3750 if (digit (*name) && all_digits (name))
3751 return 1;
3752 else if (var_is_special)
3753 return 1;
ccc6cda3
JA
3754#if defined (ARRAY_VARS)
3755 else if (valid_array_reference (name))
3756 return 1;
3757#endif /* ARRAY_VARS */
726f6388
JA
3758 else if (legal_identifier (name))
3759 return 1;
3760 else
3761 return 0;
3762}
ccc6cda3 3763
726f6388
JA
3764/* Parameter expand NAME, and return a new string which is the expansion,
3765 or NULL if there was no expansion.
3766 VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
3767 the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
3768 NAME was found inside of a double-quoted expression. */
3769static char *
3770parameter_brace_expand_word (name, var_is_special, quoted)
3771 char *name;
3772 int var_is_special, quoted;
3773{
ccc6cda3
JA
3774 char *temp, *tt;
3775 int arg_index;
3776 SHELL_VAR *var;
3777 WORD_LIST *l;
726f6388
JA
3778
3779 /* Handle multiple digit arguments, as in ${11}. */
3780 if (digit (*name))
3781 {
ccc6cda3 3782 arg_index = atoi (name);
726f6388
JA
3783 temp = get_dollar_var_value (arg_index);
3784 }
3785 else if (var_is_special) /* ${@} */
3786 {
cce855bc 3787 int sindex;
726f6388 3788 tt = xmalloc (2 + strlen (name));
cce855bc 3789 tt[sindex = 0] = '$';
726f6388 3790 strcpy (tt + 1, name);
cce855bc 3791#if 0
726f6388
JA
3792 l = expand_string_leave_quoted (tt, quoted);
3793 free (tt);
3794 temp = string_list (l);
3795 dispose_words (l);
cce855bc
JA
3796#else
3797 temp = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
3798 (int *)NULL, (int *)NULL, 0);
3799 free (tt);
3800#endif
726f6388 3801 }
ccc6cda3
JA
3802#if defined (ARRAY_VARS)
3803 else if (valid_array_reference (name))
3804 {
3805 temp = array_value (name, quoted);
3806 }
3807#endif
3808 else if (var = find_variable (name))
3809 {
3810 if (var && invisible_p (var) == 0)
3811 {
3812#if defined (ARRAY_VARS)
3813 temp = array_p (var) ? array_reference (array_cell (var), 0) : value_cell (var);
3814#else
3815 temp = value_cell (var);
3816#endif
3817
3818 if (temp)
3819 temp = quote_escapes (temp);
cce855bc
JA
3820
3821 if (tempvar_p (var))
3822 dispose_variable (var);
ccc6cda3
JA
3823 }
3824 else
3825 temp = (char *)NULL;
3826 }
726f6388 3827 else
ccc6cda3 3828 temp = (char *)NULL;
726f6388 3829
726f6388
JA
3830 return (temp);
3831}
3832
ccc6cda3
JA
3833/* Expand an indirect reference to a variable: ${!NAME} expands to the
3834 value of the variable whose name is the value of NAME. */
3835static char *
3836parameter_brace_expand_indir (name, var_is_special, quoted)
3837 char *name;
3838 int var_is_special, quoted;
3839{
3840 char *temp, *t;
3841
3842 t = parameter_brace_expand_word (name, var_is_special, quoted);
3843 if (t == 0)
3844 return (t);
bb70624e 3845#if 0
ccc6cda3 3846 temp = parameter_brace_expand_word (t, t[0] == '@' && t[1] == '\0', quoted);
bb70624e
JA
3847#else
3848 temp = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted);
3849#endif
ccc6cda3
JA
3850 free (t);
3851 return temp;
3852}
3853
726f6388
JA
3854/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
3855 depending on the value of C, the separating character. C can be one of
ccc6cda3
JA
3856 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
3857 between double quotes. */
726f6388 3858static char *
ccc6cda3 3859parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
726f6388 3860 char *name, *value;
ccc6cda3 3861 int c, quoted, *qdollaratp, *hasdollarat;
726f6388
JA
3862{
3863 WORD_LIST *l;
3864 char *t, *t1, *temp;
ccc6cda3 3865 int hasdol;
726f6388 3866
ccc6cda3
JA
3867 temp = (*value == '~' || (strchr (value, '~') && unquoted_substring ("=~", value)))
3868 ? bash_tilde_expand (value)
3869 : savestring (value);
726f6388 3870
ccc6cda3
JA
3871 /* If the entire expression is between double quotes, we want to treat
3872 the value as a double-quoted string, with the exception that we strip
3873 embedded unescaped double quotes. */
3874 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *temp)
726f6388 3875 {
ccc6cda3
JA
3876 hasdol = 0;
3877 t = string_extract_double_quoted (temp, &hasdol, 1);
726f6388
JA
3878 free (temp);
3879 temp = t;
726f6388 3880 }
ccc6cda3 3881
726f6388 3882 hasdol = 0;
ccc6cda3
JA
3883 /* XXX was 0 not quoted */
3884 l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL)
3885 : (WORD_LIST *)0;
3886 if (hasdollarat)
3887 *hasdollarat = hasdol || (l && l->next);
726f6388 3888 free (temp);
726f6388
JA
3889 if (l)
3890 {
ccc6cda3
JA
3891 /* The expansion of TEMP returned something. We need to treat things
3892 slightly differently if HASDOL is non-zero. */
726f6388 3893 temp = string_list (l);
ccc6cda3
JA
3894 /* If l->next is not null, we know that TEMP contained "$@", since that
3895 is the only expansion that creates more than one word. */
3896 if ((hasdol && quoted) || l->next)
3897 *qdollaratp = 1;
726f6388
JA
3898 dispose_words (l);
3899 }
ccc6cda3 3900 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol)
726f6388 3901 {
ccc6cda3
JA
3902 /* The brace expansion occurred between double quotes and there was
3903 a $@ in TEMP. It does not matter if the $@ is quoted, as long as
3904 it does not expand to anything. In this case, we want to return
3905 a quoted empty string. */
726f6388
JA
3906 temp = xmalloc (2);
3907 temp[0] = CTLNUL;
3908 temp[1] = '\0';
3909 }
3910 else
3911 temp = (char *)NULL;
3912
3913 if (c == '-' || c == '+')
3914 return (temp);
3915
3916 /* c == '=' */
ccc6cda3 3917 t = temp ? savestring (temp) : savestring ("");
726f6388
JA
3918 t1 = dequote_string (t);
3919 free (t);
3920 bind_variable (name, t1);
3921 free (t1);
3922 return (temp);
3923}
3924
3925/* Deal with the right hand side of a ${name:?value} expansion in the case
3926 that NAME is null or not set. If VALUE is non-null it is expanded and
3927 used as the error message to print, otherwise a standard message is
3928 printed. */
3929static void
3930parameter_brace_expand_error (name, value)
3931 char *name, *value;
3932{
ccc6cda3
JA
3933 WORD_LIST *l;
3934 char *temp;
3935
726f6388
JA
3936 if (value && *value)
3937 {
ccc6cda3
JA
3938 l = expand_string (value, 0);
3939 temp = string_list (l);
3940 report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
3941 FREE (temp);
726f6388
JA
3942 dispose_words (l);
3943 }
3944 else
3945 report_error ("%s: parameter null or not set", name);
3946
3947 /* Free the data we have allocated during this expansion, since we
3948 are about to longjmp out. */
3949 free (name);
3950 FREE (value);
3951}
3952
3953/* Return 1 if NAME is something for which parameter_brace_expand_length is
3954 OK to do. */
3955static int
3956valid_length_expression (name)
3957 char *name;
3958{
3959 return (!name[1] || /* ${#} */
3960 ((name[1] == '@' || name[1] == '*') && !name[2]) || /* ${#@}, ${#*} */
cce855bc 3961 (member (name[1], "-?$!#") && !name[2]) || /* ${#-}, etc. */
726f6388 3962 (digit (name[1]) && all_digits (name + 1)) || /* ${#11} */
ccc6cda3
JA
3963#if defined (ARRAY_VARS)
3964 valid_array_reference (name + 1) || /* ${#a[7]} */
3965#endif
726f6388
JA
3966 legal_identifier (name + 1)); /* ${#PS1} */
3967}
3968
3969/* Handle the parameter brace expansion that requires us to return the
3970 length of a parameter. */
3971static int
3972parameter_brace_expand_length (name)
3973 char *name;
3974{
ccc6cda3
JA
3975 char *t, *newname;
3976 int number;
3977 WORD_LIST *list;
3978#if defined (ARRAY_VARS)
3979 SHELL_VAR *var;
3980#endif
3981
3982 if (name[1] == '\0') /* ${#} */
3983 number = number_of_args ();
cce855bc
JA
3984 else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */
3985 number = number_of_args ();
3986 else if (member (name[1], "-?$!#") && name[2] == '\0')
3987 {
3988 /* Take the lengths of some of the shell's special parameters. */
3989 switch (name[1])
3990 {
3991 case '-':
3992 t = which_set_flags ();
3993 break;
3994 case '?':
3995 t = itos (last_command_exit_value);
3996 break;
3997 case '$':
3998 t = itos (dollar_dollar_pid);
3999 break;
4000 case '!':
4001 if (last_asynchronous_pid == NO_PID)
4002 t = (char *)NULL;
4003 else
4004 t = itos ((int)last_asynchronous_pid);
4005 break;
4006 case '#':
4007 t = itos (number_of_args ());
4008 break;
4009 }
4010 number = STRLEN (t);
4011 FREE (t);
4012 }
ccc6cda3
JA
4013#if defined (ARRAY_VARS)
4014 else if (valid_array_reference (name + 1))
4015 number = array_length_reference (name + 1);
4016#endif /* ARRAY_VARS */
cce855bc 4017 else
ccc6cda3
JA
4018 {
4019 number = 0;
4020
4021 if (digit (name[1])) /* ${#1} */
4022 {
4023 t = get_dollar_var_value (atoi (name + 1));
4024 number = STRLEN (t);
4025 FREE (t);
4026 }
4027#if defined (ARRAY_VARS)
4028 else if ((var = find_variable (name + 1)) && array_p (var))
4029 {
4030 t = array_reference (array_cell (var), 0);
4031 number = STRLEN (t);
4032 }
4033#endif
4034 else /* ${#PS1} */
4035 {
4036 newname = savestring (name);
4037 newname[0] = '$';
4038 list = expand_string (newname, Q_DOUBLE_QUOTES);
4039 t = list ? string_list (list) : (char *)NULL;
4040 free (newname);
4041 if (list)
4042 dispose_words (list);
4043
4044 number = STRLEN (t);
4045 FREE (t);
4046 }
4047 }
ccc6cda3
JA
4048
4049 return (number);
4050}
4051
4052/* Verify and limit the start and end of the desired substring. If
4053 VTYPE == 0, a regular shell variable is being used; if it is 1,
cce855bc 4054 then the positional parameters are being used; if it is 2, then
e8ce775d
JA
4055 VALUE is really a pointer to an array variable that should be used.
4056 Return value is 1 if both values were OK, 0 if there was a problem
4057 with an invalid expression, or -1 if the values were out of range. */
ccc6cda3
JA
4058static int
4059verify_substring_values (value, substr, vtype, e1p, e2p)
4060 char *value, *substr;
4061 int vtype, *e1p, *e2p;
4062{
bb70624e 4063 char *t, *temp1, *temp2;
d166f048 4064 int len, expok;
ccc6cda3
JA
4065#if defined (ARRAY_VARS)
4066 ARRAY *a;
4067#endif
4068
4069 t = strchr (substr, ':');
4070 if (t)
4071 *t = '\0';
d166f048
JA
4072 temp1 = maybe_expand_string (substr, Q_DOUBLE_QUOTES, expand_string);
4073 *e1p = evalexp (temp1, &expok);
ccc6cda3 4074 free (temp1);
d166f048
JA
4075 if (expok == 0)
4076 return (0);
ccc6cda3
JA
4077
4078 switch (vtype)
4079 {
4080 case VT_VARIABLE:
d166f048 4081 case VT_ARRAYMEMBER:
ccc6cda3
JA
4082 len = strlen (value);
4083 break;
4084 case VT_POSPARMS:
4085 len = number_of_args () + 1;
4086 break;
4087#if defined (ARRAY_VARS)
4088 case VT_ARRAYVAR:
4089 a = (ARRAY *)value;
4090 len = array_num_elements (a) + 1;
4091 break;
4092#endif
4093 }
4094
4095 if (*e1p < 0) /* negative offsets count from end */
4096 *e1p += len;
4097
d166f048 4098 if (*e1p >= len || *e1p < 0)
e8ce775d 4099 return (-1);
d166f048 4100
ccc6cda3
JA
4101 if (t)
4102 {
4103 t++;
bb70624e
JA
4104 temp2 = savestring (t);
4105 temp1 = maybe_expand_string (temp2, Q_DOUBLE_QUOTES, expand_string);
4106 free (temp2);
ccc6cda3 4107 t[-1] = ':';
d166f048 4108 *e2p = evalexp (temp1, &expok);
ccc6cda3 4109 free (temp1);
d166f048
JA
4110 if (expok == 0)
4111 return (0);
ccc6cda3
JA
4112 if (*e2p < 0)
4113 {
4114 internal_error ("%s: substring expression < 0", t);
4115 return (0);
4116 }
4117 *e2p += *e1p; /* want E2 chars starting at E1 */
4118 if (*e2p > len)
4119 *e2p = len;
4120 }
4121 else
4122 *e2p = len;
4123
4124 return (1);
4125}
4126
ccc6cda3 4127/* Return the type of variable specified by VARNAME (simple variable,
cce855bc 4128 positional param, or array variable). Also return the value specified
ccc6cda3
JA
4129 by VARNAME (value of a variable or a reference to an array element). */
4130static int
4131get_var_and_type (varname, value, varp, valp)
4132 char *varname, *value;
4133 SHELL_VAR **varp;
4134 char **valp;
4135{
4136 int vtype;
4137 char *temp;
4138#if defined (ARRAY_VARS)
4139 SHELL_VAR *v;
4140#endif
4141
4142 vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0'; /* VT_POSPARMS */
4143 *varp = (SHELL_VAR *)NULL;
4144
4145#if defined (ARRAY_VARS)
4146 if (valid_array_reference (varname))
4147 {
4148 v = array_variable_part (varname, &temp, (int *)0);
4149 if (v && array_p (v))
4150 {
d166f048 4151 if ((temp[0] == '@' || temp[0] == '*') && temp[1] == ']')
ccc6cda3
JA
4152 {
4153 vtype = VT_ARRAYVAR;
4154 *valp = (char *)array_cell (v);
4155 }
4156 else
4157 {
d166f048 4158 vtype = VT_ARRAYMEMBER;
ccc6cda3
JA
4159 *valp = array_value (varname, 1);
4160 }
4161 *varp = v;
4162 }
4163 else
4164 return -1;
4165 }
4166 else if ((v = find_variable (varname)) && array_p (v))
4167 {
4168 vtype = VT_VARIABLE;
4169 *varp = v;
4170 *valp = array_reference (array_cell (v), 0);
4171 }
4172 else
4173#endif
4174 *valp = value;
4175
4176 return vtype;
4177}
4178
cce855bc
JA
4179/******************************************************/
4180/* */
4181/* Functions to extract substrings of variable values */
4182/* */
4183/******************************************************/
4184
ccc6cda3
JA
4185/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
4186 is `@', use the positional parameters; otherwise, use the value of
4187 VARNAME. If VARNAME is an array variable, use the array elements. */
4188
4189static char *
4190parameter_brace_substring (varname, value, substr, quoted)
4191 char *varname, *value, *substr;
4192 int quoted;
4193{
e8ce775d 4194 int e1, e2, vtype, r;
ccc6cda3
JA
4195 char *temp, *val;
4196 SHELL_VAR *v;
4197
4198 if (value == 0)
4199 return ((char *)NULL);
4200
4201 this_command_name = varname;
4202
4203 vtype = get_var_and_type (varname, value, &v, &val);
4204 if (vtype == -1)
4205 return ((char *)NULL);
4206
e8ce775d
JA
4207 r = verify_substring_values (val, substr, vtype, &e1, &e2);
4208 if (r <= 0)
d166f048
JA
4209 {
4210 if (val && vtype == VT_ARRAYMEMBER)
4211 free (val);
e8ce775d 4212 return ((r == 0) ? &expand_param_error : (char *)NULL);
d166f048 4213 }
ccc6cda3
JA
4214
4215 switch (vtype)
4216 {
4217 case VT_VARIABLE:
d166f048 4218 case VT_ARRAYMEMBER:
ccc6cda3
JA
4219 temp = quoted ? quoted_substring (value, e1, e2) : substring (value, e1, e2);
4220 break;
4221 case VT_POSPARMS:
4222 temp = pos_params (varname, e1, e2, quoted);
4223 break;
4224#if defined (ARRAY_VARS)
4225 case VT_ARRAYVAR:
4226 temp = array_subrange (array_cell (v), e1, e2, quoted);
4227 break;
4228#endif
4229 }
4230
4231 return temp;
4232}
4233
cce855bc
JA
4234/****************************************************************/
4235/* */
4236/* Functions to perform pattern substitution on variable values */
4237/* */
4238/****************************************************************/
4239
ccc6cda3
JA
4240char *
4241pat_subst (string, pat, rep, mflags)
4242 char *string, *pat, *rep;
4243 int mflags;
4244{
4245 char *ret, *s, *e, *str;
4246 int rsize, rptr, l, replen, mtype;
4247
b72432fd
JA
4248 mtype = mflags & MATCH_TYPEMASK;
4249
4250 /* Special cases:
4251 * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
4252 * with REP and return the result.
4253 * 2. A null pattern with mtype == MATCH_END means to append REP to
4254 * STRING and return the result.
4255 */
4256 if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
4257 {
4258 replen = STRLEN (rep);
4259 l = strlen (string);
4260 ret = xmalloc (replen + l + 2);
bb70624e
JA
4261 if (replen == 0)
4262 strcpy (ret, string);
4263 else if (mtype == MATCH_BEG)
b72432fd
JA
4264 {
4265 strcpy (ret, rep);
4266 strcpy (ret + replen, string);
4267 }
4268 else
4269 {
4270 strcpy (ret, string);
4271 strcpy (ret + l, rep);
4272 }
4273 return (ret);
4274 }
4275
ccc6cda3
JA
4276 ret = xmalloc (rsize = 64);
4277 ret[0] = '\0';
4278
ccc6cda3
JA
4279 for (replen = STRLEN (rep), rptr = 0, str = string;;)
4280 {
4281 if (match_pattern (str, pat, mtype, &s, &e) == 0)
4282 break;
4283 l = s - str;
4284 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64);
4285
4286 /* OK, now copy the leading unmatched portion of the string (from
4287 str to s) to ret starting at rptr (the current offset). Then copy
4288 the replacement string at ret + rptr + (s - str). Increment
4289 rptr (if necessary) and str and go on. */
4290 if (l)
4291 {
4292 strncpy (ret + rptr, str, l);
4293 rptr += l;
4294 }
4295 if (replen)
4296 {
4297 strncpy (ret + rptr, rep, replen);
4298 rptr += replen;
4299 }
4300 str = e; /* e == end of match */
4301 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
4302 break;
4303 }
4304
4305 /* Now copy the unmatched portion of the input string */
4306 if (*str)
d166f048
JA
4307 {
4308 RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
4309 strcpy (ret + rptr, str);
4310 }
ccc6cda3
JA
4311 else
4312 ret[rptr] = '\0';
4313
4314 return ret;
4315}
4316
4317/* Do pattern match and replacement on the positional parameters. */
4318static char *
4319pos_params_pat_subst (string, pat, rep, mflags)
4320 char *string, *pat, *rep;
4321 int mflags;
4322{
4323 WORD_LIST *save, *params;
4324 WORD_DESC *w;
4325 char *ret;
4326
4327 save = params = list_rest_of_args ();
4328 if (save == 0)
4329 return ((char *)NULL);
4330
4331 for ( ; params; params = params->next)
4332 {
4333 ret = pat_subst (params->word->word, pat, rep, mflags);
4334 w = make_bare_word (ret);
4335 dispose_word (params->word);
4336 params->word = w;
4337 FREE (ret);
4338 }
4339
4340 ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save);
4341 dispose_words (save);
4342
4343 return (ret);
4344}
4345
cce855bc
JA
4346/* Perform pattern substitution on VALUE, which is the expansion of
4347 VARNAME. PATSUB is an expression supplying the pattern to match
4348 and the string to substitute. QUOTED is a flags word containing
4349 the type of quoting currently in effect. */
ccc6cda3
JA
4350static char *
4351parameter_brace_patsub (varname, value, patsub, quoted)
4352 char *varname, *value, *patsub;
4353 int quoted;
4354{
4355 int vtype, mflags;
bb70624e 4356 char *val, *temp, *pat, *rep, *p, *lpatsub;
ccc6cda3
JA
4357 SHELL_VAR *v;
4358
4359 if (value == 0)
4360 return ((char *)NULL);
4361
4362 this_command_name = varname;
4363
4364 vtype = get_var_and_type (varname, value, &v, &val);
4365 if (vtype == -1)
4366 return ((char *)NULL);
4367
4368 mflags = 0;
4369 if (*patsub == '/')
4370 {
4371 mflags |= MATCH_GLOBREP;
4372 patsub++;
4373 }
bb70624e
JA
4374 /* Malloc this because maybe_expand_string or one of the expansion functions
4375 in its call chain may free it on a substitution error. */
4376 lpatsub = savestring (patsub);
ccc6cda3
JA
4377
4378 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4379 mflags |= MATCH_QUOTED;
4380
bb70624e 4381 if (rep = quoted_strchr (lpatsub, '/', ST_BACKSL))
ccc6cda3
JA
4382 *rep++ = '\0';
4383 else
4384 rep = (char *)NULL;
4385
4386 if (rep && *rep == '\0')
4387 rep = (char *)NULL;
4388
4389 /* Expand PAT and REP for command, variable and parameter, arithmetic,
4390 and process substitution. Also perform quote removal. Do not
4391 perform word splitting or filename generation. */
cce855bc 4392#if 0
bb70624e 4393 pat = maybe_expand_string (lpatsub, quoted, expand_string_unsplit);
cce855bc 4394#else
bb70624e 4395 pat = maybe_expand_string (lpatsub, (quoted & ~Q_DOUBLE_QUOTES), expand_string_unsplit);
cce855bc 4396#endif
bb70624e 4397
ccc6cda3 4398 if (rep)
d166f048
JA
4399 {
4400 if ((mflags & MATCH_QUOTED) == 0)
4401 rep = maybe_expand_string (rep, quoted, expand_string_unsplit);
4402 else
4403 rep = expand_string_to_string (rep, quoted, expand_string_unsplit);
4404 }
ccc6cda3
JA
4405
4406 p = pat;
d166f048 4407 if (pat && pat[0] == '#')
ccc6cda3
JA
4408 {
4409 mflags |= MATCH_BEG;
4410 p++;
4411 }
d166f048 4412 else if (pat && pat[0] == '%')
ccc6cda3
JA
4413 {
4414 mflags |= MATCH_END;
4415 p++;
4416 }
4417 else
4418 mflags |= MATCH_ANY;
4419
cce855bc
JA
4420 /* OK, we now want to substitute REP for PAT in VAL. If
4421 flags & MATCH_GLOBREP is non-zero, the substitution is done
4422 everywhere, otherwise only the first occurrence of PAT is
4423 replaced. */
ccc6cda3
JA
4424 switch (vtype)
4425 {
4426 case VT_VARIABLE:
d166f048 4427 case VT_ARRAYMEMBER:
ccc6cda3
JA
4428 temp = pat_subst (val, p, rep, mflags);
4429 break;
4430 case VT_POSPARMS:
4431 temp = pos_params_pat_subst (val, p, rep, mflags);
4432 break;
4433#if defined (ARRAY_VARS)
4434 case VT_ARRAYVAR:
4435 temp = array_pat_subst (array_cell (v), p, rep, mflags);
4436 break;
4437#endif
4438 }
4439
d166f048
JA
4440 if (val && v && array_p (v) && vtype == VT_ARRAYMEMBER)
4441 free (val);
4442
ccc6cda3
JA
4443 FREE (pat);
4444 FREE (rep);
bb70624e 4445 free (lpatsub);
ccc6cda3
JA
4446
4447 return temp;
4448}
4449
cce855bc
JA
4450/****************************************************************/
4451/* */
4452/* Functions to perform parameter expansion on a string */
4453/* */
4454/****************************************************************/
4455
ccc6cda3
JA
4456/* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */
4457static char *
4458parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at)
4459 char *string;
4460 int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at;
4461{
4462 int check_nullness, var_is_set, var_is_null, var_is_special;
4463 int want_substring, want_indir, want_patsub;
4464 char *name, *value, *temp, *temp1;
4465 int t_index, sindex, c, number;
4466
ccc6cda3
JA
4467 value = (char *)NULL;
4468 var_is_set = var_is_null = var_is_special = check_nullness = 0;
4469 want_substring = want_indir = want_patsub = 0;
4470
cce855bc
JA
4471 sindex = *indexp;
4472 t_index = ++sindex;
4473 name = string_extract (string, &t_index, "#%:-=?+/}", 1);
4474
4475 /* If the name really consists of a special variable, then make sure
4476 that we have the entire name. We don't allow indirect references
4477 to special variables except `#', `?', `@' and `*'. */
4478 if ((sindex == t_index &&
ccc6cda3
JA
4479 (string[t_index] == '-' ||
4480 string[t_index] == '?' ||
cce855bc
JA
4481 string[t_index] == '#')) ||
4482 (sindex == t_index - 1 && string[sindex] == '!' &&
4483 (string[t_index] == '#' ||
4484 string[t_index] == '?' ||
4485 string[t_index] == '@' ||
4486 string[t_index] == '*')))
ccc6cda3
JA
4487 {
4488 t_index++;
4489 free (name);
4490 temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
4491 name = xmalloc (3 + (strlen (temp1)));
4492 *name = string[sindex];
4493 if (string[sindex] == '!')
4494 {
cce855bc
JA
4495 /* indirect reference of $#, $?, $@, or $* */
4496 name[1] = string[sindex + 1];
4497 strcpy (name + 2, temp1);
ccc6cda3 4498 }
cce855bc 4499 else
ccc6cda3
JA
4500 strcpy (name + 1, temp1);
4501 free (temp1);
4502 }
4503 sindex = t_index;
4504
4505 /* Find out what character ended the variable name. Then
4506 do the appropriate thing. */
4507 if (c = string[sindex])
4508 sindex++;
4509
4510 /* If c is followed by one of the valid parameter expansion
4511 characters, move past it as normal. If not, assume that
4512 a substring specification is being given, and do not move
4513 past it. */
4514 if (c == ':' && member (string[sindex], "-=?+"))
4515 {
4516 check_nullness++;
4517 if (c = string[sindex])
4518 sindex++;
4519 }
cce855bc 4520 else if (c == ':' && string[sindex] != RBRACE)
ccc6cda3 4521 want_substring = 1;
cce855bc 4522 else if (c == '/' && string[sindex] != RBRACE)
ccc6cda3
JA
4523 want_patsub = 1;
4524
cce855bc
JA
4525 /* Catch the valid and invalid brace expressions that made it through the
4526 tests above. */
4527 /* ${#-} is a valid expansion and means to take the length of $-.
4528 Similarly for ${#?} and ${##}... */
4529 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
4530 member (c, "-?#") && string[sindex] == RBRACE)
4531 {
4532 name = xrealloc (name, 3);
4533 name[1] = c;
4534 name[2] = '\0';
4535 c = string[sindex++];
4536 }
4537
4538 /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
4539 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
4540 member (c, "%:=+/") && string[sindex] == RBRACE)
4541 {
4542 temp = (char *)NULL;
4543 goto bad_substitution;
4544 }
4545
4546 /* Indirect expansion begins with a `!'. A valid indirect expansion is
4547 either a variable name, one of the positional parameters or a special
4548 variable that expands to one of the positional parameters. */
4549 want_indir = *name == '!' &&
4550 (legal_variable_starter (name[1]) || digit (name[1]) || member (name[1], "#?@*"));
ccc6cda3
JA
4551
4552 /* Determine the value of this variable. */
4553
cce855bc 4554 /* Check for special variables, directly referenced. */
bb70624e 4555 if (SPECIAL_VAR (name, want_indir))
ccc6cda3
JA
4556 var_is_special++;
4557
cce855bc
JA
4558 /* Check for special expansion things, like the length of a parameter */
4559 if (*name == '#' && name[1])
ccc6cda3 4560 {
cce855bc
JA
4561 /* If we are not pointing at the character just after the
4562 closing brace, then we haven't gotten all of the name.
4563 Since it begins with a special character, this is a bad
4564 substitution. Also check NAME for validity before trying
4565 to go on. */
4566 if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
ccc6cda3
JA
4567 {
4568 temp = (char *)NULL;
4569 goto bad_substitution;
4570 }
4571
4572 number = parameter_brace_expand_length (name);
4573 free (name);
4574
4575 *indexp = sindex;
4576 return ((number < 0) ? &expand_param_error : itos (number));
4577 }
4578
4579 /* ${@} is identical to $@. */
4580 if (name[0] == '@' && name[1] == '\0')
4581 {
4582 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4583 *quoted_dollar_atp = 1;
4584
4585 if (contains_dollar_at)
4586 *contains_dollar_at = 1;
4587 }
4588
bb70624e
JA
4589 /* Process ${PREFIX*} expansion. */
4590 if (want_indir && string[sindex - 1] == RBRACE &&
4591 (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
4592 legal_variable_starter (name[1]))
4593 {
4594 char **x;
4595 WORD_LIST *xlist;
4596
4597 temp1 = savestring (name + 1);
4598 number = strlen (temp1);
4599 temp1[number - 1] = '\0';
4600 x = all_variables_matching_prefix (temp1);
4601 xlist = argv_to_word_list (x, 1, 0);
4602 temp = string_list_dollar_star (xlist, quoted);
4603 free (x);
4604 free (xlist);
4605 free (temp1);
4606 *indexp = sindex;
4607 return (temp);
4608 }
4609
ccc6cda3
JA
4610 /* Make sure that NAME is valid before trying to go on. */
4611 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
4612 var_is_special) == 0)
4613 {
4614 temp = (char *)NULL;
4615 goto bad_substitution;
4616 }
4617
4618 if (want_indir)
4619 temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted);
4620 else
4621 temp = parameter_brace_expand_word (name, var_is_special, quoted);
4622
4623#if defined (ARRAY_VARS)
cce855bc 4624#if 0
ccc6cda3 4625 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && valid_array_reference (name))
cce855bc
JA
4626#else
4627 if (valid_array_reference (name))
4628#endif
ccc6cda3
JA
4629 {
4630 temp1 = strchr (name, '[');
4631 if (temp1 && temp1[1] == '@' && temp1[2] == ']')
4632 {
4633 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4634 *quoted_dollar_atp = 1;
4635 if (contains_dollar_at)
4636 *contains_dollar_at = 1;
cce855bc
JA
4637 } /* [ */
4638 /* ${array[*]}, when unquoted, should be treated like ${array[@]},
4639 which should result in separate words even when IFS is unset. */
4640 if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0)
4641 {
4642 if (contains_dollar_at)
4643 *contains_dollar_at = 1;
ccc6cda3
JA
4644 }
4645 }
4646#endif
4647
4648 var_is_set = temp != (char *)0;
4649 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
4650
4651 /* Get the rest of the stuff inside the braces. */
cce855bc 4652 if (c && c != RBRACE)
ccc6cda3
JA
4653 {
4654 /* Extract the contents of the ${ ... } expansion
4655 according to the Posix.2 rules. */
4656 value = extract_dollar_brace_string (string, &sindex, quoted);
cce855bc 4657 if (string[sindex] == RBRACE)
ccc6cda3
JA
4658 sindex++;
4659 else
4660 goto bad_substitution;
4661 }
4662 else
4663 value = (char *)NULL;
726f6388 4664
ccc6cda3
JA
4665 *indexp = sindex;
4666
4667 /* If this is a substring spec, process it and add the result. */
4668 if (want_substring)
726f6388 4669 {
ccc6cda3
JA
4670 temp1 = parameter_brace_substring (name, temp, value, quoted);
4671 FREE (name);
4672 FREE (value);
4673 FREE (temp);
4674 return (temp1);
726f6388 4675 }
ccc6cda3 4676 else if (want_patsub)
726f6388 4677 {
ccc6cda3
JA
4678 temp1 = parameter_brace_patsub (name, temp, value, quoted);
4679 FREE (name);
4680 FREE (value);
4681 FREE (temp);
4682 return (temp1);
4683 }
726f6388 4684
ccc6cda3
JA
4685 /* Do the right thing based on which character ended the variable name. */
4686 switch (c)
4687 {
4688 default:
4689 case '\0':
4690 bad_substitution:
4691 report_error ("%s: bad substitution", string ? string : "??");
4692 FREE (value);
4693 FREE (temp);
4694 free (name);
4695 return &expand_param_error;
4696
cce855bc 4697 case RBRACE:
ccc6cda3
JA
4698 if (var_is_set == 0 && unbound_vars_is_error)
4699 {
4700 report_error ("%s: unbound variable", name);
4701 FREE (value);
4702 FREE (temp);
4703 free (name);
4704 last_command_exit_value = EXECUTION_FAILURE;
d166f048 4705 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
726f6388 4706 }
ccc6cda3 4707 break;
726f6388 4708
ccc6cda3
JA
4709 case '#': /* ${param#[#]pattern} */
4710 case '%': /* ${param%[%]pattern} */
4711 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
4712 {
4713 FREE (value);
4714 break;
4715 }
4716 if ((name[0] == '@' || name[0] == '*') && name[1] == '\0')
4717 temp1 = parameter_list_remove_pattern (value, name[0], c, quoted);
4718#if defined (ARRAY_VARS)
4719 else if (valid_array_reference (name))
4720 temp1 = array_remove_pattern (value, name, temp, c, quoted);
4721#endif
4722 else
4723 temp1 = parameter_brace_remove_pattern (value, temp, c, quoted);
4724 free (temp);
4725 free (value);
4726 temp = temp1;
4727 break;
4728
4729 case '-':
4730 case '=':
4731 case '?':
4732 case '+':
4733 if (var_is_set && var_is_null == 0)
4734 {
4735 /* We don't want the value of the named variable for
4736 anything, just the value of the right hand side. */
bb70624e
JA
4737
4738 /* XXX -- if we're double-quoted and the named variable is "$@",
4739 we want to turn off any special handling of "$@" -- we're not
4740 using it, so whatever is on the rhs applies. */
4741 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4742 *quoted_dollar_atp = 0;
4743 if (contains_dollar_at)
4744 *contains_dollar_at = 0;
4745
ccc6cda3
JA
4746 if (c == '+')
4747 {
4748 FREE (temp);
4749 if (value)
4750 {
4751 temp = parameter_brace_expand_rhs (name, value, c,
4752 quoted,
4753 quoted_dollar_atp,
4754 contains_dollar_at);
4755 free (value);
4756 }
4757 else
4758 temp = (char *)NULL;
4759 }
4760 else
4761 {
4762 FREE (value);
4763 }
4764 /* Otherwise do nothing; just use the value in TEMP. */
726f6388 4765 }
ccc6cda3
JA
4766 else /* VAR not set or VAR is NULL. */
4767 {
4768 FREE (temp);
4769 temp = (char *)NULL;
4770 if (c == '=' && var_is_special)
4771 {
4772 report_error ("$%s: cannot assign in this way", name);
4773 free (name);
4774 free (value);
4775 return &expand_param_error;
4776 }
4777 else if (c == '?')
4778 {
4779 parameter_brace_expand_error (name, value);
4780 return (interactive ? &expand_param_error : &expand_param_fatal);
4781 }
4782 else if (c != '+')
4783 temp = parameter_brace_expand_rhs (name, value, c, quoted,
4784 quoted_dollar_atp,
4785 contains_dollar_at);
4786 free (value);
726f6388 4787 }
ccc6cda3 4788 break;
726f6388 4789 }
ccc6cda3
JA
4790 free (name);
4791 return (temp);
726f6388
JA
4792}
4793
cce855bc
JA
4794/* Expand a single ${xxx} expansion. The braces are optional. When
4795 the braces are used, parameter_brace_expand() does the work,
4796 possibly calling param_expand recursively. */
4797static char *
4798param_expand (string, sindex, quoted, expanded_something,
4799 contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
4800 pflags)
4801 char *string;
4802 int *sindex, quoted, *expanded_something, *contains_dollar_at;
4803 int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
4804{
4805 char *temp, *temp1;
4806 int zindex, number, c, t_index, expok;
4807 SHELL_VAR *var;
4808 WORD_LIST *list, *tlist;
4809
4810 zindex = *sindex;
4811 c = string[++zindex];
4812
4813 temp = (char *)NULL;
4814
4815 /* Do simple cases first. Switch on what follows '$'. */
4816 switch (c)
4817 {
4818 /* $0 .. $9? */
4819 case '0':
4820 case '1':
4821 case '2':
4822 case '3':
4823 case '4':
4824 case '5':
4825 case '6':
4826 case '7':
4827 case '8':
4828 case '9':
4829 temp1 = dollar_vars[digit_value (c)];
4830 if (unbound_vars_is_error && temp1 == (char *)NULL)
4831 {
4832 report_error ("$%c: unbound variable", c);
4833 last_command_exit_value = EXECUTION_FAILURE;
4834 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
4835 }
4836 temp = temp1 ? savestring (temp1) : (char *)NULL;
4837 break;
4838
4839 /* $$ -- pid of the invoking shell. */
4840 case '$':
4841 temp = itos (dollar_dollar_pid);
4842 break;
4843
4844 /* $# -- number of positional parameters. */
4845 case '#':
4846 temp = itos (number_of_args ());
4847 break;
4848
4849 /* $? -- return value of the last synchronous command. */
4850 case '?':
4851 temp = itos (last_command_exit_value);
4852 break;
4853
4854 /* $- -- flags supplied to the shell on invocation or by `set'. */
4855 case '-':
4856 temp = which_set_flags ();
4857 break;
4858
4859 /* $! -- Pid of the last asynchronous command. */
4860 case '!':
4861 /* If no asynchronous pids have been created, expand to nothing.
4862 If `set -u' has been executed, and no async processes have
4863 been created, this is an expansion error. */
4864 if (last_asynchronous_pid == NO_PID)
4865 {
4866 if (expanded_something)
4867 *expanded_something = 0;
4868 temp = (char *)NULL;
4869 if (unbound_vars_is_error)
4870 {
4871 report_error ("$%c: unbound variable", c);
4872 last_command_exit_value = EXECUTION_FAILURE;
4873 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
4874 }
4875 }
4876 else
4877 temp = itos ((int)last_asynchronous_pid);
4878 break;
4879
4880 /* The only difference between this and $@ is when the arg is quoted. */
4881 case '*': /* `$*' */
4882 list = list_rest_of_args ();
4883
4884 /* If there are no command-line arguments, this should just
4885 disappear if there are other characters in the expansion,
4886 even if it's quoted. */
4887 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
4888 temp = (char *)NULL;
4889 else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4890 {
4891 /* If we have "$*" we want to make a string of the positional
4892 parameters, separated by the first character of $IFS, and
4893 quote the whole string, including the separators. If IFS
4894 is unset, the parameters are separated by ' '; if $IFS is
4895 null, the parameters are concatenated. */
4896 temp = string_list_dollar_star (list);
4897 temp1 = quote_string (temp);
4898 free (temp);
4899 temp = temp1;
4900 }
4901 else
4902 {
4903 /* If the $* is not quoted it is identical to $@ */
4904 temp = string_list_dollar_at (list, quoted);
4905 if (contains_dollar_at)
4906 *contains_dollar_at = 1;
4907 }
4908
4909 dispose_words (list);
4910 break;
4911
4912 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
4913 means that we have to turn quoting off after we split into
4914 the individually quoted arguments so that the final split
4915 on the first character of $IFS is still done. */
4916 case '@': /* `$@' */
4917 list = list_rest_of_args ();
4918
4919 /* We want to flag the fact that we saw this. We can't turn
4920 off quoting entirely, because other characters in the
4921 string might need it (consider "\"$@\""), but we need some
4922 way to signal that the final split on the first character
4923 of $IFS should be done, even though QUOTED is 1. */
4924 if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
4925 *quoted_dollar_at_p = 1;
4926 if (contains_dollar_at)
4927 *contains_dollar_at = 1;
4928
4929 /* We want to separate the positional parameters with the first
4930 character of $IFS in case $IFS is something other than a space.
4931 We also want to make sure that splitting is done no matter what --
4932 according to POSIX.2, this expands to a list of the positional
4933 parameters no matter what IFS is set to. */
4934 temp = string_list_dollar_at (list, quoted);
4935
4936 dispose_words (list);
4937 break;
4938
4939 case LBRACE:
4940 temp = parameter_brace_expand (string, &zindex, quoted,
4941 quoted_dollar_at_p,
4942 contains_dollar_at);
4943 if (temp == &expand_param_error || temp == &expand_param_fatal)
4944 return (temp);
4945
4946 /* XXX */
bb70624e 4947 /* Quoted nulls should be removed if there is anything else
cce855bc
JA
4948 in the string. */
4949 /* Note that we saw the quoted null so we can add one back at
4950 the end of this function if there are no other characters
4951 in the string, discard TEMP, and go on. */
4952 if (temp && QUOTED_NULL (temp))
4953 {
4954 if (had_quoted_null_p)
4955 *had_quoted_null_p = 1;
4956 free (temp);
4957 temp = (char *)NULL;
4958 }
4959
4960 goto return0;
4961
4962 /* Do command or arithmetic substitution. */
4963 case LPAREN:
4964 /* We have to extract the contents of this paren substitution. */
4965 t_index = zindex + 1;
4966 temp = extract_command_subst (string, &t_index);
4967 zindex = t_index;
4968
4969 /* For Posix.2-style `$(( ))' arithmetic substitution,
4970 extract the expression and pass it to the evaluator. */
4971 if (temp && *temp == LPAREN)
4972 {
4973 char *temp2;
4974 temp1 = temp + 1;
4975 temp2 = savestring (temp1);
4976 t_index = strlen (temp2) - 1;
4977
4978 if (temp2[t_index] != RPAREN)
4979 {
4980 free (temp2);
4981 goto comsub;
4982 }
4983
4984 /* Cut off ending `)' */
4985 temp2[t_index] = '\0';
4986
4987 /* Expand variables found inside the expression. */
4988 temp1 = maybe_expand_string (temp2, Q_DOUBLE_QUOTES, expand_string);
4989 free (temp2);
4990
4991arithsub:
4992 /* No error messages. */
4993 this_command_name = (char *)NULL;
4994 number = evalexp (temp1, &expok);
4995 free (temp);
4996 free (temp1);
4997 if (expok == 0)
4998 {
4999 if (interactive_shell == 0 && posixly_correct)
5000 {
5001 last_command_exit_value = EXECUTION_FAILURE;
5002 return (&expand_param_fatal);
5003 }
5004 else
5005 return (&expand_param_error);
5006 }
5007 temp = itos (number);
5008 break;
5009 }
5010
5011comsub:
5012 temp1 = command_substitute (temp, quoted);
5013 FREE (temp);
5014 temp = temp1;
5015 break;
5016
5017 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
5018 away in a future bash release. */
5019 case '[':
bb70624e 5020 /* Extract the contents of this arithmetic substitution. */
cce855bc
JA
5021 t_index = zindex + 1;
5022 temp = extract_arithmetic_subst (string, &t_index);
5023 zindex = t_index;
5024
5025 /* Do initial variable expansion. */
5026 temp1 = maybe_expand_string (temp, Q_DOUBLE_QUOTES, expand_string);
5027
5028 goto arithsub;
5029
5030 default:
5031 /* Find the variable in VARIABLE_LIST. */
5032 temp = (char *)NULL;
5033
5034 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
5035 ;
5036 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
5037
5038 /* If this isn't a variable name, then just output the `$'. */
5039 if (temp1 == 0 || *temp1 == '\0')
5040 {
5041 FREE (temp1);
5042 temp = xmalloc (2);
5043 temp[0] = '$';
5044 temp[1] = '\0';
5045 if (expanded_something)
5046 *expanded_something = 0;
5047 goto return0;
5048 }
5049
5050 /* If the variable exists, return its value cell. */
5051 var = find_variable (temp1);
5052
5053 if (var && invisible_p (var) == 0 && value_cell (var))
5054 {
5055#if defined (ARRAY_VARS)
5056 if (array_p (var))
5057 {
5058 temp = array_reference (array_cell (var), 0);
5059 if (temp)
5060 temp = quote_escapes (temp);
5061 }
5062 else
5063#endif
5064 temp = quote_escapes (value_cell (var));
5065 free (temp1);
5066 if (tempvar_p (var)) /* XXX */
5067 {
5068 dispose_variable (var); /* XXX */
5069 var = (SHELL_VAR *)NULL;
5070 }
5071 goto return0;
5072 }
5073
5074 temp = (char *)NULL;
5075
5076 if (unbound_vars_is_error)
5077 report_error ("%s: unbound variable", temp1);
5078 else
5079 {
5080 free (temp1);
5081 goto return0;
5082 }
5083
5084 free (temp1);
5085 last_command_exit_value = EXECUTION_FAILURE;
5086 return ((unbound_vars_is_error && interactive_shell == 0)
5087 ? &expand_param_fatal
5088 : &expand_param_error);
5089 }
5090
5091 if (string[zindex])
5092 zindex++;
5093
5094return0:
5095 *sindex = zindex;
5096 return (temp);
5097}
5098
5099/* Make a word list which is the result of parameter and variable
5100 expansion, command substitution, arithmetic substitution, and
5101 quote removal of WORD. Return a pointer to a WORD_LIST which is
5102 the result of the expansion. If WORD contains a null word, the
5103 word list returned is also null.
726f6388 5104
ccc6cda3
JA
5105 QUOTED contains flag values defined in shell.h.
5106
b72432fd
JA
5107 ISEXP is used to tell expand_word_internal that the word should be
5108 treated as the result of an expansion. This has implications for
5109 how IFS characters in the word are treated.
5110
726f6388
JA
5111 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
5112 they point to an integer value which receives information about expansion.
5113 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
5114 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
5115 else zero.
5116
5117 This only does word splitting in the case of $@ expansion. In that
5118 case, we split on ' '. */
5119
5120/* Values for the local variable quoted_state. */
5121#define UNQUOTED 0
5122#define PARTIALLY_QUOTED 1
5123#define WHOLLY_QUOTED 2
5124
5125static WORD_LIST *
b72432fd 5126expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
726f6388 5127 WORD_DESC *word;
b72432fd 5128 int quoted, isexp;
726f6388
JA
5129 int *contains_dollar_at;
5130 int *expanded_something;
5131{
ccc6cda3
JA
5132 WORD_LIST *list;
5133 WORD_DESC *tword;
5134 SHELL_VAR *var;
726f6388
JA
5135
5136 /* The intermediate string that we build while expanding. */
ccc6cda3 5137 char *istring;
726f6388
JA
5138
5139 /* The current size of the above object. */
ccc6cda3 5140 int istring_size;
726f6388
JA
5141
5142 /* Index into ISTRING. */
ccc6cda3 5143 int istring_index;
726f6388
JA
5144
5145 /* Temporary string storage. */
ccc6cda3 5146 char *temp, *temp1;
726f6388
JA
5147
5148 /* The text of WORD. */
ccc6cda3 5149 register char *string;
726f6388
JA
5150
5151 /* The index into STRING. */
ccc6cda3 5152 int sindex;
726f6388
JA
5153
5154 /* This gets 1 if we see a $@ while quoted. */
ccc6cda3 5155 int quoted_dollar_at;
726f6388
JA
5156
5157 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
5158 whether WORD contains no quoting characters, a partially quoted
5159 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
ccc6cda3
JA
5160 int quoted_state;
5161
5162 int had_quoted_null;
cce855bc 5163 int has_dollar_at;
726f6388
JA
5164
5165 register int c; /* Current character. */
5166 int number; /* Temporary number value. */
5167 int t_index; /* For calls to string_extract_xxx. */
726f6388 5168
b72432fd 5169 char ifscmap[256];
bb70624e 5170 char twochars[2];
b72432fd 5171
d166f048 5172 istring = xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
ccc6cda3 5173 istring[istring_index = 0] = '\0';
cce855bc 5174 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
ccc6cda3
JA
5175 quoted_state = UNQUOTED;
5176
5177 string = word->word;
5178 if (string == 0)
5179 goto finished_with_string;
726f6388
JA
5180
5181 if (contains_dollar_at)
5182 *contains_dollar_at = 0;
5183
b72432fd
JA
5184 /* Cache a bitmap of characters in IFS for quoting IFS characters that are
5185 not part of an expansion. POSIX.2 says this is a must. */
5186 temp = getifs ();
5187 bzero (ifscmap, sizeof (ifscmap));
5188 for (temp1 = temp; temp1 && *temp1; temp1++)
5189#if 0
5190 /* This check compensates for what I think is a parsing problem -- the
5191 end brace matching algorithms for ${...} expressions differ between
5192 parse.y and subst.c. For instance, the parser passes
5193 ${abc:-G { I } K } as one word when it should be three. */
5194 if (*temp1 != ' ' && *temp1 != '\t' && *temp1 != '\n')
5195#endif
bb70624e 5196 ifscmap[(unsigned char)*temp1] = 1;
b72432fd 5197
726f6388
JA
5198 /* Begin the expansion. */
5199
ccc6cda3 5200 for (sindex = 0; ;)
726f6388
JA
5201 {
5202 c = string[sindex];
5203
5204 /* Case on toplevel character. */
5205 switch (c)
5206 {
5207 case '\0':
5208 goto finished_with_string;
5209
5210 case CTLESC:
5211 temp = xmalloc (3);
5212 temp[0] = CTLESC;
5213 temp[1] = c = string[++sindex];
5214 temp[2] = '\0';
5215
cce855bc 5216dollar_add_string:
726f6388
JA
5217 if (string[sindex])
5218 sindex++;
5219
cce855bc
JA
5220add_string:
5221 if (temp)
5222 {
5223 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
5224 temp = (char *)0;
5225 }
5226
5227 break;
726f6388
JA
5228
5229#if defined (PROCESS_SUBSTITUTION)
5230 /* Process substitution. */
5231 case '<':
5232 case '>':
5233 {
cce855bc 5234 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct)
726f6388 5235 {
bb70624e 5236 sindex--; /* add_character: label increments sindex */
726f6388
JA
5237 goto add_character;
5238 }
5239 else
cce855bc 5240 t_index = sindex + 1; /* skip past both '<' and LPAREN */
726f6388 5241
cce855bc 5242 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/
ccc6cda3 5243 sindex = t_index;
726f6388
JA
5244
5245 /* If the process substitution specification is `<()', we want to
5246 open the pipe for writing in the child and produce output; if
5247 it is `>()', we want to open the pipe for reading in the child
5248 and consume input. */
ccc6cda3 5249 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
726f6388
JA
5250
5251 FREE (temp1);
5252
5253 goto dollar_add_string;
5254 }
5255#endif /* PROCESS_SUBSTITUTION */
5256
726f6388 5257 case '$':
726f6388
JA
5258 if (expanded_something)
5259 *expanded_something = 1;
5260
cce855bc
JA
5261 has_dollar_at = 0;
5262 temp = param_expand (string, &sindex, quoted, expanded_something,
5263 &has_dollar_at, &quoted_dollar_at,
5264 &had_quoted_null, 0);
726f6388 5265
cce855bc 5266 if (temp == &expand_param_error || temp == &expand_param_fatal)
726f6388 5267 {
cce855bc
JA
5268 free (string);
5269 free (istring);
5270 return ((temp == &expand_param_error) ? &expand_word_error
5271 : &expand_word_fatal);
5272 }
5273 if (contains_dollar_at && has_dollar_at)
5274 *contains_dollar_at = 1;
5275 goto add_string;
5276 break;
726f6388 5277
cce855bc
JA
5278 case '`': /* Backquoted command substitution. */
5279 {
5280 sindex++;
726f6388 5281
cce855bc
JA
5282 if (expanded_something)
5283 *expanded_something = 1;
726f6388 5284
cce855bc
JA
5285 temp = string_extract (string, &sindex, "`", 0);
5286 de_backslash (temp);
5287 temp1 = command_substitute (temp, quoted);
5288 FREE (temp);
5289 temp = temp1;
5290 goto dollar_add_string;
5291 }
ccc6cda3 5292
cce855bc
JA
5293 case '\\':
5294 if (string[sindex + 1] == '\n')
5295 {
5296 sindex += 2;
5297 continue;
5298 }
726f6388 5299
cce855bc 5300 c = string[++sindex];
726f6388 5301
cce855bc
JA
5302 if (quoted & Q_HERE_DOCUMENT)
5303 temp1 = slashify_in_here_document;
5304 else if (quoted & Q_DOUBLE_QUOTES)
5305 temp1 = slashify_in_quotes;
5306 else
5307 temp1 = "";
726f6388 5308
cce855bc
JA
5309 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && member (c, temp1) == 0)
5310 {
bb70624e
JA
5311 twochars[0] = '\\';
5312 twochars[1] = c;
5313 }
5314 else if (c == 0)
5315 {
5316 c = CTLNUL;
5317 sindex--; /* add_character: label increments sindex */
5318 goto add_character;
cce855bc
JA
5319 }
5320 else
bb70624e
JA
5321 {
5322 twochars[0] = CTLESC;
5323 twochars[1] = c;
5324 }
726f6388 5325
bb70624e
JA
5326 sindex++;
5327add_twochars:
5328 /* BEFORE jumping here, we need to increment sindex if appropriate */
5329 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
5330 DEFAULT_ARRAY_SIZE);
5331 istring[istring_index++] = twochars[0];
5332 istring[istring_index++] = twochars[1];
5333 istring[istring_index] = '\0';
5334
5335 break;
726f6388 5336
cce855bc
JA
5337 case '"':
5338 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE))
5339 goto add_character;
ccc6cda3
JA
5340
5341 t_index = ++sindex;
5342 temp = string_extract_double_quoted (string, &sindex, 0);
5343
5344 /* If the quotes surrounded the entire string, then the
5345 whole word was quoted. */
5346 quoted_state = (t_index == 1 && string[sindex] == '\0')
5347 ? WHOLLY_QUOTED
5348 : PARTIALLY_QUOTED;
5349
5350 if (temp && *temp)
726f6388 5351 {
ccc6cda3
JA
5352 tword = make_word (temp); /* XXX */
5353 free (temp);
5354 temp = (char *)NULL;
5355
cce855bc 5356 has_dollar_at = 0;
b72432fd 5357 list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL);
726f6388 5358
ccc6cda3
JA
5359 if (list == &expand_word_error || list == &expand_word_fatal)
5360 {
5361 free (istring);
5362 free (string);
5363 /* expand_word_internal has already freed temp_word->word
5364 for us because of the way it prints error messages. */
5365 tword->word = (char *)NULL;
5366 dispose_word (tword);
5367 return list;
5368 }
726f6388 5369
ccc6cda3 5370 dispose_word (tword);
726f6388 5371
ccc6cda3
JA
5372 /* "$@" (a double-quoted dollar-at) expands into nothing,
5373 not even a NULL word, when there are no positional
5374 parameters. */
cce855bc 5375 if (list == 0 && has_dollar_at)
726f6388 5376 {
ccc6cda3
JA
5377 quoted_dollar_at++;
5378 break;
5379 }
5380
5381 /* If we get "$@", we know we have expanded something, so we
5382 need to remember it for the final split on $IFS. This is
5383 a special case; it's the only case where a quoted string
5384 can expand into more than one word. It's going to come back
5385 from the above call to expand_word_internal as a list with
5386 a single word, in which all characters are quoted and
5387 separated by blanks. What we want to do is to turn it back
5388 into a list for the next piece of code. */
5389 if (list)
5390 dequote_list (list);
5391
cce855bc 5392 if (has_dollar_at)
ccc6cda3
JA
5393 {
5394 quoted_dollar_at++;
5395 if (contains_dollar_at)
5396 *contains_dollar_at = 1;
5397 if (expanded_something)
5398 *expanded_something = 1;
5399 }
5400 }
5401 else
5402 {
5403 /* What we have is "". This is a minor optimization. */
5404 free (temp);
5405 list = (WORD_LIST *)NULL;
5406 }
5407
5408 /* The code above *might* return a list (consider the case of "$@",
5409 where it returns "$1", "$2", etc.). We can't throw away the
5410 rest of the list, and we have to make sure each word gets added
5411 as quoted. We test on tresult->next: if it is non-NULL, we
5412 quote the whole list, save it to a string with string_list, and
5413 add that string. We don't need to quote the results of this
5414 (and it would be wrong, since that would quote the separators
5415 as well), so we go directly to add_string. */
5416 if (list)
5417 {
5418 if (list->next)
5419 {
bc4cd23c
JA
5420 /* Testing quoted_dollar_at makes sure that "$@" is
5421 split correctly when $IFS does not contain a space. */
5422 temp = quoted_dollar_at
5423 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES)
5424 : string_list (quote_list (list));
ccc6cda3 5425 dispose_words (list);
726f6388
JA
5426 goto add_string;
5427 }
5428 else
5429 {
ccc6cda3
JA
5430 temp = savestring (list->word->word);
5431 dispose_words (list);
cce855bc
JA
5432#if 1
5433 /* If the string is not a quoted null string, we want
5434 to remove any embedded unquoted CTLNUL characters.
5435 We do not want to turn quoted null strings back into
5436 the empty string, though. We do this because we
5437 want to remove any quoted nulls from expansions that
5438 contain other characters. For example, if we have
5439 x"$*"y or "x$*y" and there are no positional parameters,
5440 the $* should expand into nothing. */
5441 if (QUOTED_NULL (temp) == 0)
5442 remove_quoted_nulls (temp); /* XXX */
5443#endif
726f6388
JA
5444 }
5445 }
ccc6cda3
JA
5446 else
5447 temp = (char *)NULL;
726f6388 5448
ccc6cda3
JA
5449 /* We do not want to add quoted nulls to strings that are only
5450 partially quoted; we can throw them away. */
5451 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
cce855bc 5452 continue;
726f6388 5453
ccc6cda3 5454 add_quoted_string:
726f6388 5455
ccc6cda3
JA
5456 if (temp)
5457 {
5458 temp1 = temp;
5459 temp = quote_string (temp);
5460 free (temp1);
bb70624e 5461 goto add_string;
ccc6cda3
JA
5462 }
5463 else
5464 {
5465 /* Add NULL arg. */
bb70624e
JA
5466 c = CTLNUL;
5467 sindex--; /* add_character: label increments sindex */
5468 goto add_character;
ccc6cda3 5469 }
bb70624e 5470
ccc6cda3 5471 /* break; */
726f6388 5472
ccc6cda3
JA
5473 case '\'':
5474 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE))
5475 goto add_character;
726f6388 5476
ccc6cda3
JA
5477 t_index = ++sindex;
5478 temp = string_extract_single_quoted (string, &sindex);
726f6388 5479
ccc6cda3
JA
5480 /* If the entire STRING was surrounded by single quotes,
5481 then the string is wholly quoted. */
5482 quoted_state = (t_index == 1 && string[sindex] == '\0')
5483 ? WHOLLY_QUOTED
5484 : PARTIALLY_QUOTED;
726f6388 5485
ccc6cda3
JA
5486 /* If all we had was '', it is a null expansion. */
5487 if (*temp == '\0')
5488 {
5489 free (temp);
5490 temp = (char *)NULL;
5491 }
5492 else
5493 remove_quoted_escapes (temp);
726f6388 5494
ccc6cda3
JA
5495 /* We do not want to add quoted nulls to strings that are only
5496 partially quoted; such nulls are discarded. */
5497 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
5498 continue;
726f6388 5499
bb70624e
JA
5500 /* If we have a quoted null expansion, add a quoted NULL to istring. */
5501 if (temp == 0)
5502 {
5503 c = CTLNUL;
5504 sindex--; /* add_character: label increments sindex */
5505 goto add_character;
5506 }
5507 else
5508 goto add_quoted_string;
5509
ccc6cda3 5510 /* break; */
726f6388
JA
5511
5512 default:
726f6388 5513 /* This is the fix for " $@ " */
b72432fd 5514 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && ifscmap[c]))
726f6388 5515 {
bb70624e
JA
5516 if (string[sindex]) /* from old goto dollar_add_string */
5517 sindex++;
5518 if (c == 0)
5519 {
5520 c = CTLNUL;
5521 goto add_character;
5522 }
5523 else
5524 {
5525 twochars[0] = CTLESC;
5526 twochars[1] = c;
5527 goto add_twochars;
5528 }
726f6388
JA
5529 }
5530
5531 add_character:
ccc6cda3
JA
5532 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
5533 DEFAULT_ARRAY_SIZE);
726f6388
JA
5534 istring[istring_index++] = c;
5535 istring[istring_index] = '\0';
5536
5537 /* Next character. */
5538 sindex++;
5539 }
5540 }
5541
5542finished_with_string:
726f6388
JA
5543 /* OK, we're ready to return. If we have a quoted string, and
5544 quoted_dollar_at is not set, we do no splitting at all; otherwise
5545 we split on ' '. The routines that call this will handle what to
5546 do if nothing has been expanded. */
ccc6cda3
JA
5547
5548 /* Partially and wholly quoted strings which expand to the empty
5549 string are retained as an empty arguments. Unquoted strings
5550 which expand to the empty string are discarded. The single
5551 exception is the case of expanding "$@" when there are no
5552 positional parameters. In that case, we discard the expansion. */
5553
5554 /* Because of how the code that handles "" and '' in partially
5555 quoted strings works, we need to make ISTRING into a QUOTED_NULL
5556 if we saw quoting characters, but the expansion was empty.
5557 "" and '' are tossed away before we get to this point when
5558 processing partially quoted strings. This makes "" and $xxx""
5559 equivalent when xxx is unset. We also look to see whether we
5560 saw a quoted null from a ${} expansion and add one back if we
5561 need to. */
5562
5563 /* If we expand to nothing and there were no single or double quotes
5564 in the word, we throw it away. Otherwise, we return a NULL word.
5565 The single exception is for $@ surrounded by double quotes when
5566 there are no positional parameters. In that case, we also throw
5567 the word away. */
5568
5569 if (*istring == '\0')
5570 {
5571 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
726f6388 5572 {
726f6388
JA
5573 istring[0] = CTLNUL;
5574 istring[1] = '\0';
ccc6cda3
JA
5575 tword = make_bare_word (istring);
5576 list = make_word_list (tword, (WORD_LIST *)NULL);
5577 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5578 tword->flags |= W_QUOTED;
726f6388 5579 }
ccc6cda3
JA
5580 /* According to sh, ksh, and Posix.2, if a word expands into nothing
5581 and a double-quoted "$@" appears anywhere in it, then the entire
5582 word is removed. */
5583 else if (quoted_state == UNQUOTED || quoted_dollar_at)
5584 list = (WORD_LIST *)NULL;
5585#if 0
5586 else
726f6388 5587 {
ccc6cda3
JA
5588 tword = make_bare_word (istring);
5589 list = make_word_list (tword, (WORD_LIST *)NULL);
5590 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5591 tword->flags |= W_QUOTED;
726f6388 5592 }
ccc6cda3
JA
5593#endif
5594 }
5595 else if (word->flags & W_NOSPLIT)
5596 {
5597 tword = make_bare_word (istring);
5598 list = make_word_list (tword, (WORD_LIST *)NULL);
5599 if (word->flags & W_ASSIGNMENT)
5600 tword->flags |= W_ASSIGNMENT; /* XXX */
b72432fd
JA
5601 if (word->flags & W_NOGLOB)
5602 tword->flags |= W_NOGLOB; /* XXX */
ccc6cda3
JA
5603 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5604 tword->flags |= W_QUOTED;
5605 }
5606 else
5607 {
5608 char *ifs_chars;
5609
b72432fd 5610 ifs_chars = (quoted_dollar_at || has_dollar_at) ? getifs () : (char *)NULL;
726f6388 5611
cce855bc
JA
5612 /* If we have $@, we need to split the results no matter what. If
5613 IFS is unset or NULL, string_list_dollar_at has separated the
5614 positional parameters with a space, so we split on space (we have
5615 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
5616 string_list_dollar_at has separated the positional parameters
5617 with the first character of $IFS, so we split on $IFS. */
5618 if (has_dollar_at && ifs_chars)
5619 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
ccc6cda3
JA
5620 else
5621 {
5622 tword = make_bare_word (istring);
5623 list = make_word_list (tword, (WORD_LIST *)NULL);
5624 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
5625 tword->flags |= W_QUOTED;
5626 if (word->flags & W_ASSIGNMENT)
5627 tword->flags |= W_ASSIGNMENT;
b72432fd
JA
5628 if (word->flags & W_NOGLOB)
5629 tword->flags |= W_NOGLOB;
726f6388 5630 }
726f6388 5631 }
726f6388 5632
ccc6cda3
JA
5633 free (istring);
5634 return (list);
726f6388
JA
5635}
5636
5637/* **************************************************************** */
5638/* */
5639/* Functions for Quote Removal */
5640/* */
5641/* **************************************************************** */
5642
5643/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
5644 backslash quoting rules for within double quotes. */
5645char *
5646string_quote_removal (string, quoted)
5647 char *string;
5648 int quoted;
5649{
ccc6cda3 5650 char *r, *result_string, *temp;
726f6388
JA
5651 int sindex, tindex, c, dquote;
5652
5653 /* The result can be no longer than the original string. */
5654 r = result_string = xmalloc (strlen (string) + 1);
5655
ccc6cda3 5656 for (dquote = sindex = 0; c = string[sindex];)
726f6388
JA
5657 {
5658 switch (c)
5659 {
5660 case '\\':
5661 c = string[++sindex];
ccc6cda3 5662 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && member (c, slashify_in_quotes) == 0)
726f6388 5663 *r++ = '\\';
ccc6cda3 5664 /* FALLTHROUGH */
726f6388
JA
5665
5666 default:
5667 *r++ = c;
5668 sindex++;
5669 break;
5670
5671 case '\'':
ccc6cda3 5672 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
726f6388
JA
5673 {
5674 *r++ = c;
5675 sindex++;
ccc6cda3 5676 break;
726f6388 5677 }
ccc6cda3
JA
5678 tindex = sindex + 1;
5679 temp = string_extract_single_quoted (string, &tindex);
5680 if (temp)
726f6388 5681 {
ccc6cda3
JA
5682 strcpy (r, temp);
5683 r += strlen (r);
5684 free (temp);
726f6388 5685 }
ccc6cda3 5686 sindex = tindex;
726f6388
JA
5687 break;
5688
5689 case '"':
5690 dquote = 1 - dquote;
5691 sindex++;
5692 break;
5693 }
5694 }
5695 *r = '\0';
5696 return (result_string);
5697}
5698
ccc6cda3
JA
5699#if 0
5700/* UNUSED */
726f6388
JA
5701/* Perform quote removal on word WORD. This allocates and returns a new
5702 WORD_DESC *. */
5703WORD_DESC *
5704word_quote_removal (word, quoted)
5705 WORD_DESC *word;
5706 int quoted;
5707{
5708 WORD_DESC *w;
5709 char *t;
5710
5711 t = string_quote_removal (word->word, quoted);
ccc6cda3 5712 w = make_bare_word (t);
d166f048 5713 free (t);
726f6388
JA
5714 return (w);
5715}
5716
5717/* Perform quote removal on all words in LIST. If QUOTED is non-zero,
5718 the members of the list are treated as if they are surrounded by
5719 double quotes. Return a new list, or NULL if LIST is NULL. */
5720WORD_LIST *
5721word_list_quote_removal (list, quoted)
5722 WORD_LIST *list;
5723 int quoted;
5724{
ccc6cda3 5725 WORD_LIST *result, *t, *tresult;
726f6388 5726
ccc6cda3 5727 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
726f6388
JA
5728 {
5729 tresult = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
5730 tresult->word = word_quote_removal (t->word, quoted);
5731 tresult->next = (WORD_LIST *)NULL;
5732 result = (WORD_LIST *) list_append (result, tresult);
726f6388
JA
5733 }
5734 return (result);
5735}
ccc6cda3 5736#endif
726f6388 5737
726f6388
JA
5738/*******************************************
5739 * *
5740 * Functions to perform word splitting *
5741 * *
5742 *******************************************/
5743
b72432fd
JA
5744static char *
5745getifs ()
5746{
5747 SHELL_VAR *ifs;
5748
5749 ifs = find_variable ("IFS");
5750 /* If IFS is unset, it defaults to " \t\n". */
5751 return (ifs ? value_cell (ifs) : " \t\n");
5752}
5753
726f6388
JA
5754/* This splits a single word into a WORD LIST on $IFS, but only if the word
5755 is not quoted. list_string () performs quote removal for us, even if we
5756 don't do any splitting. */
5757WORD_LIST *
5758word_split (w)
5759 WORD_DESC *w;
5760{
5761 WORD_LIST *result;
ccc6cda3
JA
5762 SHELL_VAR *ifs;
5763 char *ifs_chars;
726f6388
JA
5764
5765 if (w)
5766 {
ccc6cda3 5767 ifs = find_variable ("IFS");
726f6388 5768 /* If IFS is unset, it defaults to " \t\n". */
ccc6cda3 5769 ifs_chars = ifs ? value_cell (ifs) : " \t\n";
726f6388 5770
ccc6cda3 5771 if ((w->flags & W_QUOTED) || !ifs_chars)
726f6388
JA
5772 ifs_chars = "";
5773
ccc6cda3 5774 result = list_string (w->word, ifs_chars, w->flags & W_QUOTED);
cce855bc
JA
5775
5776 if (ifs && tempvar_p (ifs)) /* XXX */
5777 dispose_variable (ifs); /* XXX */
726f6388
JA
5778 }
5779 else
5780 result = (WORD_LIST *)NULL;
ccc6cda3 5781
726f6388
JA
5782 return (result);
5783}
5784
5785/* Perform word splitting on LIST and return the RESULT. It is possible
5786 to return (WORD_LIST *)NULL. */
5787static WORD_LIST *
5788word_list_split (list)
5789 WORD_LIST *list;
5790{
ccc6cda3 5791 WORD_LIST *result, *t, *tresult;
726f6388 5792
ccc6cda3 5793 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
726f6388
JA
5794 {
5795 tresult = word_split (t->word);
5796 result = (WORD_LIST *) list_append (result, tresult);
726f6388
JA
5797 }
5798 return (result);
5799}
5800
5801/**************************************************
5802 * *
cce855bc 5803 * Functions to expand an entire WORD_LIST *
726f6388
JA
5804 * *
5805 **************************************************/
5806
cce855bc
JA
5807/* Put NLIST (which is a WORD_LIST * of only one element) at the front of
5808 ELIST, and set ELIST to the new list. */
5809#define PREPEND_LIST(nlist, elist) \
5810 do { nlist->next = elist; elist = nlist; } while (0)
5811
726f6388
JA
5812/* Separate out any initial variable assignments from TLIST. If set -k has
5813 been executed, remove all assignment statements from TLIST. Initial
5814 variable assignments and other environment assignments are placed
bb70624e 5815 on SUBST_ASSIGN_VARLIST. */
726f6388
JA
5816static WORD_LIST *
5817separate_out_assignments (tlist)
5818 WORD_LIST *tlist;
5819{
5820 register WORD_LIST *vp, *lp;
5821
5822 if (!tlist)
5823 return ((WORD_LIST *)NULL);
5824
bb70624e
JA
5825 if (subst_assign_varlist)
5826 dispose_words (subst_assign_varlist); /* Clean up after previous error */
b72432fd 5827
bb70624e 5828 subst_assign_varlist = (WORD_LIST *)NULL;
726f6388
JA
5829 vp = lp = tlist;
5830
5831 /* Separate out variable assignments at the start of the command.
5832 Loop invariant: vp->next == lp
5833 Loop postcondition:
5834 lp = list of words left after assignment statements skipped
5835 tlist = original list of words
5836 */
ccc6cda3 5837 while (lp && (lp->word->flags & W_ASSIGNMENT))
726f6388
JA
5838 {
5839 vp = lp;
5840 lp = lp->next;
5841 }
5842
bb70624e
JA
5843 /* If lp != tlist, we have some initial assignment statements.
5844 We make SUBST_ASSIGN_VARLIST point to the list of assignment
5845 words and TLIST point to the remaining words. */
726f6388
JA
5846 if (lp != tlist)
5847 {
bb70624e 5848 subst_assign_varlist = tlist;
726f6388
JA
5849 /* ASSERT(vp->next == lp); */
5850 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
5851 tlist = lp; /* remainder of word list */
5852 }
5853
5854 /* vp == end of variable list */
5855 /* tlist == remainder of original word list without variable assignments */
5856 if (!tlist)
5857 /* All the words in tlist were assignment statements */
5858 return ((WORD_LIST *)NULL);
5859
5860 /* ASSERT(tlist != NULL); */
ccc6cda3 5861 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
726f6388
JA
5862
5863 /* If the -k option is in effect, we need to go through the remaining
bb70624e
JA
5864 words, separate out the assignment words, and place them on
5865 SUBST_ASSIGN_VARLIST. */
726f6388
JA
5866 if (place_keywords_in_env)
5867 {
5868 WORD_LIST *tp; /* tp == running pointer into tlist */
5869
5870 tp = tlist;
5871 lp = tlist->next;
5872
5873 /* Loop Invariant: tp->next == lp */
5874 /* Loop postcondition: tlist == word list without assignment statements */
5875 while (lp)
5876 {
ccc6cda3 5877 if (lp->word->flags & W_ASSIGNMENT)
726f6388
JA
5878 {
5879 /* Found an assignment statement, add this word to end of
bb70624e
JA
5880 subst_assign_varlist (vp). */
5881 if (!subst_assign_varlist)
5882 subst_assign_varlist = vp = lp;
726f6388
JA
5883 else
5884 {
5885 vp->next = lp;
5886 vp = lp;
5887 }
5888
5889 /* Remove the word pointed to by LP from TLIST. */
5890 tp->next = lp->next;
5891 /* ASSERT(vp == lp); */
5892 lp->next = (WORD_LIST *)NULL;
5893 lp = tp->next;
5894 }
5895 else
5896 {
5897 tp = lp;
5898 lp = lp->next;
5899 }
5900 }
5901 }
5902 return (tlist);
5903}
5904
cce855bc
JA
5905#define WEXP_VARASSIGN 0x001
5906#define WEXP_BRACEEXP 0x002
5907#define WEXP_TILDEEXP 0x004
5908#define WEXP_PARAMEXP 0x008
5909#define WEXP_PATHEXP 0x010
5910
5911/* All of the expansions, including variable assignments at the start of
5912 the list. */
5913#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
5914
5915/* All of the expansions except variable assignments at the start of
5916 the list. */
5917#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
5918
5919/* All of the `shell expansions': brace expansion, tilde expansion, parameter
5920 expansion, command substitution, arithmetic expansion, word splitting, and
5921 quote removal. */
5922#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
5923
726f6388
JA
5924/* Take the list of words in LIST and do the various substitutions. Return
5925 a new list of words which is the expanded list, and without things like
5926 variable assignments. */
5927
5928WORD_LIST *
5929expand_words (list)
5930 WORD_LIST *list;
5931{
cce855bc 5932 return (expand_word_list_internal (list, WEXP_ALL));
726f6388
JA
5933}
5934
5935/* Same as expand_words (), but doesn't hack variable or environment
5936 variables. */
5937WORD_LIST *
5938expand_words_no_vars (list)
5939 WORD_LIST *list;
5940{
cce855bc 5941 return (expand_word_list_internal (list, WEXP_NOVARS));
726f6388
JA
5942}
5943
cce855bc
JA
5944WORD_LIST *
5945expand_words_shellexp (list)
726f6388 5946 WORD_LIST *list;
726f6388 5947{
cce855bc
JA
5948 return (expand_word_list_internal (list, WEXP_SHELLEXP));
5949}
726f6388 5950
cce855bc
JA
5951static WORD_LIST *
5952glob_expand_word_list (tlist, eflags)
5953 WORD_LIST *tlist;
5954 int eflags;
5955{
5956 char **glob_array, *temp_string;
5957 register int glob_index;
5958 WORD_LIST *glob_list, *output_list, *disposables, *next;
5959 WORD_DESC *tword;
726f6388 5960
cce855bc
JA
5961 output_list = disposables = (WORD_LIST *)NULL;
5962 glob_array = (char **)NULL;
5963 while (tlist)
5964 {
5965 /* For each word, either globbing is attempted or the word is
5966 added to orig_list. If globbing succeeds, the results are
5967 added to orig_list and the word (tlist) is added to the list
5968 of disposable words. If globbing fails and failed glob
5969 expansions are left unchanged (the shell default), the
5970 original word is added to orig_list. If globbing fails and
5971 failed glob expansions are removed, the original word is
5972 added to the list of disposable words. orig_list ends up
5973 in reverse order and requires a call to reverse_list to
5974 be set right. After all words are examined, the disposable
5975 words are freed. */
5976 next = tlist->next;
726f6388 5977
cce855bc
JA
5978 /* If the word isn't an assignment and contains an unquoted
5979 pattern matching character, then glob it. */
b72432fd 5980#if 0
cce855bc 5981 if ((tlist->word->flags & W_ASSIGNMENT) == 0 &&
b72432fd
JA
5982#else
5983 if ((tlist->word->flags & W_NOGLOB) == 0 &&
5984#endif
cce855bc 5985 unquoted_glob_pattern_p (tlist->word->word))
726f6388 5986 {
cce855bc
JA
5987 glob_array = shell_glob_filename (tlist->word->word);
5988
5989 /* Handle error cases.
5990 I don't think we should report errors like "No such file
5991 or directory". However, I would like to report errors
5992 like "Read failed". */
5993
5994 if (GLOB_FAILED (glob_array))
726f6388 5995 {
bb70624e 5996 glob_array = (char **)xmalloc (sizeof (char *));
cce855bc
JA
5997 glob_array[0] = (char *)NULL;
5998 }
5999
6000 /* Dequote the current word in case we have to use it. */
6001 if (glob_array[0] == NULL)
6002 {
6003 temp_string = dequote_string (tlist->word->word);
6004 free (tlist->word->word);
6005 tlist->word->word = temp_string;
6006 }
6007
6008 /* Make the array into a word list. */
6009 glob_list = (WORD_LIST *)NULL;
6010 for (glob_index = 0; glob_array[glob_index]; glob_index++)
6011 {
6012 tword = make_bare_word (glob_array[glob_index]);
6013 tword->flags |= W_GLOBEXP; /* XXX */
6014 glob_list = make_word_list (tword, glob_list);
6015 }
6016
6017 if (glob_list)
6018 {
6019 output_list = (WORD_LIST *)list_append (glob_list, output_list);
6020 PREPEND_LIST (tlist, disposables);
6021 }
6022 else if (allow_null_glob_expansion == 0)
6023 {
6024 /* Failed glob expressions are left unchanged. */
6025 PREPEND_LIST (tlist, output_list);
6026 }
6027 else
6028 {
6029 /* Failed glob expressions are removed. */
6030 PREPEND_LIST (tlist, disposables);
726f6388 6031 }
726f6388 6032 }
cce855bc
JA
6033 else
6034 {
6035 /* Dequote the string. */
6036 temp_string = dequote_string (tlist->word->word);
6037 free (tlist->word->word);
6038 tlist->word->word = temp_string;
6039 PREPEND_LIST (tlist, output_list);
6040 }
6041
6042 free_array (glob_array);
6043 glob_array = (char **)NULL;
6044
6045 tlist = next;
726f6388
JA
6046 }
6047
cce855bc
JA
6048 if (disposables)
6049 dispose_words (disposables);
6050
6051 if (output_list)
6052 output_list = REVERSE_LIST (output_list, WORD_LIST *);
6053
6054 return (output_list);
6055}
726f6388
JA
6056
6057#if defined (BRACE_EXPANSION)
cce855bc
JA
6058static WORD_LIST *
6059brace_expand_word_list (tlist, eflags)
6060 WORD_LIST *tlist;
6061 int eflags;
6062{
6063 register char **expansions;
6064 char *temp_string;
6065 WORD_LIST *disposables, *output_list, *next;
6066 WORD_DESC *w;
6067 int eindex;
6068
6069 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
726f6388 6070 {
cce855bc 6071 next = tlist->next;
726f6388 6072
cce855bc
JA
6073 /* Only do brace expansion if the word has a brace character. If
6074 not, just add the word list element to BRACES and continue. In
6075 the common case, at least when running shell scripts, this will
6076 degenerate to a bunch of calls to `strchr', and then what is
6077 basically a reversal of TLIST into BRACES, which is corrected
6078 by a call to reverse_list () on BRACES when the end of TLIST
6079 is reached. */
6080 if (strchr (tlist->word->word, LBRACE))
726f6388 6081 {
cce855bc 6082 expansions = brace_expand (tlist->word->word);
726f6388 6083
cce855bc 6084 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
726f6388 6085 {
cce855bc
JA
6086 w = make_word (temp_string);
6087 /* If brace expansion didn't change the word, preserve
6088 the flags. We may want to preserve the flags
6089 unconditionally someday -- XXX */
6090 if (STREQ (temp_string, tlist->word->word))
6091 w->flags = tlist->word->flags;
6092 output_list = make_word_list (w, output_list);
6093 free (expansions[eindex]);
726f6388 6094 }
cce855bc 6095 free (expansions);
726f6388 6096
cce855bc
JA
6097 /* Add TLIST to the list of words to be freed after brace
6098 expansion has been performed. */
6099 PREPEND_LIST (tlist, disposables);
6100 }
6101 else
6102 PREPEND_LIST (tlist, output_list);
726f6388 6103 }
cce855bc
JA
6104
6105 if (disposables)
6106 dispose_words (disposables);
6107
6108 if (output_list)
6109 output_list = REVERSE_LIST (output_list, WORD_LIST *);
6110
6111 return (output_list);
6112}
6113#endif
6114
6115static WORD_LIST *
6116shell_expand_word_list (tlist, eflags)
6117 WORD_LIST *tlist;
6118 int eflags;
6119{
6120 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list;
6121 int expanded_something, has_dollar_at;
6122 char *temp_string;
726f6388 6123
726f6388 6124 /* We do tilde expansion all the time. This is what 1003.2 says. */
cce855bc
JA
6125 new_list = (WORD_LIST *)NULL;
6126 for (orig_list = tlist; tlist; tlist = next)
726f6388 6127 {
ccc6cda3 6128 temp_string = tlist->word->word;
726f6388
JA
6129
6130 next = tlist->next;
6131
6132 /* Posix.2 section 3.6.1 says that tildes following `=' in words
6133 which are not assignment statements are not expanded. We do
ccc6cda3
JA
6134 this only if POSIXLY_CORRECT is enabled. Essentially, we do
6135 tilde expansion on unquoted assignment statements (flags include
6136 W_ASSIGNMENT but not W_QUOTED). */
6137 if (temp_string[0] == '~' ||
6138 (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) &&
6139 posixly_correct == 0 &&
6140 strchr (temp_string, '~') &&
6141 (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string))))
726f6388 6142 {
ccc6cda3
JA
6143 tlist->word->word = bash_tilde_expand (temp_string);
6144 free (temp_string);
726f6388
JA
6145 }
6146
ccc6cda3 6147 expanded_something = 0;
726f6388 6148 expanded = expand_word_internal
b72432fd 6149 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
726f6388
JA
6150
6151 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
6152 {
6153 /* By convention, each time this error is returned,
6154 tlist->word->word has already been freed. */
6155 tlist->word->word = (char *)NULL;
ccc6cda3 6156
726f6388
JA
6157 /* Dispose our copy of the original list. */
6158 dispose_words (orig_list);
d166f048 6159 /* Dispose the new list we're building. */
726f6388
JA
6160 dispose_words (new_list);
6161
6162 if (expanded == &expand_word_error)
ccc6cda3 6163 jump_to_top_level (DISCARD);
726f6388 6164 else
ccc6cda3 6165 jump_to_top_level (FORCE_EOF);
726f6388
JA
6166 }
6167
ccc6cda3
JA
6168 /* Don't split words marked W_NOSPLIT. */
6169 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
726f6388 6170 {
ccc6cda3 6171 temp_list = word_list_split (expanded);
726f6388
JA
6172 dispose_words (expanded);
6173 }
6174 else
6175 {
6176 /* If no parameter expansion, command substitution, process
6177 substitution, or arithmetic substitution took place, then
6178 do not do word splitting. We still have to remove quoted
6179 null characters from the result. */
6180 word_list_remove_quoted_nulls (expanded);
ccc6cda3 6181 temp_list = expanded;
726f6388
JA
6182 }
6183
ccc6cda3
JA
6184 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
6185 new_list = (WORD_LIST *)list_append (expanded, new_list);
726f6388
JA
6186 }
6187
cce855bc
JA
6188 if (orig_list)
6189 dispose_words (orig_list);
726f6388 6190
726f6388 6191 if (new_list)
cce855bc 6192 new_list = REVERSE_LIST (new_list, WORD_LIST *);
726f6388 6193
cce855bc
JA
6194 return (new_list);
6195}
726f6388 6196
cce855bc
JA
6197/* The workhorse for expand_words () and expand_words_no_vars ().
6198 First arg is LIST, a WORD_LIST of words.
b72432fd
JA
6199 Second arg EFLAGS is a flags word controlling which expansions are
6200 performed.
726f6388 6201
cce855bc
JA
6202 This does all of the substitutions: brace expansion, tilde expansion,
6203 parameter expansion, command substitution, arithmetic expansion,
6204 process substitution, word splitting, and pathname expansion, according
6205 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
6206 set, or for which no expansion is done, do not undergo word splitting.
b72432fd 6207 Words with the W_NOGLOB bit set do not undergo pathname expansion. */
cce855bc
JA
6208static WORD_LIST *
6209expand_word_list_internal (list, eflags)
6210 WORD_LIST *list;
6211 int eflags;
6212{
6213 WORD_LIST *new_list, *temp_list;
6214 int tint;
726f6388 6215
cce855bc
JA
6216 if (list == 0)
6217 return ((WORD_LIST *)NULL);
726f6388 6218
bb70624e 6219 garglist = new_list = copy_word_list (list);
cce855bc
JA
6220 if (eflags & WEXP_VARASSIGN)
6221 {
bb70624e 6222 garglist = new_list = separate_out_assignments (new_list);
cce855bc
JA
6223 if (new_list == 0)
6224 {
bb70624e 6225 if (subst_assign_varlist)
cce855bc
JA
6226 {
6227 /* All the words were variable assignments, so they are placed
6228 into the shell's environment. */
bb70624e 6229 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
cce855bc
JA
6230 {
6231 this_command_name = (char *)NULL; /* no arithmetic errors */
6232 tint = do_assignment (temp_list->word->word);
6233 /* Variable assignment errors in non-interactive shells
6234 running in Posix.2 mode cause the shell to exit. */
6235 if (tint == 0 && interactive_shell == 0 && posixly_correct)
ccc6cda3 6236 {
cce855bc
JA
6237 last_command_exit_value = EXECUTION_FAILURE;
6238 jump_to_top_level (FORCE_EOF);
ccc6cda3 6239 }
726f6388 6240 }
bb70624e
JA
6241 dispose_words (subst_assign_varlist);
6242 subst_assign_varlist = (WORD_LIST *)NULL;
cce855bc
JA
6243 }
6244 return ((WORD_LIST *)NULL);
6245 }
6246 }
726f6388 6247
cce855bc
JA
6248 /* Begin expanding the words that remain. The expansions take place on
6249 things that aren't really variable assignments. */
726f6388 6250
cce855bc
JA
6251#if defined (BRACE_EXPANSION)
6252 /* Do brace expansion on this word if there are any brace characters
6253 in the string. */
6254 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
6255 new_list = brace_expand_word_list (new_list, eflags);
6256#endif /* BRACE_EXPANSION */
726f6388 6257
cce855bc
JA
6258 /* Perform the `normal' shell expansions: tilde expansion, parameter and
6259 variable substitution, command substitution, arithmetic expansion,
6260 and word splitting. */
6261 new_list = shell_expand_word_list (new_list, eflags);
726f6388 6262
cce855bc
JA
6263 /* Okay, we're almost done. Now let's just do some filename
6264 globbing. */
6265 if (new_list)
6266 {
6267 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
6268 /* Glob expand the word list unless globbing has been disabled. */
6269 new_list = glob_expand_word_list (new_list, eflags);
726f6388 6270 else
cce855bc
JA
6271 /* Dequote the words, because we're not performing globbing. */
6272 new_list = dequote_list (new_list);
726f6388
JA
6273 }
6274
bb70624e 6275 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
726f6388 6276 {
726f6388
JA
6277 Function *assign_func;
6278
6279 /* If the remainder of the words expand to nothing, Posix.2 requires
6280 that the variable and environment assignments affect the shell's
6281 environment. */
6282 assign_func = new_list ? assign_in_env : do_assignment;
6283
bb70624e 6284 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
726f6388 6285 {
ccc6cda3
JA
6286 this_command_name = (char *)NULL;
6287 tint = (*assign_func) (temp_list->word->word);
6288 /* Variable assignment errors in non-interactive shells running
6289 in Posix.2 mode cause the shell to exit. */
6290 if (tint == 0 && assign_func == do_assignment &&
6291 interactive_shell == 0 && posixly_correct)
6292 {
6293 last_command_exit_value = EXECUTION_FAILURE;
6294 jump_to_top_level (FORCE_EOF);
6295 }
726f6388 6296 }
726f6388 6297
bb70624e
JA
6298 dispose_words (subst_assign_varlist);
6299 subst_assign_varlist = (WORD_LIST *)NULL;
726f6388
JA
6300 }
6301
cce855bc 6302#if 0
ccc6cda3
JA
6303 tint = list_length (new_list) + 1;
6304 RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
cce855bc
JA
6305 for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next)
6306 glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0';
ccc6cda3 6307 glob_argv_flags[tint] = '\0';
ccc6cda3 6308#endif
726f6388 6309
cce855bc 6310 return (new_list);
ccc6cda3 6311}