]> git.ipfire.org Git - thirdparty/bash.git/blob - subst.c
Imported from ../bash-2.01.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 static int
3511 verify_substring_values (value, substr, vtype, e1p, e2p)
3512 char *value, *substr;
3513 int vtype, *e1p, *e2p;
3514 {
3515 char *t, *temp1;
3516 int len, expok;
3517 #if defined (ARRAY_VARS)
3518 ARRAY *a;
3519 #endif
3520
3521 t = strchr (substr, ':');
3522 if (t)
3523 *t = '\0';
3524 temp1 = maybe_expand_string (substr, Q_DOUBLE_QUOTES, expand_string);
3525 *e1p = evalexp (temp1, &expok);
3526 free (temp1);
3527 if (expok == 0)
3528 return (0);
3529
3530 switch (vtype)
3531 {
3532 case VT_VARIABLE:
3533 case VT_ARRAYMEMBER:
3534 len = strlen (value);
3535 break;
3536 case VT_POSPARMS:
3537 len = number_of_args () + 1;
3538 break;
3539 #if defined (ARRAY_VARS)
3540 case VT_ARRAYVAR:
3541 a = (ARRAY *)value;
3542 len = array_num_elements (a) + 1;
3543 break;
3544 #endif
3545 }
3546
3547 if (*e1p < 0) /* negative offsets count from end */
3548 *e1p += len;
3549
3550 if (*e1p >= len || *e1p < 0)
3551 return (0);
3552
3553 if (t)
3554 {
3555 t++;
3556 temp1 = maybe_expand_string (t, Q_DOUBLE_QUOTES, expand_string);
3557 t[-1] = ':';
3558 *e2p = evalexp (temp1, &expok);
3559 free (temp1);
3560 if (expok == 0)
3561 return (0);
3562 if (*e2p < 0)
3563 {
3564 internal_error ("%s: substring expression < 0", t);
3565 return (0);
3566 }
3567 *e2p += *e1p; /* want E2 chars starting at E1 */
3568 if (*e2p > len)
3569 *e2p = len;
3570 }
3571 else
3572 *e2p = len;
3573
3574 return (1);
3575 }
3576
3577 /* Return a string containing the positional parameters from START to
3578 END, inclusive. If STRING[0] == '*', we obey the rules for $*,
3579 which only makes a difference if QUOTED is non-zero. */
3580 static char *
3581 pos_params (string, start, end, quoted)
3582 char *string;
3583 int start, end, quoted;
3584 {
3585 WORD_LIST *save, *params, *h, *t;
3586 char *ret;
3587 int i;
3588
3589 save = params = list_rest_of_args ();
3590 if (save == 0)
3591 return ((char *)NULL);
3592
3593 for (i = 1; params && i < start; i++)
3594 params = params->next;
3595 if (params == 0)
3596 return ((char *)NULL);
3597 for (h = t = params; params && i < end; i++)
3598 {
3599 t = params;
3600 params = params->next;
3601 }
3602
3603 t->next = (WORD_LIST *)NULL;
3604 if (string[0] == '*')
3605 ret = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? string_list_dollar_star (h) : string_list (h);
3606 else
3607 ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (h) : h);
3608 t->next = params;
3609
3610 dispose_words (save);
3611 return (ret);
3612 }
3613
3614 /* Return the type of variable specified by VARNAME (simple variable,
3615 positional param, or array variable. Also return the value specified
3616 by VARNAME (value of a variable or a reference to an array element). */
3617 static int
3618 get_var_and_type (varname, value, varp, valp)
3619 char *varname, *value;
3620 SHELL_VAR **varp;
3621 char **valp;
3622 {
3623 int vtype;
3624 char *temp;
3625 #if defined (ARRAY_VARS)
3626 SHELL_VAR *v;
3627 #endif
3628
3629 vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0'; /* VT_POSPARMS */
3630 *varp = (SHELL_VAR *)NULL;
3631
3632 #if defined (ARRAY_VARS)
3633 if (valid_array_reference (varname))
3634 {
3635 v = array_variable_part (varname, &temp, (int *)0);
3636 if (v && array_p (v))
3637 {
3638 if ((temp[0] == '@' || temp[0] == '*') && temp[1] == ']')
3639 {
3640 vtype = VT_ARRAYVAR;
3641 *valp = (char *)array_cell (v);
3642 }
3643 else
3644 {
3645 vtype = VT_ARRAYMEMBER;
3646 *valp = array_value (varname, 1);
3647 }
3648 *varp = v;
3649 }
3650 else
3651 return -1;
3652 }
3653 else if ((v = find_variable (varname)) && array_p (v))
3654 {
3655 vtype = VT_VARIABLE;
3656 *varp = v;
3657 *valp = array_reference (array_cell (v), 0);
3658 }
3659 else
3660 #endif
3661 *valp = value;
3662
3663 return vtype;
3664 }
3665
3666 /* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
3667 is `@', use the positional parameters; otherwise, use the value of
3668 VARNAME. If VARNAME is an array variable, use the array elements. */
3669
3670 static char *
3671 parameter_brace_substring (varname, value, substr, quoted)
3672 char *varname, *value, *substr;
3673 int quoted;
3674 {
3675 int e1, e2, vtype;
3676 char *temp, *val;
3677 SHELL_VAR *v;
3678
3679 if (value == 0)
3680 return ((char *)NULL);
3681
3682 this_command_name = varname;
3683
3684 vtype = get_var_and_type (varname, value, &v, &val);
3685 if (vtype == -1)
3686 return ((char *)NULL);
3687
3688 if (verify_substring_values (val, substr, vtype, &e1, &e2) == 0)
3689 {
3690 if (val && vtype == VT_ARRAYMEMBER)
3691 free (val);
3692 return (&expand_param_error);
3693 }
3694
3695 switch (vtype)
3696 {
3697 case VT_VARIABLE:
3698 case VT_ARRAYMEMBER:
3699 temp = quoted ? quoted_substring (value, e1, e2) : substring (value, e1, e2);
3700 break;
3701 case VT_POSPARMS:
3702 temp = pos_params (varname, e1, e2, quoted);
3703 break;
3704 #if defined (ARRAY_VARS)
3705 case VT_ARRAYVAR:
3706 temp = array_subrange (array_cell (v), e1, e2, quoted);
3707 break;
3708 #endif
3709 }
3710
3711 return temp;
3712 }
3713
3714 char *
3715 pat_subst (string, pat, rep, mflags)
3716 char *string, *pat, *rep;
3717 int mflags;
3718 {
3719 char *ret, *s, *e, *str;
3720 int rsize, rptr, l, replen, mtype;
3721
3722 ret = xmalloc (rsize = 64);
3723 ret[0] = '\0';
3724
3725 mtype = mflags & MATCH_TYPEMASK;
3726
3727 for (replen = STRLEN (rep), rptr = 0, str = string;;)
3728 {
3729 if (match_pattern (str, pat, mtype, &s, &e) == 0)
3730 break;
3731 l = s - str;
3732 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + replen), rsize, 64);
3733
3734 /* OK, now copy the leading unmatched portion of the string (from
3735 str to s) to ret starting at rptr (the current offset). Then copy
3736 the replacement string at ret + rptr + (s - str). Increment
3737 rptr (if necessary) and str and go on. */
3738 if (l)
3739 {
3740 strncpy (ret + rptr, str, l);
3741 rptr += l;
3742 }
3743 if (replen)
3744 {
3745 strncpy (ret + rptr, rep, replen);
3746 rptr += replen;
3747 }
3748 str = e; /* e == end of match */
3749 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
3750 break;
3751 }
3752
3753 /* Now copy the unmatched portion of the input string */
3754 if (*str)
3755 {
3756 RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
3757 strcpy (ret + rptr, str);
3758 }
3759 else
3760 ret[rptr] = '\0';
3761
3762 return ret;
3763 }
3764
3765 /* Do pattern match and replacement on the positional parameters. */
3766 static char *
3767 pos_params_pat_subst (string, pat, rep, mflags)
3768 char *string, *pat, *rep;
3769 int mflags;
3770 {
3771 WORD_LIST *save, *params;
3772 WORD_DESC *w;
3773 char *ret;
3774
3775 save = params = list_rest_of_args ();
3776 if (save == 0)
3777 return ((char *)NULL);
3778
3779 for ( ; params; params = params->next)
3780 {
3781 ret = pat_subst (params->word->word, pat, rep, mflags);
3782 w = make_bare_word (ret);
3783 dispose_word (params->word);
3784 params->word = w;
3785 FREE (ret);
3786 }
3787
3788 ret = string_list ((mflags & MATCH_QUOTED) ? quote_list (save) : save);
3789 dispose_words (save);
3790
3791 return (ret);
3792 }
3793
3794 static char *
3795 parameter_brace_patsub (varname, value, patsub, quoted)
3796 char *varname, *value, *patsub;
3797 int quoted;
3798 {
3799 int vtype, mflags;
3800 char *val, *temp, *pat, *rep, *p;
3801 SHELL_VAR *v;
3802
3803 if (value == 0)
3804 return ((char *)NULL);
3805
3806 this_command_name = varname;
3807
3808 vtype = get_var_and_type (varname, value, &v, &val);
3809 if (vtype == -1)
3810 return ((char *)NULL);
3811
3812 mflags = 0;
3813 if (*patsub == '/')
3814 {
3815 mflags |= MATCH_GLOBREP;
3816 patsub++;
3817 }
3818
3819 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
3820 mflags |= MATCH_QUOTED;
3821
3822 if (rep = quoted_strchr (patsub, '/', ST_BACKSL))
3823 *rep++ = '\0';
3824 else
3825 rep = (char *)NULL;
3826
3827 if (rep && *rep == '\0')
3828 rep = (char *)NULL;
3829
3830 /* Expand PAT and REP for command, variable and parameter, arithmetic,
3831 and process substitution. Also perform quote removal. Do not
3832 perform word splitting or filename generation. */
3833 pat = maybe_expand_string (patsub, quoted, expand_string_unsplit);
3834 if (rep)
3835 {
3836 if ((mflags & MATCH_QUOTED) == 0)
3837 rep = maybe_expand_string (rep, quoted, expand_string_unsplit);
3838 else
3839 rep = expand_string_to_string (rep, quoted, expand_string_unsplit);
3840 }
3841
3842 p = pat;
3843 if (pat && pat[0] == '#')
3844 {
3845 mflags |= MATCH_BEG;
3846 p++;
3847 }
3848 else if (pat && pat[0] == '%')
3849 {
3850 mflags |= MATCH_END;
3851 p++;
3852 }
3853 else
3854 mflags |= MATCH_ANY;
3855
3856 /* OK, we now want to substitute REP for PAT in VAL. If GLOBAL is 1,
3857 the substitution is done everywhere, otherwise only the first
3858 occurrence of PAT is replaced. */
3859 switch (vtype)
3860 {
3861 case VT_VARIABLE:
3862 case VT_ARRAYMEMBER:
3863 temp = pat_subst (val, p, rep, mflags);
3864 break;
3865 case VT_POSPARMS:
3866 temp = pos_params_pat_subst (val, p, rep, mflags);
3867 break;
3868 #if defined (ARRAY_VARS)
3869 case VT_ARRAYVAR:
3870 temp = array_pat_subst (array_cell (v), p, rep, mflags);
3871 break;
3872 #endif
3873 }
3874
3875 if (val && v && array_p (v) && vtype == VT_ARRAYMEMBER)
3876 free (val);
3877
3878 FREE (pat);
3879 FREE (rep);
3880
3881 return temp;
3882 }
3883
3884 /* ${[#][!]name[[:]#[#]%[%]-=?+[word][:e1[:e2]]]} */
3885 static char *
3886 parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_dollar_at)
3887 char *string;
3888 int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at;
3889 {
3890 int check_nullness, var_is_set, var_is_null, var_is_special;
3891 int want_substring, want_indir, want_patsub;
3892 char *name, *value, *temp, *temp1;
3893 int t_index, sindex, c, number;
3894
3895 sindex = *indexp;
3896 t_index = ++sindex;
3897 name = string_extract (string, &t_index, "#%:-=?+/}", 1);
3898 value = (char *)NULL;
3899 var_is_set = var_is_null = var_is_special = check_nullness = 0;
3900 want_substring = want_indir = want_patsub = 0;
3901
3902 /* If the name really consists of a special variable, then
3903 make sure that we have the entire name. Handle indirect
3904 references to special variables here, too. */
3905 if ((sindex == t_index ||
3906 ((sindex == t_index - 1) && string[sindex] == '!')) &&
3907 (string[t_index] == '-' ||
3908 string[t_index] == '?' ||
3909 string[t_index] == '#'))
3910 {
3911 t_index++;
3912 free (name);
3913 temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
3914 name = xmalloc (3 + (strlen (temp1)));
3915 *name = string[sindex];
3916 if (string[sindex] == '!')
3917 {
3918 /* indirect ref. of special variable */
3919 name[1] = string[sindex + 1];
3920 strcpy (name + 2, temp1);
3921 }
3922 else
3923 strcpy (name + 1, temp1);
3924 free (temp1);
3925 }
3926 sindex = t_index;
3927
3928 /* Find out what character ended the variable name. Then
3929 do the appropriate thing. */
3930 if (c = string[sindex])
3931 sindex++;
3932
3933 /* If c is followed by one of the valid parameter expansion
3934 characters, move past it as normal. If not, assume that
3935 a substring specification is being given, and do not move
3936 past it. */
3937 if (c == ':' && member (string[sindex], "-=?+"))
3938 {
3939 check_nullness++;
3940 if (c = string[sindex])
3941 sindex++;
3942 }
3943 else if (c == ':')
3944 want_substring = 1;
3945 else if (c == '/')
3946 want_patsub = 1;
3947
3948 want_indir = *name == '!';
3949
3950 /* Determine the value of this variable. */
3951
3952 /* Check for special variables, directly and indirectly
3953 referenced. */
3954 if ((digit (*name) && all_digits (name)) ||
3955 (name[1] == '\0' && member (*name, "#-?$!@*")) ||
3956 (want_indir && name[2] == '\0' && member (name[1], "#-?$!@*")))
3957 var_is_special++;
3958
3959 /* Check for special expansion things. */
3960 if (*name == '#') /* length of a parameter */
3961 {
3962 /* Take the lengths of some of the shell's special
3963 parameters. */
3964 if (string[sindex] == '}' && name[1] == '\0' &&
3965 check_nullness == 0 && member (c, "-?$!#"))
3966 {
3967 free (name);
3968 switch (c)
3969 {
3970 case '-':
3971 temp1 = which_set_flags ();
3972 break;
3973 case '?':
3974 temp1 = itos (last_command_exit_value);
3975 break;
3976 case '$':
3977 temp1 = itos (dollar_dollar_pid);
3978 break;
3979 case '!':
3980 if (last_asynchronous_pid == NO_PID)
3981 temp1 = (char *)NULL;
3982 else
3983 temp1 = itos ((int)last_asynchronous_pid);
3984 break;
3985 case '#':
3986 temp1 = itos (number_of_args ());
3987 break;
3988 }
3989 number = STRLEN (temp1);
3990 FREE (temp1);
3991 *indexp = ++sindex; /* { string[sindex] == '}' */
3992 return (itos (number));
3993 }
3994
3995 /* Don't allow things like ${#:-foo} to go by; they are
3996 errors. If we are not pointing at the character just
3997 after the closing brace, then we haven't gotten all of
3998 the name. Since it begins with a special character,
3999 this is a bad substitution. Explicitly check for ${#:},
4000 which the rules do not catch. Also check NAME for
4001 validity before trying to go on. */
4002 if (string[sindex - 1] != '}' ||
4003 member (c, "?-=+") ||
4004 (name[1] == '\0' && c == '}' && check_nullness) ||
4005 (valid_length_expression (name) == 0))
4006 {
4007 temp = (char *)NULL;
4008 goto bad_substitution;
4009 }
4010
4011 number = parameter_brace_expand_length (name);
4012 free (name);
4013
4014 *indexp = sindex;
4015 return ((number < 0) ? &expand_param_error : itos (number));
4016 }
4017
4018 /* ${@} is identical to $@. */
4019 if (name[0] == '@' && name[1] == '\0')
4020 {
4021 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4022 *quoted_dollar_atp = 1;
4023
4024 if (contains_dollar_at)
4025 *contains_dollar_at = 1;
4026 }
4027
4028 /* Make sure that NAME is valid before trying to go on. */
4029 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
4030 var_is_special) == 0)
4031 {
4032 temp = (char *)NULL;
4033 goto bad_substitution;
4034 }
4035
4036 if (want_indir)
4037 temp = parameter_brace_expand_indir (name + 1, var_is_special, quoted);
4038 else
4039 temp = parameter_brace_expand_word (name, var_is_special, quoted);
4040
4041 #if defined (ARRAY_VARS)
4042 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && valid_array_reference (name))
4043 {
4044 temp1 = strchr (name, '[');
4045 if (temp1 && temp1[1] == '@' && temp1[2] == ']')
4046 {
4047 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
4048 *quoted_dollar_atp = 1;
4049 if (contains_dollar_at)
4050 *contains_dollar_at = 1;
4051 }
4052 }
4053 #endif
4054
4055 var_is_set = temp != (char *)0;
4056 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
4057
4058 /* Get the rest of the stuff inside the braces. */
4059 if (c && c != '}')
4060 {
4061 /* Extract the contents of the ${ ... } expansion
4062 according to the Posix.2 rules. */
4063 value = extract_dollar_brace_string (string, &sindex, quoted);
4064 /*{*/
4065 if (string[sindex] == '}')
4066 sindex++;
4067 else
4068 goto bad_substitution;
4069 }
4070 else
4071 value = (char *)NULL;
4072
4073 *indexp = sindex;
4074
4075 /* If this is a substring spec, process it and add the result. */
4076 if (want_substring)
4077 {
4078 temp1 = parameter_brace_substring (name, temp, value, quoted);
4079 FREE (name);
4080 FREE (value);
4081 FREE (temp);
4082 return (temp1);
4083 }
4084 else if (want_patsub)
4085 {
4086 temp1 = parameter_brace_patsub (name, temp, value, quoted);
4087 FREE (name);
4088 FREE (value);
4089 FREE (temp);
4090 return (temp1);
4091 }
4092
4093 /* Do the right thing based on which character ended the variable name. */
4094 switch (c)
4095 {
4096 default:
4097 case '\0':
4098 bad_substitution:
4099 report_error ("%s: bad substitution", string ? string : "??");
4100 FREE (value);
4101 FREE (temp);
4102 free (name);
4103 return &expand_param_error;
4104
4105 /*{*/
4106 case '}':
4107 if (var_is_set == 0 && unbound_vars_is_error)
4108 {
4109 report_error ("%s: unbound variable", name);
4110 FREE (value);
4111 FREE (temp);
4112 free (name);
4113 last_command_exit_value = EXECUTION_FAILURE;
4114 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
4115 }
4116 break;
4117
4118 case '#': /* ${param#[#]pattern} */
4119 case '%': /* ${param%[%]pattern} */
4120 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
4121 {
4122 FREE (value);
4123 break;
4124 }
4125 if ((name[0] == '@' || name[0] == '*') && name[1] == '\0')
4126 temp1 = parameter_list_remove_pattern (value, name[0], c, quoted);
4127 #if defined (ARRAY_VARS)
4128 else if (valid_array_reference (name))
4129 temp1 = array_remove_pattern (value, name, temp, c, quoted);
4130 #endif
4131 else
4132 temp1 = parameter_brace_remove_pattern (value, temp, c, quoted);
4133 free (temp);
4134 free (value);
4135 temp = temp1;
4136 break;
4137
4138 case '-':
4139 case '=':
4140 case '?':
4141 case '+':
4142 if (var_is_set && var_is_null == 0)
4143 {
4144 /* We don't want the value of the named variable for
4145 anything, just the value of the right hand side. */
4146 if (c == '+')
4147 {
4148 FREE (temp);
4149 if (value)
4150 {
4151 temp = parameter_brace_expand_rhs (name, value, c,
4152 quoted,
4153 quoted_dollar_atp,
4154 contains_dollar_at);
4155 free (value);
4156 }
4157 else
4158 temp = (char *)NULL;
4159 }
4160 else
4161 {
4162 FREE (value);
4163 }
4164 /* Otherwise do nothing; just use the value in TEMP. */
4165 }
4166 else /* VAR not set or VAR is NULL. */
4167 {
4168 FREE (temp);
4169 temp = (char *)NULL;
4170 if (c == '=' && var_is_special)
4171 {
4172 report_error ("$%s: cannot assign in this way", name);
4173 free (name);
4174 free (value);
4175 return &expand_param_error;
4176 }
4177 else if (c == '?')
4178 {
4179 parameter_brace_expand_error (name, value);
4180 return (interactive ? &expand_param_error : &expand_param_fatal);
4181 }
4182 else if (c != '+')
4183 temp = parameter_brace_expand_rhs (name, value, c, quoted,
4184 quoted_dollar_atp,
4185 contains_dollar_at);
4186 free (value);
4187 }
4188 break;
4189 }
4190 free (name);
4191 return (temp);
4192 }
4193
4194 /* Make a word list which is the parameter and variable expansion,
4195 command substitution, arithmetic substitution, and quote removed
4196 expansion of WORD. Return a pointer to a WORD_LIST which is the
4197 result of the expansion. If WORD contains a null word, the word
4198 list returned is also null.
4199
4200 QUOTED contains flag values defined in shell.h.
4201
4202 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
4203 they point to an integer value which receives information about expansion.
4204 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
4205 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
4206 else zero.
4207
4208 This only does word splitting in the case of $@ expansion. In that
4209 case, we split on ' '. */
4210
4211 /* Values for the local variable quoted_state. */
4212 #define UNQUOTED 0
4213 #define PARTIALLY_QUOTED 1
4214 #define WHOLLY_QUOTED 2
4215
4216 static WORD_LIST *
4217 expand_word_internal (word, quoted, contains_dollar_at, expanded_something)
4218 WORD_DESC *word;
4219 int quoted;
4220 int *contains_dollar_at;
4221 int *expanded_something;
4222 {
4223 WORD_LIST *list;
4224 WORD_DESC *tword;
4225 SHELL_VAR *var;
4226
4227 /* The intermediate string that we build while expanding. */
4228 char *istring;
4229
4230 /* The current size of the above object. */
4231 int istring_size;
4232
4233 /* Index into ISTRING. */
4234 int istring_index;
4235
4236 /* Temporary string storage. */
4237 char *temp, *temp1;
4238
4239 /* The text of WORD. */
4240 register char *string;
4241
4242 /* The index into STRING. */
4243 int sindex;
4244
4245 /* This gets 1 if we see a $@ while quoted. */
4246 int quoted_dollar_at;
4247
4248 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
4249 whether WORD contains no quoting characters, a partially quoted
4250 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
4251 int quoted_state;
4252
4253 int had_quoted_null;
4254
4255 int expok;
4256
4257 register int c; /* Current character. */
4258 int number; /* Temporary number value. */
4259 int t_index; /* For calls to string_extract_xxx. */
4260
4261 istring = xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
4262 istring[istring_index = 0] = '\0';
4263
4264 quoted_dollar_at = had_quoted_null = 0;
4265 quoted_state = UNQUOTED;
4266
4267 string = word->word;
4268 if (string == 0)
4269 goto finished_with_string;
4270
4271 if (contains_dollar_at)
4272 *contains_dollar_at = 0;
4273
4274 /* Begin the expansion. */
4275
4276 for (sindex = 0; ;)
4277 {
4278 c = string[sindex];
4279
4280 /* Case on toplevel character. */
4281 switch (c)
4282 {
4283 case '\0':
4284 goto finished_with_string;
4285
4286 case CTLESC:
4287 temp = xmalloc (3);
4288 temp[0] = CTLESC;
4289 temp[1] = c = string[++sindex];
4290 temp[2] = '\0';
4291
4292 if (string[sindex])
4293 sindex++;
4294
4295 goto add_string;
4296
4297 #if defined (PROCESS_SUBSTITUTION)
4298 /* Process substitution. */
4299 case '<':
4300 case '>':
4301 {
4302 if (string[++sindex] != '(' || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || posixly_correct)
4303 {
4304 sindex--;
4305 goto add_character;
4306 }
4307 else
4308 t_index = sindex + 1; /* skip past both '<' and '(' */
4309
4310 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index);
4311 sindex = t_index;
4312
4313 /* If the process substitution specification is `<()', we want to
4314 open the pipe for writing in the child and produce output; if
4315 it is `>()', we want to open the pipe for reading in the child
4316 and consume input. */
4317 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
4318
4319 FREE (temp1);
4320
4321 goto dollar_add_string;
4322 }
4323 #endif /* PROCESS_SUBSTITUTION */
4324
4325 /* See about breaking this into a separate function:
4326 char *
4327 param_expand (string, sindex, quoted, expanded_something,
4328 contains_dollar_at, quoted_dollar_at)
4329 char *string;
4330 int *sindex, quoted, *expanded_something, *contains_dollar_at;
4331 int *quoted_dollar_at;
4332 */
4333 case '$':
4334
4335 if (expanded_something)
4336 *expanded_something = 1;
4337
4338 c = string[++sindex];
4339
4340 /* Do simple cases first. Switch on what follows '$'. */
4341 switch (c)
4342 {
4343 /* $0 .. $9? */
4344 case '0':
4345 case '1':
4346 case '2':
4347 case '3':
4348 case '4':
4349 case '5':
4350 case '6':
4351 case '7':
4352 case '8':
4353 case '9':
4354 temp1 = dollar_vars[digit_value (c)];
4355 if (unbound_vars_is_error && temp1 == (char *)NULL)
4356 {
4357 report_error ("$%c: unbound variable", c);
4358 free (string);
4359 free (istring);
4360 last_command_exit_value = EXECUTION_FAILURE;
4361 return (interactive_shell ? &expand_word_error : &expand_word_fatal);
4362 }
4363 temp = temp1 ? savestring (temp1) : (char *)NULL;
4364 goto dollar_add_string;
4365
4366 /* $$ -- pid of the invoking shell. */
4367 case '$':
4368 number = dollar_dollar_pid;
4369
4370 add_number:
4371 temp = itos (number);
4372 dollar_add_string:
4373 if (string[sindex]) sindex++;
4374
4375 /* Add TEMP to ISTRING. */
4376 add_string:
4377 if (temp)
4378 {
4379 istring = sub_append_string
4380 (temp, istring, &istring_index, &istring_size);
4381 temp = (char *)0;
4382 }
4383
4384 break;
4385
4386 /* $# -- number of positional parameters. */
4387 case '#':
4388 number = number_of_args ();
4389 goto add_number;
4390
4391 /* $? -- return value of the last synchronous command. */
4392 case '?':
4393 number = last_command_exit_value;
4394 goto add_number;
4395
4396 /* $- -- flags supplied to the shell on invocation or
4397 by `set'. */
4398 case '-':
4399 temp = which_set_flags ();
4400 goto dollar_add_string;
4401
4402 /* $! -- Pid of the last asynchronous command. */
4403 case '!':
4404 number = (int)last_asynchronous_pid;
4405
4406 /* If no asynchronous pids have been created, expand
4407 to nothing. */
4408 if (number == (int)NO_PID)
4409 {
4410 if (string[sindex])
4411 sindex++;
4412 if (expanded_something)
4413 *expanded_something = 0;
4414 break;
4415 }
4416 goto add_number;
4417
4418 /* The only difference between this and $@ is when the
4419 arg is quoted. */
4420 case '*': /* `$*' */
4421 temp = string_rest_of_args (quoted);
4422
4423 /* If there are no command-line arguments, this should just
4424 disappear if there are other characters in the expansion,
4425 even if it's quoted. */
4426 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && temp && *temp == '\0')
4427 {
4428 free (temp);
4429 temp = (char *)NULL;
4430 }
4431 /* In the case of a quoted string, quote the entire arg-list.
4432 "$1 $2 $3". Otherwise quote the special escape characters. */
4433 if (temp)
4434 {
4435 temp1 = temp;
4436 temp = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4437 ? quote_string (temp)
4438 : quote_escapes (temp);
4439 free (temp1);
4440 }
4441 goto dollar_add_string;
4442
4443 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
4444 means that we have to turn quoting off after we split into
4445 the individually quoted arguments so that the final split
4446 on the first character of $IFS is still done. */
4447 case '@': /* `$@' */
4448 list = list_rest_of_args ();
4449
4450 /* We want to flag the fact that we saw this. We can't turn
4451 off quoting entirely, because other characters in the
4452 string might need it (consider "\"$@\""), but we need some
4453 way to signal that the final split on the first character
4454 of $IFS should be done, even though QUOTED is 1. */
4455 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4456 quoted_dollar_at = 1;
4457 if (contains_dollar_at)
4458 *contains_dollar_at = 1;
4459 temp = string_list (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list) ? quote_list (list) : list);
4460 /* If the expansion is not quoted, protect any special escape
4461 characters in the expansion by quoting them. */
4462 if (temp && quoted == 0)
4463 {
4464 temp1 = temp;
4465 temp = quote_escapes (temp);
4466 free (temp1);
4467 }
4468 dispose_words (list);
4469 goto dollar_add_string;
4470
4471 case '{': /*}*/
4472 temp = parameter_brace_expand (string, &sindex, quoted,
4473 &quoted_dollar_at,
4474 contains_dollar_at);
4475 if (temp == &expand_param_error || temp == &expand_param_fatal)
4476 {
4477 free (string);
4478 free (istring);
4479 return (temp == &expand_param_error) ? &expand_word_error
4480 : &expand_word_fatal;
4481 }
4482 /* XXX */
4483 /* quoted nulls should be removed if there is anything else
4484 in the string. */
4485 /* Note that we saw the quoted null so we can add one back at
4486 the end of this function if there are no other characters
4487 in the string, discard TEMP, and go on. */
4488 if (temp && QUOTED_NULL (temp))
4489 {
4490 had_quoted_null = 1;
4491 free (temp);
4492 break;
4493 }
4494
4495 goto add_string;
4496 /* break; */
4497
4498 /* Do command or arithmetic substitution. */
4499 case '(': /*)*/
4500 /* We have to extract the contents of this paren substitution. */
4501 t_index = sindex + 1;
4502 temp = extract_command_subst (string, &t_index);
4503 sindex = t_index;
4504
4505 /* For Posix.2-style `$(( ))' arithmetic substitution,
4506 extract the expression and pass it to the evaluator. */
4507 if (temp && *temp == '(')
4508 {
4509 temp1 = temp + 1;
4510 t_index = strlen (temp1) - 1;
4511
4512 if (temp1[t_index] != ')')
4513 {
4514 #if 0
4515 report_error ("%s: bad arithmetic substitution", temp);
4516 free (temp);
4517 free (string);
4518 free (istring);
4519 return (&expand_word_error);
4520 #else
4521 goto comsub;
4522 #endif
4523 }
4524
4525 /* Cut off ending `)' */
4526 temp1[t_index] = '\0';
4527
4528 /* Expand variables found inside the expression. */
4529 temp1 = maybe_expand_string (temp1, Q_DOUBLE_QUOTES, expand_string);
4530
4531 /* No error messages. */
4532 this_command_name = (char *)NULL;
4533 number = evalexp (temp1, &expok);
4534 free (temp);
4535 free (temp1);
4536 if (expok == 0)
4537 {
4538 free (string);
4539 free (istring);
4540 return (&expand_word_error);
4541 }
4542 goto add_number;
4543 }
4544
4545 comsub:
4546 temp1 = command_substitute (temp, quoted);
4547 FREE (temp);
4548 temp = temp1;
4549 goto dollar_add_string;
4550
4551 /* Do straight arithmetic substitution. */
4552 case '[':
4553 /* We have to extract the contents of this
4554 arithmetic substitution. */
4555 t_index = sindex + 1;
4556 temp = extract_arithmetic_subst (string, &t_index);
4557 sindex = t_index;
4558
4559 /* Do initial variable expansion. */
4560 temp1 = maybe_expand_string (temp, Q_DOUBLE_QUOTES, expand_string);
4561
4562 /* No error messages. */
4563 this_command_name = (char *)NULL;
4564 number = evalexp (temp1, &expok);
4565 free (temp1);
4566 free (temp);
4567 if (expok == 0)
4568 {
4569 free (string);
4570 free (istring);
4571 return (&expand_word_error);
4572 }
4573 goto add_number;
4574
4575 default:
4576 /* Find the variable in VARIABLE_LIST. */
4577 temp = (char *)NULL;
4578
4579 for (t_index = sindex;
4580 (c = string[sindex]) && legal_variable_char (c);
4581 sindex++);
4582 temp1 = substring (string, t_index, sindex);
4583
4584 /* If this isn't a variable name, then just output the `$'. */
4585 if (temp1 == 0 || *temp1 == '\0')
4586 {
4587 FREE (temp1);
4588 temp = xmalloc (2);
4589 temp[0] = '$';
4590 temp[1] = '\0';
4591 if (expanded_something)
4592 *expanded_something = 0;
4593 goto add_string;
4594 }
4595
4596 /* If the variable exists, return its value cell. */
4597 var = find_variable (temp1);
4598
4599 if (var && invisible_p (var) == 0 && value_cell (var))
4600 {
4601 #if defined (ARRAY_VARS)
4602 if (array_p (var))
4603 {
4604 temp = array_reference (array_cell (var), 0);
4605 if (temp)
4606 temp = quote_escapes (temp);
4607 }
4608 else
4609 #endif
4610 temp = quote_escapes (value_cell (var));
4611 free (temp1);
4612 goto add_string;
4613 }
4614
4615 temp = (char *)NULL;
4616
4617 if (unbound_vars_is_error)
4618 report_error ("%s: unbound variable", temp1);
4619 else
4620 {
4621 free (temp1);
4622 goto add_string;
4623 }
4624
4625 free (temp1);
4626 free (string);
4627 last_command_exit_value = EXECUTION_FAILURE;
4628 free (istring);
4629 return ((unbound_vars_is_error && interactive_shell == 0)
4630 ? &expand_word_fatal
4631 : &expand_word_error);
4632 }
4633 break; /* End case '$': */
4634
4635 case '`': /* Backquoted command substitution. */
4636 {
4637 sindex++;
4638
4639 if (expanded_something)
4640 *expanded_something = 1;
4641
4642 temp = string_extract (string, &sindex, "`", 0);
4643 de_backslash (temp);
4644 temp1 = command_substitute (temp, quoted);
4645 FREE (temp);
4646 temp = temp1;
4647 goto dollar_add_string;
4648 }
4649
4650 case '\\':
4651 if (string[sindex + 1] == '\n')
4652 {
4653 sindex += 2;
4654 continue;
4655 }
4656
4657 c = string[++sindex];
4658
4659 if (quoted & Q_HERE_DOCUMENT)
4660 temp1 = slashify_in_here_document;
4661 else if (quoted & Q_DOUBLE_QUOTES)
4662 temp1 = slashify_in_quotes;
4663 else
4664 temp1 = "";
4665
4666 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && member (c, temp1) == 0)
4667 {
4668 temp = xmalloc (3);
4669 temp[0] = '\\'; temp[1] = c; temp[2] = '\0';
4670 }
4671 else
4672 /* This character is quoted, so add it in quoted mode. */
4673 temp = make_quoted_char (c);
4674
4675 if (c)
4676 sindex++;
4677 goto add_string;
4678
4679 case '"':
4680 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE))
4681 goto add_character;
4682
4683 t_index = ++sindex;
4684 temp = string_extract_double_quoted (string, &sindex, 0);
4685
4686 /* If the quotes surrounded the entire string, then the
4687 whole word was quoted. */
4688 quoted_state = (t_index == 1 && string[sindex] == '\0')
4689 ? WHOLLY_QUOTED
4690 : PARTIALLY_QUOTED;
4691
4692 if (temp && *temp)
4693 {
4694 int dollar_at_flag;
4695
4696 tword = make_word (temp); /* XXX */
4697 free (temp);
4698 temp = (char *)NULL;
4699
4700 list = expand_word_internal (tword, Q_DOUBLE_QUOTES, &dollar_at_flag, (int *)NULL);
4701
4702 if (list == &expand_word_error || list == &expand_word_fatal)
4703 {
4704 free (istring);
4705 free (string);
4706 /* expand_word_internal has already freed temp_word->word
4707 for us because of the way it prints error messages. */
4708 tword->word = (char *)NULL;
4709 dispose_word (tword);
4710 return list;
4711 }
4712
4713 dispose_word (tword);
4714
4715 /* "$@" (a double-quoted dollar-at) expands into nothing,
4716 not even a NULL word, when there are no positional
4717 parameters. */
4718 if (list == 0 && dollar_at_flag)
4719 {
4720 quoted_dollar_at++;
4721 break;
4722 }
4723
4724 /* If we get "$@", we know we have expanded something, so we
4725 need to remember it for the final split on $IFS. This is
4726 a special case; it's the only case where a quoted string
4727 can expand into more than one word. It's going to come back
4728 from the above call to expand_word_internal as a list with
4729 a single word, in which all characters are quoted and
4730 separated by blanks. What we want to do is to turn it back
4731 into a list for the next piece of code. */
4732 if (list)
4733 dequote_list (list);
4734
4735 if (dollar_at_flag)
4736 {
4737 quoted_dollar_at++;
4738 if (contains_dollar_at)
4739 *contains_dollar_at = 1;
4740 if (expanded_something)
4741 *expanded_something = 1;
4742 }
4743 }
4744 else
4745 {
4746 /* What we have is "". This is a minor optimization. */
4747 free (temp);
4748 list = (WORD_LIST *)NULL;
4749 }
4750
4751 /* The code above *might* return a list (consider the case of "$@",
4752 where it returns "$1", "$2", etc.). We can't throw away the
4753 rest of the list, and we have to make sure each word gets added
4754 as quoted. We test on tresult->next: if it is non-NULL, we
4755 quote the whole list, save it to a string with string_list, and
4756 add that string. We don't need to quote the results of this
4757 (and it would be wrong, since that would quote the separators
4758 as well), so we go directly to add_string. */
4759 if (list)
4760 {
4761 if (list->next)
4762 {
4763 temp = string_list (quote_list (list));
4764 dispose_words (list);
4765 goto add_string;
4766 }
4767 else
4768 {
4769 temp = savestring (list->word->word);
4770 dispose_words (list);
4771 }
4772 }
4773 else
4774 temp = (char *)NULL;
4775
4776 /* We do not want to add quoted nulls to strings that are only
4777 partially quoted; we can throw them away. */
4778 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
4779 {
4780 FREE (temp);
4781 continue;
4782 }
4783
4784 add_quoted_string:
4785
4786 if (temp)
4787 {
4788 temp1 = temp;
4789 temp = quote_string (temp);
4790 free (temp1);
4791 }
4792 else
4793 {
4794 /* Add NULL arg. */
4795 temp = xmalloc (2);
4796 temp[0] = CTLNUL;
4797 temp[1] = '\0';
4798 }
4799 goto add_string;
4800 /* break; */
4801
4802 case '\'':
4803 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT|Q_NOQUOTE))
4804 goto add_character;
4805
4806 t_index = ++sindex;
4807 temp = string_extract_single_quoted (string, &sindex);
4808
4809 /* If the entire STRING was surrounded by single quotes,
4810 then the string is wholly quoted. */
4811 quoted_state = (t_index == 1 && string[sindex] == '\0')
4812 ? WHOLLY_QUOTED
4813 : PARTIALLY_QUOTED;
4814
4815 /* If all we had was '', it is a null expansion. */
4816 if (*temp == '\0')
4817 {
4818 free (temp);
4819 temp = (char *)NULL;
4820 }
4821 else
4822 remove_quoted_escapes (temp);
4823
4824 /* We do not want to add quoted nulls to strings that are only
4825 partially quoted; such nulls are discarded. */
4826 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
4827 continue;
4828
4829 goto add_quoted_string;
4830 /* break; */
4831
4832 default:
4833 /* This is the fix for " $@ " */
4834 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4835 {
4836 temp = make_quoted_char (c);
4837 goto dollar_add_string;
4838 }
4839
4840 add_character:
4841 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
4842 DEFAULT_ARRAY_SIZE);
4843 istring[istring_index++] = c;
4844 istring[istring_index] = '\0';
4845
4846 /* Next character. */
4847 sindex++;
4848 }
4849 }
4850
4851 finished_with_string:
4852 /* OK, we're ready to return. If we have a quoted string, and
4853 quoted_dollar_at is not set, we do no splitting at all; otherwise
4854 we split on ' '. The routines that call this will handle what to
4855 do if nothing has been expanded. */
4856
4857 /* Partially and wholly quoted strings which expand to the empty
4858 string are retained as an empty arguments. Unquoted strings
4859 which expand to the empty string are discarded. The single
4860 exception is the case of expanding "$@" when there are no
4861 positional parameters. In that case, we discard the expansion. */
4862
4863 /* Because of how the code that handles "" and '' in partially
4864 quoted strings works, we need to make ISTRING into a QUOTED_NULL
4865 if we saw quoting characters, but the expansion was empty.
4866 "" and '' are tossed away before we get to this point when
4867 processing partially quoted strings. This makes "" and $xxx""
4868 equivalent when xxx is unset. We also look to see whether we
4869 saw a quoted null from a ${} expansion and add one back if we
4870 need to. */
4871
4872 /* If we expand to nothing and there were no single or double quotes
4873 in the word, we throw it away. Otherwise, we return a NULL word.
4874 The single exception is for $@ surrounded by double quotes when
4875 there are no positional parameters. In that case, we also throw
4876 the word away. */
4877
4878 if (*istring == '\0')
4879 {
4880 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
4881 {
4882 istring[0] = CTLNUL;
4883 istring[1] = '\0';
4884 tword = make_bare_word (istring);
4885 list = make_word_list (tword, (WORD_LIST *)NULL);
4886 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4887 tword->flags |= W_QUOTED;
4888 }
4889 /* According to sh, ksh, and Posix.2, if a word expands into nothing
4890 and a double-quoted "$@" appears anywhere in it, then the entire
4891 word is removed. */
4892 else if (quoted_state == UNQUOTED || quoted_dollar_at)
4893 list = (WORD_LIST *)NULL;
4894 #if 0
4895 else
4896 {
4897 tword = make_bare_word (istring);
4898 list = make_word_list (tword, (WORD_LIST *)NULL);
4899 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4900 tword->flags |= W_QUOTED;
4901 }
4902 #endif
4903 }
4904 else if (word->flags & W_NOSPLIT)
4905 {
4906 tword = make_bare_word (istring);
4907 list = make_word_list (tword, (WORD_LIST *)NULL);
4908 if (word->flags & W_ASSIGNMENT)
4909 tword->flags |= W_ASSIGNMENT; /* XXX */
4910 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4911 tword->flags |= W_QUOTED;
4912 }
4913 else
4914 {
4915 char *ifs_chars;
4916
4917 if (quoted_dollar_at)
4918 {
4919 var = find_variable ("IFS");
4920 ifs_chars = var ? value_cell (var) : " \t\n";
4921 }
4922 else
4923 ifs_chars = (char *)NULL;
4924
4925 /* According to Posix.2, "$@" expands to a single word if
4926 IFS="" and the positional parameters are not empty. */
4927 if (quoted_dollar_at && ifs_chars && *ifs_chars)
4928 {
4929 list = list_string (istring, " ", 1);
4930 }
4931 else
4932 {
4933 tword = make_bare_word (istring);
4934 list = make_word_list (tword, (WORD_LIST *)NULL);
4935 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
4936 tword->flags |= W_QUOTED;
4937 if (word->flags & W_ASSIGNMENT)
4938 tword->flags |= W_ASSIGNMENT;
4939 }
4940 }
4941
4942 free (istring);
4943 return (list);
4944 }
4945
4946 /* **************************************************************** */
4947 /* */
4948 /* Functions for Quote Removal */
4949 /* */
4950 /* **************************************************************** */
4951
4952 /* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
4953 backslash quoting rules for within double quotes. */
4954 char *
4955 string_quote_removal (string, quoted)
4956 char *string;
4957 int quoted;
4958 {
4959 char *r, *result_string, *temp;
4960 int sindex, tindex, c, dquote;
4961
4962 /* The result can be no longer than the original string. */
4963 r = result_string = xmalloc (strlen (string) + 1);
4964
4965 for (dquote = sindex = 0; c = string[sindex];)
4966 {
4967 switch (c)
4968 {
4969 case '\\':
4970 c = string[++sindex];
4971 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && member (c, slashify_in_quotes) == 0)
4972 *r++ = '\\';
4973 /* FALLTHROUGH */
4974
4975 default:
4976 *r++ = c;
4977 sindex++;
4978 break;
4979
4980 case '\'':
4981 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
4982 {
4983 *r++ = c;
4984 sindex++;
4985 break;
4986 }
4987 tindex = sindex + 1;
4988 temp = string_extract_single_quoted (string, &tindex);
4989 if (temp)
4990 {
4991 strcpy (r, temp);
4992 r += strlen (r);
4993 free (temp);
4994 }
4995 sindex = tindex;
4996 break;
4997
4998 case '"':
4999 dquote = 1 - dquote;
5000 sindex++;
5001 break;
5002 }
5003 }
5004 *r = '\0';
5005 return (result_string);
5006 }
5007
5008 #if 0
5009 /* UNUSED */
5010 /* Perform quote removal on word WORD. This allocates and returns a new
5011 WORD_DESC *. */
5012 WORD_DESC *
5013 word_quote_removal (word, quoted)
5014 WORD_DESC *word;
5015 int quoted;
5016 {
5017 WORD_DESC *w;
5018 char *t;
5019
5020 t = string_quote_removal (word->word, quoted);
5021 w = make_bare_word (t);
5022 free (t);
5023 return (w);
5024 }
5025
5026 /* Perform quote removal on all words in LIST. If QUOTED is non-zero,
5027 the members of the list are treated as if they are surrounded by
5028 double quotes. Return a new list, or NULL if LIST is NULL. */
5029 WORD_LIST *
5030 word_list_quote_removal (list, quoted)
5031 WORD_LIST *list;
5032 int quoted;
5033 {
5034 WORD_LIST *result, *t, *tresult;
5035
5036 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
5037 {
5038 tresult = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
5039 tresult->word = word_quote_removal (t->word, quoted);
5040 tresult->next = (WORD_LIST *)NULL;
5041 result = (WORD_LIST *) list_append (result, tresult);
5042 }
5043 return (result);
5044 }
5045 #endif
5046
5047 /* Return 1 if CHARACTER appears in an unquoted portion of
5048 STRING. Return 0 otherwise. */
5049 static int
5050 unquoted_member (character, string)
5051 int character;
5052 char *string;
5053 {
5054 int sindex, c;
5055
5056 for (sindex = 0; c = string[sindex]; )
5057 {
5058 if (c == character)
5059 return (1);
5060
5061 switch (c)
5062 {
5063 default:
5064 sindex++;
5065 break;
5066
5067 case '\\':
5068 sindex++;
5069 if (string[sindex])
5070 sindex++;
5071 break;
5072
5073 case '\'':
5074 sindex = skip_single_quoted (string, ++sindex);
5075 break;
5076
5077 case '"':
5078 sindex = skip_double_quoted (string, ++sindex);
5079 break;
5080 }
5081 }
5082 return (0);
5083 }
5084
5085 /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
5086 static int
5087 unquoted_substring (substr, string)
5088 char *substr, *string;
5089 {
5090 int sindex, c, sublen;
5091
5092 if (substr == 0 || *substr == '\0')
5093 return (0);
5094
5095 sublen = strlen (substr);
5096 for (sindex = 0; c = string[sindex]; )
5097 {
5098 if (STREQN (string + sindex, substr, sublen))
5099 return (1);
5100
5101 switch (c)
5102 {
5103 case '\\':
5104 sindex++;
5105
5106 if (string[sindex])
5107 sindex++;
5108 break;
5109
5110 case '\'':
5111 sindex = skip_single_quoted (string, ++sindex);
5112 break;
5113
5114 case '"':
5115 sindex = skip_double_quoted (string, ++sindex);
5116 break;
5117
5118 default:
5119 sindex++;
5120 break;
5121 }
5122 }
5123 return (0);
5124 }
5125
5126 /*******************************************
5127 * *
5128 * Functions to perform word splitting *
5129 * *
5130 *******************************************/
5131
5132 /* This splits a single word into a WORD LIST on $IFS, but only if the word
5133 is not quoted. list_string () performs quote removal for us, even if we
5134 don't do any splitting. */
5135 WORD_LIST *
5136 word_split (w)
5137 WORD_DESC *w;
5138 {
5139 WORD_LIST *result;
5140 SHELL_VAR *ifs;
5141 char *ifs_chars;
5142
5143 if (w)
5144 {
5145 ifs = find_variable ("IFS");
5146 /* If IFS is unset, it defaults to " \t\n". */
5147 ifs_chars = ifs ? value_cell (ifs) : " \t\n";
5148
5149 if ((w->flags & W_QUOTED) || !ifs_chars)
5150 ifs_chars = "";
5151
5152 result = list_string (w->word, ifs_chars, w->flags & W_QUOTED);
5153 }
5154 else
5155 result = (WORD_LIST *)NULL;
5156
5157 return (result);
5158 }
5159
5160 /* Perform word splitting on LIST and return the RESULT. It is possible
5161 to return (WORD_LIST *)NULL. */
5162 static WORD_LIST *
5163 word_list_split (list)
5164 WORD_LIST *list;
5165 {
5166 WORD_LIST *result, *t, *tresult;
5167
5168 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
5169 {
5170 tresult = word_split (t->word);
5171 result = (WORD_LIST *) list_append (result, tresult);
5172 }
5173 return (result);
5174 }
5175
5176 /**************************************************
5177 * *
5178 * Functions to expand an entire WORD_LIST *
5179 * *
5180 **************************************************/
5181
5182 static WORD_LIST *varlist = (WORD_LIST *)NULL;
5183
5184 /* Separate out any initial variable assignments from TLIST. If set -k has
5185 been executed, remove all assignment statements from TLIST. Initial
5186 variable assignments and other environment assignments are placed
5187 on VARLIST. */
5188 static WORD_LIST *
5189 separate_out_assignments (tlist)
5190 WORD_LIST *tlist;
5191 {
5192 register WORD_LIST *vp, *lp;
5193
5194 if (!tlist)
5195 return ((WORD_LIST *)NULL);
5196
5197 varlist = (WORD_LIST *)NULL;
5198 vp = lp = tlist;
5199
5200 /* Separate out variable assignments at the start of the command.
5201 Loop invariant: vp->next == lp
5202 Loop postcondition:
5203 lp = list of words left after assignment statements skipped
5204 tlist = original list of words
5205 */
5206 while (lp && (lp->word->flags & W_ASSIGNMENT))
5207 {
5208 vp = lp;
5209 lp = lp->next;
5210 }
5211
5212 /* If lp != tlist, we have some initial assignment statements. */
5213 /* We make VARLIST point to the list of assignment words and
5214 TLIST point to the remaining words. */
5215 if (lp != tlist)
5216 {
5217 varlist = tlist;
5218 /* ASSERT(vp->next == lp); */
5219 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
5220 tlist = lp; /* remainder of word list */
5221 }
5222
5223 /* vp == end of variable list */
5224 /* tlist == remainder of original word list without variable assignments */
5225 if (!tlist)
5226 /* All the words in tlist were assignment statements */
5227 return ((WORD_LIST *)NULL);
5228
5229 /* ASSERT(tlist != NULL); */
5230 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
5231
5232 /* If the -k option is in effect, we need to go through the remaining
5233 words, separate out the assignment words, and place them on VARLIST. */
5234 if (place_keywords_in_env)
5235 {
5236 WORD_LIST *tp; /* tp == running pointer into tlist */
5237
5238 tp = tlist;
5239 lp = tlist->next;
5240
5241 /* Loop Invariant: tp->next == lp */
5242 /* Loop postcondition: tlist == word list without assignment statements */
5243 while (lp)
5244 {
5245 if (lp->word->flags & W_ASSIGNMENT)
5246 {
5247 /* Found an assignment statement, add this word to end of
5248 varlist (vp). */
5249 if (!varlist)
5250 varlist = vp = lp;
5251 else
5252 {
5253 vp->next = lp;
5254 vp = lp;
5255 }
5256
5257 /* Remove the word pointed to by LP from TLIST. */
5258 tp->next = lp->next;
5259 /* ASSERT(vp == lp); */
5260 lp->next = (WORD_LIST *)NULL;
5261 lp = tp->next;
5262 }
5263 else
5264 {
5265 tp = lp;
5266 lp = lp->next;
5267 }
5268 }
5269 }
5270 return (tlist);
5271 }
5272
5273 /* Take the list of words in LIST and do the various substitutions. Return
5274 a new list of words which is the expanded list, and without things like
5275 variable assignments. */
5276
5277 WORD_LIST *
5278 expand_words (list)
5279 WORD_LIST *list;
5280 {
5281 return (expand_word_list_internal (list, 1));
5282 }
5283
5284 /* Same as expand_words (), but doesn't hack variable or environment
5285 variables. */
5286 WORD_LIST *
5287 expand_words_no_vars (list)
5288 WORD_LIST *list;
5289 {
5290 return (expand_word_list_internal (list, 0));
5291 }
5292
5293 /* The workhorse for expand_words () and expand_words_no_vars ().
5294 First arg is LIST, a WORD_LIST of words.
5295 Second arg DO_VARS is non-zero if you want to do environment and
5296 variable assignments, else zero.
5297
5298 This does all of the substitutions: brace expansion, tilde expansion,
5299 parameter expansion, command substitution, arithmetic expansion,
5300 process substitution, word splitting, and pathname expansion. Words
5301 with the W_QUOTED or W_NOSPLIT bits set, or for which no expansion
5302 is done, do not undergo word splitting. Words with the W_ASSIGNMENT
5303 bit set do not undergo pathname expansion. */
5304 static WORD_LIST *
5305 expand_word_list_internal (list, do_vars)
5306 WORD_LIST *list;
5307 int do_vars;
5308 {
5309 WORD_LIST *tlist, *new_list, *next, *temp_list, *orig_list, *disposables;
5310 char *temp_string;
5311 int tint;
5312
5313 if (list == 0)
5314 return ((WORD_LIST *)NULL);
5315
5316 tlist = copy_word_list (list);
5317
5318 if (do_vars)
5319 {
5320 tlist = separate_out_assignments (tlist);
5321 if (tlist == 0)
5322 {
5323 if (varlist)
5324 {
5325 /* All the words were variable assignments, so they are placed
5326 into the shell's environment. */
5327 for (new_list = varlist; new_list; new_list = new_list->next)
5328 {
5329 this_command_name = (char *)NULL; /* no arithmetic errors */
5330 tint = do_assignment (new_list->word->word);
5331 /* Variable assignment errors in non-interactive shells
5332 running in Posix.2 mode cause the shell to exit. */
5333 if (tint == 0 && interactive_shell == 0 && posixly_correct)
5334 {
5335 last_command_exit_value = EXECUTION_FAILURE;
5336 jump_to_top_level (FORCE_EOF);
5337 }
5338 }
5339 dispose_words (varlist);
5340 varlist = (WORD_LIST *)NULL;
5341 }
5342 return ((WORD_LIST *)NULL);
5343 }
5344 }
5345
5346 /* Begin expanding the words that remain. The expansions take place on
5347 things that aren't really variable assignments. */
5348
5349 #if defined (BRACE_EXPANSION)
5350 /* Do brace expansion on this word if there are any brace characters
5351 in the string. */
5352 if (brace_expansion && tlist)
5353 {
5354 register char **expansions;
5355 WORD_LIST *braces;
5356 WORD_DESC *w;
5357 int eindex;
5358
5359 for (braces = disposables = (WORD_LIST *)NULL; tlist; tlist = next)
5360 {
5361 next = tlist->next;
5362
5363 /* Only do brace expansion if the word has a brace character. If
5364 not, just add the word list element to BRACES and continue. In
5365 the common case, at least when running shell scripts, this will
5366 degenerate to a bunch of calls to `strchr', and then what is
5367 basically a reversal of TLIST into BRACES, which is corrected
5368 by a call to reverse_list () on BRACES when the end of TLIST
5369 is reached. */
5370 if (strchr (tlist->word->word, '{'))
5371 {
5372 expansions = brace_expand (tlist->word->word);
5373
5374 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
5375 {
5376 w = make_word (temp_string);
5377 /* If brace expansion didn't change the word, preserve
5378 the flags. We may want to preserve the flags
5379 unconditionally someday -- XXX */
5380 if (STREQ (temp_string, tlist->word->word))
5381 w->flags = tlist->word->flags;
5382 braces = make_word_list (w, braces);
5383 free (expansions[eindex]);
5384 }
5385 free (expansions);
5386
5387 /* Add TLIST to the list of words to be freed after brace
5388 expansion has been performed. */
5389 tlist->next = disposables;
5390 disposables = tlist;
5391 }
5392 else
5393 {
5394 tlist->next = braces;
5395 braces = tlist;
5396 }
5397 }
5398
5399 dispose_words (disposables);
5400 tlist = REVERSE_LIST (braces, WORD_LIST *);
5401 }
5402 #endif /* BRACE_EXPANSION */
5403
5404 /* We do tilde expansion all the time. This is what 1003.2 says. */
5405 for (orig_list = tlist, new_list = (WORD_LIST *)NULL; tlist; tlist = next)
5406 {
5407 WORD_LIST *expanded;
5408 int expanded_something, has_dollar_at;
5409
5410 temp_string = tlist->word->word;
5411
5412 next = tlist->next;
5413
5414 /* Posix.2 section 3.6.1 says that tildes following `=' in words
5415 which are not assignment statements are not expanded. We do
5416 this only if POSIXLY_CORRECT is enabled. Essentially, we do
5417 tilde expansion on unquoted assignment statements (flags include
5418 W_ASSIGNMENT but not W_QUOTED). */
5419 if (temp_string[0] == '~' ||
5420 (((tlist->word->flags & (W_ASSIGNMENT|W_QUOTED)) == W_ASSIGNMENT) &&
5421 posixly_correct == 0 &&
5422 strchr (temp_string, '~') &&
5423 (unquoted_substring ("=~", temp_string) || unquoted_substring (":~", temp_string))))
5424 {
5425 tlist->word->word = bash_tilde_expand (temp_string);
5426 free (temp_string);
5427 }
5428
5429 expanded_something = 0;
5430 expanded = expand_word_internal
5431 (tlist->word, 0, &has_dollar_at, &expanded_something);
5432
5433 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
5434 {
5435 /* By convention, each time this error is returned,
5436 tlist->word->word has already been freed. */
5437 tlist->word->word = (char *)NULL;
5438
5439 /* Dispose our copy of the original list. */
5440 dispose_words (orig_list);
5441 /* Dispose the new list we're building. */
5442 dispose_words (new_list);
5443
5444 if (expanded == &expand_word_error)
5445 jump_to_top_level (DISCARD);
5446 else
5447 jump_to_top_level (FORCE_EOF);
5448 }
5449
5450 /* Don't split words marked W_NOSPLIT. */
5451 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
5452 {
5453 temp_list = word_list_split (expanded);
5454 dispose_words (expanded);
5455 }
5456 else
5457 {
5458 /* If no parameter expansion, command substitution, process
5459 substitution, or arithmetic substitution took place, then
5460 do not do word splitting. We still have to remove quoted
5461 null characters from the result. */
5462 word_list_remove_quoted_nulls (expanded);
5463 temp_list = expanded;
5464 }
5465
5466 /* In the most common cases, t will be a list containing only one
5467 element, so the call to reverse_list would be wasted. */
5468 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
5469 new_list = (WORD_LIST *)list_append (expanded, new_list);
5470 }
5471
5472 new_list = REVERSE_LIST (new_list, WORD_LIST *);
5473
5474 dispose_words (orig_list);
5475
5476 /* Okay, we're almost done. Now let's just do some filename
5477 globbing. */
5478 if (new_list)
5479 {
5480 char **glob_array;
5481 register int glob_index;
5482 WORD_LIST *glob_list;
5483 WORD_DESC *tword;
5484
5485 orig_list = disposables = (WORD_LIST *)NULL;
5486 tlist = new_list;
5487
5488 /* orig_list == output list, despite the name. */
5489 if (disallow_filename_globbing == 0)
5490 {
5491 glob_array = (char **)NULL;
5492 while (tlist)
5493 {
5494 /* For each word, either globbing is attempted or the word is
5495 added to orig_list. If globbing succeeds, the results are
5496 added to orig_list and the word (tlist) is added to the list
5497 of disposable words. If globbing fails and failed glob
5498 expansions are left unchanged (the shell default), the
5499 original word is added to orig_list. If globbing fails and
5500 failed glob expansions are removed, the original word is
5501 added to the list of disposable words. orig_list ends up
5502 in reverse order and requires a call to reverse_list to
5503 be set right. After all words are examined, the disposable
5504 words are freed. */
5505 next = tlist->next;
5506
5507 /* If the word isn't an assignment and contains an unquoted
5508 pattern matching character, then glob it. */
5509 #if 0
5510 if ((tlist->word->flags & (W_QUOTED|W_ASSIGNMENT)) == 0 &&
5511 #else
5512 if ((tlist->word->flags & W_ASSIGNMENT) == 0 &&
5513 #endif
5514 unquoted_glob_pattern_p (tlist->word->word))
5515 {
5516 glob_array = shell_glob_filename (tlist->word->word);
5517
5518 /* Handle error cases.
5519 I don't think we should report errors like "No such file
5520 or directory". However, I would like to report errors
5521 like "Read failed". */
5522
5523 if (GLOB_FAILED (glob_array))
5524 {
5525 glob_array = (char **) xmalloc (sizeof (char *));
5526 glob_array[0] = (char *)NULL;
5527 }
5528
5529 /* Dequote the current word in case we have to use it. */
5530 if (glob_array[0] == NULL)
5531 {
5532 temp_string = dequote_string (tlist->word->word);
5533 free (tlist->word->word);
5534 tlist->word->word = temp_string;
5535 }
5536
5537 /* Make the array into a word list. */
5538 glob_list = (WORD_LIST *)NULL;
5539 for (glob_index = 0; glob_array[glob_index]; glob_index++)
5540 {
5541 tword = make_bare_word (glob_array[glob_index]);
5542 tword->flags |= W_GLOBEXP; /* XXX */
5543 glob_list = make_word_list (tword, glob_list);
5544 }
5545
5546 if (glob_list)
5547 {
5548 orig_list = (WORD_LIST *)list_append (glob_list, orig_list);
5549 tlist->next = disposables;
5550 disposables = tlist;
5551 }
5552 else if (allow_null_glob_expansion == 0)
5553 {
5554 /* Failed glob expressions are left unchanged. */
5555 tlist->next = orig_list;
5556 orig_list = tlist;
5557 }
5558 else
5559 {
5560 /* Failed glob expressions are removed. */
5561 tlist->next = disposables;
5562 disposables = tlist;
5563 }
5564 }
5565 else
5566 {
5567 /* Dequote the string. */
5568 temp_string = dequote_string (tlist->word->word);
5569 free (tlist->word->word);
5570 tlist->word->word = temp_string;
5571 tlist->next = orig_list;
5572 orig_list = tlist;
5573 }
5574
5575 free_array (glob_array);
5576 glob_array = (char **)NULL;
5577
5578 tlist = next;
5579 }
5580
5581 if (disposables)
5582 dispose_words (disposables);
5583
5584 new_list = REVERSE_LIST (orig_list, WORD_LIST *);
5585 }
5586 else
5587 {
5588 /* Dequote the words, because we're not performing globbing. */
5589 for (temp_list = new_list; temp_list; temp_list = temp_list->next)
5590 {
5591 temp_string = dequote_string (temp_list->word->word);
5592 free (temp_list->word->word);
5593 temp_list->word->word = temp_string;
5594 }
5595 }
5596 }
5597
5598 if (do_vars)
5599 {
5600 Function *assign_func;
5601
5602 /* If the remainder of the words expand to nothing, Posix.2 requires
5603 that the variable and environment assignments affect the shell's
5604 environment. */
5605 assign_func = new_list ? assign_in_env : do_assignment;
5606
5607 for (temp_list = varlist; temp_list; temp_list = temp_list->next)
5608 {
5609 this_command_name = (char *)NULL;
5610 tint = (*assign_func) (temp_list->word->word);
5611 /* Variable assignment errors in non-interactive shells running
5612 in Posix.2 mode cause the shell to exit. */
5613 if (tint == 0 && assign_func == do_assignment &&
5614 interactive_shell == 0 && posixly_correct)
5615 {
5616 last_command_exit_value = EXECUTION_FAILURE;
5617 jump_to_top_level (FORCE_EOF);
5618 }
5619 }
5620
5621 dispose_words (varlist);
5622 varlist = (WORD_LIST *)NULL;
5623 }
5624
5625 tint = list_length (new_list) + 1;
5626 RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
5627 for (tint = 0, tlist = new_list; tlist; tlist = tlist->next)
5628 glob_argv_flags[tint++] = (tlist->word->flags & W_GLOBEXP) ? '1' : '0';
5629 glob_argv_flags[tint] = '\0';
5630
5631 return (new_list);
5632 }
5633
5634 /*************************************************
5635 * *
5636 * Functions to manage special variables *
5637 * *
5638 *************************************************/
5639
5640 /* An alist of name.function for each special variable. Most of the
5641 functions don't do much, and in fact, this would be faster with a
5642 switch statement, but by the end of this file, I am sick of switch
5643 statements. */
5644
5645 #define SET_INT_VAR(name, intvar) intvar = find_variable (name) != 0
5646
5647 struct name_and_function {
5648 char *name;
5649 VFunction *function;
5650 } special_vars[] = {
5651 { "PATH", sv_path },
5652 { "MAIL", sv_mail },
5653 { "MAILPATH", sv_mail },
5654 { "MAILCHECK", sv_mail },
5655
5656 { "POSIXLY_CORRECT", sv_strict_posix },
5657 { "GLOBIGNORE", sv_globignore },
5658
5659 /* Variables which only do something special when READLINE is defined. */
5660 #if defined (READLINE)
5661 { "TERM", sv_terminal },
5662 { "TERMCAP", sv_terminal },
5663 { "TERMINFO", sv_terminal },
5664 { "HOSTFILE", sv_hostfile },
5665 #endif /* READLINE */
5666
5667 /* Variables which only do something special when HISTORY is defined. */
5668 #if defined (HISTORY)
5669 { "HISTIGNORE", sv_histignore },
5670 { "HISTSIZE", sv_histsize },
5671 { "HISTFILESIZE", sv_histsize },
5672 { "HISTCONTROL", sv_history_control },
5673 # if defined (BANG_HISTORY)
5674 { "histchars", sv_histchars },
5675 # endif /* BANG_HISTORY */
5676 #endif /* HISTORY */
5677
5678 { "IGNOREEOF", sv_ignoreeof },
5679 { "ignoreeof", sv_ignoreeof },
5680
5681 { "OPTIND", sv_optind },
5682 { "OPTERR", sv_opterr },
5683
5684 { "TEXTDOMAIN", sv_locale },
5685 { "TEXTDOMAINDIR", sv_locale },
5686 { "LC_ALL", sv_locale },
5687 { "LC_COLLATE", sv_locale },
5688 { "LC_CTYPE", sv_locale },
5689 { "LC_MESSAGES", sv_locale },
5690 { "LANG", sv_locale },
5691
5692 #if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
5693 { "TZ", sv_tz },
5694 #endif
5695
5696 { (char *)0, (VFunction *)0 }
5697 };
5698
5699 /* The variable in NAME has just had its state changed. Check to see if it
5700 is one of the special ones where something special happens. */
5701 void
5702 stupidly_hack_special_variables (name)
5703 char *name;
5704 {
5705 int i;
5706
5707 for (i = 0; special_vars[i].name; i++)
5708 {
5709 if (STREQ (special_vars[i].name, name))
5710 {
5711 (*(special_vars[i].function)) (name);
5712 return;
5713 }
5714 }
5715 }
5716
5717 /* What to do just after the PATH variable has changed. */
5718 void
5719 sv_path (name)
5720 char *name;
5721 {
5722 /* hash -r */
5723 flush_hashed_filenames ();
5724 }
5725
5726 /* What to do just after one of the MAILxxxx variables has changed. NAME
5727 is the name of the variable. This is called with NAME set to one of
5728 MAIL, MAILCHECK, or MAILPATH. */
5729 void
5730 sv_mail (name)
5731 char *name;
5732 {
5733 /* If the time interval for checking the files has changed, then
5734 reset the mail timer. Otherwise, one of the pathname vars
5735 to the users mailbox has changed, so rebuild the array of
5736 filenames. */
5737 if (name[4] == 'C') /* if (strcmp (name, "MAILCHECK") == 0) */
5738 reset_mail_timer ();
5739 else
5740 {
5741 free_mail_files ();
5742 remember_mail_dates ();
5743 }
5744 }
5745
5746 /* What to do when GLOBIGNORE changes. */
5747 void
5748 sv_globignore (name)
5749 char *name;
5750 {
5751 setup_glob_ignore (name);
5752 }
5753
5754 #if defined (READLINE)
5755 /* What to do just after one of the TERMxxx variables has changed.
5756 If we are an interactive shell, then try to reset the terminal
5757 information in readline. */
5758 void
5759 sv_terminal (name)
5760 char *name;
5761 {
5762 if (interactive_shell && no_line_editing == 0)
5763 rl_reset_terminal (get_string_value ("TERM"));
5764 }
5765
5766 void
5767 sv_hostfile (name)
5768 char *name;
5769 {
5770 hostname_list_initialized = 0;
5771 }
5772 #endif /* READLINE */
5773
5774 #if defined (HISTORY)
5775 /* What to do after the HISTSIZE or HISTFILESIZE variables change.
5776 If there is a value for this HISTSIZE (and it is numeric), then stifle
5777 the history. Otherwise, if there is NO value for this variable,
5778 unstifle the history. If name is HISTFILESIZE, and its value is
5779 numeric, truncate the history file to hold no more than that many
5780 lines. */
5781 void
5782 sv_histsize (name)
5783 char *name;
5784 {
5785 char *temp;
5786 long num;
5787
5788 temp = get_string_value (name);
5789
5790 if (temp && *temp)
5791 {
5792 if (legal_number (temp, &num))
5793 {
5794 if (name[4] == 'S')
5795 {
5796 stifle_history (num);
5797 num = where_history ();
5798 if (history_lines_this_session > num)
5799 history_lines_this_session = num;
5800 }
5801 else
5802 {
5803 history_truncate_file (get_string_value ("HISTFILE"), (int)num);
5804 if (num <= history_lines_in_file)
5805 history_lines_in_file = num;
5806 }
5807 }
5808 }
5809 else if (name[4] == 'S')
5810 unstifle_history ();
5811 }
5812
5813 /* What to do after the HISTIGNORE variable changes. */
5814 void
5815 sv_histignore (name)
5816 char *name;
5817 {
5818 setup_history_ignore (name);
5819 }
5820
5821 /* What to do after the HISTCONTROL variable changes. */
5822 void
5823 sv_history_control (name)
5824 char *name;
5825 {
5826 char *temp;
5827
5828 history_control = 0;
5829 temp = get_string_value (name);
5830
5831 if (temp && *temp && STREQN (temp, "ignore", 6))
5832 {
5833 if (temp[6] == 's') /* ignorespace */
5834 history_control = 1;
5835 else if (temp[6] == 'd') /* ignoredups */
5836 history_control = 2;
5837 else if (temp[6] == 'b') /* ignoreboth */
5838 history_control = 3;
5839 }
5840 }
5841
5842 #if defined (BANG_HISTORY)
5843 /* Setting/unsetting of the history expansion character. */
5844 void
5845 sv_histchars (name)
5846 char *name;
5847 {
5848 char *temp;
5849
5850 temp = get_string_value (name);
5851 if (temp)
5852 {
5853 history_expansion_char = *temp;
5854 if (temp[0] && temp[1])
5855 {
5856 history_subst_char = temp[1];
5857 if (temp[2])
5858 history_comment_char = temp[2];
5859 }
5860 }
5861 else
5862 {
5863 history_expansion_char = '!';
5864 history_subst_char = '^';
5865 history_comment_char = '#';
5866 }
5867 }
5868 #endif /* BANG_HISTORY */
5869 #endif /* HISTORY */
5870
5871 #if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
5872 void
5873 sv_tz (name)
5874 char *name;
5875 {
5876 tzset ();
5877 }
5878 #endif
5879
5880 /* If the variable exists, then the value of it can be the number
5881 of times we actually ignore the EOF. The default is small,
5882 (smaller than csh, anyway). */
5883 void
5884 sv_ignoreeof (name)
5885 char *name;
5886 {
5887 SHELL_VAR *tmp_var;
5888 char *temp;
5889
5890 eof_encountered = 0;
5891
5892 tmp_var = find_variable (name);
5893 ignoreeof = tmp_var != 0;
5894 temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
5895 if (temp)
5896 eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
5897 set_shellopts (); /* make sure `ignoreeof' is/is not in $SHELLOPTS */
5898 }
5899
5900 void
5901 sv_optind (name)
5902 char *name;
5903 {
5904 char *tt;
5905 int s;
5906
5907 tt = get_string_value ("OPTIND");
5908 if (tt && *tt)
5909 {
5910 s = atoi (tt);
5911
5912 /* According to POSIX, setting OPTIND=1 resets the internal state
5913 of getopt (). */
5914 if (s < 0 || s == 1)
5915 s = 0;
5916 }
5917 else
5918 s = 0;
5919 getopts_reset (s);
5920 }
5921
5922 void
5923 sv_opterr (name)
5924 char *name;
5925 {
5926 char *tt;
5927
5928 tt = get_string_value ("OPTERR");
5929 sh_opterr = (tt && *tt) ? atoi (tt) : 1;
5930 }
5931
5932 void
5933 sv_strict_posix (name)
5934 char *name;
5935 {
5936 SET_INT_VAR (name, posixly_correct);
5937 posix_initialize (posixly_correct);
5938 #if defined (READLINE)
5939 if (interactive_shell)
5940 posix_readline_initialize (posixly_correct);
5941 #endif /* READLINE */
5942 set_shellopts (); /* make sure `posix' is/is not in $SHELLOPTS */
5943 }
5944
5945 void
5946 sv_locale (name)
5947 char *name;
5948 {
5949 char *v;
5950
5951 v = get_string_value (name);
5952 if (name[0] == 'L' && name[1] == 'A') /* LANG */
5953 set_lang (name, v);
5954 else
5955 set_locale_var (name, v); /* LC_*, TEXTDOMAIN* */
5956 }