]> git.ipfire.org Git - thirdparty/bash.git/blob - subst.c
Imported from ../bash-2.01.1.tar.gz.
[thirdparty/bash.git] / subst.c
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
22 #include "config.h"
23
24 #include "bashtypes.h"
25 #include <stdio.h>
26 #include <pwd.h>
27 #include <signal.h>
28 #include <errno.h>
29
30 #if defined (HAVE_UNISTD_H)
31 # include <unistd.h>
32 #endif
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"
42 #include "trap.h"
43 #include "pathexp.h"
44 #include "mailcheck.h"
45
46 #if !defined (HAVE_RESTARTABLE_SYSCALLS) /* for getc_with_restart */
47 #include "input.h"
48 #endif
49
50 #include "builtins/getopt.h"
51 #include "builtins/common.h"
52
53 #if defined (READLINE)
54 # include "bashline.h"
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>
66
67 #if !defined (errno)
68 extern int errno;
69 #endif /* !errno */
70
71 /* The size that strings change by. */
72 #define DEFAULT_INITIAL_ARRAY_SIZE 112
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
79 #define VT_ARRAYMEMBER 3
80
81 /* Flags for quoted_strchr */
82 #define ST_BACKSL 0x01
83 #define ST_CTLESC 0x02
84
85 /* How to quote character C. */
86 static char *make_quoted_char ();
87
88 /* Process ID of the last command executed within command substitution. */
89 pid_t last_command_subst_pid = NO_PID;
90
91 /* Extern functions and variables from different files. */
92 extern int last_command_exit_value, interactive, interactive_shell;
93 extern int subshell_environment, startup_state;
94 extern int dollar_dollar_pid;
95 extern int posixly_correct;
96 extern int eof_encountered, eof_encountered_limit, ignoreeof;
97 extern char *this_command_name;
98 extern struct fd_bitmap *current_fds_to_close;
99 #if defined (READLINE)
100 extern int no_line_editing;
101 extern int hostname_list_initialized;
102 #endif
103
104 extern void getopts_reset ();
105
106 /* Non-zero means to allow unmatched globbed filenames to expand to
107 a null file. */
108 int 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. */
113 char *glob_argv_flags;
114 static int glob_argv_flags_size;
115
116 static WORD_LIST expand_word_error, expand_word_fatal;
117 static char expand_param_error, expand_param_fatal;
118
119 static WORD_LIST *expand_string_internal ();
120 static WORD_LIST *expand_word_internal (), *expand_word_list_internal ();
121 static WORD_LIST *expand_string_leave_quoted ();
122 static WORD_LIST *expand_string_for_rhs ();
123 static WORD_LIST *word_list_split ();
124 static WORD_LIST *quote_list (), *dequote_list ();
125 static int unquoted_substring (), unquoted_member ();
126 static int do_assignment_internal ();
127 static char *string_extract_verbatim (), *string_extract ();
128 static char *string_extract_double_quoted (), *string_extract_single_quoted ();
129 static int skip_single_quoted (), skip_double_quoted ();
130 static char *extract_delimited_string ();
131 static 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. */
141 char *
142 substring (string, start, end)
143 char *string;
144 int start, end;
145 {
146 register int len;
147 register char *result;
148
149 len = end - start;
150 result = xmalloc (len + 1);
151 strncpy (result, string + start, len);
152 result[len] = '\0';
153 return (result);
154 }
155
156 static char *
157 quoted_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. */
200 static inline char *
201 quoted_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
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. */
234 static char *
235 remove_quoted_escapes (string)
236 char *string;
237 {
238 register char *s;
239 int docopy;
240 char *t, *t1;
241
242 if (string == NULL)
243 return (string);
244
245 t1 = t = xmalloc (strlen (string) + 1);
246 for (docopy = 0, s = string; *s; s++, t1++)
247 {
248 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL))
249 {
250 s++;
251 docopy = 1;
252 }
253 *t1 = *s;
254 }
255 *t1 = '\0';
256 if (docopy)
257 strcpy (string, t);
258 free (t);
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. */
265 static char *
266 quote_escapes (string)
267 char *string;
268 {
269 register char *s, *t;
270 char *result;
271
272 result = xmalloc ((strlen (string) * 2) + 1);
273 for (s = string, t = result; *s; )
274 {
275 if (*s == CTLESC || *s == CTLNUL)
276 *t++ = CTLESC;
277 *t++ = *s++;
278 }
279 *t = '\0';
280 return (result);
281 }
282
283 #ifdef INCLUDE_UNUSED
284 static char *
285 dequote_escapes (string)
286 char *string;
287 {
288 register char *s, *t;
289 char *result;
290
291 result = xmalloc (strlen (string) + 1);
292 for (s = string, t = result; *s; )
293 {
294 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL))
295 {
296 s++;
297 if (*s == '\0')
298 break;
299 }
300 *t++ = *s++;
301 }
302 *t = '\0';
303 return result;
304 }
305 #endif
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.
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. */
313 static char *
314 string_extract (string, sindex, charlist, varname)
315 char *string, *charlist;
316 int *sindex, varname;
317 {
318 register int c, i;
319 char *temp;
320
321 for (i = *sindex; c = string[i]; i++)
322 {
323 if (c == '\\')
324 if (string[i + 1])
325 i++;
326 else
327 break;
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))
339 break;
340 }
341 c = i - *sindex;
342 temp = xmalloc (1 + c);
343 strncpy (temp, string + *sindex, c);
344 temp[c] = '\0';
345 *sindex = i;
346 return (temp);
347 }
348
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. */
356 static inline char *
357 string_extract_double_quoted (string, sindex, stripdq)
358 char *string;
359 int *sindex, stripdq;
360 {
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;
365
366 pass_next = backquote = dquote = 0;
367 temp = xmalloc (1 + strlen (string) - *sindex);
368
369 for (j = 0, i = *sindex; c = string[i]; i++)
370 {
371 /* Process a character that was quoted by a backslash. */
372 if (pass_next)
373 {
374 /* Posix.2 sez:
375
376 ``The backslash shall retain its special meaning as an escape
377 character only when followed by one of the characters:
378 $ ` " \ <newline>''.
379
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 }
403
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 == '\\')
408 {
409 pass_next++;
410 continue;
411 }
412
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)
418 {
419 if (c == '`')
420 backquote = 0;
421 temp[j++] = c;
422 continue;
423 }
424
425 if (c == '`')
426 {
427 temp[j++] = c;
428 backquote++;
429 continue;
430 }
431
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] == '{')))
435 {
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);
441
442 temp[j++] = '$';
443 temp[j++] = string[i + 1];
444
445 for (t = 0; ret[t]; t++, j++)
446 temp[j] = ret[t];
447 temp[j++] = string[si];
448
449 i = si;
450 free (ret);
451 continue;
452 }
453
454 /* Add any character but a double quote to the quoted string we're
455 accumulating. */
456 if (c != '"')
457 {
458 temp[j++] = c;
459 continue;
460 }
461
462 /* c == '"' */
463 if (stripdq)
464 {
465 dquote ^= 1;
466 continue;
467 }
468
469 break;
470 }
471 temp[j] = '\0';
472
473 /* Point to after the closing quote. */
474 if (c)
475 i++;
476 *sindex = i;
477
478 return (temp);
479 }
480
481 /* This should really be another option to string_extract_double_quoted. */
482 static inline int
483 skip_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++)
494 {
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;
532 }
533
534 if (c)
535 i++;
536
537 return (i);
538 }
539
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. */
544 static inline char *
545 string_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
567 static inline int
568 skip_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. */
583 static char *
584 string_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 ")". */
623 char *
624 extract_command_subst (string, sindex)
625 char *string;
626 int *sindex;
627 {
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 "]". */
634 char *
635 extract_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 ")". */
646 char *
647 extract_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)
657 char *
658 extract_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. */
674 static char *
675 extract_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;
682 int pass_character, nesting_level;
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);
688
689 pass_character = 0;
690
691 nesting_level = 1;
692 i = *sindex;
693
694 while (nesting_level)
695 {
696 c = string[i];
697
698 if (c == 0)
699 break;
700
701 if (pass_character) /* previous char was backslash */
702 {
703 pass_character = 0;
704 i++;
705 continue;
706 }
707
708 if (c == CTLESC)
709 {
710 pass_character++;
711 i++;
712 continue;
713 }
714
715 #if 0
716 if (c == '\\' && delimiter == '"' &&
717 (member (string[i], slashify_in_quotes)))
718 #else
719 if (c == '\\')
720 #endif
721 {
722 pass_character++;
723 i++;
724 continue;
725 }
726
727 /* Process a nested OPENER. */
728 if (STREQN (string + i, opener, len_opener))
729 {
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;
735 }
736
737 /* Process a nested ALT_OPENER */
738 if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
739 {
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);
744 continue;
745 }
746
747 /* If the current substring terminates the delimited string, decrement
748 the nesting level. */
749 if (STREQN (string + i, closer, len_closer))
750 {
751 i += len_closer - 1; /* move to last char of the closer */
752 nesting_level--;
753 if (nesting_level == 0)
754 break;
755 }
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. */
784 }
785
786 si = i - *sindex - len_closer + 1;
787 result = xmalloc (1 + si);
788 strncpy (result, string + *sindex, si);
789 result[si] = '\0';
790 *sindex = i;
791
792 if (c == 0 && nesting_level)
793 {
794 report_error ("bad substitution: no `%s' in %s", closer, string);
795 free (result);
796 jump_to_top_level (DISCARD);
797 }
798
799 return (result);
800 }
801
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 */
810 static char *
811 extract_dollar_brace_string (string, sindex, quoted)
812 char *string;
813 int *sindex, quoted;
814 {
815 register int i, c, l;
816 int pass_character, nesting_level, si;
817 char *result, *t;
818
819 pass_character = 0;
820
821 nesting_level = 1;
822
823 for (i = *sindex; (c = string[i]); i++)
824 {
825 if (pass_character)
826 {
827 pass_character = 0;
828 continue;
829 }
830
831 if (c == CTLESC)
832 {
833 pass_character++;
834 continue;
835 }
836
837 /* Backslashes quote the next character. */
838 if (c == '\\')
839 {
840 pass_character++;
841 continue;
842 }
843
844 if (string[i] == '$' && string[i+1] == '{')
845 {
846 nesting_level++;
847 i++;
848 continue;
849 }
850
851 if (c == '}')
852 {
853 nesting_level--;
854 if (nesting_level == 0)
855 break;
856 continue;
857 }
858
859 /* Pass the contents of old-style command substitutions through
860 verbatim. */
861 if (c == '`')
862 {
863 si = i + 1;
864 t = string_extract (string, &si, "`", 0);
865 i = si;
866 free (t);
867 continue;
868 }
869
870 /* Pass the contents of new-style command substitutions through
871 verbatim. */
872 if (string[i] == '$' && string[i+1] == '(')
873 {
874 si = i + 2;
875 t = extract_delimited_string (string, &si, "$(", "(", ")");
876 i = si;
877 free (t);
878 continue;
879 }
880
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 }
890
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 }
900 }
901
902 l = i - *sindex;
903 result = xmalloc (1 + l);
904 strncpy (result, string + *sindex, l);
905 result[l] = '\0';
906 *sindex = i;
907
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);
916 }
917
918 /* Remove backslashes which are quoting backquotes from STRING. Modifies
919 STRING, and returns a pointer to it. */
920 char *
921 de_backslash (string)
922 char *string;
923 {
924 register int i, l;
925
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 }
932
933 #if 0
934 /* Replace instances of \! in a string with !. */
935 void
936 unquote_bang (string)
937 char *string;
938 {
939 register int i, j;
940 register char *temp;
941
942 temp = xmalloc (1 + strlen (string));
943
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);
954 }
955 #endif
956
957 #if defined (READLINE)
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. */
961 int
962 char_is_quoted (string, eindex)
963 char *string;
964 int eindex;
965 {
966 int i, pass_next, quoted;
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 }
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 }
985 else if (string[i] == '\\')
986 {
987 pass_next = 1;
988 continue;
989 }
990 }
991 return (0);
992 }
993
994 int
995 unclosed_pair (string, eindex, openstr)
996 char *string;
997 int eindex;
998 char *openstr;
999 {
1000 int i, pass_next, openc, olen;
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 }
1017 else if (string[i] == '\'' || string[i] == '"')
1018 {
1019 i = (string[i] == '\'') ? skip_single_quoted (string, i)
1020 : skip_double_quoted (string, i);
1021 if (i > eindex)
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
1034 #if 0
1035 /* UNUSED */
1036 /* Extract the name of the variable to bind to from the assignment string. */
1037 char *
1038 assignment_name (string)
1039 char *string;
1040 {
1041 int offset;
1042 char *temp;
1043
1044 offset = assignment (string);
1045 if (offset == 0)
1046 return (char *)NULL;
1047 temp = xmalloc (offset + 1);
1048 strncpy (temp, string, offset);
1049 temp[offset] = '\0';
1050 return (temp);
1051 }
1052 #endif
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. */
1056 static char *
1057 string_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
1065 if (list == 0)
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 {
1085 if (sep_len > 1)
1086 {
1087 FASTCOPY (sep, r, sep_len);
1088 r += sep_len;
1089 }
1090 else
1091 *r++ = sep[0];
1092 }
1093
1094 word_len = strlen (t->word->word);
1095 FASTCOPY (t->word->word, r, word_len);
1096 r += word_len;
1097 }
1098
1099 *r = '\0';
1100 return (result);
1101 }
1102
1103 /* Return a single string of all the words present in LIST, separating
1104 each word with a space. */
1105 char *
1106 string_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." */
1117 char *
1118 string_list_dollar_star (list)
1119 WORD_LIST *list;
1120 {
1121 char *ifs, sep[2];
1122
1123 ifs = get_string_value ("IFS");
1124 if (ifs == 0)
1125 sep[0] = ' ';
1126 else if (*ifs == '\0')
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
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
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. */
1166 /*
1167 #define remove_quoted_nulls(string) \
1168 do { if (QUOTED_NULL (string)) string[0] ='\0'; } while (0)
1169 */
1170 static void
1171 remove_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 {
1182 *p++ = *s++; /* CTLESC */
1183 if (*s == 0)
1184 break;
1185 *p++ = *s; /* quoted char */
1186 continue;
1187 }
1188 if (*s == CTLNUL)
1189 continue;
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. */
1199 void
1200 word_list_remove_quoted_nulls (list)
1201 WORD_LIST *list;
1202 {
1203 register WORD_LIST *t;
1204
1205 for (t = list; t; t = t->next)
1206 remove_quoted_nulls (t->word->word);
1207 }
1208
1209 /* This performs word splitting and quoted null character removal on
1210 STRING. */
1211 #define issep(c) (member ((c), separators))
1212
1213 WORD_LIST *
1214 list_string (string, separators, quoted)
1215 register char *string, *separators;
1216 int quoted;
1217 {
1218 WORD_LIST *result;
1219 WORD_DESC *t;
1220 char *current_word, *s;
1221 int sindex, sh_style_split;
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. */
1247 for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
1248 {
1249 current_word = string_extract_verbatim (string, &sindex, separators);
1250 if (current_word == 0)
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 {
1259 t = make_bare_word ("");
1260 t->flags |= W_QUOTED;
1261 free (t->word);
1262 t->word = make_quoted_char ('\0');
1263 result = make_word_list (t, result);
1264 }
1265 else if (current_word[0] != '\0')
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);
1271 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
1272 result->word->flags |= W_QUOTED;
1273 }
1274
1275 /* If we're not doing sequences of separators in the traditional
1276 Bourne shell style, then add a quoted null argument. */
1277 else if (!sh_style_split && !spctabnl (string[sindex]))
1278 {
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);
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++;
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 */
1305 char *
1306 get_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);
1315
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.
1341
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. */
1369 char *
1370 strip_trailing_ifs_whitespace (string, separators, saw_escape)
1371 char *string, *separators;
1372 int saw_escape;
1373 {
1374 char *s;
1375
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
1384 #if 0
1385 #if defined (ARRAY_VARS)
1386 WORD_LIST *
1387 list_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
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. */
1448 static char *
1449 maybe_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;
1457
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])
1467 {
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 }
1477 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
1478 ret = string_quote_removal (string, quoted);
1479 else
1480 ret = savestring (string);
1481 return ret;
1482 }
1483
1484 static inline char *
1485 expand_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
1508 #if defined (ARRAY_VARS)
1509 SHELL_VAR *
1510 do_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
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. */
1546 static int
1547 do_assignment_internal (string, expand)
1548 char *string;
1549 int expand;
1550 {
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;
1562
1563 if (name[offset] == '=')
1564 {
1565 char *temp;
1566
1567 name[offset] = 0;
1568 temp = name + offset + 1;
1569
1570 #if defined (ARRAY_VARS)
1571 if (expand && temp[0] == '(' && strchr (temp, ')'))
1572 {
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);
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)
1594 {
1595 value = xmalloc (1);
1596 value[0] = '\0';
1597 }
1598
1599 if (echo_command_at_execute)
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
1605 fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value);
1606
1607 #define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
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
1627 stupidly_hack_special_variables (name);
1628
1629 if (entry)
1630 entry->attributes &= ~att_invisible;
1631
1632 /* Return 1 if the assignment seems to have been performed correctly. */
1633 ASSIGN_RETURN (entry ? ((entry->attributes & att_readonly) == 0) : 0);
1634 }
1635
1636 /* Perform the assignment statement in STRING, and expand the
1637 right side by doing command and parameter expansion. */
1638 int
1639 do_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. */
1648 int
1649 do_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
1665 case nothing happens. Gets rid of SOURCE by freeing it.
1666 Returns TARGET in case the location has changed. */
1667 inline char *
1668 sub_append_string (source, target, indx, size)
1669 char *source, *target;
1670 int *indx, *size;
1671 {
1672 if (source)
1673 {
1674 int srclen, n;
1675
1676 srclen = STRLEN (source);
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
1693 #if 0
1694 /* UNUSED */
1695 /* Append the textual representation of NUMBER to TARGET.
1696 INDX and SIZE are as in SUB_APPEND_STRING. */
1697 char *
1698 sub_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 }
1707 #endif
1708
1709 /* Return the word list that corresponds to `$*'. */
1710 WORD_LIST *
1711 list_rest_of_args ()
1712 {
1713 register WORD_LIST *list, *args;
1714 int i;
1715
1716 /* Break out of the loop as soon as one of the dollar variables is null. */
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);
1722
1723 return (REVERSE_LIST (list, WORD_LIST *));
1724 }
1725
1726 int
1727 number_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
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. */
1742 char *
1743 string_rest_of_args (dollar_star)
1744 int dollar_star;
1745 {
1746 register WORD_LIST *list;
1747 char *string;
1748
1749 list = list_rest_of_args ();
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. */
1763 static WORD_LIST *
1764 call_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)
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 }
1779 else if (result == &expand_word_fatal)
1780 jump_to_top_level (FORCE_EOF);
1781 /* NOTREACHED */
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. */
1788 static WORD_LIST *
1789 expand_string_internal (string, quoted)
1790 char *string;
1791 int quoted;
1792 {
1793 WORD_DESC td;
1794 WORD_LIST *tresult;
1795
1796 if (string == 0 || *string == 0)
1797 return ((WORD_LIST *)NULL);
1798
1799 bzero ((char *)&td, sizeof (td));
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. */
1810 WORD_LIST *
1811 expand_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
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. */
1835 static WORD_LIST *
1836 expand_string_leave_quoted (string, quoted)
1837 char *string;
1838 int quoted;
1839 {
1840 WORD_LIST *tlist;
1841 WORD_LIST *tresult;
1842
1843 if (string == 0 || *string == '\0')
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
1857 /* This does not perform word splitting or dequote the WORD_LIST
1858 it returns. */
1859 static WORD_LIST *
1860 expand_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
1870 bzero ((char *)&td, sizeof (td));
1871 td.word = string;
1872 tresult = call_expand_word_internal (&td, quoted, dollar_at_p, has_dollar_at);
1873 return (tresult);
1874 }
1875
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. */
1881 WORD_LIST *
1882 expand_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);
1892 return (result ? dequote_list (result) : result);
1893 }
1894
1895 /***************************************************
1896 * *
1897 * Functions to handle quoting chars *
1898 * *
1899 ***************************************************/
1900
1901 static WORD_LIST *
1902 dequote_list (list)
1903 WORD_LIST *list;
1904 {
1905 register char *s;
1906 register WORD_LIST *tlist;
1907
1908 for (tlist = list; tlist; tlist = tlist->next)
1909 {
1910 s = dequote_string (tlist->word->word);
1911 free (tlist->word->word);
1912 tlist->word->word = s;
1913 }
1914 return list;
1915 }
1916
1917 static char *
1918 make_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. */
1939 char *
1940 quote_string (string)
1941 char *string;
1942 {
1943 register char *t;
1944 char *result;
1945
1946 if (*string == 0)
1947 {
1948 result = xmalloc (2);
1949 result[0] = CTLNUL;
1950 result[1] = '\0';
1951 }
1952 else
1953 {
1954 result = xmalloc ((strlen (string) * 2) + 1);
1955
1956 for (t = result; *string; )
1957 {
1958 *t++ = CTLESC;
1959 *t++ = *string++;
1960 }
1961 *t = '\0';
1962 }
1963 return (result);
1964 }
1965
1966 /* De-quoted quoted characters in STRING. */
1967 char *
1968 dequote_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
1990 for (t = result; *string; string++, t++)
1991 {
1992 if (*string == CTLESC)
1993 {
1994 string++;
1995
1996 if (!*string)
1997 break;
1998 }
1999
2000 *t = *string;
2001 }
2002
2003 *t = '\0';
2004 return (result);
2005 }
2006
2007 /* Quote the entire WORD_LIST list. */
2008 static WORD_LIST *
2009 quote_list (list)
2010 WORD_LIST *list;
2011 {
2012 register WORD_LIST *w;
2013 char *t;
2014
2015 for (w = list; w; w = w->next)
2016 {
2017 t = w->word->word;
2018 w->word->word = quote_string (t);
2019 free (t);
2020 w->word->flags |= W_QUOTED;
2021 }
2022 return list;
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
2044 static char *
2045 remove_pattern (param, pattern, op)
2046 char *param, *pattern;
2047 int op;
2048 {
2049 register int len;
2050 register char *end;
2051 register char *p, *ret, c;
2052
2053 if (param == NULL || *param == '\0')
2054 return (param);
2055 if (pattern == NULL || *pattern == '\0') /* minor optimization */
2056 return (savestring (param));
2057
2058 len = STRLEN (param);
2059 end = param + len;
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
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(). */
2120 static int
2121 match_pattern_char (pat, string)
2122 char *pat, *string;
2123 {
2124 #if 0
2125 register char *np;
2126 int neg;
2127 char c1;
2128 #endif
2129 char c;
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 '?':
2141 return (*string != '\0');
2142 case '*':
2143 return (1);
2144 case '[':
2145 #if 0
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 }
2163 #else
2164 return (*string != '\0');
2165 #endif
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. */
2175 static int
2176 match_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);
2229
2230 case MATCH_END:
2231 for (p = string; p <= end; p++)
2232 if (fnmatch (pat, p, 0) == 0)
2233 {
2234 *sp = p;
2235 *ep = end;
2236 return 1;
2237 }
2238 return (0);
2239 }
2240
2241 return (0);
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
2254 WORD_LIST *
2255 expand_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);
2264 return (result ? dequote_list (result) : result);
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. */
2270 WORD_LIST *
2271 expand_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);
2278 return (result ? dequote_list (result) : result);
2279 }
2280
2281 /* Perform shell expansions on WORD, but do not perform word splitting or
2282 quote removal on the result. */
2283 WORD_LIST *
2284 expand_word_leave_quoted (word, quoted)
2285 WORD_DESC *word;
2286 int quoted;
2287 {
2288 return (call_expand_word_internal (word, quoted, (int *)NULL, (int *)NULL));
2289 }
2290
2291 /* Return the value of a positional parameter. This handles values > 10. */
2292 char *
2293 get_dollar_var_value (ind)
2294 int ind;
2295 {
2296 char *temp;
2297 WORD_LIST *p;
2298
2299 if (ind < 10)
2300 temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
2301 else /* We want something like ${11} */
2302 {
2303 ind -= 10;
2304 for (p = rest_of_args; p && ind--; p = p->next)
2305 ;
2306 temp = p ? savestring (p->word->word) : (char *)NULL;
2307 }
2308 return (temp);
2309 }
2310
2311 #if defined (PROCESS_SUBSTITUTION)
2312
2313 /* **************************************************************** */
2314 /* */
2315 /* Hacking Process Substitution */
2316 /* */
2317 /* **************************************************************** */
2318
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
2325 extern char *mktemp ();
2326
2327 static char **fifo_list = (char **)NULL;
2328 static int nfifo;
2329 static int fifo_list_size;
2330
2331 static void
2332 add_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
2345 void
2346 unlink_fifo_list ()
2347 {
2348 if (nfifo == 0)
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
2360 static char *
2361 make_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
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. */
2382 static char *dev_fd_list = (char *)NULL;
2383 static int nfds;
2384 static int totfds; /* The highest possible number of open files. */
2385
2386 static void
2387 add_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
2409 void
2410 unlink_fifo_list ()
2411 {
2412 register int i;
2413
2414 if (nfds == 0)
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)
2429 print_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
2445 static char *
2446 make_dev_fd_filename (fd)
2447 int fd;
2448 {
2449 char *ret;
2450
2451 ret = xmalloc (sizeof (DEV_FD_PREFIX) + 4);
2452 sprintf (ret, "%s%d", DEV_FD_PREFIX, fd);
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
2471 static char *
2472 process_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;
2485 #endif
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 {
2495 sys_error ("cannot make pipe for process substitution");
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];
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
2506 pathname = make_dev_fd_filename (parent_pipe_fd);
2507 #endif /* HAVE_DEV_FD */
2508
2509 if (!pathname)
2510 {
2511 sys_error ("cannot make pipe for process substitution");
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;
2520 #if 0
2521 cleanup_the_pipeline ();
2522 #else
2523 save_pipeline (1);
2524 #endif
2525 #endif /* JOB_CONTROL */
2526
2527 pid = make_child ((char *)NULL, 1);
2528 if (pid == 0)
2529 {
2530 reset_terminating_signals (); /* XXX */
2531 /* Cancel traps, in trap.c. */
2532 restore_original_signals ();
2533 setup_async_signals ();
2534 subshell_environment = SUBSHELL_COMSUB;
2535 }
2536
2537 #if defined (JOB_CONTROL)
2538 set_sigchld_handler ();
2539 stop_making_children ();
2540 pipeline_pgrp = old_pipeline_pgrp;
2541 #endif /* JOB_CONTROL */
2542
2543 if (pid < 0)
2544 {
2545 sys_error ("cannot make child for process substitution");
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 {
2556 #if defined (JOB_CONTROL)
2557 restore_pipeline (1);
2558 #endif
2559
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. */
2581 fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY);
2582 if (fd < 0)
2583 {
2584 sys_error ("cannot open named pipe %s for %s", pathname,
2585 open_for_read_in_child ? "reading" : "writing");
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 {
2594 sys_error ("cannot duplicate named pipe %s as fd %d", pathname,
2595 open_for_read_in_child ? 0 : 1);
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
2617 result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
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
2629 static char *
2630 read_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
2698 /* Perform command substitution on STRING. This returns a string,
2699 possibly quoted. */
2700 static char *
2701 command_substitute (string, quoted)
2702 char *string;
2703 int quoted;
2704 {
2705 pid_t pid, old_pid, old_pipeline_pgrp;
2706 char *istring;
2707 int result, fildes[2];
2708
2709 istring = (char *)NULL;
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 {
2719 sys_error ("cannot make pipes for command substitution");
2720 goto error_exit;
2721 }
2722
2723 old_pid = last_made_pid;
2724 #if defined (JOB_CONTROL)
2725 old_pipeline_pgrp = pipeline_pgrp;
2726 pipeline_pgrp = shell_pgrp;
2727 cleanup_the_pipeline ();
2728 #endif
2729
2730 pid = make_child ((char *)NULL, 0);
2731 if (pid == 0)
2732 /* Reset the signal handlers in the child, but don't free the
2733 trap strings. */
2734 reset_signal_handlers ();
2735
2736 #if defined (JOB_CONTROL)
2737 set_sigchld_handler ();
2738 stop_making_children ();
2739 pipeline_pgrp = old_pipeline_pgrp;
2740 #endif /* JOB_CONTROL */
2741
2742 if (pid < 0)
2743 {
2744 sys_error ("cannot make child for command substitution");
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 {
2761 sys_error ("command_substitute: cannot duplicate pipe as fd 1");
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
2784 /* This is a subshell environment. */
2785 subshell_environment = SUBSHELL_COMSUB;
2786
2787 /* Command substitution does not inherit the -e flag. */
2788 exit_immediately_on_error = 0;
2789
2790 remove_quoted_escapes (string);
2791
2792 startup_state = 2; /* see if we can avoid a fork */
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
2802 exit (parse_and_execute (string, "command substitution", SEVAL_NOHIST));
2803 }
2804 else
2805 {
2806 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
2807 close_pgrp_pipe ();
2808 #endif /* JOB_CONTROL && PGRP_PIPE */
2809
2810 close (fildes[1]);
2811
2812 istring = read_comsub (fildes[0], quoted);
2813
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
2833 return (istring);
2834 }
2835 }
2836
2837 /********************************************************
2838 * *
2839 * Utility functions for parameter expansion *
2840 * *
2841 ********************************************************/
2842
2843 static int
2844 getpatspec (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#'*'}". */
2862 static char *
2863 getpattern (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
2905 /* Handle removing a pattern from a string as a result of ${name%[%]value}
2906 or ${name#[#]value}. */
2907 static char *
2908 parameter_brace_remove_pattern (value, temp, c, quoted)
2909 char *value, *temp;
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
2927 static char *
2928 list_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);
2941 free (tword);
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
2955 static char *
2956 parameter_list_remove_pattern (value, type, c, quoted)
2957 char *value;
2958 int type, c, quoted;
2959 {
2960 int patspec;
2961 char *pattern, *ret;
2962 WORD_LIST *list;
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
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);
2975 }
2976
2977 #if defined (ARRAY_VARS)
2978 static char *
2979 array_remove_pattern (value, aspec, aval, c, quoted)
2980 char *value, *aspec, *aval; /* AVAL == evaluated ASPEC */
2981 int c, quoted;
2982 {
2983 SHELL_VAR *var;
2984 int len, patspec;
2985 #if 0
2986 int ind;
2987 #endif
2988 char *ret, *t, *pattern;
2989 WORD_LIST *l;
2990
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);
3006 FREE (pattern);
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
3016 {
3017 #if 0
3018 ind = array_expand_index (t, len);
3019 if (ind < 0)
3020 {
3021 report_error ("%s: bad array subscript", aspec);
3022 FREE (pattern);
3023 return ((char *)NULL);
3024 }
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)
3034 {
3035 t = quote_escapes (ret);
3036 free (ret);
3037 ret = t;
3038 }
3039 }
3040
3041 FREE (pattern);
3042 return ret;
3043 }
3044
3045 int
3046 valid_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. */
3073 int
3074 array_expand_index (s, len)
3075 char *s;
3076 int len;
3077 {
3078 char *exp, *t;
3079 int val, expok;
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;
3086 val = evalexp (t, &expok);
3087 free (t);
3088 free (exp);
3089 if (expok == 0)
3090 jump_to_top_level (DISCARD);
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. */
3097 SHELL_VAR *
3098 array_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] != ']')
3110 {
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
3126 static char *
3127 array_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)
3163 {
3164 report_error ("%s: bad array subscript", var->name);
3165 return ((char *)NULL);
3166 }
3167 if (array_p (var) == 0)
3168 return (ind == 0 ? savestring (value_cell (var)) : (char *)NULL);
3169 retval = array_reference (array_cell (var), ind);
3170 if (retval)
3171 retval = quote_escapes (retval);
3172 }
3173
3174 return retval;
3175 }
3176
3177 static char *
3178 array_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. */
3189 char *
3190 get_array_value (s, allow_all)
3191 char *s;
3192 int allow_all;
3193 {
3194 return (array_value_internal (s, 0, allow_all));
3195 }
3196
3197 static int
3198 array_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);
3207
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)
3211 {
3212 ind = *--t;
3213 *t = '\0';
3214 report_error ("%s: unbound variable", s);
3215 *t++ = (char)ind;
3216 return (-1);
3217 }
3218 else if (var == 0)
3219 return 0;
3220 else if (array_p (var) == 0)
3221 return 1;
3222
3223 array = array_cell (var);
3224
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);
3238 }
3239 #endif /* ARRAY_VARS */
3240
3241 static int
3242 valid_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;
3250 #if defined (ARRAY_VARS)
3251 else if (valid_array_reference (name))
3252 return 1;
3253 #endif /* ARRAY_VARS */
3254 else if (legal_identifier (name))
3255 return 1;
3256 else
3257 return 0;
3258 }
3259
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. */
3265 static char *
3266 parameter_brace_expand_word (name, var_is_special, quoted)
3267 char *name;
3268 int var_is_special, quoted;
3269 {
3270 char *temp, *tt;
3271 int arg_index;
3272 SHELL_VAR *var;
3273 WORD_LIST *l;
3274
3275 /* Handle multiple digit arguments, as in ${11}. */
3276 if (digit (*name))
3277 {
3278 arg_index = atoi (name);
3279 temp = get_dollar_var_value (arg_index);
3280 }
3281 else if (var_is_special) /* ${@} */
3282 {
3283 tt = xmalloc (2 + strlen (name));
3284 tt[0] = '$';
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 }
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 }
3313 else
3314 temp = (char *)NULL;
3315
3316 return (temp);
3317 }
3318
3319 /* Expand an indirect reference to a variable: ${!NAME} expands to the
3320 value of the variable whose name is the value of NAME. */
3321 static char *
3322 parameter_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
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
3338 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
3339 between double quotes. */
3340 static char *
3341 parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
3342 char *name, *value;
3343 int c, quoted, *qdollaratp, *hasdollarat;
3344 {
3345 WORD_LIST *l;
3346 char *t, *t1, *temp;
3347 int hasdol;
3348
3349 temp = (*value == '~' || (strchr (value, '~') && unquoted_substring ("=~", value)))
3350 ? bash_tilde_expand (value)
3351 : savestring (value);
3352
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)
3357 {
3358 hasdol = 0;
3359 t = string_extract_double_quoted (temp, &hasdol, 1);
3360 free (temp);
3361 temp = t;
3362 }
3363
3364 hasdol = 0;
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);
3370 free (temp);
3371 if (l)
3372 {
3373 /* The expansion of TEMP returned something. We need to treat things
3374 slightly differently if HASDOL is non-zero. */
3375 temp = string_list (l);
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;
3380 dispose_words (l);
3381 }
3382 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol)
3383 {
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. */
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 == '=' */
3399 t = temp ? savestring (temp) : savestring ("");
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. */
3411 static void
3412 parameter_brace_expand_error (name, value)
3413 char *name, *value;
3414 {
3415 WORD_LIST *l;
3416 char *temp;
3417
3418 if (value && *value)
3419 {
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);
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. */
3437 static int
3438 valid_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} */
3444 #if defined (ARRAY_VARS)
3445 valid_array_reference (name + 1) || /* ${#a[7]} */
3446 #endif
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. */
3452 static int
3453 parameter_brace_expand_length (name)
3454 char *name;
3455 {
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
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. */
3512 static int
3513 verify_substring_values (value, substr, vtype, e1p, e2p)
3514 char *value, *substr;
3515 int vtype, *e1p, *e2p;
3516 {
3517 char *t, *temp1;
3518 int len, expok;
3519 #if defined (ARRAY_VARS)
3520 ARRAY *a;
3521 #endif
3522
3523 t = strchr (substr, ':');
3524 if (t)
3525 *t = '\0';
3526 temp1 = maybe_expand_string (substr, Q_DOUBLE_QUOTES, expand_string);
3527 *e1p = evalexp (temp1, &expok);
3528 free (temp1);
3529 if (expok == 0)
3530 return (0);
3531
3532 switch (vtype)
3533 {
3534 case VT_VARIABLE:
3535 case VT_ARRAYMEMBER:
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
3552 if (*e1p >= len || *e1p < 0)
3553 return (-1);
3554
3555 if (t)
3556 {
3557 t++;
3558 temp1 = maybe_expand_string (t, Q_DOUBLE_QUOTES, expand_string);
3559 t[-1] = ':';
3560 *e2p = evalexp (temp1, &expok);
3561 free (temp1);
3562 if (expok == 0)
3563 return (0);
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. */
3582 static char *
3583 pos_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). */
3619 static int
3620 get_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 {
3640 if ((temp[0] == '@' || temp[0] == '*') && temp[1] == ']')
3641 {
3642 vtype = VT_ARRAYVAR;
3643 *valp = (char *)array_cell (v);
3644 }
3645 else
3646 {
3647 vtype = VT_ARRAYMEMBER;
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
3672 static char *
3673 parameter_brace_substring (varname, value, substr, quoted)
3674 char *varname, *value, *substr;
3675 int quoted;
3676 {
3677 int e1, e2, vtype, r;
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
3690 r = verify_substring_values (val, substr, vtype, &e1, &e2);
3691 if (r <= 0)
3692 {
3693 if (val && vtype == VT_ARRAYMEMBER)
3694 free (val);
3695 return ((r == 0) ? &expand_param_error : (char *)NULL);
3696 }
3697
3698 switch (vtype)
3699 {
3700 case VT_VARIABLE:
3701 case VT_ARRAYMEMBER:
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
3717 char *
3718 pat_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)
3758 {
3759 RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
3760 strcpy (ret + rptr, str);
3761 }
3762 else
3763 ret[rptr] = '\0';
3764
3765 return ret;
3766 }
3767
3768 /* Do pattern match and replacement on the positional parameters. */
3769 static char *
3770 pos_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
3797 static char *
3798 parameter_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)
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 }
3844
3845 p = pat;
3846 if (pat && pat[0] == '#')
3847 {
3848 mflags |= MATCH_BEG;
3849 p++;
3850 }
3851 else if (pat && pat[0] == '%')
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:
3865 case VT_ARRAYMEMBER:
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
3878 if (val && v && array_p (v) && vtype == VT_ARRAYMEMBER)
3879 free (val);
3880
3881 FREE (pat);
3882 FREE (rep);
3883
3884 return temp;
3885 }
3886
3887 /* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */
3888 static char *
3889 parameter_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;
4075
4076 *indexp = sindex;
4077
4078 /* If this is a substring spec, process it and add the result. */
4079 if (want_substring)
4080 {
4081 temp1 = parameter_brace_substring (name, temp, value, quoted);
4082 FREE (name);
4083 FREE (value);
4084 FREE (temp);
4085 return (temp1);
4086 }
4087 else if (want_patsub)
4088 {
4089 temp1 = parameter_brace_patsub (name, temp, value, quoted);
4090 FREE (name);
4091 FREE (value);
4092 FREE (temp);
4093 return (temp1);
4094 }
4095
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;
4117 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
4118 }
4119 break;
4120
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. */
4168 }
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);
4190 }
4191 break;
4192 }
4193 free (name);
4194 return (temp);
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
4203 QUOTED contains flag values defined in shell.h.
4204
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
4219 static WORD_LIST *
4220 expand_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 {
4226 WORD_LIST *list;
4227 WORD_DESC *tword;
4228 SHELL_VAR *var;
4229
4230 /* The intermediate string that we build while expanding. */
4231 char *istring;
4232
4233 /* The current size of the above object. */
4234 int istring_size;
4235
4236 /* Index into ISTRING. */
4237 int istring_index;
4238
4239 /* Temporary string storage. */
4240 char *temp, *temp1;
4241
4242 /* The text of WORD. */
4243 register char *string;
4244
4245 /* The index into STRING. */
4246 int sindex;
4247
4248 /* This gets 1 if we see a $@ while quoted. */
4249 int quoted_dollar_at;
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"). */
4254 int quoted_state;
4255
4256 int had_quoted_null;
4257
4258 int expok;
4259
4260 register int c; /* Current character. */
4261 int number; /* Temporary number value. */
4262 int t_index; /* For calls to string_extract_xxx. */
4263
4264 istring = xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
4265 istring[istring_index = 0] = '\0';
4266
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;
4273
4274 if (contains_dollar_at)
4275 *contains_dollar_at = 0;
4276
4277 /* Begin the expansion. */
4278
4279 for (sindex = 0; ;)
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 {
4305 if (string[++sindex] != '(' || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct)
4306 {
4307 sindex--;
4308 goto add_character;
4309 }
4310 else
4311 t_index = sindex + 1; /* skip past both '<' and '(' */
4312
4313 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index);
4314 sindex = t_index;
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. */
4320 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
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':
4357 temp1 = dollar_vars[digit_value (c)];
4358 if (unbound_vars_is_error && temp1 == (char *)NULL)
4359 {
4360 report_error ("$%c: unbound variable", c);
4361 free (string);
4362 free (istring);
4363 last_command_exit_value = EXECUTION_FAILURE;
4364 return (interactive_shell ? &expand_word_error : &expand_word_fatal);
4365 }
4366 temp = temp1 ? savestring (temp1) : (char *)NULL;
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:
4380 if (temp)
4381 {
4382 istring = sub_append_string
4383 (temp, istring, &istring_index, &istring_size);
4384 temp = (char *)0;
4385 }
4386
4387 break;
4388
4389 /* $# -- number of positional parameters. */
4390 case '#':
4391 number = number_of_args ();
4392 goto add_number;
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
4409 /* If no asynchronous pids have been created, expand
4410 to nothing. */
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
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')
4430 {
4431 free (temp);
4432 temp = (char *)NULL;
4433 }
4434 /* In the case of a quoted string, quote the entire arg-list.
4435 "$1 $2 $3". Otherwise quote the special escape characters. */
4436 if (temp)
4437 {
4438 temp1 = temp;
4439 temp = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4440 ? quote_string (temp)
4441 : quote_escapes (temp);
4442 free (temp1);
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 '@': /* `$@' */
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;
4473
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;
4499 /* break; */
4500
4501 /* Do command or arithmetic substitution. */
4502 case '(': /*)*/
4503 /* We have to extract the contents of this paren substitution. */
4504 t_index = sindex + 1;
4505 temp = extract_command_subst (string, &t_index);
4506 sindex = t_index;
4507
4508 /* For Posix.2-style `$(( ))' arithmetic substitution,
4509 extract the expression and pass it to the evaluator. */
4510 if (temp && *temp == '(')
4511 {
4512 char *temp2;
4513 temp1 = temp + 1;
4514 temp2 = savestring (temp1);
4515 t_index = strlen (temp2) - 1;
4516
4517 if (temp2[t_index] != ')')
4518 {
4519 free (temp2);
4520 #if 0
4521 report_error ("%s: bad arithmetic substitution", temp);
4522 free (temp);
4523 free (string);
4524 free (istring);
4525 return (&expand_word_error);
4526 #else
4527 goto comsub;
4528 #endif
4529 }
4530
4531 /* Cut off ending `)' */
4532 temp2[t_index] = '\0';
4533
4534 /* Expand variables found inside the expression. */
4535 temp1 = maybe_expand_string (temp2, Q_DOUBLE_QUOTES, expand_string);
4536 free (temp2);
4537
4538 /* No error messages. */
4539 this_command_name = (char *)NULL;
4540 number = evalexp (temp1, &expok);
4541 free (temp);
4542 free (temp1);
4543 if (expok == 0)
4544 {
4545 free (string);
4546 free (istring);
4547 return (&expand_word_error);
4548 }
4549 goto add_number;
4550 }
4551
4552 comsub:
4553 temp1 = command_substitute (temp, quoted);
4554 FREE (temp);
4555 temp = temp1;
4556 goto dollar_add_string;
4557
4558 /* Do straight arithmetic substitution. */
4559 case '[':
4560 /* We have to extract the contents of this
4561 arithmetic substitution. */
4562 t_index = sindex + 1;
4563 temp = extract_arithmetic_subst (string, &t_index);
4564 sindex = t_index;
4565
4566 /* Do initial variable expansion. */
4567 temp1 = maybe_expand_string (temp, Q_DOUBLE_QUOTES, expand_string);
4568
4569 /* No error messages. */
4570 this_command_name = (char *)NULL;
4571 number = evalexp (temp1, &expok);
4572 free (temp1);
4573 free (temp);
4574 if (expok == 0)
4575 {
4576 free (string);
4577 free (istring);
4578 return (&expand_word_error);
4579 }
4580 goto add_number;
4581
4582 default:
4583 /* Find the variable in VARIABLE_LIST. */
4584 temp = (char *)NULL;
4585
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);
4636 return ((unbound_vars_is_error && interactive_shell == 0)
4637 ? &expand_word_fatal
4638 : &expand_word_error);
4639 }
4640 break; /* End case '$': */
4641
4642 case '`': /* Backquoted command substitution. */
4643 {
4644 sindex++;
4645
4646 if (expanded_something)
4647 *expanded_something = 1;
4648
4649 temp = string_extract (string, &sindex, "`", 0);
4650 de_backslash (temp);
4651 temp1 = command_substitute (temp, quoted);
4652 FREE (temp);
4653 temp = temp1;
4654 goto dollar_add_string;
4655 }
4656
4657 case '\\':
4658 if (string[sindex + 1] == '\n')
4659 {
4660 sindex += 2;
4661 continue;
4662 }
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 }
4678 else
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)
4700 {
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);
4708
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 }
4719
4720 dispose_word (tword);
4721
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)
4726 {
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);
4772 goto add_string;
4773 }
4774 else
4775 {
4776 temp = savestring (list->word->word);
4777 dispose_words (list);
4778 }
4779 }
4780 else
4781 temp = (char *)NULL;
4782
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 }
4790
4791 add_quoted_string:
4792
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; */
4808
4809 case '\'':
4810 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE))
4811 goto add_character;
4812
4813 t_index = ++sindex;
4814 temp = string_extract_single_quoted (string, &sindex);
4815
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;
4821
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);
4830
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;
4835
4836 goto add_quoted_string;
4837 /* break; */
4838
4839 default:
4840 /* This is the fix for " $@ " */
4841 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4842 {
4843 temp = make_quoted_char (c);
4844 goto dollar_add_string;
4845 }
4846
4847 add_character:
4848 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
4849 DEFAULT_ARRAY_SIZE);
4850 istring[istring_index++] = c;
4851 istring[istring_index] = '\0';
4852
4853 /* Next character. */
4854 sindex++;
4855 }
4856 }
4857
4858 finished_with_string:
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. */
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))
4888 {
4889 istring[0] = CTLNUL;
4890 istring[1] = '\0';
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;
4895 }
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
4903 {
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;
4908 }
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)
4925 {
4926 var = find_variable ("IFS");
4927 ifs_chars = var ? value_cell (var) : " \t\n";
4928 }
4929 else
4930 ifs_chars = (char *)NULL;
4931
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;
4946 }
4947 }
4948
4949 free (istring);
4950 return (list);
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. */
4961 char *
4962 string_quote_removal (string, quoted)
4963 char *string;
4964 int quoted;
4965 {
4966 char *r, *result_string, *temp;
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
4972 for (dquote = sindex = 0; c = string[sindex];)
4973 {
4974 switch (c)
4975 {
4976 case '\\':
4977 c = string[++sindex];
4978 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && member (c, slashify_in_quotes) == 0)
4979 *r++ = '\\';
4980 /* FALLTHROUGH */
4981
4982 default:
4983 *r++ = c;
4984 sindex++;
4985 break;
4986
4987 case '\'':
4988 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
4989 {
4990 *r++ = c;
4991 sindex++;
4992 break;
4993 }
4994 tindex = sindex + 1;
4995 temp = string_extract_single_quoted (string, &tindex);
4996 if (temp)
4997 {
4998 strcpy (r, temp);
4999 r += strlen (r);
5000 free (temp);
5001 }
5002 sindex = tindex;
5003 break;
5004
5005 case '"':
5006 dquote = 1 - dquote;
5007 sindex++;
5008 break;
5009 }
5010 }
5011 *r = '\0';
5012 return (result_string);
5013 }
5014
5015 #if 0
5016 /* UNUSED */
5017 /* Perform quote removal on word WORD. This allocates and returns a new
5018 WORD_DESC *. */
5019 WORD_DESC *
5020 word_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);
5028 w = make_bare_word (t);
5029 free (t);
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. */
5036 WORD_LIST *
5037 word_list_quote_removal (list, quoted)
5038 WORD_LIST *list;
5039 int quoted;
5040 {
5041 WORD_LIST *result, *t, *tresult;
5042
5043 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
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);
5049 }
5050 return (result);
5051 }
5052 #endif
5053
5054 /* Return 1 if CHARACTER appears in an unquoted portion of
5055 STRING. Return 0 otherwise. */
5056 static int
5057 unquoted_member (character, string)
5058 int character;
5059 char *string;
5060 {
5061 int sindex, c;
5062
5063 for (sindex = 0; c = string[sindex]; )
5064 {
5065 if (c == character)
5066 return (1);
5067
5068 switch (c)
5069 {
5070 default:
5071 sindex++;
5072 break;
5073
5074 case '\\':
5075 sindex++;
5076 if (string[sindex])
5077 sindex++;
5078 break;
5079
5080 case '\'':
5081 sindex = skip_single_quoted (string, ++sindex);
5082 break;
5083
5084 case '"':
5085 sindex = skip_double_quoted (string, ++sindex);
5086 break;
5087 }
5088 }
5089 return (0);
5090 }
5091
5092 /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
5093 static int
5094 unquoted_substring (substr, string)
5095 char *substr, *string;
5096 {
5097 int sindex, c, sublen;
5098
5099 if (substr == 0 || *substr == '\0')
5100 return (0);
5101
5102 sublen = strlen (substr);
5103 for (sindex = 0; c = string[sindex]; )
5104 {
5105 if (STREQN (string + sindex, substr, sublen))
5106 return (1);
5107
5108 switch (c)
5109 {
5110 case '\\':
5111 sindex++;
5112
5113 if (string[sindex])
5114 sindex++;
5115 break;
5116
5117 case '\'':
5118 sindex = skip_single_quoted (string, ++sindex);
5119 break;
5120
5121 case '"':
5122 sindex = skip_double_quoted (string, ++sindex);
5123 break;
5124
5125 default:
5126 sindex++;
5127 break;
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. */
5142 WORD_LIST *
5143 word_split (w)
5144 WORD_DESC *w;
5145 {
5146 WORD_LIST *result;
5147 SHELL_VAR *ifs;
5148 char *ifs_chars;
5149
5150 if (w)
5151 {
5152 ifs = find_variable ("IFS");
5153 /* If IFS is unset, it defaults to " \t\n". */
5154 ifs_chars = ifs ? value_cell (ifs) : " \t\n";
5155
5156 if ((w->flags & W_QUOTED) || !ifs_chars)
5157 ifs_chars = "";
5158
5159 result = list_string (w->word, ifs_chars, w->flags & W_QUOTED);
5160 }
5161 else
5162 result = (WORD_LIST *)NULL;
5163
5164 return (result);
5165 }
5166
5167 /* Perform word splitting on LIST and return the RESULT. It is possible
5168 to return (WORD_LIST *)NULL. */
5169 static WORD_LIST *
5170 word_list_split (list)
5171 WORD_LIST *list;
5172 {
5173 WORD_LIST *result, *t, *tresult;
5174
5175 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
5176 {
5177 tresult = word_split (t->word);
5178 result = (WORD_LIST *) list_append (result, tresult);
5179 }
5180 return (result);
5181 }
5182
5183 /**************************************************
5184 * *
5185 * Functions to expand an entire WORD_LIST *
5186 * *
5187 **************************************************/
5188
5189 static 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. */
5195 static WORD_LIST *
5196 separate_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 */
5213 while (lp && (lp->word->flags & W_ASSIGNMENT))
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); */
5237 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
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 {
5252 if (lp->word->flags & W_ASSIGNMENT)
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
5284 WORD_LIST *
5285 expand_words (list)
5286 WORD_LIST *list;
5287 {
5288 return (expand_word_list_internal (list, 1));
5289 }
5290
5291 /* Same as expand_words (), but doesn't hack variable or environment
5292 variables. */
5293 WORD_LIST *
5294 expand_words_no_vars (list)
5295 WORD_LIST *list;
5296 {
5297 return (expand_word_list_internal (list, 0));
5298 }
5299
5300 /* The workhorse for expand_words () and expand_words_no_vars ().
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,
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. */
5311 static WORD_LIST *
5312 expand_word_list_internal (list, do_vars)
5313 WORD_LIST *list;
5314 int do_vars;
5315 {
5316 WORD_LIST *tlist, *new_list, *next, *temp_list, *orig_list, *disposables;
5317 char *temp_string;
5318 int tint;
5319
5320 if (list == 0)
5321 return ((WORD_LIST *)NULL);
5322
5323 tlist = copy_word_list (list);
5324
5325 if (do_vars)
5326 {
5327 tlist = separate_out_assignments (tlist);
5328 if (tlist == 0)
5329 {
5330 if (varlist)
5331 {
5332 /* All the words were variable assignments, so they are placed
5333 into the shell's environment. */
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 }
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. */
5359 if (brace_expansion && tlist)
5360 {
5361 register char **expansions;
5362 WORD_LIST *braces;
5363 WORD_DESC *w;
5364 int eindex;
5365
5366 for (braces = disposables = (WORD_LIST *)NULL; tlist; tlist = next)
5367 {
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
5381 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
5382 {
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);
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 }
5404 }
5405
5406 dispose_words (disposables);
5407 tlist = REVERSE_LIST (braces, WORD_LIST *);
5408 }
5409 #endif /* BRACE_EXPANSION */
5410
5411 /* We do tilde expansion all the time. This is what 1003.2 says. */
5412 for (orig_list = tlist, new_list = (WORD_LIST *)NULL; tlist; tlist = next)
5413 {
5414 WORD_LIST *expanded;
5415 int expanded_something, has_dollar_at;
5416
5417 temp_string = tlist->word->word;
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
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))))
5431 {
5432 tlist->word->word = bash_tilde_expand (temp_string);
5433 free (temp_string);
5434 }
5435
5436 expanded_something = 0;
5437 expanded = expand_word_internal
5438 (tlist->word, 0, &has_dollar_at, &expanded_something);
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;
5445
5446 /* Dispose our copy of the original list. */
5447 dispose_words (orig_list);
5448 /* Dispose the new list we're building. */
5449 dispose_words (new_list);
5450
5451 if (expanded == &expand_word_error)
5452 jump_to_top_level (DISCARD);
5453 else
5454 jump_to_top_level (FORCE_EOF);
5455 }
5456
5457 /* Don't split words marked W_NOSPLIT. */
5458 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
5459 {
5460 temp_list = word_list_split (expanded);
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);
5470 temp_list = expanded;
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. */
5475 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
5476 new_list = (WORD_LIST *)list_append (expanded, new_list);
5477 }
5478
5479 new_list = REVERSE_LIST (new_list, WORD_LIST *);
5480
5481 dispose_words (orig_list);
5482
5483 /* Okay, we're almost done. Now let's just do some filename
5484 globbing. */
5485 if (new_list)
5486 {
5487 char **glob_array;
5488 register int glob_index;
5489 WORD_LIST *glob_list;
5490 WORD_DESC *tword;
5491
5492 orig_list = disposables = (WORD_LIST *)NULL;
5493 tlist = new_list;
5494
5495 /* orig_list == output list, despite the name. */
5496 if (disallow_filename_globbing == 0)
5497 {
5498 glob_array = (char **)NULL;
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. */
5512 next = tlist->next;
5513
5514 /* If the word isn't an assignment and contains an unquoted
5515 pattern matching character, then glob it. */
5516 #if 0
5517 if ((tlist->word->flags & (W_QUOTED|W_ASSIGNMENT)) == 0 &&
5518 #else
5519 if ((tlist->word->flags & W_ASSIGNMENT) == 0 &&
5520 #endif
5521 unquoted_glob_pattern_p (tlist->word->word))
5522 {
5523 glob_array = shell_glob_filename (tlist->word->word);
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
5530 if (GLOB_FAILED (glob_array))
5531 {
5532 glob_array = (char **) xmalloc (sizeof (char *));
5533 glob_array[0] = (char *)NULL;
5534 }
5535
5536 /* Dequote the current word in case we have to use it. */
5537 if (glob_array[0] == NULL)
5538 {
5539 temp_string = dequote_string (tlist->word->word);
5540 free (tlist->word->word);
5541 tlist->word->word = temp_string;
5542 }
5543
5544 /* Make the array into a word list. */
5545 glob_list = (WORD_LIST *)NULL;
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 }
5552
5553 if (glob_list)
5554 {
5555 orig_list = (WORD_LIST *)list_append (glob_list, orig_list);
5556 tlist->next = disposables;
5557 disposables = tlist;
5558 }
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 }
5565 else
5566 {
5567 /* Failed glob expressions are removed. */
5568 tlist->next = disposables;
5569 disposables = tlist;
5570 }
5571 }
5572 else
5573 {
5574 /* Dequote the string. */
5575 temp_string = dequote_string (tlist->word->word);
5576 free (tlist->word->word);
5577 tlist->word->word = temp_string;
5578 tlist->next = orig_list;
5579 orig_list = tlist;
5580 }
5581
5582 free_array (glob_array);
5583 glob_array = (char **)NULL;
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. */
5596 for (temp_list = new_list; temp_list; temp_list = temp_list->next)
5597 {
5598 temp_string = dequote_string (temp_list->word->word);
5599 free (temp_list->word->word);
5600 temp_list->word->word = temp_string;
5601 }
5602 }
5603 }
5604
5605 if (do_vars)
5606 {
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
5614 for (temp_list = varlist; temp_list; temp_list = temp_list->next)
5615 {
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 }
5626 }
5627
5628 dispose_words (varlist);
5629 varlist = (WORD_LIST *)NULL;
5630 }
5631
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';
5637
5638 return (new_list);
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
5652 #define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0
5653
5654 struct 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 },
5664 { "GLOBIGNORE", sv_globignore },
5665
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 },
5671 { "HOSTFILE", sv_hostfile },
5672 #endif /* READLINE */
5673
5674 /* Variables which only do something special when HISTORY is defined. */
5675 #if defined (HISTORY)
5676 { "HISTIGNORE", sv_histignore },
5677 { "HISTSIZE", sv_histsize },
5678 { "HISTFILESIZE", sv_histsize },
5679 { "HISTCONTROL", sv_history_control },
5680 # if defined (BANG_HISTORY)
5681 { "histchars", sv_histchars },
5682 # endif /* BANG_HISTORY */
5683 #endif /* HISTORY */
5684
5685 { "IGNOREEOF", sv_ignoreeof },
5686 { "ignoreeof", sv_ignoreeof },
5687
5688 { "OPTIND", sv_optind },
5689 { "OPTERR", sv_opterr },
5690
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 }
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. */
5708 void
5709 stupidly_hack_special_variables (name)
5710 char *name;
5711 {
5712 int i;
5713
5714 for (i = 0; special_vars[i].name; i++)
5715 {
5716 if (STREQ (special_vars[i].name, name))
5717 {
5718 (*(special_vars[i].function)) (name);
5719 return;
5720 }
5721 }
5722 }
5723
5724 /* What to do just after the PATH variable has changed. */
5725 void
5726 sv_path (name)
5727 char *name;
5728 {
5729 /* hash -r */
5730 flush_hashed_filenames ();
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. */
5736 void
5737 sv_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
5753 /* What to do when GLOBIGNORE changes. */
5754 void
5755 sv_globignore (name)
5756 char *name;
5757 {
5758 setup_glob_ignore (name);
5759 }
5760
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. */
5765 void
5766 sv_terminal (name)
5767 char *name;
5768 {
5769 if (interactive_shell && no_line_editing == 0)
5770 rl_reset_terminal (get_string_value ("TERM"));
5771 }
5772
5773 void
5774 sv_hostfile (name)
5775 char *name;
5776 {
5777 hostname_list_initialized = 0;
5778 }
5779 #endif /* READLINE */
5780
5781 #if defined (HISTORY)
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
5784 the history. Otherwise, if there is NO value for this variable,
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. */
5788 void
5789 sv_histsize (name)
5790 char *name;
5791 {
5792 char *temp;
5793 long num;
5794
5795 temp = get_string_value (name);
5796
5797 if (temp && *temp)
5798 {
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 }
5814 }
5815 }
5816 else if (name[4] == 'S')
5817 unstifle_history ();
5818 }
5819
5820 /* What to do after the HISTIGNORE variable changes. */
5821 void
5822 sv_histignore (name)
5823 char *name;
5824 {
5825 setup_history_ignore (name);
5826 }
5827
5828 /* What to do after the HISTCONTROL variable changes. */
5829 void
5830 sv_history_control (name)
5831 char *name;
5832 {
5833 char *temp;
5834
5835 history_control = 0;
5836 temp = get_string_value (name);
5837
5838 if (temp && *temp && STREQN (temp, "ignore", 6))
5839 {
5840 if (temp[6] == 's') /* ignorespace */
5841 history_control = 1;
5842 else if (temp[6] == 'd') /* ignoredups */
5843 history_control = 2;
5844 else if (temp[6] == 'b') /* ignoreboth */
5845 history_control = 3;
5846 }
5847 }
5848
5849 #if defined (BANG_HISTORY)
5850 /* Setting/unsetting of the history expansion character. */
5851 void
5852 sv_histchars (name)
5853 char *name;
5854 {
5855 char *temp;
5856
5857 temp = get_string_value (name);
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 }
5875 #endif /* BANG_HISTORY */
5876 #endif /* HISTORY */
5877
5878 #if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
5879 void
5880 sv_tz (name)
5881 char *name;
5882 {
5883 tzset ();
5884 }
5885 #endif
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). */
5890 void
5891 sv_ignoreeof (name)
5892 char *name;
5893 {
5894 SHELL_VAR *tmp_var;
5895 char *temp;
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)
5903 eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
5904 set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */
5905 }
5906
5907 void
5908 sv_optind (name)
5909 char *name;
5910 {
5911 char *tt;
5912 int s;
5913
5914 tt = get_string_value ("OPTIND");
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 }
5924 else
5925 s = 0;
5926 getopts_reset (s);
5927 }
5928
5929 void
5930 sv_opterr (name)
5931 char *name;
5932 {
5933 char *tt;
5934
5935 tt = get_string_value ("OPTERR");
5936 sh_opterr = (tt && *tt) ? atoi (tt) : 1;
5937 }
5938
5939 void
5940 sv_strict_posix (name)
5941 char *name;
5942 {
5943 SET_INT_VAR (name, posixly_correct);
5944 posix_initialize (posixly_correct);
5945 #if defined (READLINE)
5946 if (interactive_shell)
5947 posix_readline_initialize (posixly_correct);
5948 #endif /* READLINE */
5949 set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */
5950 }
5951
5952 void
5953 sv_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 }