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