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