]> git.ipfire.org Git - thirdparty/bash.git/blame - subst.c.save1
commit bash-20110218 snapshot
[thirdparty/bash.git] / subst.c.save1
CommitLineData
e192f341
CR
1/* subst.c -- The part of the shell that does parameter, command, arithmetic,
2 and globbing substitutions. */
3
4/* ``Have a little faith, there's magic in the night. You ain't a
5 beauty, but, hey, you're alright.'' */
6
7/* Copyright (C) 1987-2010 Free Software Foundation, Inc.
8
9 This file is part of GNU Bash, the Bourne Again SHell.
10
11 Bash is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 Bash is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with Bash. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "config.h"
26
27#include "bashtypes.h"
28#include <stdio.h>
29#include "chartypes.h"
30#if defined (HAVE_PWD_H)
31# include <pwd.h>
32#endif
33#include <signal.h>
34#include <errno.h>
35
36#if defined (HAVE_UNISTD_H)
37# include <unistd.h>
38#endif
39
40#include "bashansi.h"
41#include "posixstat.h"
42#include "bashintl.h"
43
44#include "shell.h"
45#include "parser.h"
46#include "flags.h"
47#include "jobs.h"
48#include "execute_cmd.h"
49#include "filecntl.h"
50#include "trap.h"
51#include "pathexp.h"
52#include "mailcheck.h"
53
54#include "shmbutil.h"
55#include "typemax.h"
56
57#include "builtins/getopt.h"
58#include "builtins/common.h"
59
60#include "builtins/builtext.h"
61
62#include <tilde/tilde.h>
63#include <glob/strmatch.h>
64
65#if !defined (errno)
66extern int errno;
67#endif /* !errno */
68
69/* The size that strings change by. */
70#define DEFAULT_INITIAL_ARRAY_SIZE 112
71#define DEFAULT_ARRAY_SIZE 128
72
73/* Variable types. */
74#define VT_VARIABLE 0
75#define VT_POSPARMS 1
76#define VT_ARRAYVAR 2
77#define VT_ARRAYMEMBER 3
78#define VT_ASSOCVAR 4
79
80#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
81
82/* Flags for quoted_strchr */
83#define ST_BACKSL 0x01
84#define ST_CTLESC 0x02
85#define ST_SQUOTE 0x04 /* unused yet */
86#define ST_DQUOTE 0x08 /* unused yet */
87
88/* Flags for the `pflags' argument to param_expand() */
89#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
90#define PF_IGNUNBOUND 0x02 /* ignore unbound vars even if -u set */
91#define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 */
92
93/* These defs make it easier to use the editor. */
94#define LBRACE '{'
95#define RBRACE '}'
96#define LPAREN '('
97#define RPAREN ')'
98
99#if defined (HANDLE_MULTIBYTE)
100#define WLPAREN L'('
101#define WRPAREN L')'
102#endif
103
104/* Evaluates to 1 if C is one of the shell's special parameters whose length
105 can be taken, but is also one of the special expansion characters. */
106#define VALID_SPECIAL_LENGTH_PARAM(c) \
107 ((c) == '-' || (c) == '?' || (c) == '#')
108
109/* Evaluates to 1 if C is one of the shell's special parameters for which an
110 indirect variable reference may be made. */
111#define VALID_INDIR_PARAM(c) \
112 ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
113
114/* Evaluates to 1 if C is one of the OP characters that follows the parameter
115 in ${parameter[:]OPword}. */
116#define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)
117
118/* Evaluates to 1 if this is one of the shell's special variables. */
119#define SPECIAL_VAR(name, wi) \
120 ((DIGIT (*name) && all_digits (name)) || \
121 (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \
122 (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1])))
123
124/* An expansion function that takes a string and a quoted flag and returns
125 a WORD_LIST *. Used as the type of the third argument to
126 expand_string_if_necessary(). */
127typedef WORD_LIST *EXPFUNC __P((char *, int));
128
129/* Process ID of the last command executed within command substitution. */
130pid_t last_command_subst_pid = NO_PID;
131pid_t current_command_subst_pid = NO_PID;
132
133/* Variables used to keep track of the characters in IFS. */
134SHELL_VAR *ifs_var;
135char *ifs_value;
136unsigned char ifs_cmap[UCHAR_MAX + 1];
137
138#if defined (HANDLE_MULTIBYTE)
139unsigned char ifs_firstc[MB_LEN_MAX];
140size_t ifs_firstc_len;
141#else
142unsigned char ifs_firstc;
143#endif
144
145/* Sentinel to tell when we are performing variable assignments preceding a
146 command name and putting them into the environment. Used to make sure
147 we use the temporary environment when looking up variable values. */
148int assigning_in_environment;
149
150/* Used to hold a list of variable assignments preceding a command. Global
151 so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
152 SIGCHLD trap and so it can be saved and restored by the trap handlers. */
153WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
154
155/* Extern functions and variables from different files. */
156extern int last_command_exit_value, last_command_exit_signal;
157extern int subshell_environment, line_number;
158extern int subshell_level, parse_and_execute_level, sourcelevel;
159extern int eof_encountered;
160extern int return_catch_flag, return_catch_value;
161extern pid_t dollar_dollar_pid;
162extern int posixly_correct;
163extern char *this_command_name;
164extern struct fd_bitmap *current_fds_to_close;
165extern int wordexp_only;
166extern int expanding_redir;
167extern int tempenv_assign_error;
168
169#if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)
170extern wchar_t *wcsdup __P((const wchar_t *));
171#endif
172
173/* Non-zero means to allow unmatched globbed filenames to expand to
174 a null file. */
175int allow_null_glob_expansion;
176
177/* Non-zero means to throw an error when globbing fails to match anything. */
178int fail_glob_expansion;
179
180#if 0
181/* Variables to keep track of which words in an expanded word list (the
182 output of expand_word_list_internal) are the result of globbing
183 expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c.
184 (CURRENTLY UNUSED). */
185char *glob_argv_flags;
186static int glob_argv_flags_size;
187#endif
188
189static WORD_LIST expand_word_error, expand_word_fatal;
190static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
191static char expand_param_error, expand_param_fatal;
192static char extract_string_error, extract_string_fatal;
193
194/* Tell the expansion functions to not longjmp back to top_level on fatal
195 errors. Enabled when doing completion and prompt string expansion. */
196static int no_longjmp_on_fatal_error = 0;
197
198/* Set by expand_word_unsplit; used to inhibit splitting and re-joining
199 $* on $IFS, primarily when doing assignment statements. */
200static int expand_no_split_dollar_star = 0;
201
202/* A WORD_LIST of words to be expanded by expand_word_list_internal,
203 without any leading variable assignments. */
204static WORD_LIST *garglist = (WORD_LIST *)NULL;
205
206static char *quoted_substring __P((char *, int, int));
207static int quoted_strlen __P((char *));
208static char *quoted_strchr __P((char *, int, int));
209
210static char *expand_string_if_necessary __P((char *, int, EXPFUNC *));
211static inline char *expand_string_to_string_internal __P((char *, int, EXPFUNC *));
212static WORD_LIST *call_expand_word_internal __P((WORD_DESC *, int, int, int *, int *));
213static WORD_LIST *expand_string_internal __P((char *, int));
214static WORD_LIST *expand_string_leave_quoted __P((char *, int));
215static WORD_LIST *expand_string_for_rhs __P((char *, int, int *, int *));
216
217static WORD_LIST *list_quote_escapes __P((WORD_LIST *));
218static char *make_quoted_char __P((int));
219static WORD_LIST *quote_list __P((WORD_LIST *));
220
221static int unquoted_substring __P((char *, char *));
222static int unquoted_member __P((int, char *));
223
224#if defined (ARRAY_VARS)
225static SHELL_VAR *do_compound_assignment __P((char *, char *, int));
226#endif
227static int do_assignment_internal __P((const WORD_DESC *, int));
228
229static char *string_extract_verbatim __P((char *, size_t, int *, char *, int));
230static char *string_extract __P((char *, int *, char *, int));
231static char *string_extract_double_quoted __P((char *, int *, int));
232static inline char *string_extract_single_quoted __P((char *, int *));
233static inline int skip_single_quoted __P((const char *, size_t, int));
234static int skip_double_quoted __P((char *, size_t, int));
235static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int));
236static char *extract_dollar_brace_string __P((char *, int *, int, int));
237static int skip_matched_pair __P((const char *, int, int, int, int));
238
239static char *pos_params __P((char *, int, int, int));
240
241static unsigned char *mb_getcharlens __P((char *, int));
242
243static char *remove_upattern __P((char *, char *, int));
244#if defined (HANDLE_MULTIBYTE)
245static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int));
246#endif
247static char *remove_pattern __P((char *, char *, int));
248
249static int match_upattern __P((char *, char *, int, char **, char **));
250#if defined (HANDLE_MULTIBYTE)
251static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
252#endif
253static int match_pattern __P((char *, char *, int, char **, char **));
254static int getpatspec __P((int, char *));
255static char *getpattern __P((char *, int, int));
256static char *variable_remove_pattern __P((char *, char *, int, int));
257static char *list_remove_pattern __P((WORD_LIST *, char *, int, int, int));
258static char *parameter_list_remove_pattern __P((int, char *, int, int));
259#ifdef ARRAY_VARS
260static char *array_remove_pattern __P((SHELL_VAR *, char *, int, char *, int));
261#endif
262static char *parameter_brace_remove_pattern __P((char *, char *, int, char *, int, int, int));
263
264static char *process_substitute __P((char *, int));
265
266static char *read_comsub __P((int, int, int *));
267
268#ifdef ARRAY_VARS
269static arrayind_t array_length_reference __P((char *));
270#endif
271
272static int valid_brace_expansion_word __P((char *, int));
273static int chk_atstar __P((char *, int, int *, int *));
274static int chk_arithsub __P((const char *, int));
275
276static WORD_DESC *parameter_brace_expand_word __P((char *, int, int, int, arrayind_t *));
277static WORD_DESC *parameter_brace_expand_indir __P((char *, int, int, int *, int *));
278static WORD_DESC *parameter_brace_expand_rhs __P((char *, char *, int, int, int *, int *));
279static void parameter_brace_expand_error __P((char *, char *));
280
281static int valid_length_expression __P((char *));
282static intmax_t parameter_brace_expand_length __P((char *));
283
284static char *skiparith __P((char *, int));
285static int verify_substring_values __P((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
286static int get_var_and_type __P((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **));
287static char *mb_substring __P((char *, int, int));
288static char *parameter_brace_substring __P((char *, char *, int, char *, int, int));
289
290static int shouldexp_replacement __P((char *));
291
292static char *pos_params_pat_subst __P((char *, char *, char *, int));
293
294static char *parameter_brace_patsub __P((char *, char *, int, char *, int, int));
295
296static char *pos_params_casemod __P((char *, char *, int, int));
297static char *parameter_brace_casemod __P((char *, char *, int, int, char *, int, int));
298
299static WORD_DESC *parameter_brace_expand __P((char *, int *, int, int, int *, int *));
300static WORD_DESC *param_expand __P((char *, int *, int, int *, int *, int *, int *, int));
301
302static WORD_LIST *expand_word_internal __P((WORD_DESC *, int, int, int *, int *));
303
304static WORD_LIST *word_list_split __P((WORD_LIST *));
305
306static void exp_jump_to_top_level __P((int));
307
308static WORD_LIST *separate_out_assignments __P((WORD_LIST *));
309static WORD_LIST *glob_expand_word_list __P((WORD_LIST *, int));
310#ifdef BRACE_EXPANSION
311static WORD_LIST *brace_expand_word_list __P((WORD_LIST *, int));
312#endif
313#if defined (ARRAY_VARS)
314static int make_internal_declare __P((char *, char *));
315#endif
316static WORD_LIST *shell_expand_word_list __P((WORD_LIST *, int));
317static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int));
318
319/* **************************************************************** */
320/* */
321/* Utility Functions */
322/* */
323/* **************************************************************** */
324
325#if defined (DEBUG)
326void
327dump_word_flags (flags)
328 int flags;
329{
330 int f;
331
332 f = flags;
333 fprintf (stderr, "%d -> ", f);
334 if (f & W_ASSIGNASSOC)
335 {
336 f &= ~W_ASSIGNASSOC;
337 fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
338 }
339 if (f & W_HASCTLESC)
340 {
341 f &= ~W_HASCTLESC;
342 fprintf (stderr, "W_HASCTLESC%s", f ? "|" : "");
343 }
344 if (f & W_NOPROCSUB)
345 {
346 f &= ~W_NOPROCSUB;
347 fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
348 }
349 if (f & W_DQUOTE)
350 {
351 f &= ~W_DQUOTE;
352 fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
353 }
354 if (f & W_HASQUOTEDNULL)
355 {
356 f &= ~W_HASQUOTEDNULL;
357 fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
358 }
359 if (f & W_ASSIGNARG)
360 {
361 f &= ~W_ASSIGNARG;
362 fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
363 }
364 if (f & W_ASSNBLTIN)
365 {
366 f &= ~W_ASSNBLTIN;
367 fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
368 }
369 if (f & W_COMPASSIGN)
370 {
371 f &= ~W_COMPASSIGN;
372 fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
373 }
374 if (f & W_NOEXPAND)
375 {
376 f &= ~W_NOEXPAND;
377 fprintf (stderr, "W_NOEXPAND%s", f ? "|" : "");
378 }
379 if (f & W_ITILDE)
380 {
381 f &= ~W_ITILDE;
382 fprintf (stderr, "W_ITILDE%s", f ? "|" : "");
383 }
384 if (f & W_NOTILDE)
385 {
386 f &= ~W_NOTILDE;
387 fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
388 }
389 if (f & W_ASSIGNRHS)
390 {
391 f &= ~W_ASSIGNRHS;
392 fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
393 }
394 if (f & W_NOCOMSUB)
395 {
396 f &= ~W_NOCOMSUB;
397 fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
398 }
399 if (f & W_DOLLARSTAR)
400 {
401 f &= ~W_DOLLARSTAR;
402 fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : "");
403 }
404 if (f & W_DOLLARAT)
405 {
406 f &= ~W_DOLLARAT;
407 fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
408 }
409 if (f & W_TILDEEXP)
410 {
411 f &= ~W_TILDEEXP;
412 fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
413 }
414 if (f & W_NOSPLIT2)
415 {
416 f &= ~W_NOSPLIT2;
417 fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
418 }
419 if (f & W_NOGLOB)
420 {
421 f &= ~W_NOGLOB;
422 fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
423 }
424 if (f & W_NOSPLIT)
425 {
426 f &= ~W_NOSPLIT;
427 fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
428 }
429 if (f & W_GLOBEXP)
430 {
431 f &= ~W_GLOBEXP;
432 fprintf (stderr, "W_GLOBEXP%s", f ? "|" : "");
433 }
434 if (f & W_ASSIGNMENT)
435 {
436 f &= ~W_ASSIGNMENT;
437 fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
438 }
439 if (f & W_QUOTED)
440 {
441 f &= ~W_QUOTED;
442 fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
443 }
444 if (f & W_HASDOLLAR)
445 {
446 f &= ~W_HASDOLLAR;
447 fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
448 }
449 fprintf (stderr, "\n");
450 fflush (stderr);
451}
452#endif
453
454#ifdef INCLUDE_UNUSED
455static char *
456quoted_substring (string, start, end)
457 char *string;
458 int start, end;
459{
460 register int len, l;
461 register char *result, *s, *r;
462
463 len = end - start;
464
465 /* Move to string[start], skipping quoted characters. */
466 for (s = string, l = 0; *s && l < start; )
467 {
468 if (*s == CTLESC)
469 {
470 s++;
471 continue;
472 }
473 l++;
474 if (*s == 0)
475 break;
476 }
477
478 r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */
479
480 /* Copy LEN characters, including quote characters. */
481 s = string + l;
482 for (l = 0; l < len; s++)
483 {
484 if (*s == CTLESC)
485 *r++ = *s++;
486 *r++ = *s;
487 l++;
488 if (*s == 0)
489 break;
490 }
491 *r = '\0';
492 return result;
493}
494#endif
495
496#ifdef INCLUDE_UNUSED
497/* Return the length of S, skipping over quoted characters */
498static int
499quoted_strlen (s)
500 char *s;
501{
502 register char *p;
503 int i;
504
505 i = 0;
506 for (p = s; *p; p++)
507 {
508 if (*p == CTLESC)
509 {
510 p++;
511 if (*p == 0)
512 return (i + 1);
513 }
514 i++;
515 }
516
517 return i;
518}
519#endif
520
521/* Find the first occurrence of character C in string S, obeying shell
522 quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
523 characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters
524 escaped with CTLESC are skipped. */
525static char *
526quoted_strchr (s, c, flags)
527 char *s;
528 int c, flags;
529{
530 register char *p;
531
532 for (p = s; *p; p++)
533 {
534 if (((flags & ST_BACKSL) && *p == '\\')
535 || ((flags & ST_CTLESC) && *p == CTLESC))
536 {
537 p++;
538 if (*p == '\0')
539 return ((char *)NULL);
540 continue;
541 }
542 else if (*p == c)
543 return p;
544 }
545 return ((char *)NULL);
546}
547
548/* Return 1 if CHARACTER appears in an unquoted portion of
549 STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */
550static int
551unquoted_member (character, string)
552 int character;
553 char *string;
554{
555 size_t slen;
556 int sindex, c;
557 DECLARE_MBSTATE;
558
559 slen = strlen (string);
560 sindex = 0;
561 while (c = string[sindex])
562 {
563 if (c == character)
564 return (1);
565
566 switch (c)
567 {
568 default:
569 ADVANCE_CHAR (string, slen, sindex);
570 break;
571
572 case '\\':
573 sindex++;
574 if (string[sindex])
575 ADVANCE_CHAR (string, slen, sindex);
576 break;
577
578 case '\'':
579 sindex = skip_single_quoted (string, slen, ++sindex);
580 break;
581
582 case '"':
583 sindex = skip_double_quoted (string, slen, ++sindex);
584 break;
585 }
586 }
587 return (0);
588}
589
590/* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
591static int
592unquoted_substring (substr, string)
593 char *substr, *string;
594{
595 size_t slen;
596 int sindex, c, sublen;
597 DECLARE_MBSTATE;
598
599 if (substr == 0 || *substr == '\0')
600 return (0);
601
602 slen = strlen (string);
603 sublen = strlen (substr);
604 for (sindex = 0; c = string[sindex]; )
605 {
606 if (STREQN (string + sindex, substr, sublen))
607 return (1);
608
609 switch (c)
610 {
611 case '\\':
612 sindex++;
613 if (string[sindex])
614 ADVANCE_CHAR (string, slen, sindex);
615 break;
616
617 case '\'':
618 sindex = skip_single_quoted (string, slen, ++sindex);
619 break;
620
621 case '"':
622 sindex = skip_double_quoted (string, slen, ++sindex);
623 break;
624
625 default:
626 ADVANCE_CHAR (string, slen, sindex);
627 break;
628 }
629 }
630 return (0);
631}
632
633/* Most of the substitutions must be done in parallel. In order
634 to avoid using tons of unclear goto's, I have some functions
635 for manipulating malloc'ed strings. They all take INDX, a
636 pointer to an integer which is the offset into the string
637 where manipulation is taking place. They also take SIZE, a
638 pointer to an integer which is the current length of the
639 character array for this string. */
640
641/* Append SOURCE to TARGET at INDEX. SIZE is the current amount
642 of space allocated to TARGET. SOURCE can be NULL, in which
643 case nothing happens. Gets rid of SOURCE by freeing it.
644 Returns TARGET in case the location has changed. */
645INLINE char *
646sub_append_string (source, target, indx, size)
647 char *source, *target;
648 int *indx, *size;
649{
650 if (source)
651 {
652 int srclen, n;
653
654 srclen = STRLEN (source);
655 if (srclen >= (int)(*size - *indx))
656 {
657 n = srclen + *indx;
658 n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
659 target = (char *)xrealloc (target, (*size = n));
660 }
661
662 FASTCOPY (source, target + *indx, srclen);
663 *indx += srclen;
664 target[*indx] = '\0';
665
666 free (source);
667 }
668 return (target);
669}
670
671#if 0
672/* UNUSED */
673/* Append the textual representation of NUMBER to TARGET.
674 INDX and SIZE are as in SUB_APPEND_STRING. */
675char *
676sub_append_number (number, target, indx, size)
677 intmax_t number;
678 int *indx, *size;
679 char *target;
680{
681 char *temp;
682
683 temp = itos (number);
684 return (sub_append_string (temp, target, indx, size));
685}
686#endif
687
688/* Extract a substring from STRING, starting at SINDEX and ending with
689 one of the characters in CHARLIST. Don't make the ending character
690 part of the string. Leave SINDEX pointing at the ending character.
691 Understand about backslashes in the string. If (flags & SX_VARNAME)
692 is non-zero, and array variables have been compiled into the shell,
693 everything between a `[' and a corresponding `]' is skipped over.
694 If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
695 update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must
696 contain a closing character from CHARLIST. */
697static char *
698string_extract (string, sindex, charlist, flags)
699 char *string;
700 int *sindex;
701 char *charlist;
702 int flags;
703{
704 register int c, i;
705 int found;
706 size_t slen;
707 char *temp;
708 DECLARE_MBSTATE;
709
710 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
711 i = *sindex;
712 found = 0;
713 while (c = string[i])
714 {
715 if (c == '\\')
716 {
717 if (string[i + 1])
718 i++;
719 else
720 break;
721 }
722#if defined (ARRAY_VARS)
723 else if ((flags & SX_VARNAME) && c == '[')
724 {
725 int ni;
726 /* If this is an array subscript, skip over it and continue. */
727 ni = skipsubscript (string, i, 0);
728 if (string[ni] == ']')
729 i = ni;
730 }
731#endif
732 else if (MEMBER (c, charlist))
733 {
734 found = 1;
735 break;
736 }
737
738 ADVANCE_CHAR (string, slen, i);
739 }
740
741 /* If we had to have a matching delimiter and didn't find one, return an
742 error and let the caller deal with it. */
743 if ((flags & SX_REQMATCH) && found == 0)
744 {
745 *sindex = i;
746 return (&extract_string_error);
747 }
748
749 temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
750 *sindex = i;
751
752 return (temp);
753}
754
755/* Extract the contents of STRING as if it is enclosed in double quotes.
756 SINDEX, when passed in, is the offset of the character immediately
757 following the opening double quote; on exit, SINDEX is left pointing after
758 the closing double quote. If STRIPDQ is non-zero, unquoted double
759 quotes are stripped and the string is terminated by a null byte.
760 Backslashes between the embedded double quotes are processed. If STRIPDQ
761 is zero, an unquoted `"' terminates the string. */
762static char *
763string_extract_double_quoted (string, sindex, stripdq)
764 char *string;
765 int *sindex, stripdq;
766{
767 size_t slen;
768 char *send;
769 int j, i, t;
770 unsigned char c;
771 char *temp, *ret; /* The new string we return. */
772 int pass_next, backquote, si; /* State variables for the machine. */
773 int dquote;
774 DECLARE_MBSTATE;
775
776 slen = strlen (string + *sindex) + *sindex;
777 send = string + slen;
778
779 pass_next = backquote = dquote = 0;
780 temp = (char *)xmalloc (1 + slen - *sindex);
781
782 j = 0;
783 i = *sindex;
784 while (c = string[i])
785 {
786 /* Process a character that was quoted by a backslash. */
787 if (pass_next)
788 {
789 /* XXX - take another look at this in light of Interp 221 */
790 /* Posix.2 sez:
791
792 ``The backslash shall retain its special meaning as an escape
793 character only when followed by one of the characters:
794 $ ` " \ <newline>''.
795
796 If STRIPDQ is zero, we handle the double quotes here and let
797 expand_word_internal handle the rest. If STRIPDQ is non-zero,
798 we have already been through one round of backslash stripping,
799 and want to strip these backslashes only if DQUOTE is non-zero,
800 indicating that we are inside an embedded double-quoted string. */
801
802 /* If we are in an embedded quoted string, then don't strip
803 backslashes before characters for which the backslash
804 retains its special meaning, but remove backslashes in
805 front of other characters. If we are not in an
806 embedded quoted string, don't strip backslashes at all.
807 This mess is necessary because the string was already
808 surrounded by double quotes (and sh has some really weird
809 quoting rules).
810 The returned string will be run through expansion as if
811 it were double-quoted. */
812 if ((stripdq == 0 && c != '"') ||
813 (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0)))
814 temp[j++] = '\\';
815 pass_next = 0;
816
817add_one_character:
818 COPY_CHAR_I (temp, j, string, send, i);
819 continue;
820 }
821
822 /* A backslash protects the next character. The code just above
823 handles preserving the backslash in front of any character but
824 a double quote. */
825 if (c == '\\')
826 {
827 pass_next++;
828 i++;
829 continue;
830 }
831
832 /* Inside backquotes, ``the portion of the quoted string from the
833 initial backquote and the characters up to the next backquote
834 that is not preceded by a backslash, having escape characters
835 removed, defines that command''. */
836 if (backquote)
837 {
838 if (c == '`')
839 backquote = 0;
840 temp[j++] = c;
841 i++;
842 continue;
843 }
844
845 if (c == '`')
846 {
847 temp[j++] = c;
848 backquote++;
849 i++;
850 continue;
851 }
852
853 /* Pass everything between `$(' and the matching `)' or a quoted
854 ${ ... } pair through according to the Posix.2 specification. */
855 if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
856 {
857 int free_ret = 1;
858
859 si = i + 2;
860 if (string[i + 1] == LPAREN)
861 ret = extract_command_subst (string, &si, 0);
862 else
863 ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0);
864
865 temp[j++] = '$';
866 temp[j++] = string[i + 1];
867
868 /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error
869 is set. */
870 if (ret == 0 && no_longjmp_on_fatal_error)
871 {
872 free_ret = 0;
873 ret = string + i + 2;
874 }
875
876 for (t = 0; ret[t]; t++, j++)
877 temp[j] = ret[t];
878 temp[j] = string[si];
879
880 if (string[si])
881 {
882 j++;
883 i = si + 1;
884 }
885 else
886 i = si;
887
888 if (free_ret)
889 free (ret);
890 continue;
891 }
892
893 /* Add any character but a double quote to the quoted string we're
894 accumulating. */
895 if (c != '"')
896 goto add_one_character;
897
898 /* c == '"' */
899 if (stripdq)
900 {
901 dquote ^= 1;
902 i++;
903 continue;
904 }
905
906 break;
907 }
908 temp[j] = '\0';
909
910 /* Point to after the closing quote. */
911 if (c)
912 i++;
913 *sindex = i;
914
915 return (temp);
916}
917
918/* This should really be another option to string_extract_double_quoted. */
919static int
920skip_double_quoted (string, slen, sind)
921 char *string;
922 size_t slen;
923 int sind;
924{
925 int c, i;
926 char *ret;
927 int pass_next, backquote, si;
928 DECLARE_MBSTATE;
929
930 pass_next = backquote = 0;
931 i = sind;
932 while (c = string[i])
933 {
934 if (pass_next)
935 {
936 pass_next = 0;
937 ADVANCE_CHAR (string, slen, i);
938 continue;
939 }
940 else if (c == '\\')
941 {
942 pass_next++;
943 i++;
944 continue;
945 }
946 else if (backquote)
947 {
948 if (c == '`')
949 backquote = 0;
950 ADVANCE_CHAR (string, slen, i);
951 continue;
952 }
953 else if (c == '`')
954 {
955 backquote++;
956 i++;
957 continue;
958 }
959 else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
960 {
961 si = i + 2;
962 if (string[i + 1] == LPAREN)
963 ret = extract_command_subst (string, &si, SX_NOALLOC);
964 else
965 ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC);
966
967 i = si + 1;
968 continue;
969 }
970 else if (c != '"')
971 {
972 ADVANCE_CHAR (string, slen, i);
973 continue;
974 }
975 else
976 break;
977 }
978
979 if (c)
980 i++;
981
982 return (i);
983}
984
985/* Extract the contents of STRING as if it is enclosed in single quotes.
986 SINDEX, when passed in, is the offset of the character immediately
987 following the opening single quote; on exit, SINDEX is left pointing after
988 the closing single quote. */
989static inline char *
990string_extract_single_quoted (string, sindex)
991 char *string;
992 int *sindex;
993{
994 register int i;
995 size_t slen;
996 char *t;
997 DECLARE_MBSTATE;
998
999 /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */
1000 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
1001 i = *sindex;
1002 while (string[i] && string[i] != '\'')
1003 ADVANCE_CHAR (string, slen, i);
1004
1005 t = substring (string, *sindex, i);
1006
1007 if (string[i])
1008 i++;
1009 *sindex = i;
1010
1011 return (t);
1012}
1013
1014static inline int
1015skip_single_quoted (string, slen, sind)
1016 const char *string;
1017 size_t slen;
1018 int sind;
1019{
1020 register int c;
1021 DECLARE_MBSTATE;
1022
1023 c = sind;
1024 while (string[c] && string[c] != '\'')
1025 ADVANCE_CHAR (string, slen, c);
1026
1027 if (string[c])
1028 c++;
1029 return c;
1030}
1031
1032/* Just like string_extract, but doesn't hack backslashes or any of
1033 that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */
1034static char *
1035string_extract_verbatim (string, slen, sindex, charlist, flags)
1036 char *string;
1037 size_t slen;
1038 int *sindex;
1039 char *charlist;
1040 int flags;
1041{
1042 register int i;
1043#if defined (HANDLE_MULTIBYTE)
1044 size_t clen;
1045 wchar_t *wcharlist;
1046#endif
1047 int c;
1048 char *temp;
1049 DECLARE_MBSTATE;
1050
1051 if (charlist[0] == '\'' && charlist[1] == '\0')
1052 {
1053 temp = string_extract_single_quoted (string, sindex);
1054 --*sindex; /* leave *sindex at separator character */
1055 return temp;
1056 }
1057
1058 i = *sindex;
1059#if 0
1060 /* See how the MBLEN and ADVANCE_CHAR macros work to understand why we need
1061 this only if MB_CUR_MAX > 1. */
1062 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 1;
1063#endif
1064#if defined (HANDLE_MULTIBYTE)
1065 clen = strlen (charlist);
1066 wcharlist = 0;
1067#endif
1068 while (c = string[i])
1069 {
1070#if defined (HANDLE_MULTIBYTE)
1071 size_t mblength;
1072#endif
1073 if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
1074 {
1075 i += 2;
1076 continue;
1077 }
1078 /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
1079 through, to protect the CTLNULs from later calls to
1080 remove_quoted_nulls. */
1081 else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
1082 {
1083 i += 2;
1084 continue;
1085 }
1086
1087#if defined (HANDLE_MULTIBYTE)
1088 mblength = MBLEN (string + i, slen - i);
1089 if (mblength > 1)
1090 {
1091 wchar_t wc;
1092 mblength = mbtowc (&wc, string + i, slen - i);
1093 if (MB_INVALIDCH (mblength))
1094 {
1095 if (MEMBER (c, charlist))
1096 break;
1097 }
1098 else
1099 {
1100 if (wcharlist == 0)
1101 {
1102 size_t len;
1103 len = mbstowcs (wcharlist, charlist, 0);
1104 if (len == -1)
1105 len = 0;
1106 wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
1107 mbstowcs (wcharlist, charlist, len + 1);
1108 }
1109
1110 if (wcschr (wcharlist, wc))
1111 break;
1112 }
1113 }
1114 else
1115#endif
1116 if (MEMBER (c, charlist))
1117 break;
1118
1119 ADVANCE_CHAR (string, slen, i);
1120 }
1121
1122#if defined (HANDLE_MULTIBYTE)
1123 FREE (wcharlist);
1124#endif
1125
1126 temp = substring (string, *sindex, i);
1127 *sindex = i;
1128
1129 return (temp);
1130}
1131
1132/* Extract the $( construct in STRING, and return a new string.
1133 Start extracting at (SINDEX) as if we had just seen "$(".
1134 Make (SINDEX) get the position of the matching ")". )
1135 XFLAGS is additional flags to pass to other extraction functions. */
1136char *
1137extract_command_subst (string, sindex, xflags)
1138 char *string;
1139 int *sindex;
1140 int xflags;
1141{
1142 if (string[*sindex] == LPAREN)
1143 return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
1144 else
1145 {
1146 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1147 return (xparse_dolparen (string, string+*sindex, sindex, xflags));
1148 }
1149}
1150
1151/* Extract the $[ construct in STRING, and return a new string. (])
1152 Start extracting at (SINDEX) as if we had just seen "$[".
1153 Make (SINDEX) get the position of the matching "]". */
1154char *
1155extract_arithmetic_subst (string, sindex)
1156 char *string;
1157 int *sindex;
1158{
1159 return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/
1160}
1161
1162#if defined (PROCESS_SUBSTITUTION)
1163/* Extract the <( or >( construct in STRING, and return a new string.
1164 Start extracting at (SINDEX) as if we had just seen "<(".
1165 Make (SINDEX) get the position of the matching ")". */ /*))*/
1166char *
1167extract_process_subst (string, starter, sindex)
1168 char *string;
1169 char *starter;
1170 int *sindex;
1171{
1172 return (extract_delimited_string (string, sindex, starter, "(", ")", 0));
1173}
1174#endif /* PROCESS_SUBSTITUTION */
1175
1176#if defined (ARRAY_VARS)
1177/* This can be fooled by unquoted right parens in the passed string. If
1178 each caller verifies that the last character in STRING is a right paren,
1179 we don't even need to call extract_delimited_string. */
1180char *
1181extract_array_assignment_list (string, sindex)
1182 char *string;
1183 int *sindex;
1184{
1185 int slen;
1186 char *ret;
1187
1188 slen = strlen (string); /* ( */
1189 if (string[slen - 1] == ')')
1190 {
1191 ret = substring (string, *sindex, slen - 1);
1192 *sindex = slen - 1;
1193 return ret;
1194 }
1195 return 0;
1196}
1197#endif
1198
1199/* Extract and create a new string from the contents of STRING, a
1200 character string delimited with OPENER and CLOSER. SINDEX is
1201 the address of an int describing the current offset in STRING;
1202 it should point to just after the first OPENER found. On exit,
1203 SINDEX gets the position of the last character of the matching CLOSER.
1204 If OPENER is more than a single character, ALT_OPENER, if non-null,
1205 contains a character string that can also match CLOSER and thus
1206 needs to be skipped. */
1207static char *
1208extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
1209 char *string;
1210 int *sindex;
1211 char *opener, *alt_opener, *closer;
1212 int flags;
1213{
1214 int i, c, si;
1215 size_t slen;
1216 char *t, *result;
1217 int pass_character, nesting_level, in_comment;
1218 int len_closer, len_opener, len_alt_opener;
1219 DECLARE_MBSTATE;
1220
1221 slen = strlen (string + *sindex) + *sindex;
1222 len_opener = STRLEN (opener);
1223 len_alt_opener = STRLEN (alt_opener);
1224 len_closer = STRLEN (closer);
1225
1226 pass_character = in_comment = 0;
1227
1228 nesting_level = 1;
1229 i = *sindex;
1230
1231 while (nesting_level)
1232 {
1233 c = string[i];
1234
1235 if (c == 0)
1236 break;
1237
1238 if (in_comment)
1239 {
1240 if (c == '\n')
1241 in_comment = 0;
1242 ADVANCE_CHAR (string, slen, i);
1243 continue;
1244 }
1245
1246 if (pass_character) /* previous char was backslash */
1247 {
1248 pass_character = 0;
1249 ADVANCE_CHAR (string, slen, i);
1250 continue;
1251 }
1252
1253 /* Not exactly right yet; should handle shell metacharacters and
1254 multibyte characters, too. See COMMENT_BEGIN define in parse.y */
1255 if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
1256 {
1257 in_comment = 1;
1258 ADVANCE_CHAR (string, slen, i);
1259 continue;
1260 }
1261
1262 if (c == CTLESC || c == '\\')
1263 {
1264 pass_character++;
1265 i++;
1266 continue;
1267 }
1268
1269 /* Process a nested command substitution, but only if we're parsing an
1270 arithmetic substitution. */
1271 if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
1272 {
1273 si = i + 2;
1274 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1275 i = si + 1;
1276 continue;
1277 }
1278
1279 /* Process a nested OPENER. */
1280 if (STREQN (string + i, opener, len_opener))
1281 {
1282 si = i + len_opener;
1283 t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
1284 i = si + 1;
1285 continue;
1286 }
1287
1288 /* Process a nested ALT_OPENER */
1289 if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
1290 {
1291 si = i + len_alt_opener;
1292 t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
1293 i = si + 1;
1294 continue;
1295 }
1296
1297 /* If the current substring terminates the delimited string, decrement
1298 the nesting level. */
1299 if (STREQN (string + i, closer, len_closer))
1300 {
1301 i += len_closer - 1; /* move to last byte of the closer */
1302 nesting_level--;
1303 if (nesting_level == 0)
1304 break;
1305 }
1306
1307 /* Pass old-style command substitution through verbatim. */
1308 if (c == '`')
1309 {
1310 si = i + 1;
1311 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1312 i = si + 1;
1313 continue;
1314 }
1315
1316 /* Pass single-quoted and double-quoted strings through verbatim. */
1317 if (c == '\'' || c == '"')
1318 {
1319 si = i + 1;
1320 i = (c == '\'') ? skip_single_quoted (string, slen, si)
1321 : skip_double_quoted (string, slen, si);
1322 continue;
1323 }
1324
1325 /* move past this character, which was not special. */
1326 ADVANCE_CHAR (string, slen, i);
1327 }
1328
1329 if (c == 0 && nesting_level)
1330 {
1331 if (no_longjmp_on_fatal_error == 0)
1332 {
1333 report_error (_("bad substitution: no closing `%s' in %s"), closer, string);
1334 last_command_exit_value = EXECUTION_FAILURE;
1335 exp_jump_to_top_level (DISCARD);
1336 }
1337 else
1338 {
1339 *sindex = i;
1340 return (char *)NULL;
1341 }
1342 }
1343
1344 si = i - *sindex - len_closer + 1;
1345 if (flags & SX_NOALLOC)
1346 result = (char *)NULL;
1347 else
1348 {
1349 result = (char *)xmalloc (1 + si);
1350 strncpy (result, string + *sindex, si);
1351 result[si] = '\0';
1352 }
1353 *sindex = i;
1354
1355 return (result);
1356}
1357
1358/* Extract a parameter expansion expression within ${ and } from STRING.
1359 Obey the Posix.2 rules for finding the ending `}': count braces while
1360 skipping over enclosed quoted strings and command substitutions.
1361 SINDEX is the address of an int describing the current offset in STRING;
1362 it should point to just after the first `{' found. On exit, SINDEX
1363 gets the position of the matching `}'. QUOTED is non-zero if this
1364 occurs inside double quotes. */
1365/* XXX -- this is very similar to extract_delimited_string -- XXX */
1366static char *
1367extract_dollar_brace_string (string, sindex, quoted, flags)
1368 char *string;
1369 int *sindex, quoted, flags;
1370{
1371 register int i, c;
1372 size_t slen;
1373 int pass_character, nesting_level, si, dolbrace_state;
1374 char *result, *t;
1375 DECLARE_MBSTATE;
1376
1377 pass_character = 0;
1378 nesting_level = 1;
1379 slen = strlen (string + *sindex) + *sindex;
1380
1381 /* The handling of dolbrace_state needs to agree with the code in parse.y:
1382 parse_matched_pair(). The different initial value is to handle the
1383 case where this function is called to parse the word in
9c2db999
CR
1384 ${param op word} (SX_WORD). */
1385 dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM;
e192f341
CR
1386 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP))
1387 dolbrace_state = DOLBRACE_QUOTE;
1388
1389 i = *sindex;
1390 while (c = string[i])
1391 {
1392 if (pass_character)
1393 {
1394 pass_character = 0;
1395 ADVANCE_CHAR (string, slen, i);
1396 continue;
1397 }
1398
1399 /* CTLESCs and backslashes quote the next character. */
1400 if (c == CTLESC || c == '\\')
1401 {
1402 pass_character++;
1403 i++;
1404 continue;
1405 }
1406
1407 if (string[i] == '$' && string[i+1] == LBRACE)
1408 {
1409 nesting_level++;
1410 i += 2;
1411 continue;
1412 }
1413
1414 if (c == RBRACE)
1415 {
1416 nesting_level--;
1417 if (nesting_level == 0)
1418 break;
1419 i++;
1420 continue;
1421 }
1422
1423 /* Pass the contents of old-style command substitutions through
1424 verbatim. */
1425 if (c == '`')
1426 {
1427 si = i + 1;
1428 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1429 i = si + 1;
1430 continue;
1431 }
1432
1433 /* Pass the contents of new-style command substitutions and
1434 arithmetic substitutions through verbatim. */
1435 if (string[i] == '$' && string[i+1] == LPAREN)
1436 {
1437 si = i + 2;
1438 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1439 i = si + 1;
1440 continue;
1441 }
1442
1443#if 0
1444 /* Pass the contents of single-quoted and double-quoted strings
1445 through verbatim. */
1446 if (c == '\'' || c == '"')
1447 {
1448 si = i + 1;
1449 i = (c == '\'') ? skip_single_quoted (string, slen, si)
1450 : skip_double_quoted (string, slen, si);
1451 /* skip_XXX_quoted leaves index one past close quote */
1452 continue;
1453 }
1454#else /* XXX - bash-4.2 */
1455 /* Pass the contents of double-quoted strings through verbatim. */
1456 if (c == '"')
1457 {
1458 si = i + 1;
1459 i = skip_double_quoted (string, slen, si);
1460 /* skip_XXX_quoted leaves index one past close quote */
1461 continue;
1462 }
1463
1464 if (c == '\'')
1465 {
1466/*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
1467 if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1468 ADVANCE_CHAR (string, slen, i);
1469 else
1470 {
1471 si = i + 1;
1472 i = skip_single_quoted (string, slen, si);
1473 }
1474
1475 continue;
1476 }
1477#endif
1478
1479 /* move past this character, which was not special. */
1480 ADVANCE_CHAR (string, slen, i);
1481
1482 /* This logic must agree with parse.y:parse_matched_pair, since they
1483 share the same defines. */
1484 if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
1485 dolbrace_state = DOLBRACE_QUOTE;
1486 else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
1487 dolbrace_state = DOLBRACE_QUOTE;
1488 else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
1489 dolbrace_state = DOLBRACE_QUOTE;
1490 else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
1491 dolbrace_state = DOLBRACE_QUOTE;
1492 else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
1493 dolbrace_state = DOLBRACE_QUOTE;
1494 else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
1495 dolbrace_state = DOLBRACE_OP;
1496 else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
1497 dolbrace_state = DOLBRACE_WORD;
1498 }
1499
1500 if (c == 0 && nesting_level)
1501 {
1502 if (no_longjmp_on_fatal_error == 0)
1503 { /* { */
1504 report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
1505 last_command_exit_value = EXECUTION_FAILURE;
1506 exp_jump_to_top_level (DISCARD);
1507 }
1508 else
1509 {
1510 *sindex = i;
1511 return ((char *)NULL);
1512 }
1513 }
1514
1515 result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
1516 *sindex = i;
1517
1518 return (result);
1519}
1520
1521/* Remove backslashes which are quoting backquotes from STRING. Modifies
1522 STRING, and returns a pointer to it. */
1523char *
1524de_backslash (string)
1525 char *string;
1526{
1527 register size_t slen;
1528 register int i, j, prev_i;
1529 DECLARE_MBSTATE;
1530
1531 slen = strlen (string);
1532 i = j = 0;
1533
1534 /* Loop copying string[i] to string[j], i >= j. */
1535 while (i < slen)
1536 {
1537 if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
1538 string[i + 1] == '$'))
1539 i++;
1540 prev_i = i;
1541 ADVANCE_CHAR (string, slen, i);
1542 if (j < prev_i)
1543 do string[j++] = string[prev_i++]; while (prev_i < i);
1544 else
1545 j = i;
1546 }
1547 string[j] = '\0';
1548
1549 return (string);
1550}
1551
1552#if 0
1553/*UNUSED*/
1554/* Replace instances of \! in a string with !. */
1555void
1556unquote_bang (string)
1557 char *string;
1558{
1559 register int i, j;
1560 register char *temp;
1561
1562 temp = (char *)xmalloc (1 + strlen (string));
1563
1564 for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
1565 {
1566 if (string[i] == '\\' && string[i + 1] == '!')
1567 {
1568 temp[j] = '!';
1569 i++;
1570 }
1571 }
1572 strcpy (string, temp);
1573 free (temp);
1574}
1575#endif
1576
1577#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
1578
1579/* This function assumes s[i] == open; returns with s[ret] == close; used to
1580 parse array subscripts. FLAGS & 1 means to not attempt to skip over
1581 matched pairs of quotes or backquotes, or skip word expansions; it is
1582 intended to be used after expansion has been performed and during final
1583 assignment parsing (see arrayfunc.c:assign_compound_array_list()). */
1584static int
1585skip_matched_pair (string, start, open, close, flags)
1586 const char *string;
1587 int start, open, close, flags;
1588{
1589 int i, pass_next, backq, si, c, count;
1590 size_t slen;
1591 char *temp, *ss;
1592 DECLARE_MBSTATE;
1593
1594 slen = strlen (string + start) + start;
1595 no_longjmp_on_fatal_error = 1;
1596
1597 i = start + 1; /* skip over leading bracket */
1598 count = 1;
1599 pass_next = backq = 0;
1600 ss = (char *)string;
1601 while (c = string[i])
1602 {
1603 if (pass_next)
1604 {
1605 pass_next = 0;
1606 if (c == 0)
1607 CQ_RETURN(i);
1608 ADVANCE_CHAR (string, slen, i);
1609 continue;
1610 }
1611 else if (c == '\\')
1612 {
1613 pass_next = 1;
1614 i++;
1615 continue;
1616 }
1617 else if (backq)
1618 {
1619 if (c == '`')
1620 backq = 0;
1621 ADVANCE_CHAR (string, slen, i);
1622 continue;
1623 }
1624 else if ((flags & 1) == 0 && c == '`')
1625 {
1626 backq = 1;
1627 i++;
1628 continue;
1629 }
1630 else if ((flags & 1) == 0 && c == open)
1631 {
1632 count++;
1633 i++;
1634 continue;
1635 }
1636 else if (c == close)
1637 {
1638 count--;
1639 if (count == 0)
1640 break;
1641 i++;
1642 continue;
1643 }
1644 else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
1645 {
1646 i = (c == '\'') ? skip_single_quoted (ss, slen, ++i)
1647 : skip_double_quoted (ss, slen, ++i);
1648 /* no increment, the skip functions increment past the closing quote. */
1649 }
1650 else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
1651 {
1652 si = i + 2;
1653 if (string[si] == '\0')
1654 CQ_RETURN(si);
1655
1656 if (string[i+1] == LPAREN)
1657 temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
1658 else
1659 temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
1660 i = si;
1661 if (string[i] == '\0') /* don't increment i past EOS in loop */
1662 break;
1663 i++;
1664 continue;
1665 }
1666 else
1667 ADVANCE_CHAR (string, slen, i);
1668 }
1669
1670 CQ_RETURN(i);
1671}
1672
1673#if defined (ARRAY_VARS)
1674int
1675skipsubscript (string, start, flags)
1676 const char *string;
1677 int start, flags;
1678{
1679 return (skip_matched_pair (string, start, '[', ']', flags));
1680}
1681#endif
1682
1683/* Skip characters in STRING until we find a character in DELIMS, and return
1684 the index of that character. START is the index into string at which we
1685 begin. This is similar in spirit to strpbrk, but it returns an index into
1686 STRING and takes a starting index. This little piece of code knows quite
1687 a lot of shell syntax. It's very similar to skip_double_quoted and other
1688 functions of that ilk. */
1689int
1690skip_to_delim (string, start, delims, flags)
1691 char *string;
1692 int start;
1693 char *delims;
1694 int flags;
1695{
1696 int i, pass_next, backq, si, c, invert, skipquote, skipcmd;
1697 size_t slen;
1698 char *temp, open[3];
1699 DECLARE_MBSTATE;
1700
1701 slen = strlen (string + start) + start;
1702 if (flags & SD_NOJMP)
1703 no_longjmp_on_fatal_error = 1;
1704 invert = (flags & SD_INVERT);
1705 skipcmd = (flags & SD_NOSKIPCMD) == 0;
1706
1707 i = start;
1708 pass_next = backq = 0;
1709 while (c = string[i])
1710 {
1711 /* If this is non-zero, we should not let quote characters be delimiters
1712 and the current character is a single or double quote. We should not
1713 test whether or not it's a delimiter until after we skip single- or
1714 double-quoted strings. */
1715 skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
1716 if (pass_next)
1717 {
1718 pass_next = 0;
1719 if (c == 0)
1720 CQ_RETURN(i);
1721 ADVANCE_CHAR (string, slen, i);
1722 continue;
1723 }
1724 else if (c == '\\')
1725 {
1726 pass_next = 1;
1727 i++;
1728 continue;
1729 }
1730 else if (backq)
1731 {
1732 if (c == '`')
1733 backq = 0;
1734 ADVANCE_CHAR (string, slen, i);
1735 continue;
1736 }
1737 else if (c == '`')
1738 {
1739 backq = 1;
1740 i++;
1741 continue;
1742 }
1743 else if (skipquote == 0 && invert == 0 && member (c, delims))
1744 break;
1745 else if (c == '\'' || c == '"')
1746 {
1747 i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
1748 : skip_double_quoted (string, slen, ++i);
1749 /* no increment, the skip functions increment past the closing quote. */
1750 }
1751 else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
1752 {
1753 si = i + 2;
1754 if (string[si] == '\0')
1755 CQ_RETURN(si);
1756
1757 if (string[i+1] == LPAREN)
1758 temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
1759 else
1760 temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
1761 i = si;
1762 if (string[i] == '\0') /* don't increment i past EOS in loop */
1763 break;
1764 i++;
1765 continue;
1766 }
1767#if defined (PROCESS_SUBSTITUTION)
1768 else if (skipcmd && (c == '<' || c == '>') && string[i+1] == LPAREN)
1769 {
1770 si = i + 2;
1771 if (string[si] == '\0')
1772 CQ_RETURN(si);
1773 temp = extract_process_subst (string, (c == '<') ? "<(" : ">(", &si);
1774 i = si;
1775 if (string[i] == '\0')
1776 break;
1777 i++;
1778 continue;
1779 }
1780#endif /* PROCESS_SUBSTITUTION */
1781#if defined (EXTENDED_GLOB)
1782 else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@"))
1783 {
1784 si = i + 2;
1785 if (string[si] == '\0')
1786 CQ_RETURN(si);
1787
1788 open[0] = c;
1789 open[1] = LPAREN;
1790 open[2] = '\0';
1791 temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */
1792
1793 i = si;
1794 if (string[i] == '\0') /* don't increment i past EOS in loop */
1795 break;
1796 i++;
1797 continue;
1798 }
1799#endif
1800 else if ((skipquote || invert) && (member (c, delims) == 0))
1801 break;
1802 else
1803 ADVANCE_CHAR (string, slen, i);
1804 }
1805
1806 CQ_RETURN(i);
1807}
1808
1809#if defined (READLINE)
1810/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
1811 an unclosed quoted string), or if the character at EINDEX is quoted
1812 by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various
1813 single and double-quoted string parsing functions should not return an
1814 error if there are unclosed quotes or braces. The characters that this
1815 recognizes need to be the same as the contents of
1816 rl_completer_quote_characters. */
1817
1818int
1819char_is_quoted (string, eindex)
1820 char *string;
1821 int eindex;
1822{
1823 int i, pass_next, c;
1824 size_t slen;
1825 DECLARE_MBSTATE;
1826
1827 slen = strlen (string);
1828 no_longjmp_on_fatal_error = 1;
1829 i = pass_next = 0;
1830 while (i <= eindex)
1831 {
1832 c = string[i];
1833
1834 if (pass_next)
1835 {
1836 pass_next = 0;
1837 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
1838 CQ_RETURN(1);
1839 ADVANCE_CHAR (string, slen, i);
1840 continue;
1841 }
1842 else if (c == '\\')
1843 {
1844 pass_next = 1;
1845 i++;
1846 continue;
1847 }
1848 else if (c == '\'' || c == '"')
1849 {
1850 i = (c == '\'') ? skip_single_quoted (string, slen, ++i)
1851 : skip_double_quoted (string, slen, ++i);
1852 if (i > eindex)
1853 CQ_RETURN(1);
1854 /* no increment, the skip_xxx functions go one past end */
1855 }
1856 else
1857 ADVANCE_CHAR (string, slen, i);
1858 }
1859
1860 CQ_RETURN(0);
1861}
1862
1863int
1864unclosed_pair (string, eindex, openstr)
1865 char *string;
1866 int eindex;
1867 char *openstr;
1868{
1869 int i, pass_next, openc, olen;
1870 size_t slen;
1871 DECLARE_MBSTATE;
1872
1873 slen = strlen (string);
1874 olen = strlen (openstr);
1875 i = pass_next = openc = 0;
1876 while (i <= eindex)
1877 {
1878 if (pass_next)
1879 {
1880 pass_next = 0;
1881 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
1882 return 0;
1883 ADVANCE_CHAR (string, slen, i);
1884 continue;
1885 }
1886 else if (string[i] == '\\')
1887 {
1888 pass_next = 1;
1889 i++;
1890 continue;
1891 }
1892 else if (STREQN (string + i, openstr, olen))
1893 {
1894 openc = 1 - openc;
1895 i += olen;
1896 }
1897 else if (string[i] == '\'' || string[i] == '"')
1898 {
1899 i = (string[i] == '\'') ? skip_single_quoted (string, slen, i)
1900 : skip_double_quoted (string, slen, i);
1901 if (i > eindex)
1902 return 0;
1903 }
1904 else
1905 ADVANCE_CHAR (string, slen, i);
1906 }
1907 return (openc);
1908}
1909
1910/* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
1911 individual words. If DELIMS is NULL, the current value of $IFS is used
1912 to split the string, and the function follows the shell field splitting
1913 rules. SENTINEL is an index to look for. NWP, if non-NULL,
1914 gets the number of words in the returned list. CWP, if non-NULL, gets
1915 the index of the word containing SENTINEL. Non-whitespace chars in
1916 DELIMS delimit separate fields. */
1917WORD_LIST *
1918split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
1919 char *string;
1920 int slen;
1921 char *delims;
1922 int sentinel, flags;
1923 int *nwp, *cwp;
1924{
1925 int ts, te, i, nw, cw, ifs_split, dflags;
1926 char *token, *d, *d2;
1927 WORD_LIST *ret, *tl;
1928
1929 if (string == 0 || *string == '\0')
1930 {
1931 if (nwp)
1932 *nwp = 0;
1933 if (cwp)
1934 *cwp = 0;
1935 return ((WORD_LIST *)NULL);
1936 }
1937
1938 d = (delims == 0) ? ifs_value : delims;
1939 ifs_split = delims == 0;
1940
1941 /* Make d2 the non-whitespace characters in delims */
1942 d2 = 0;
1943 if (delims)
1944 {
1945 size_t slength;
1946#if defined (HANDLE_MULTIBYTE)
1947 size_t mblength = 1;
1948#endif
1949 DECLARE_MBSTATE;
1950
1951 slength = strlen (delims);
1952 d2 = (char *)xmalloc (slength + 1);
1953 i = ts = 0;
1954 while (delims[i])
1955 {
1956#if defined (HANDLE_MULTIBYTE)
1957 mbstate_t state_bak;
1958 state_bak = state;
1959 mblength = MBRLEN (delims + i, slength, &state);
1960 if (MB_INVALIDCH (mblength))
1961 state = state_bak;
1962 else if (mblength > 1)
1963 {
1964 memcpy (d2 + ts, delims + i, mblength);
1965 ts += mblength;
1966 i += mblength;
1967 slength -= mblength;
1968 continue;
1969 }
1970#endif
1971 if (whitespace (delims[i]) == 0)
1972 d2[ts++] = delims[i];
1973
1974 i++;
1975 slength--;
1976 }
1977 d2[ts] = '\0';
1978 }
1979
1980 ret = (WORD_LIST *)NULL;
1981
1982 /* Remove sequences of whitespace characters at the start of the string, as
1983 long as those characters are delimiters. */
1984 for (i = 0; member (string[i], d) && spctabnl (string[i]); i++)
1985 ;
1986 if (string[i] == '\0')
1987 return (ret);
1988
1989 ts = i;
1990 nw = 0;
1991 cw = -1;
1992 dflags = flags|SD_NOJMP;
1993 while (1)
1994 {
1995 te = skip_to_delim (string, ts, d, dflags);
1996
1997 /* If we have a non-whitespace delimiter character, use it to make a
1998 separate field. This is just about what $IFS splitting does and
1999 is closer to the behavior of the shell parser. */
2000 if (ts == te && d2 && member (string[ts], d2))
2001 {
2002 te = ts + 1;
2003 /* If we're using IFS splitting, the non-whitespace delimiter char
2004 and any additional IFS whitespace delimits a field. */
2005 if (ifs_split)
2006 while (member (string[te], d) && spctabnl (string[te]))
2007 te++;
2008 else
2009 while (member (string[te], d2))
2010 te++;
2011 }
2012
2013 token = substring (string, ts, te);
2014
2015 ret = add_string_to_list (token, ret);
2016 free (token);
2017 nw++;
2018
2019 if (sentinel >= ts && sentinel <= te)
2020 cw = nw;
2021
2022 /* If the cursor is at whitespace just before word start, set the
2023 sentinel word to the current word. */
2024 if (cwp && cw == -1 && sentinel == ts-1)
2025 cw = nw;
2026
2027 /* If the cursor is at whitespace between two words, make a new, empty
2028 word, add it before (well, after, since the list is in reverse order)
2029 the word we just added, and set the current word to that one. */
2030 if (cwp && cw == -1 && sentinel < ts)
2031 {
2032 tl = make_word_list (make_word (""), ret->next);
2033 ret->next = tl;
2034 cw = nw;
2035 nw++;
2036 }
2037
2038 if (string[te] == 0)
2039 break;
2040
2041 i = te;
2042 while (member (string[i], d) && (ifs_split || spctabnl(string[i])))
2043 i++;
2044
2045 if (string[i])
2046 ts = i;
2047 else
2048 break;
2049 }
2050
2051 /* Special case for SENTINEL at the end of STRING. If we haven't found
2052 the word containing SENTINEL yet, and the index we're looking for is at
2053 the end of STRING (or past the end of the previously-found token,
2054 possible if the end of the line is composed solely of IFS whitespace)
2055 add an additional null argument and set the current word pointer to that. */
2056 if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
2057 {
2058 if (whitespace (string[sentinel - 1]))
2059 {
2060 token = "";
2061 ret = add_string_to_list (token, ret);
2062 nw++;
2063 }
2064 cw = nw;
2065 }
2066
2067 if (nwp)
2068 *nwp = nw;
2069 if (cwp)
2070 *cwp = cw;
2071
2072 return (REVERSE_LIST (ret, WORD_LIST *));
2073}
2074#endif /* READLINE */
2075
2076#if 0
2077/* UNUSED */
2078/* Extract the name of the variable to bind to from the assignment string. */
2079char *
2080assignment_name (string)
2081 char *string;
2082{
2083 int offset;
2084 char *temp;
2085
2086 offset = assignment (string, 0);
2087 if (offset == 0)
2088 return (char *)NULL;
2089 temp = substring (string, 0, offset);
2090 return (temp);
2091}
2092#endif
2093
2094/* **************************************************************** */
2095/* */
2096/* Functions to convert strings to WORD_LISTs and vice versa */
2097/* */
2098/* **************************************************************** */
2099
2100/* Return a single string of all the words in LIST. SEP is the separator
2101 to put between individual elements of LIST in the output string. */
2102char *
2103string_list_internal (list, sep)
2104 WORD_LIST *list;
2105 char *sep;
2106{
2107 register WORD_LIST *t;
2108 char *result, *r;
2109 int word_len, sep_len, result_size;
2110
2111 if (list == 0)
2112 return ((char *)NULL);
2113
2114 /* Short-circuit quickly if we don't need to separate anything. */
2115 if (list->next == 0)
2116 return (savestring (list->word->word));
2117
2118 /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
2119 sep_len = STRLEN (sep);
2120 result_size = 0;
2121
2122 for (t = list; t; t = t->next)
2123 {
2124 if (t != list)
2125 result_size += sep_len;
2126 result_size += strlen (t->word->word);
2127 }
2128
2129 r = result = (char *)xmalloc (result_size + 1);
2130
2131 for (t = list; t; t = t->next)
2132 {
2133 if (t != list && sep_len)
2134 {
2135 if (sep_len > 1)
2136 {
2137 FASTCOPY (sep, r, sep_len);
2138 r += sep_len;
2139 }
2140 else
2141 *r++ = sep[0];
2142 }
2143
2144 word_len = strlen (t->word->word);
2145 FASTCOPY (t->word->word, r, word_len);
2146 r += word_len;
2147 }
2148
2149 *r = '\0';
2150 return (result);
2151}
2152
2153/* Return a single string of all the words present in LIST, separating
2154 each word with a space. */
2155char *
2156string_list (list)
2157 WORD_LIST *list;
2158{
2159 return (string_list_internal (list, " "));
2160}
2161
2162/* An external interface that can be used by the rest of the shell to
2163 obtain a string containing the first character in $IFS. Handles all
2164 the multibyte complications. If LENP is non-null, it is set to the
2165 length of the returned string. */
2166char *
2167ifs_firstchar (lenp)
2168 int *lenp;
2169{
2170 char *ret;
2171 int len;
2172
2173 ret = xmalloc (MB_LEN_MAX + 1);
2174#if defined (HANDLE_MULTIBYTE)
2175 if (ifs_firstc_len == 1)
2176 {
2177 ret[0] = ifs_firstc[0];
2178 ret[1] = '\0';
2179 len = ret[0] ? 1 : 0;
2180 }
2181 else
2182 {
2183 memcpy (ret, ifs_firstc, ifs_firstc_len);
2184 ret[len = ifs_firstc_len] = '\0';
2185 }
2186#else
2187 ret[0] = ifs_firstc;
2188 ret[1] = '\0';
2189 len = ret[0] ? 0 : 1;
2190#endif
2191
2192 if (lenp)
2193 *lenp = len;
2194
2195 return ret;
2196}
2197
2198/* Return a single string of all the words present in LIST, obeying the
2199 quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
2200 expansion [of $*] appears within a double quoted string, it expands
2201 to a single field with the value of each parameter separated by the
2202 first character of the IFS variable, or by a <space> if IFS is unset." */
2203char *
2204string_list_dollar_star (list)
2205 WORD_LIST *list;
2206{
2207 char *ret;
2208#if defined (HANDLE_MULTIBYTE)
2209# if defined (__GNUC__)
2210 char sep[MB_CUR_MAX + 1];
2211# else
2212 char *sep = 0;
2213# endif
2214#else
2215 char sep[2];
2216#endif
2217
2218#if defined (HANDLE_MULTIBYTE)
2219# if !defined (__GNUC__)
2220 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2221# endif /* !__GNUC__ */
2222 if (ifs_firstc_len == 1)
2223 {
2224 sep[0] = ifs_firstc[0];
2225 sep[1] = '\0';
2226 }
2227 else
2228 {
2229 memcpy (sep, ifs_firstc, ifs_firstc_len);
2230 sep[ifs_firstc_len] = '\0';
2231 }
2232#else
2233 sep[0] = ifs_firstc;
2234 sep[1] = '\0';
2235#endif
2236
2237 ret = string_list_internal (list, sep);
2238#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2239 free (sep);
2240#endif
2241 return ret;
2242}
2243
2244/* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
2245 is non-zero, the $@ appears within double quotes, and we should quote
2246 the list before converting it into a string. If IFS is unset, and the
2247 word is not quoted, we just need to quote CTLESC and CTLNUL characters
2248 in the words in the list, because the default value of $IFS is
2249 <space><tab><newline>, IFS characters in the words in the list should
2250 also be split. If IFS is null, and the word is not quoted, we need
2251 to quote the words in the list to preserve the positional parameters
2252 exactly. */
2253char *
2254string_list_dollar_at (list, quoted)
2255 WORD_LIST *list;
2256 int quoted;
2257{
2258 char *ifs, *ret;
2259#if defined (HANDLE_MULTIBYTE)
2260# if defined (__GNUC__)
2261 char sep[MB_CUR_MAX + 1];
2262# else
2263 char *sep = 0;
2264# endif /* !__GNUC__ */
2265#else
2266 char sep[2];
2267#endif
2268 WORD_LIST *tlist;
2269
2270 /* XXX this could just be ifs = ifs_value; */
2271 ifs = ifs_var ? value_cell (ifs_var) : (char *)0;
2272
2273#if defined (HANDLE_MULTIBYTE)
2274# if !defined (__GNUC__)
2275 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2276# endif /* !__GNUC__ */
2277 if (ifs && *ifs)
2278 {
2279 if (ifs_firstc_len == 1)
2280 {
2281 sep[0] = ifs_firstc[0];
2282 sep[1] = '\0';
2283 }
2284 else
2285 {
2286 memcpy (sep, ifs_firstc, ifs_firstc_len);
2287 sep[ifs_firstc_len] = '\0';
2288 }
2289 }
2290 else
2291 {
2292 sep[0] = ' ';
2293 sep[1] = '\0';
2294 }
2295#else
2296 sep[0] = (ifs == 0 || *ifs == 0) ? ' ' : *ifs;
2297 sep[1] = '\0';
2298#endif
2299
2300 /* XXX -- why call quote_list if ifs == 0? we can get away without doing
2301 it now that quote_escapes quotes spaces */
2302 tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
2303 ? quote_list (list)
2304 : list_quote_escapes (list);
2305
2306 ret = string_list_internal (tlist, sep);
2307#if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2308 free (sep);
2309#endif
2310 return ret;
2311}
2312
2313/* Turn the positional paramters into a string, understanding quoting and
2314 the various subtleties of using the first character of $IFS as the
2315 separator. Calls string_list_dollar_at, string_list_dollar_star, and
2316 string_list as appropriate. */
2317char *
2318string_list_pos_params (pchar, list, quoted)
2319 int pchar;
2320 WORD_LIST *list;
2321 int quoted;
2322{
2323 char *ret;
2324 WORD_LIST *tlist;
2325
2326 if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
2327 {
2328 tlist = quote_list (list);
2329 word_list_remove_quoted_nulls (tlist);
2330 ret = string_list_dollar_star (tlist);
2331 }
2332 else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
2333 {
2334 tlist = quote_list (list);
2335 word_list_remove_quoted_nulls (tlist);
2336 ret = string_list (tlist);
2337 }
2338 else if (pchar == '*')
2339 {
2340 /* Even when unquoted, string_list_dollar_star does the right thing
2341 making sure that the first character of $IFS is used as the
2342 separator. */
2343 ret = string_list_dollar_star (list);
2344 }
2345 else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
2346 /* We use string_list_dollar_at, but only if the string is quoted, since
2347 that quotes the escapes if it's not, which we don't want. We could
2348 use string_list (the old code did), but that doesn't do the right
2349 thing if the first character of $IFS is not a space. We use
2350 string_list_dollar_star if the string is unquoted so we make sure that
2351 the elements of $@ are separated by the first character of $IFS for
2352 later splitting. */
2353 ret = string_list_dollar_at (list, quoted);
2354 else if (pchar == '@')
2355 ret = string_list_dollar_star (list);
2356 else
2357 ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
2358
2359 return ret;
2360}
2361
2362/* Return the list of words present in STRING. Separate the string into
2363 words at any of the characters found in SEPARATORS. If QUOTED is
2364 non-zero then word in the list will have its quoted flag set, otherwise
2365 the quoted flag is left as make_word () deemed fit.
2366
2367 This obeys the P1003.2 word splitting semantics. If `separators' is
2368 exactly <space><tab><newline>, then the splitting algorithm is that of
2369 the Bourne shell, which treats any sequence of characters from `separators'
2370 as a delimiter. If IFS is unset, which results in `separators' being set
2371 to "", no splitting occurs. If separators has some other value, the
2372 following rules are applied (`IFS white space' means zero or more
2373 occurrences of <space>, <tab>, or <newline>, as long as those characters
2374 are in `separators'):
2375
2376 1) IFS white space is ignored at the start and the end of the
2377 string.
2378 2) Each occurrence of a character in `separators' that is not
2379 IFS white space, along with any adjacent occurrences of
2380 IFS white space delimits a field.
2381 3) Any nonzero-length sequence of IFS white space delimits a field.
2382 */
2383
2384/* BEWARE! list_string strips null arguments. Don't call it twice and
2385 expect to have "" preserved! */
2386
2387/* This performs word splitting and quoted null character removal on
2388 STRING. */
2389#define issep(c) \
2390 (((separators)[0]) ? ((separators)[1] ? isifs(c) \
2391 : (c) == (separators)[0]) \
2392 : 0)
2393
2394WORD_LIST *
2395list_string (string, separators, quoted)
2396 register char *string, *separators;
2397 int quoted;
2398{
2399 WORD_LIST *result;
2400 WORD_DESC *t;
2401 char *current_word, *s;
2402 int sindex, sh_style_split, whitesep, xflags;
2403 size_t slen;
2404
2405 if (!string || !*string)
2406 return ((WORD_LIST *)NULL);
2407
2408 sh_style_split = separators && separators[0] == ' ' &&
2409 separators[1] == '\t' &&
2410 separators[2] == '\n' &&
2411 separators[3] == '\0';
2412 for (xflags = 0, s = ifs_value; s && *s; s++)
2413 {
2414 if (*s == CTLESC) xflags |= SX_NOCTLESC;
2415 else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
2416 }
2417
2418 slen = 0;
2419 /* Remove sequences of whitespace at the beginning of STRING, as
2420 long as those characters appear in IFS. Do not do this if
2421 STRING is quoted or if there are no separator characters. */
2422 if (!quoted || !separators || !*separators)
2423 {
2424 for (s = string; *s && spctabnl (*s) && issep (*s); s++);
2425
2426 if (!*s)
2427 return ((WORD_LIST *)NULL);
2428
2429 string = s;
2430 }
2431
2432 /* OK, now STRING points to a word that does not begin with white space.
2433 The splitting algorithm is:
2434 extract a word, stopping at a separator
2435 skip sequences of spc, tab, or nl as long as they are separators
2436 This obeys the field splitting rules in Posix.2. */
2437 slen = (MB_CUR_MAX > 1) ? strlen (string) : 1;
2438 for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
2439 {
2440 /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
2441 unless multibyte chars are possible. */
2442 current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
2443 if (current_word == 0)
2444 break;
2445
2446 /* If we have a quoted empty string, add a quoted null argument. We
2447 want to preserve the quoted null character iff this is a quoted
2448 empty string; otherwise the quoted null characters are removed
2449 below. */
2450 if (QUOTED_NULL (current_word))
2451 {
2452 t = alloc_word_desc ();
2453 t->word = make_quoted_char ('\0');
2454 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
2455 result = make_word_list (t, result);
2456 }
2457 else if (current_word[0] != '\0')
2458 {
2459 /* If we have something, then add it regardless. However,
2460 perform quoted null character removal on the current word. */
2461 remove_quoted_nulls (current_word);
2462 result = add_string_to_list (current_word, result);
2463 result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */
2464 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
2465 result->word->flags |= W_QUOTED;
2466 }
2467
2468 /* If we're not doing sequences of separators in the traditional
2469 Bourne shell style, then add a quoted null argument. */
2470 else if (!sh_style_split && !spctabnl (string[sindex]))
2471 {
2472 t = alloc_word_desc ();
2473 t->word = make_quoted_char ('\0');
2474 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
2475 result = make_word_list (t, result);
2476 }
2477
2478 free (current_word);
2479
2480 /* Note whether or not the separator is IFS whitespace, used later. */
2481 whitesep = string[sindex] && spctabnl (string[sindex]);
2482
2483 /* Move past the current separator character. */
2484 if (string[sindex])
2485 {
2486 DECLARE_MBSTATE;
2487 ADVANCE_CHAR (string, slen, sindex);
2488 }
2489
2490 /* Now skip sequences of space, tab, or newline characters if they are
2491 in the list of separators. */
2492 while (string[sindex] && spctabnl (string[sindex]) && issep (string[sindex]))
2493 sindex++;
2494
2495 /* If the first separator was IFS whitespace and the current character
2496 is a non-whitespace IFS character, it should be part of the current
2497 field delimiter, not a separate delimiter that would result in an
2498 empty field. Look at POSIX.2, 3.6.5, (3)(b). */
2499 if (string[sindex] && whitesep && issep (string[sindex]) && !spctabnl (string[sindex]))
2500 {
2501 sindex++;
2502 /* An IFS character that is not IFS white space, along with any
2503 adjacent IFS white space, shall delimit a field. (SUSv3) */
2504 while (string[sindex] && spctabnl (string[sindex]) && isifs (string[sindex]))
2505 sindex++;
2506 }
2507 }
2508 return (REVERSE_LIST (result, WORD_LIST *));
2509}
2510
2511/* Parse a single word from STRING, using SEPARATORS to separate fields.
2512 ENDPTR is set to the first character after the word. This is used by
2513 the `read' builtin. This is never called with SEPARATORS != $IFS;
2514 it should be simplified.
2515
2516 XXX - this function is very similar to list_string; they should be
2517 combined - XXX */
2518char *
2519get_word_from_string (stringp, separators, endptr)
2520 char **stringp, *separators, **endptr;
2521{
2522 register char *s;
2523 char *current_word;
2524 int sindex, sh_style_split, whitesep, xflags;
2525 size_t slen;
2526
2527 if (!stringp || !*stringp || !**stringp)
2528 return ((char *)NULL);
2529
2530 sh_style_split = separators && separators[0] == ' ' &&
2531 separators[1] == '\t' &&
2532 separators[2] == '\n' &&
2533 separators[3] == '\0';
2534 for (xflags = 0, s = ifs_value; s && *s; s++)
2535 {
2536 if (*s == CTLESC) xflags |= SX_NOCTLESC;
2537 if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
2538 }
2539
2540 s = *stringp;
2541 slen = 0;
2542
2543 /* Remove sequences of whitespace at the beginning of STRING, as
2544 long as those characters appear in IFS. */
2545 if (sh_style_split || !separators || !*separators)
2546 {
2547 for (; *s && spctabnl (*s) && isifs (*s); s++);
2548
2549 /* If the string is nothing but whitespace, update it and return. */
2550 if (!*s)
2551 {
2552 *stringp = s;
2553 if (endptr)
2554 *endptr = s;
2555 return ((char *)NULL);
2556 }
2557 }
2558
2559 /* OK, S points to a word that does not begin with white space.
2560 Now extract a word, stopping at a separator, save a pointer to
2561 the first character after the word, then skip sequences of spc,
2562 tab, or nl as long as they are separators.
2563
2564 This obeys the field splitting rules in Posix.2. */
2565 sindex = 0;
2566 /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
2567 unless multibyte chars are possible. */
2568 slen = (MB_CUR_MAX > 1) ? strlen (s) : 1;
2569 current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
2570
2571 /* Set ENDPTR to the first character after the end of the word. */
2572 if (endptr)
2573 *endptr = s + sindex;
2574
2575 /* Note whether or not the separator is IFS whitespace, used later. */
2576 whitesep = s[sindex] && spctabnl (s[sindex]);
2577
2578 /* Move past the current separator character. */
2579 if (s[sindex])
2580 {
2581 DECLARE_MBSTATE;
2582 ADVANCE_CHAR (s, slen, sindex);
2583 }
2584
2585 /* Now skip sequences of space, tab, or newline characters if they are
2586 in the list of separators. */
2587 while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
2588 sindex++;
2589
2590 /* If the first separator was IFS whitespace and the current character is
2591 a non-whitespace IFS character, it should be part of the current field
2592 delimiter, not a separate delimiter that would result in an empty field.
2593 Look at POSIX.2, 3.6.5, (3)(b). */
2594 if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (s[sindex]))
2595 {
2596 sindex++;
2597 /* An IFS character that is not IFS white space, along with any adjacent
2598 IFS white space, shall delimit a field. */
2599 while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex]))
2600 sindex++;
2601 }
2602
2603 /* Update STRING to point to the next field. */
2604 *stringp = s + sindex;
2605 return (current_word);
2606}
2607
2608/* Remove IFS white space at the end of STRING. Start at the end
2609 of the string and walk backwards until the beginning of the string
2610 or we find a character that's not IFS white space and not CTLESC.
2611 Only let CTLESC escape a white space character if SAW_ESCAPE is
2612 non-zero. */
2613char *
2614strip_trailing_ifs_whitespace (string, separators, saw_escape)
2615 char *string, *separators;
2616 int saw_escape;
2617{
2618 char *s;
2619
2620 s = string + STRLEN (string) - 1;
2621 while (s > string && ((spctabnl (*s) && isifs (*s)) ||
2622 (saw_escape && *s == CTLESC && spctabnl (s[1]))))
2623 s--;
2624 *++s = '\0';
2625 return string;
2626}
2627
2628#if 0
2629/* UNUSED */
2630/* Split STRING into words at whitespace. Obeys shell-style quoting with
2631 backslashes, single and double quotes. */
2632WORD_LIST *
2633list_string_with_quotes (string)
2634 char *string;
2635{
2636 WORD_LIST *list;
2637 char *token, *s;
2638 size_t s_len;
2639 int c, i, tokstart, len;
2640
2641 for (s = string; s && *s && spctabnl (*s); s++)
2642 ;
2643 if (s == 0 || *s == 0)
2644 return ((WORD_LIST *)NULL);
2645
2646 s_len = strlen (s);
2647 tokstart = i = 0;
2648 list = (WORD_LIST *)NULL;
2649 while (1)
2650 {
2651 c = s[i];
2652 if (c == '\\')
2653 {
2654 i++;
2655 if (s[i])
2656 i++;
2657 }
2658 else if (c == '\'')
2659 i = skip_single_quoted (s, s_len, ++i);
2660 else if (c == '"')
2661 i = skip_double_quoted (s, s_len, ++i);
2662 else if (c == 0 || spctabnl (c))
2663 {
2664 /* We have found the end of a token. Make a word out of it and
2665 add it to the word list. */
2666 token = substring (s, tokstart, i);
2667 list = add_string_to_list (token, list);
2668 free (token);
2669 while (spctabnl (s[i]))
2670 i++;
2671 if (s[i])
2672 tokstart = i;
2673 else
2674 break;
2675 }
2676 else
2677 i++; /* normal character */
2678 }
2679 return (REVERSE_LIST (list, WORD_LIST *));
2680}
2681#endif
2682
2683/********************************************************/
2684/* */
2685/* Functions to perform assignment statements */
2686/* */
2687/********************************************************/
2688
2689#if defined (ARRAY_VARS)
2690static SHELL_VAR *
2691do_compound_assignment (name, value, flags)
2692 char *name, *value;
2693 int flags;
2694{
2695 SHELL_VAR *v;
2696 int mklocal, mkassoc;
2697 WORD_LIST *list;
2698
2699 mklocal = flags & ASS_MKLOCAL;
2700 mkassoc = flags & ASS_MKASSOC;
2701
2702 if (mklocal && variable_context)
2703 {
2704 v = find_variable (name);
2705 list = expand_compound_array_assignment (v, value, flags);
2706 if (mkassoc)
2707 v = make_local_assoc_variable (name);
2708 else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context)
2709 v = make_local_array_variable (name);
2710 assign_compound_array_list (v, list, flags);
2711 }
2712 else
2713 v = assign_array_from_string (name, value, flags);
2714
2715 return (v);
2716}
2717#endif
2718
2719/* Given STRING, an assignment string, get the value of the right side
2720 of the `=', and bind it to the left side. If EXPAND is true, then
2721 perform parameter expansion, command substitution, and arithmetic
2722 expansion on the right-hand side. Perform tilde expansion in any
2723 case. Do not perform word splitting on the result of expansion. */
2724static int
2725do_assignment_internal (word, expand)
2726 const WORD_DESC *word;
2727 int expand;
2728{
2729 int offset, appendop, assign_list, aflags, retval;
2730 char *name, *value, *temp;
2731 SHELL_VAR *entry;
2732#if defined (ARRAY_VARS)
2733 char *t;
2734 int ni;
2735#endif
2736 const char *string;
2737
2738 if (word == 0 || word->word == 0)
2739 return 0;
2740
2741 appendop = assign_list = aflags = 0;
2742 string = word->word;
2743 offset = assignment (string, 0);
2744 name = savestring (string);
2745 value = (char *)NULL;
2746
2747 if (name[offset] == '=')
2748 {
2749 if (name[offset - 1] == '+')
2750 {
2751 appendop = 1;
2752 name[offset - 1] = '\0';
2753 }
2754
2755 name[offset] = 0; /* might need this set later */
2756 temp = name + offset + 1;
2757
2758#if defined (ARRAY_VARS)
2759 if (expand && (word->flags & W_COMPASSIGN))
2760 {
2761 assign_list = ni = 1;
2762 value = extract_array_assignment_list (temp, &ni);
2763 }
2764 else
2765#endif
2766 if (expand && temp[0])
2767 value = expand_string_if_necessary (temp, 0, expand_string_assignment);
2768 else
2769 value = savestring (temp);
2770 }
2771
2772 if (value == 0)
2773 {
2774 value = (char *)xmalloc (1);
2775 value[0] = '\0';
2776 }
2777
2778 if (echo_command_at_execute)
2779 {
2780 if (appendop)
2781 name[offset - 1] = '+';
2782 xtrace_print_assignment (name, value, assign_list, 1);
2783 if (appendop)
2784 name[offset - 1] = '\0';
2785 }
2786
2787#define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
2788
2789 if (appendop)
2790 aflags |= ASS_APPEND;
2791
2792#if defined (ARRAY_VARS)
2793 if (t = mbschr (name, '[')) /*]*/
2794 {
2795 if (assign_list)
2796 {
2797 report_error (_("%s: cannot assign list to array member"), name);
2798 ASSIGN_RETURN (0);
2799 }
2800 entry = assign_array_element (name, value, aflags);
2801 if (entry == 0)
2802 ASSIGN_RETURN (0);
2803 }
2804 else if (assign_list)
2805 {
2806 if (word->flags & W_ASSIGNARG)
2807 aflags |= ASS_MKLOCAL;
2808 if (word->flags & W_ASSIGNASSOC)
2809 aflags |= ASS_MKASSOC;
2810 entry = do_compound_assignment (name, value, aflags);
2811 }
2812 else
2813#endif /* ARRAY_VARS */
2814 entry = bind_variable (name, value, aflags);
2815
2816 stupidly_hack_special_variables (name);
2817
2818#if 1
2819 /* Return 1 if the assignment seems to have been performed correctly. */
2820 if (entry == 0 || readonly_p (entry))
2821 retval = 0; /* assignment failure */
2822 else if (noassign_p (entry))
2823 {
2824 last_command_exit_value = EXECUTION_FAILURE;
2825 retval = 1; /* error status, but not assignment failure */
2826 }
2827 else
2828 retval = 1;
2829
2830 if (entry && retval != 0 && noassign_p (entry) == 0)
2831 VUNSETATTR (entry, att_invisible);
2832
2833 ASSIGN_RETURN (retval);
2834#else
2835 if (entry)
2836 VUNSETATTR (entry, att_invisible);
2837
2838 ASSIGN_RETURN (entry ? ((readonly_p (entry) == 0) && noassign_p (entry) == 0) : 0);
2839#endif
2840}
2841
2842/* Perform the assignment statement in STRING, and expand the
2843 right side by doing tilde, command and parameter expansion. */
2844int
2845do_assignment (string)
2846 char *string;
2847{
2848 WORD_DESC td;
2849
2850 td.flags = W_ASSIGNMENT;
2851 td.word = string;
2852
2853 return do_assignment_internal (&td, 1);
2854}
2855
2856int
2857do_word_assignment (word, flags)
2858 WORD_DESC *word;
2859 int flags;
2860{
2861 return do_assignment_internal (word, 1);
2862}
2863
2864/* Given STRING, an assignment string, get the value of the right side
2865 of the `=', and bind it to the left side. Do not perform any word
2866 expansions on the right hand side. */
2867int
2868do_assignment_no_expand (string)
2869 char *string;
2870{
2871 WORD_DESC td;
2872
2873 td.flags = W_ASSIGNMENT;
2874 td.word = string;
2875
2876 return (do_assignment_internal (&td, 0));
2877}
2878
2879/***************************************************
2880 * *
2881 * Functions to manage the positional parameters *
2882 * *
2883 ***************************************************/
2884
2885/* Return the word list that corresponds to `$*'. */
2886WORD_LIST *
2887list_rest_of_args ()
2888{
2889 register WORD_LIST *list, *args;
2890 int i;
2891
2892 /* Break out of the loop as soon as one of the dollar variables is null. */
2893 for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
2894 list = make_word_list (make_bare_word (dollar_vars[i]), list);
2895
2896 for (args = rest_of_args; args; args = args->next)
2897 list = make_word_list (make_bare_word (args->word->word), list);
2898
2899 return (REVERSE_LIST (list, WORD_LIST *));
2900}
2901
2902int
2903number_of_args ()
2904{
2905 register WORD_LIST *list;
2906 int n;
2907
2908 for (n = 0; n < 9 && dollar_vars[n+1]; n++)
2909 ;
2910 for (list = rest_of_args; list; list = list->next)
2911 n++;
2912 return n;
2913}
2914
2915/* Return the value of a positional parameter. This handles values > 10. */
2916char *
2917get_dollar_var_value (ind)
2918 intmax_t ind;
2919{
2920 char *temp;
2921 WORD_LIST *p;
2922
2923 if (ind < 10)
2924 temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
2925 else /* We want something like ${11} */
2926 {
2927 ind -= 10;
2928 for (p = rest_of_args; p && ind--; p = p->next)
2929 ;
2930 temp = p ? savestring (p->word->word) : (char *)NULL;
2931 }
2932 return (temp);
2933}
2934
2935/* Make a single large string out of the dollar digit variables,
2936 and the rest_of_args. If DOLLAR_STAR is 1, then obey the special
2937 case of "$*" with respect to IFS. */
2938char *
2939string_rest_of_args (dollar_star)
2940 int dollar_star;
2941{
2942 register WORD_LIST *list;
2943 char *string;
2944
2945 list = list_rest_of_args ();
2946 string = dollar_star ? string_list_dollar_star (list) : string_list (list);
2947 dispose_words (list);
2948 return (string);
2949}
2950
2951/* Return a string containing the positional parameters from START to
2952 END, inclusive. If STRING[0] == '*', we obey the rules for $*,
2953 which only makes a difference if QUOTED is non-zero. If QUOTED includes
2954 Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise
2955 no quoting chars are added. */
2956static char *
2957pos_params (string, start, end, quoted)
2958 char *string;
2959 int start, end, quoted;
2960{
2961 WORD_LIST *save, *params, *h, *t;
2962 char *ret;
2963 int i;
2964
2965 /* see if we can short-circuit. if start == end, we want 0 parameters. */
2966 if (start == end)
2967 return ((char *)NULL);
2968
2969 save = params = list_rest_of_args ();
2970 if (save == 0)
2971 return ((char *)NULL);
2972
2973 if (start == 0) /* handle ${@:0[:x]} specially */
2974 {
2975 t = make_word_list (make_word (dollar_vars[0]), params);
2976 save = params = t;
2977 }
2978
2979 for (i = start ? 1 : 0; params && i < start; i++)
2980 params = params->next;
2981 if (params == 0)
2982 return ((char *)NULL);
2983 for (h = t = params; params && i < end; i++)
2984 {
2985 t = params;
2986 params = params->next;
2987 }
2988
2989 t->next = (WORD_LIST *)NULL;
2990
2991 ret = string_list_pos_params (string[0], h, quoted);
2992
2993 if (t != params)
2994 t->next = params;
2995
2996 dispose_words (save);
2997 return (ret);
2998}
2999
3000/******************************************************************/
3001/* */
3002/* Functions to expand strings to strings or WORD_LISTs */
3003/* */
3004/******************************************************************/
3005
3006#if defined (PROCESS_SUBSTITUTION)
3007#define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~')
3008#else
3009#define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
3010#endif
3011
3012/* If there are any characters in STRING that require full expansion,
3013 then call FUNC to expand STRING; otherwise just perform quote
3014 removal if necessary. This returns a new string. */
3015static char *
3016expand_string_if_necessary (string, quoted, func)
3017 char *string;
3018 int quoted;
3019 EXPFUNC *func;
3020{
3021 WORD_LIST *list;
3022 size_t slen;
3023 int i, saw_quote;
3024 char *ret;
3025 DECLARE_MBSTATE;
3026
3027 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3028 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
3029 i = saw_quote = 0;
3030 while (string[i])
3031 {
3032 if (EXP_CHAR (string[i]))
3033 break;
3034 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3035 saw_quote = 1;
3036 ADVANCE_CHAR (string, slen, i);
3037 }
3038
3039 if (string[i])
3040 {
3041 list = (*func) (string, quoted);
3042 if (list)
3043 {
3044 ret = string_list (list);
3045 dispose_words (list);
3046 }
3047 else
3048 ret = (char *)NULL;
3049 }
3050 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3051 ret = string_quote_removal (string, quoted);
3052 else
3053 ret = savestring (string);
3054
3055 return ret;
3056}
3057
3058static inline char *
3059expand_string_to_string_internal (string, quoted, func)
3060 char *string;
3061 int quoted;
3062 EXPFUNC *func;
3063{
3064 WORD_LIST *list;
3065 char *ret;
3066
3067 if (string == 0 || *string == '\0')
3068 return ((char *)NULL);
3069
3070 list = (*func) (string, quoted);
3071 if (list)
3072 {
3073 ret = string_list (list);
3074 dispose_words (list);
3075 }
3076 else
3077 ret = (char *)NULL;
3078
3079 return (ret);
3080}
3081
3082char *
3083expand_string_to_string (string, quoted)
3084 char *string;
3085 int quoted;
3086{
3087 return (expand_string_to_string_internal (string, quoted, expand_string));
3088}
3089
3090char *
3091expand_string_unsplit_to_string (string, quoted)
3092 char *string;
3093 int quoted;
3094{
3095 return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
3096}
3097
3098char *
3099expand_assignment_string_to_string (string, quoted)
3100 char *string;
3101 int quoted;
3102{
3103 return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
3104}
3105
3106char *
3107expand_arith_string (string, quoted)
3108 char *string;
3109 int quoted;
3110{
3111 return (expand_string_if_necessary (string, quoted, expand_string));
3112}
3113
3114#if defined (COND_COMMAND)
3115/* Just remove backslashes in STRING. Returns a new string. */
3116char *
3117remove_backslashes (string)
3118 char *string;
3119{
3120 char *r, *ret, *s;
3121
3122 r = ret = (char *)xmalloc (strlen (string) + 1);
3123 for (s = string; s && *s; )
3124 {
3125 if (*s == '\\')
3126 s++;
3127 if (*s == 0)
3128 break;
3129 *r++ = *s++;
3130 }
3131 *r = '\0';
3132 return ret;
3133}
3134
3135/* This needs better error handling. */
3136/* Expand W for use as an argument to a unary or binary operator in a
3137 [[...]] expression. If SPECIAL is 1, this is the rhs argument
3138 to the != or == operator, and should be treated as a pattern. In
3139 this case, we quote the string specially for the globbing code. If
3140 SPECIAL is 2, this is an rhs argument for the =~ operator, and should
3141 be quoted appropriately for regcomp/regexec. The caller is responsible
3142 for removing the backslashes if the unquoted word is needed later. */
3143char *
3144cond_expand_word (w, special)
3145 WORD_DESC *w;
3146 int special;
3147{
3148 char *r, *p;
3149 WORD_LIST *l;
3150 int qflags;
3151
3152 if (w->word == 0 || w->word[0] == '\0')
3153 return ((char *)NULL);
3154
3155 w->flags |= W_NOSPLIT2;
3156 l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
3157 if (l)
3158 {
3159 if (special == 0)
3160 {
3161 dequote_list (l);
3162 r = string_list (l);
3163 }
3164 else
3165 {
3166 qflags = QGLOB_CVTNULL;
3167 if (special == 2)
3168 qflags |= QGLOB_REGEXP;
3169 p = string_list (l);
3170 r = quote_string_for_globbing (p, qflags);
3171 free (p);
3172 }
3173 dispose_words (l);
3174 }
3175 else
3176 r = (char *)NULL;
3177
3178 return r;
3179}
3180#endif
3181
3182/* Call expand_word_internal to expand W and handle error returns.
3183 A convenience function for functions that don't want to handle
3184 any errors or free any memory before aborting. */
3185static WORD_LIST *
3186call_expand_word_internal (w, q, i, c, e)
3187 WORD_DESC *w;
3188 int q, i, *c, *e;
3189{
3190 WORD_LIST *result;
3191
3192 result = expand_word_internal (w, q, i, c, e);
3193 if (result == &expand_word_error || result == &expand_word_fatal)
3194 {
3195 /* By convention, each time this error is returned, w->word has
3196 already been freed (it sometimes may not be in the fatal case,
3197 but that doesn't result in a memory leak because we're going
3198 to exit in most cases). */
3199 w->word = (char *)NULL;
3200 last_command_exit_value = EXECUTION_FAILURE;
3201 exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
3202 /* NOTREACHED */
3203 }
3204 else
3205 return (result);
3206}
3207
3208/* Perform parameter expansion, command substitution, and arithmetic
9c2db999
CR
3209 expansion on STRING, as if it were a word. Leave the result quoted.
3210 Since this does not perform word splitting, it leaves quoted nulls
3211 in the result. */
e192f341
CR
3212static WORD_LIST *
3213expand_string_internal (string, quoted)
3214 char *string;
3215 int quoted;
3216{
3217 WORD_DESC td;
3218 WORD_LIST *tresult;
3219
3220 if (string == 0 || *string == 0)
3221 return ((WORD_LIST *)NULL);
3222
3223 td.flags = 0;
3224 td.word = savestring (string);
3225
3226 tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3227
3228 FREE (td.word);
3229 return (tresult);
3230}
3231
3232/* Expand STRING by performing parameter expansion, command substitution,
3233 and arithmetic expansion. Dequote the resulting WORD_LIST before
3234 returning it, but do not perform word splitting. The call to
3235 remove_quoted_nulls () is in here because word splitting normally
3236 takes care of quote removal. */
3237WORD_LIST *
3238expand_string_unsplit (string, quoted)
3239 char *string;
3240 int quoted;
3241{
3242 WORD_LIST *value;
3243
3244 if (string == 0 || *string == '\0')
3245 return ((WORD_LIST *)NULL);
3246
3247 expand_no_split_dollar_star = 1;
3248 value = expand_string_internal (string, quoted);
3249 expand_no_split_dollar_star = 0;
3250
3251 if (value)
3252 {
3253 if (value->word)
3254 {
3255 remove_quoted_nulls (value->word->word);
3256 value->word->flags &= ~W_HASQUOTEDNULL;
3257 }
3258 dequote_list (value);
3259 }
3260 return (value);
3261}
3262
3263/* Expand the rhs of an assignment statement */
3264WORD_LIST *
3265expand_string_assignment (string, quoted)
3266 char *string;
3267 int quoted;
3268{
3269 WORD_DESC td;
3270 WORD_LIST *value;
3271
3272 if (string == 0 || *string == '\0')
3273 return ((WORD_LIST *)NULL);
3274
3275 expand_no_split_dollar_star = 1;
3276
3277 td.flags = W_ASSIGNRHS;
3278 td.word = savestring (string);
3279 value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3280 FREE (td.word);
3281
3282 expand_no_split_dollar_star = 0;
3283
3284 if (value)
3285 {
3286 if (value->word)
3287 {
3288 remove_quoted_nulls (value->word->word);
3289 value->word->flags &= ~W_HASQUOTEDNULL;
3290 }
3291 dequote_list (value);
3292 }
3293 return (value);
3294}
3295
3296
3297/* Expand one of the PS? prompt strings. This is a sort of combination of
3298 expand_string_unsplit and expand_string_internal, but returns the
3299 passed string when an error occurs. Might want to trap other calls
3300 to jump_to_top_level here so we don't endlessly loop. */
3301WORD_LIST *
3302expand_prompt_string (string, quoted, wflags)
3303 char *string;
3304 int quoted;
3305 int wflags;
3306{
3307 WORD_LIST *value;
3308 WORD_DESC td;
3309
3310 if (string == 0 || *string == 0)
3311 return ((WORD_LIST *)NULL);
3312
3313 td.flags = wflags;
3314 td.word = savestring (string);
3315
3316 no_longjmp_on_fatal_error = 1;
3317 value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3318 no_longjmp_on_fatal_error = 0;
3319
3320 if (value == &expand_word_error || value == &expand_word_fatal)
3321 {
3322 value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
3323 return value;
3324 }
3325 FREE (td.word);
3326 if (value)
3327 {
3328 if (value->word)
3329 {
3330 remove_quoted_nulls (value->word->word);
3331 value->word->flags &= ~W_HASQUOTEDNULL;
3332 }
3333 dequote_list (value);
3334 }
3335 return (value);
3336}
3337
3338/* Expand STRING just as if you were expanding a word, but do not dequote
3339 the resultant WORD_LIST. This is called only from within this file,
3340 and is used to correctly preserve quoted characters when expanding
3341 things like ${1+"$@"}. This does parameter expansion, command
3342 substitution, arithmetic expansion, and word splitting. */
3343static WORD_LIST *
3344expand_string_leave_quoted (string, quoted)
3345 char *string;
3346 int quoted;
3347{
3348 WORD_LIST *tlist;
3349 WORD_LIST *tresult;
3350
3351 if (string == 0 || *string == '\0')
3352 return ((WORD_LIST *)NULL);
3353
3354 tlist = expand_string_internal (string, quoted);
3355
3356 if (tlist)
3357 {
3358 tresult = word_list_split (tlist);
3359 dispose_words (tlist);
3360 return (tresult);
3361 }
3362 return ((WORD_LIST *)NULL);
3363}
3364
3365/* This does not perform word splitting or dequote the WORD_LIST
3366 it returns. */
3367static WORD_LIST *
3368expand_string_for_rhs (string, quoted, dollar_at_p, has_dollar_at)
3369 char *string;
3370 int quoted, *dollar_at_p, *has_dollar_at;
3371{
3372 WORD_DESC td;
3373 WORD_LIST *tresult;
3374
3375 if (string == 0 || *string == '\0')
3376 return (WORD_LIST *)NULL;
3377
9c2db999 3378 td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */
e192f341
CR
3379 td.word = string;
3380 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at);
3381 return (tresult);
3382}
3383
3384/* Expand STRING just as if you were expanding a word. This also returns
3385 a list of words. Note that filename globbing is *NOT* done for word
3386 or string expansion, just when the shell is expanding a command. This
3387 does parameter expansion, command substitution, arithmetic expansion,
3388 and word splitting. Dequote the resultant WORD_LIST before returning. */
3389WORD_LIST *
3390expand_string (string, quoted)
3391 char *string;
3392 int quoted;
3393{
3394 WORD_LIST *result;
3395
3396 if (string == 0 || *string == '\0')
3397 return ((WORD_LIST *)NULL);
3398
3399 result = expand_string_leave_quoted (string, quoted);
3400 return (result ? dequote_list (result) : result);
3401}
3402
3403/***************************************************
3404 * *
3405 * Functions to handle quoting chars *
3406 * *
3407 ***************************************************/
3408
3409/* Conventions:
3410
3411 A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
3412 The parser passes CTLNUL as CTLESC CTLNUL. */
3413
3414/* Quote escape characters in string s, but no other characters. This is
3415 used to protect CTLESC and CTLNUL in variable values from the rest of
3416 the word expansion process after the variable is expanded (word splitting
3417 and filename generation). If IFS is null, we quote spaces as well, just
3418 in case we split on spaces later (in the case of unquoted $@, we will
3419 eventually attempt to split the entire word on spaces). Corresponding
3420 code exists in dequote_escapes. Even if we don't end up splitting on
3421 spaces, quoting spaces is not a problem. This should never be called on
3422 a string that is quoted with single or double quotes or part of a here
3423 document (effectively double-quoted). */
3424char *
3425quote_escapes (string)
3426 char *string;
3427{
3428 register char *s, *t;
3429 size_t slen;
3430 char *result, *send;
3431 int quote_spaces, skip_ctlesc, skip_ctlnul;
3432 DECLARE_MBSTATE;
3433
3434 slen = strlen (string);
3435 send = string + slen;
3436
3437 quote_spaces = (ifs_value && *ifs_value == 0);
3438
3439 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
3440 skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
3441
3442 t = result = (char *)xmalloc ((slen * 2) + 1);
3443 s = string;
3444
3445 while (*s)
3446 {
3447 if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
3448 *t++ = CTLESC;
3449 COPY_CHAR_P (t, s, send);
3450 }
3451 *t = '\0';
3452 return (result);
3453}
3454
3455static WORD_LIST *
3456list_quote_escapes (list)
3457 WORD_LIST *list;
3458{
3459 register WORD_LIST *w;
3460 char *t;
3461
3462 for (w = list; w; w = w->next)
3463 {
3464 t = w->word->word;
3465 w->word->word = quote_escapes (t);
3466 free (t);
3467 }
3468 return list;
3469}
3470
3471/* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
3472
3473 The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
3474 This is necessary to make unquoted CTLESC and CTLNUL characters in the
3475 data stream pass through properly.
3476
3477 We need to remove doubled CTLESC characters inside quoted strings before
3478 quoting the entire string, so we do not double the number of CTLESC
3479 characters.
3480
3481 Also used by parts of the pattern substitution code. */
3482char *
3483dequote_escapes (string)
3484 char *string;
3485{
3486 register char *s, *t, *s1;
3487 size_t slen;
3488 char *result, *send;
3489 int quote_spaces;
3490 DECLARE_MBSTATE;
3491
3492 if (string == 0)
3493 return string;
3494
3495 slen = strlen (string);
3496 send = string + slen;
3497
3498 t = result = (char *)xmalloc (slen + 1);
3499
3500 if (strchr (string, CTLESC) == 0)
3501 return (strcpy (result, string));
3502
3503 quote_spaces = (ifs_value && *ifs_value == 0);
3504
3505 s = string;
3506 while (*s)
3507 {
3508 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
3509 {
3510 s++;
3511 if (*s == '\0')
3512 break;
3513 }
3514 COPY_CHAR_P (t, s, send);
3515 }
3516 *t = '\0';
3517 return result;
3518}
3519
3520/* Return a new string with the quoted representation of character C.
3521 This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
3522 set in any resultant WORD_DESC where this value is the word. */
3523static char *
3524make_quoted_char (c)
3525 int c;
3526{
3527 char *temp;
3528
3529 temp = (char *)xmalloc (3);
3530 if (c == 0)
3531 {
3532 temp[0] = CTLNUL;
3533 temp[1] = '\0';
3534 }
3535 else
3536 {
3537 temp[0] = CTLESC;
3538 temp[1] = c;
3539 temp[2] = '\0';
3540 }
3541 return (temp);
3542}
3543
3544/* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so
3545 the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
3546 this value is the word. */
3547char *
3548quote_string (string)
3549 char *string;
3550{
3551 register char *t;
3552 size_t slen;
3553 char *result, *send;
3554
3555 if (*string == 0)
3556 {
3557 result = (char *)xmalloc (2);
3558 result[0] = CTLNUL;
3559 result[1] = '\0';
3560 }
3561 else
3562 {
3563 DECLARE_MBSTATE;
3564
3565 slen = strlen (string);
3566 send = string + slen;
3567
3568 result = (char *)xmalloc ((slen * 2) + 1);
3569
3570 for (t = result; string < send; )
3571 {
3572 *t++ = CTLESC;
3573 COPY_CHAR_P (t, string, send);
3574 }
3575 *t = '\0';
3576 }
3577 return (result);
3578}
3579
3580/* De-quote quoted characters in STRING. */
3581char *
3582dequote_string (string)
3583 char *string;
3584{
3585 register char *s, *t;
3586 size_t slen;
3587 char *result, *send;
3588 DECLARE_MBSTATE;
3589
3590 slen = strlen (string);
3591
3592 t = result = (char *)xmalloc (slen + 1);
3593
3594 if (QUOTED_NULL (string))
3595 {
3596 result[0] = '\0';
3597 return (result);
3598 }
3599
3600 /* If no character in the string can be quoted, don't bother examining
3601 each character. Just return a copy of the string passed to us. */
3602 if (strchr (string, CTLESC) == NULL)
3603 return (strcpy (result, string));
3604
3605 send = string + slen;
3606 s = string;
3607 while (*s)
3608 {
3609 if (*s == CTLESC)
3610 {
3611 s++;
3612 if (*s == '\0')
3613 break;
3614 }
3615 COPY_CHAR_P (t, s, send);
3616 }
3617
3618 *t = '\0';
3619 return (result);
3620}
3621
3622/* Quote the entire WORD_LIST list. */
3623static WORD_LIST *
3624quote_list (list)
3625 WORD_LIST *list;
3626{
3627 register WORD_LIST *w;
3628 char *t;
3629
3630 for (w = list; w; w = w->next)
3631 {
3632 t = w->word->word;
3633 w->word->word = quote_string (t);
3634 if (*t == 0)
3635 w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
3636 w->word->flags |= W_QUOTED;
3637 free (t);
3638 }
3639 return list;
3640}
3641
3642/* De-quote quoted characters in each word in LIST. */
3643WORD_LIST *
3644dequote_list (list)
3645 WORD_LIST *list;
3646{
3647 register char *s;
3648 register WORD_LIST *tlist;
3649
3650 for (tlist = list; tlist; tlist = tlist->next)
3651 {
3652 s = dequote_string (tlist->word->word);
3653 if (QUOTED_NULL (tlist->word->word))
3654 tlist->word->flags &= ~W_HASQUOTEDNULL;
3655 free (tlist->word->word);
3656 tlist->word->word = s;
3657 }
3658 return list;
3659}
3660
3661/* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
3662 string. */
3663char *
3664remove_quoted_escapes (string)
3665 char *string;
3666{
3667 char *t;
3668
3669 if (string)
3670 {
3671 t = dequote_escapes (string);
3672 strcpy (string, t);
3673 free (t);
3674 }
3675
3676 return (string);
3677}
3678
3679/* Perform quoted null character removal on STRING. We don't allow any
3680 quoted null characters in the middle or at the ends of strings because
3681 of how expand_word_internal works. remove_quoted_nulls () turns
3682 STRING into an empty string iff it only consists of a quoted null,
3683 and removes all unquoted CTLNUL characters. */
3684char *
3685remove_quoted_nulls (string)
3686 char *string;
3687{
3688 register size_t slen;
3689 register int i, j, prev_i;
3690 DECLARE_MBSTATE;
3691
3692 if (strchr (string, CTLNUL) == 0) /* XXX */
3693 return string; /* XXX */
3694
3695 slen = strlen (string);
3696 i = j = 0;
3697
3698 while (i < slen)
3699 {
3700 if (string[i] == CTLESC)
3701 {
3702 /* Old code had j++, but we cannot assume that i == j at this
3703 point -- what if a CTLNUL has already been removed from the
3704 string? We don't want to drop the CTLESC or recopy characters
3705 that we've already copied down. */
3706 i++; string[j++] = CTLESC;
3707 if (i == slen)
3708 break;
3709 }
3710 else if (string[i] == CTLNUL)
3711 i++;
3712
3713 prev_i = i;
3714 ADVANCE_CHAR (string, slen, i);
3715 if (j < prev_i)
3716 {
3717 do string[j++] = string[prev_i++]; while (prev_i < i);
3718 }
3719 else
3720 j = i;
3721 }
3722 string[j] = '\0';
3723
3724 return (string);
3725}
3726
3727/* Perform quoted null character removal on each element of LIST.
3728 This modifies LIST. */
3729void
3730word_list_remove_quoted_nulls (list)
3731 WORD_LIST *list;
3732{
3733 register WORD_LIST *t;
3734
3735 for (t = list; t; t = t->next)
3736 {
3737 remove_quoted_nulls (t->word->word);
3738 t->word->flags &= ~W_HASQUOTEDNULL;
3739 }
3740}
3741
3742/* **************************************************************** */
3743/* */
3744/* Functions for Matching and Removing Patterns */
3745/* */
3746/* **************************************************************** */
3747
3748#if defined (HANDLE_MULTIBYTE)
3749#if 0 /* Currently unused */
3750static unsigned char *
3751mb_getcharlens (string, len)
3752 char *string;
3753 int len;
3754{
3755 int i, offset, last;
3756 unsigned char *ret;
3757 char *p;
3758 DECLARE_MBSTATE;
3759
3760 i = offset = 0;
3761 last = 0;
3762 ret = (unsigned char *)xmalloc (len);
3763 memset (ret, 0, len);
3764 while (string[last])
3765 {
3766 ADVANCE_CHAR (string, len, offset);
3767 ret[last] = offset - last;
3768 last = offset;
3769 }
3770 return ret;
3771}
3772#endif
3773#endif
3774
3775/* Remove the portion of PARAM matched by PATTERN according to OP, where OP
3776 can have one of 4 values:
3777 RP_LONG_LEFT remove longest matching portion at start of PARAM
3778 RP_SHORT_LEFT remove shortest matching portion at start of PARAM
3779 RP_LONG_RIGHT remove longest matching portion at end of PARAM
3780 RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
3781*/
3782
3783#define RP_LONG_LEFT 1
3784#define RP_SHORT_LEFT 2
3785#define RP_LONG_RIGHT 3
3786#define RP_SHORT_RIGHT 4
3787
3788/* Returns its first argument if nothing matched; new memory otherwise */
3789static char *
3790remove_upattern (param, pattern, op)
3791 char *param, *pattern;
3792 int op;
3793{
3794 register int len;
3795 register char *end;
3796 register char *p, *ret, c;
3797
3798 len = STRLEN (param);
3799 end = param + len;
3800
3801 switch (op)
3802 {
3803 case RP_LONG_LEFT: /* remove longest match at start */
3804 for (p = end; p >= param; p--)
3805 {
3806 c = *p; *p = '\0';
3807 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3808 {
3809 *p = c;
3810 return (savestring (p));
3811 }
3812 *p = c;
3813
3814 }
3815 break;
3816
3817 case RP_SHORT_LEFT: /* remove shortest match at start */
3818 for (p = param; p <= end; p++)
3819 {
3820 c = *p; *p = '\0';
3821 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3822 {
3823 *p = c;
3824 return (savestring (p));
3825 }
3826 *p = c;
3827 }
3828 break;
3829
3830 case RP_LONG_RIGHT: /* remove longest match at end */
3831 for (p = param; p <= end; p++)
3832 {
3833 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3834 {
3835 c = *p; *p = '\0';
3836 ret = savestring (param);
3837 *p = c;
3838 return (ret);
3839 }
3840 }
3841 break;
3842
3843 case RP_SHORT_RIGHT: /* remove shortest match at end */
3844 for (p = end; p >= param; p--)
3845 {
3846 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3847 {
3848 c = *p; *p = '\0';
3849 ret = savestring (param);
3850 *p = c;
3851 return (ret);
3852 }
3853 }
3854 break;
3855 }
3856
3857 return (param); /* no match, return original string */
3858}
3859
3860#if defined (HANDLE_MULTIBYTE)
3861/* Returns its first argument if nothing matched; new memory otherwise */
3862static wchar_t *
3863remove_wpattern (wparam, wstrlen, wpattern, op)
3864 wchar_t *wparam;
3865 size_t wstrlen;
3866 wchar_t *wpattern;
3867 int op;
3868{
3869 wchar_t wc, *ret;
3870 int n;
3871
3872 switch (op)
3873 {
3874 case RP_LONG_LEFT: /* remove longest match at start */
3875 for (n = wstrlen; n >= 0; n--)
3876 {
3877 wc = wparam[n]; wparam[n] = L'\0';
3878 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3879 {
3880 wparam[n] = wc;
3881 return (wcsdup (wparam + n));
3882 }
3883 wparam[n] = wc;
3884 }
3885 break;
3886
3887 case RP_SHORT_LEFT: /* remove shortest match at start */
3888 for (n = 0; n <= wstrlen; n++)
3889 {
3890 wc = wparam[n]; wparam[n] = L'\0';
3891 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3892 {
3893 wparam[n] = wc;
3894 return (wcsdup (wparam + n));
3895 }
3896 wparam[n] = wc;
3897 }
3898 break;
3899
3900 case RP_LONG_RIGHT: /* remove longest match at end */
3901 for (n = 0; n <= wstrlen; n++)
3902 {
3903 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3904 {
3905 wc = wparam[n]; wparam[n] = L'\0';
3906 ret = wcsdup (wparam);
3907 wparam[n] = wc;
3908 return (ret);
3909 }
3910 }
3911 break;
3912
3913 case RP_SHORT_RIGHT: /* remove shortest match at end */
3914 for (n = wstrlen; n >= 0; n--)
3915 {
3916 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
3917 {
3918 wc = wparam[n]; wparam[n] = L'\0';
3919 ret = wcsdup (wparam);
3920 wparam[n] = wc;
3921 return (ret);
3922 }
3923 }
3924 break;
3925 }
3926
3927 return (wparam); /* no match, return original string */
3928}
3929#endif /* HANDLE_MULTIBYTE */
3930
3931static char *
3932remove_pattern (param, pattern, op)
3933 char *param, *pattern;
3934 int op;
3935{
3936 char *xret;
3937
3938 if (param == NULL)
3939 return (param);
3940 if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
3941 return (savestring (param));
3942
3943#if defined (HANDLE_MULTIBYTE)
3944 if (MB_CUR_MAX > 1)
3945 {
3946 wchar_t *ret, *oret;
3947 size_t n;
3948 wchar_t *wparam, *wpattern;
3949 mbstate_t ps;
3950
3951 n = xdupmbstowcs (&wpattern, NULL, pattern);
3952 if (n == (size_t)-1)
3953 {
3954 xret = remove_upattern (param, pattern, op);
3955 return ((xret == param) ? savestring (param) : xret);
3956 }
3957 n = xdupmbstowcs (&wparam, NULL, param);
3958 if (n == (size_t)-1)
3959 {
3960 free (wpattern);
3961 xret = remove_upattern (param, pattern, op);
3962 return ((xret == param) ? savestring (param) : xret);
3963 }
3964 oret = ret = remove_wpattern (wparam, n, wpattern, op);
3965 /* Don't bother to convert wparam back to multibyte string if nothing
3966 matched; just return copy of original string */
3967 if (ret == wparam)
3968 {
3969 free (wparam);
3970 free (wpattern);
3971 return (savestring (param));
3972 }
3973
3974 free (wparam);
3975 free (wpattern);
3976
3977 n = strlen (param);
3978 xret = (char *)xmalloc (n + 1);
3979 memset (&ps, '\0', sizeof (mbstate_t));
3980 n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
3981 xret[n] = '\0'; /* just to make sure */
3982 free (oret);
3983 return xret;
3984 }
3985 else
3986#endif
3987 {
3988 xret = remove_upattern (param, pattern, op);
3989 return ((xret == param) ? savestring (param) : xret);
3990 }
3991}
3992
3993/* Match PAT anywhere in STRING and return the match boundaries.
3994 This returns 1 in case of a successful match, 0 otherwise. SP
3995 and EP are pointers into the string where the match begins and
3996 ends, respectively. MTYPE controls what kind of match is attempted.
3997 MATCH_BEG and MATCH_END anchor the match at the beginning and end
3998 of the string, respectively. The longest match is returned. */
3999static int
4000match_upattern (string, pat, mtype, sp, ep)
4001 char *string, *pat;
4002 int mtype;
4003 char **sp, **ep;
4004{
4005 int c, len, mlen;
4006 register char *p, *p1, *npat;
4007 char *end;
4008 int n1;
4009
4010 /* If the pattern doesn't match anywhere in the string, go ahead and
4011 short-circuit right away. A minor optimization, saves a bunch of
4012 unnecessary calls to strmatch (up to N calls for a string of N
4013 characters) if the match is unsuccessful. To preserve the semantics
4014 of the substring matches below, we make sure that the pattern has
4015 `*' as first and last character, making a new pattern if necessary. */
4016 /* XXX - check this later if I ever implement `**' with special meaning,
4017 since this will potentially result in `**' at the beginning or end */
4018 len = STRLEN (pat);
4019 if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
4020 {
4021 p = npat = (char *)xmalloc (len + 3);
4022 p1 = pat;
4023 if (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))
4024 *p++ = '*';
4025 while (*p1)
4026 *p++ = *p1++;
4027 if (p1[-1] != '*' || p[-2] == '\\')
4028 *p++ = '*';
4029 *p = '\0';
4030 }
4031 else
4032 npat = pat;
4033 c = strmatch (npat, string, FNMATCH_EXTFLAG);
4034 if (npat != pat)
4035 free (npat);
4036 if (c == FNM_NOMATCH)
4037 return (0);
4038
4039 len = STRLEN (string);
4040 end = string + len;
4041
4042 mlen = umatchlen (pat, len);
4043
4044 switch (mtype)
4045 {
4046 case MATCH_ANY:
4047 for (p = string; p <= end; p++)
4048 {
4049 if (match_pattern_char (pat, p))
4050 {
4051#if 0
4052 for (p1 = end; p1 >= p; p1--)
4053#else
4054 p1 = (mlen == -1) ? end : p + mlen;
4055 /* p1 - p = length of portion of string to be considered
4056 p = current position in string
4057 mlen = number of characters consumed by match (-1 for entire string)
4058 end = end of string
4059 we want to break immediately if the potential match len
4060 is greater than the number of characters remaining in the
4061 string
4062 */
4063 if (p1 > end)
4064 break;
4065 for ( ; p1 >= p; p1--)
4066#endif
4067 {
4068 c = *p1; *p1 = '\0';
4069 if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
4070 {
4071 *p1 = c;
4072 *sp = p;
4073 *ep = p1;
4074 return 1;
4075 }
4076 *p1 = c;
4077#if 1
4078 /* If MLEN != -1, we have a fixed length pattern. */
4079 if (mlen != -1)
4080 break;
4081#endif
4082 }
4083 }
4084 }
4085
4086 return (0);
4087
4088 case MATCH_BEG:
4089 if (match_pattern_char (pat, string) == 0)
4090 return (0);
4091
4092#if 0
4093 for (p = end; p >= string; p--)
4094#else
4095 for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
4096#endif
4097 {
4098 c = *p; *p = '\0';
4099 if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0)
4100 {
4101 *p = c;
4102 *sp = string;
4103 *ep = p;
4104 return 1;
4105 }
4106 *p = c;
4107#if 1
4108 /* If MLEN != -1, we have a fixed length pattern. */
4109 if (mlen != -1)
4110 break;
4111#endif
4112 }
4113
4114 return (0);
4115
4116 case MATCH_END:
4117#if 0
4118 for (p = string; p <= end; p++)
4119#else
4120 for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
4121#endif
4122 {
4123 if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
4124 {
4125 *sp = p;
4126 *ep = end;
4127 return 1;
4128 }
4129#if 1
4130 /* If MLEN != -1, we have a fixed length pattern. */
4131 if (mlen != -1)
4132 break;
4133#endif
4134 }
4135
4136 return (0);
4137 }
4138
4139 return (0);
4140}
4141
4142#if defined (HANDLE_MULTIBYTE)
4143/* Match WPAT anywhere in WSTRING and return the match boundaries.
4144 This returns 1 in case of a successful match, 0 otherwise. Wide
4145 character version. */
4146static int
4147match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
4148 wchar_t *wstring;
4149 char **indices;
4150 size_t wstrlen;
4151 wchar_t *wpat;
4152 int mtype;
4153 char **sp, **ep;
4154{
4155 wchar_t wc, *wp, *nwpat, *wp1;
4156 size_t len;
4157 int mlen;
4158 int n, n1, n2, simple;
4159
4160 simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
4161#if defined (EXTENDED_GLOB)
4162 if (extended_glob)
4163 simple |= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
4164#endif
4165
4166 /* If the pattern doesn't match anywhere in the string, go ahead and
4167 short-circuit right away. A minor optimization, saves a bunch of
4168 unnecessary calls to strmatch (up to N calls for a string of N
4169 characters) if the match is unsuccessful. To preserve the semantics
4170 of the substring matches below, we make sure that the pattern has
4171 `*' as first and last character, making a new pattern if necessary. */
4172 len = wcslen (wpat);
4173 if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
4174 {
4175 wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
4176 wp1 = wpat;
4177 if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
4178 *wp++ = L'*';
4179 while (*wp1 != L'\0')
4180 *wp++ = *wp1++;
4181 if (wp1[-1] != L'*' || wp1[-2] == L'\\')
4182 *wp++ = L'*';
4183 *wp = '\0';
4184 }
4185 else
4186 nwpat = wpat;
4187 len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG);
4188 if (nwpat != wpat)
4189 free (nwpat);
4190 if (len == FNM_NOMATCH)
4191 return (0);
4192
4193 mlen = wmatchlen (wpat, wstrlen);
4194
4195/* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
4196 switch (mtype)
4197 {
4198 case MATCH_ANY:
4199 for (n = 0; n <= wstrlen; n++)
4200 {
4201#if 1
4202 n2 = simple ? (*wpat == wstring[n]) : match_pattern_wchar (wpat, wstring + n);
4203#else
4204 n2 = match_pattern_wchar (wpat, wstring + n);
4205#endif
4206 if (n2)
4207 {
4208#if 0
4209 for (n1 = wstrlen; n1 >= n; n1--)
4210#else
4211 n1 = (mlen == -1) ? wstrlen : n + mlen;
4212 if (n1 > wstrlen)
4213 break;
4214
4215 for ( ; n1 >= n; n1--)
4216#endif
4217 {
4218 wc = wstring[n1]; wstring[n1] = L'\0';
4219 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
4220 {
4221 wstring[n1] = wc;
4222 *sp = indices[n];
4223 *ep = indices[n1];
4224 return 1;
4225 }
4226 wstring[n1] = wc;
4227#if 1
4228 /* If MLEN != -1, we have a fixed length pattern. */
4229 if (mlen != -1)
4230 break;
4231#endif
4232 }
4233 }
4234 }
4235
4236 return (0);
4237
4238 case MATCH_BEG:
4239 if (match_pattern_wchar (wpat, wstring) == 0)
4240 return (0);
4241
4242#if 0
4243 for (n = wstrlen; n >= 0; n--)
4244#else
4245 for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
4246#endif
4247 {
4248 wc = wstring[n]; wstring[n] = L'\0';
4249 if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0)
4250 {
4251 wstring[n] = wc;
4252 *sp = indices[0];
4253 *ep = indices[n];
4254 return 1;
4255 }
4256 wstring[n] = wc;
4257#if 1
4258 /* If MLEN != -1, we have a fixed length pattern. */
4259 if (mlen != -1)
4260 break;
4261#endif
4262 }
4263
4264 return (0);
4265
4266 case MATCH_END:
4267#if 0
4268 for (n = 0; n <= wstrlen; n++)
4269#else
4270 for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
4271#endif
4272 {
4273 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
4274 {
4275 *sp = indices[n];
4276 *ep = indices[wstrlen];
4277 return 1;
4278 }
4279#if 1
4280 /* If MLEN != -1, we have a fixed length pattern. */
4281 if (mlen != -1)
4282 break;
4283#endif
4284 }
4285
4286 return (0);
4287 }
4288
4289 return (0);
4290}
4291#endif /* HANDLE_MULTIBYTE */
4292
4293static int
4294match_pattern (string, pat, mtype, sp, ep)
4295 char *string, *pat;
4296 int mtype;
4297 char **sp, **ep;
4298{
4299#if defined (HANDLE_MULTIBYTE)
4300 int ret;
4301 size_t n;
4302 wchar_t *wstring, *wpat;
4303 char **indices;
4304 size_t slen, plen, mslen, mplen;
4305#endif
4306
4307 if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
4308 return (0);
4309
4310#if defined (HANDLE_MULTIBYTE)
4311 if (MB_CUR_MAX > 1)
4312 {
4313#if 0
4314 slen = STRLEN (string);
4315 mslen = MBSLEN (string);
4316 plen = STRLEN (pat);
4317 mplen = MBSLEN (pat);
4318 if (slen == mslen && plen == mplen)
4319#else
4320 if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
4321#endif
4322 return (match_upattern (string, pat, mtype, sp, ep));
4323
4324 n = xdupmbstowcs (&wpat, NULL, pat);
4325 if (n == (size_t)-1)
4326 return (match_upattern (string, pat, mtype, sp, ep));
4327 n = xdupmbstowcs (&wstring, &indices, string);
4328 if (n == (size_t)-1)
4329 {
4330 free (wpat);
4331 return (match_upattern (string, pat, mtype, sp, ep));
4332 }
4333 ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
4334
4335 free (wpat);
4336 free (wstring);
4337 free (indices);
4338
4339 return (ret);
4340 }
4341 else
4342#endif
4343 return (match_upattern (string, pat, mtype, sp, ep));
4344}
4345
4346static int
4347getpatspec (c, value)
4348 int c;
4349 char *value;
4350{
4351 if (c == '#')
4352 return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
4353 else /* c == '%' */
4354 return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
4355}
4356
4357/* Posix.2 says that the WORD should be run through tilde expansion,
4358 parameter expansion, command substitution and arithmetic expansion.
4359 This leaves the result quoted, so quote_string_for_globbing () has
4360 to be called to fix it up for strmatch (). If QUOTED is non-zero,
4361 it means that the entire expression was enclosed in double quotes.
4362 This means that quoting characters in the pattern do not make any
4363 special pattern characters quoted. For example, the `*' in the
4364 following retains its special meaning: "${foo#'*'}". */
4365static char *
4366getpattern (value, quoted, expandpat)
4367 char *value;
4368 int quoted, expandpat;
4369{
4370 char *pat, *tword;
4371 WORD_LIST *l;
4372#if 0
4373 int i;
4374#endif
4375 /* There is a problem here: how to handle single or double quotes in the
4376 pattern string when the whole expression is between double quotes?
4377 POSIX.2 says that enclosing double quotes do not cause the pattern to
4378 be quoted, but does that leave us a problem with @ and array[@] and their
4379 expansions inside a pattern? */
4380#if 0
4381 if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
4382 {
4383 i = 0;
4384 pat = string_extract_double_quoted (tword, &i, 1);
4385 free (tword);
4386 tword = pat;
4387 }
4388#endif
4389
4390 /* expand_string_for_rhs () leaves WORD quoted and does not perform
4391 word splitting. */
4392 l = *value ? expand_string_for_rhs (value,
4393 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
4394 (int *)NULL, (int *)NULL)
4395 : (WORD_LIST *)0;
4396 pat = string_list (l);
4397 dispose_words (l);
4398 if (pat)
4399 {
4400 tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
4401 free (pat);
4402 pat = tword;
4403 }
4404 return (pat);
4405}
4406
4407#if 0
4408/* Handle removing a pattern from a string as a result of ${name%[%]value}
4409 or ${name#[#]value}. */
4410static char *
4411variable_remove_pattern (value, pattern, patspec, quoted)
4412 char *value, *pattern;
4413 int patspec, quoted;
4414{
4415 char *tword;
4416
4417 tword = remove_pattern (value, pattern, patspec);
4418
4419 return (tword);
4420}
4421#endif
4422
4423static char *
4424list_remove_pattern (list, pattern, patspec, itype, quoted)
4425 WORD_LIST *list;
4426 char *pattern;
4427 int patspec, itype, quoted;
4428{
4429 WORD_LIST *new, *l;
4430 WORD_DESC *w;
4431 char *tword;
4432
4433 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
4434 {
4435 tword = remove_pattern (l->word->word, pattern, patspec);
4436 w = alloc_word_desc ();
4437 w->word = tword ? tword : savestring ("");
4438 new = make_word_list (w, new);
4439 }
4440
4441 l = REVERSE_LIST (new, WORD_LIST *);
4442 tword = string_list_pos_params (itype, l, quoted);
4443 dispose_words (l);
4444
4445 return (tword);
4446}
4447
4448static char *
4449parameter_list_remove_pattern (itype, pattern, patspec, quoted)
4450 int itype;
4451 char *pattern;
4452 int patspec, quoted;
4453{
4454 char *ret;
4455 WORD_LIST *list;
4456
4457 list = list_rest_of_args ();
4458 if (list == 0)
4459 return ((char *)NULL);
4460 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
4461 dispose_words (list);
4462 return (ret);
4463}
4464
4465#if defined (ARRAY_VARS)
4466static char *
4467array_remove_pattern (var, pattern, patspec, varname, quoted)
4468 SHELL_VAR *var;
4469 char *pattern;
4470 int patspec;
4471 char *varname; /* so we can figure out how it's indexed */
4472 int quoted;
4473{
4474 ARRAY *a;
4475 HASH_TABLE *h;
4476 int itype;
4477 char *ret;
4478 WORD_LIST *list;
4479 SHELL_VAR *v;
4480
4481 /* compute itype from varname here */
4482 v = array_variable_part (varname, &ret, 0);
4483 itype = ret[0];
4484
4485 a = (v && array_p (v)) ? array_cell (v) : 0;
4486 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
4487
4488 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
4489 if (list == 0)
4490 return ((char *)NULL);
4491 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
4492 dispose_words (list);
4493
4494 return ret;
4495}
4496#endif /* ARRAY_VARS */
4497
4498static char *
4499parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags)
4500 char *varname, *value;
4501 int ind;
4502 char *patstr;
4503 int rtype, quoted, flags;
4504{
4505 int vtype, patspec, starsub;
4506 char *temp1, *val, *pattern;
4507 SHELL_VAR *v;
4508
4509 if (value == 0)
4510 return ((char *)NULL);
4511
4512 this_command_name = varname;
4513
4514 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
4515 if (vtype == -1)
4516 return ((char *)NULL);
4517
4518 starsub = vtype & VT_STARSUB;
4519 vtype &= ~VT_STARSUB;
4520
4521 patspec = getpatspec (rtype, patstr);
4522 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
4523 patstr++;
4524
4525 /* Need to pass getpattern newly-allocated memory in case of expansion --
4526 the expansion code will free the passed string on an error. */
4527 temp1 = savestring (patstr);
4528 pattern = getpattern (temp1, quoted, 1);
4529 free (temp1);
4530
4531 temp1 = (char *)NULL; /* shut up gcc */
4532 switch (vtype)
4533 {
4534 case VT_VARIABLE:
4535 case VT_ARRAYMEMBER:
4536 temp1 = remove_pattern (val, pattern, patspec);
4537 if (vtype == VT_VARIABLE)
4538 FREE (val);
4539 if (temp1)
4540 {
4541 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
4542 ? quote_string (temp1)
4543 : quote_escapes (temp1);
4544 free (temp1);
4545 temp1 = val;
4546 }
4547 break;
4548#if defined (ARRAY_VARS)
4549 case VT_ARRAYVAR:
4550 temp1 = array_remove_pattern (v, pattern, patspec, varname, quoted);
4551 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4552 {
4553 val = quote_escapes (temp1);
4554 free (temp1);
4555 temp1 = val;
4556 }
4557 break;
4558#endif
4559 case VT_POSPARMS:
4560 temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
4561 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4562 {
4563 val = quote_escapes (temp1);
4564 free (temp1);
4565 temp1 = val;
4566 }
4567 break;
4568 }
4569
4570 FREE (pattern);
4571 return temp1;
4572}
4573
4574/*******************************************
4575 * *
4576 * Functions to expand WORD_DESCs *
4577 * *
4578 *******************************************/
4579
4580/* Expand WORD, performing word splitting on the result. This does
4581 parameter expansion, command substitution, arithmetic expansion,
4582 word splitting, and quote removal. */
4583
4584WORD_LIST *
4585expand_word (word, quoted)
4586 WORD_DESC *word;
4587 int quoted;
4588{
4589 WORD_LIST *result, *tresult;
4590
4591 tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4592 result = word_list_split (tresult);
4593 dispose_words (tresult);
4594 return (result ? dequote_list (result) : result);
4595}
4596
4597/* Expand WORD, but do not perform word splitting on the result. This
4598 does parameter expansion, command substitution, arithmetic expansion,
4599 and quote removal. */
4600WORD_LIST *
4601expand_word_unsplit (word, quoted)
4602 WORD_DESC *word;
4603 int quoted;
4604{
4605 WORD_LIST *result;
4606
4607 expand_no_split_dollar_star = 1;
4608#if defined (HANDLE_MULTIBYTE)
4609 if (ifs_firstc[0] == 0)
4610#else
4611 if (ifs_firstc == 0)
4612#endif
4613 word->flags |= W_NOSPLIT;
4614 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4615 expand_no_split_dollar_star = 0;
4616
4617 return (result ? dequote_list (result) : result);
4618}
4619
4620/* Perform shell expansions on WORD, but do not perform word splitting or
4621 quote removal on the result. Virtually identical to expand_word_unsplit;
4622 could be combined if implementations don't diverge. */
4623WORD_LIST *
4624expand_word_leave_quoted (word, quoted)
4625 WORD_DESC *word;
4626 int quoted;
4627{
4628 WORD_LIST *result;
4629
4630 expand_no_split_dollar_star = 1;
4631#if defined (HANDLE_MULTIBYTE)
4632 if (ifs_firstc[0] == 0)
4633#else
4634 if (ifs_firstc == 0)
4635#endif
4636 word->flags |= W_NOSPLIT;
4637 word->flags |= W_NOSPLIT2;
4638 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4639 expand_no_split_dollar_star = 0;
4640
4641 return result;
4642}
4643
4644#if defined (PROCESS_SUBSTITUTION)
4645
4646/*****************************************************************/
4647/* */
4648/* Hacking Process Substitution */
4649/* */
4650/*****************************************************************/
4651
4652#if !defined (HAVE_DEV_FD)
4653/* Named pipes must be removed explicitly with `unlink'. This keeps a list
4654 of FIFOs the shell has open. unlink_fifo_list will walk the list and
4655 unlink all of them. add_fifo_list adds the name of an open FIFO to the
4656 list. NFIFO is a count of the number of FIFOs in the list. */
4657#define FIFO_INCR 20
4658
4659struct temp_fifo {
4660 char *file;
4661 pid_t proc;
4662};
4663
4664static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
4665static int nfifo;
4666static int fifo_list_size;
4667
4668char *
4669copy_fifo_list (sizep)
4670 int *sizep;
4671{
4672 if (sizep)
4673 *sizep = 0;
4674 return (char *)NULL;
4675}
4676
4677static void
4678add_fifo_list (pathname)
4679 char *pathname;
4680{
4681 if (nfifo >= fifo_list_size - 1)
4682 {
4683 fifo_list_size += FIFO_INCR;
4684 fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
4685 fifo_list_size * sizeof (struct temp_fifo));
4686 }
4687
4688 fifo_list[nfifo].file = savestring (pathname);
4689 nfifo++;
4690}
4691
4692void
4693unlink_fifo (i)
4694 int i;
4695{
4696 if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1))
4697 {
4698 unlink (fifo_list[i].file);
4699 free (fifo_list[i].file);
4700 fifo_list[i].file = (char *)NULL;
4701 fifo_list[i].proc = -1;
4702 }
4703}
4704
4705void
4706unlink_fifo_list ()
4707{
4708 int saved, i, j;
4709
4710 if (nfifo == 0)
4711 return;
4712
4713 for (i = saved = 0; i < nfifo; i++)
4714 {
4715 if ((fifo_list[i].proc == -1) || (kill(fifo_list[i].proc, 0) == -1))
4716 {
4717 unlink (fifo_list[i].file);
4718 free (fifo_list[i].file);
4719 fifo_list[i].file = (char *)NULL;
4720 fifo_list[i].proc = -1;
4721 }
4722 else
4723 saved++;
4724 }
4725
4726 /* If we didn't remove some of the FIFOs, compact the list. */
4727 if (saved)
4728 {
4729 for (i = j = 0; i < nfifo; i++)
4730 if (fifo_list[i].file)
4731 {
4732 fifo_list[j].file = fifo_list[i].file;
4733 fifo_list[j].proc = fifo_list[i].proc;
4734 j++;
4735 }
4736 nfifo = j;
4737 }
4738 else
4739 nfifo = 0;
4740}
4741
4742/* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
4743 from some point in the past, and close all open FIFOs in fifo_list
4744 that are not marked as active in LIST. If LIST is NULL, close
4745 everything in fifo_list. LSIZE is the number of elements in LIST, in
4746 case it's larger than fifo_list_size (size of fifo_list). */
4747void
4748close_new_fifos (list, lsize)
4749 char *list;
4750 int lsize;
4751{
4752 int i;
4753
4754 if (list == 0)
4755 {
4756 unlink_fifo_list ();
4757 return;
4758 }
4759
4760 for (i = 0; i < lsize; i++)
4761 if (list[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
4762 unlink_fifo (i);
4763
4764 for (i = lsize; i < fifo_list_size; i++)
4765 unlink_fifo (i);
4766}
4767
4768int
4769fifos_pending ()
4770{
4771 return nfifo;
4772}
4773
4774int
4775num_fifos ()
4776{
4777 return nfifo;
4778}
4779
4780static char *
4781make_named_pipe ()
4782{
4783 char *tname;
4784
4785 tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
4786 if (mkfifo (tname, 0600) < 0)
4787 {
4788 free (tname);
4789 return ((char *)NULL);
4790 }
4791
4792 add_fifo_list (tname);
4793 return (tname);
4794}
4795
4796#else /* HAVE_DEV_FD */
4797
4798/* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
4799 has open to children. NFDS is a count of the number of bits currently
4800 set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
4801 of open files. */
4802static char *dev_fd_list = (char *)NULL;
4803static int nfds;
4804static int totfds; /* The highest possible number of open files. */
4805
4806char *
4807copy_fifo_list (sizep)
4808 int *sizep;
4809{
4810 char *ret;
4811
4812 if (nfds == 0 || totfds == 0)
4813 {
4814 if (sizep)
4815 *sizep = 0;
4816 return (char *)NULL;
4817 }
4818
4819 if (sizep)
4820 *sizep = totfds;
4821 ret = (char *)xmalloc (totfds);
4822 return (memcpy (ret, dev_fd_list, totfds));
4823}
4824
4825static void
4826add_fifo_list (fd)
4827 int fd;
4828{
4829 if (dev_fd_list == 0 || fd >= totfds)
4830 {
4831 int ofds;
4832
4833 ofds = totfds;
4834 totfds = getdtablesize ();
4835 if (totfds < 0 || totfds > 256)
4836 totfds = 256;
4837 if (fd >= totfds)
4838 totfds = fd + 2;
4839
4840 dev_fd_list = (char *)xrealloc (dev_fd_list, totfds);
4841 memset (dev_fd_list + ofds, '\0', totfds - ofds);
4842 }
4843
4844 dev_fd_list[fd] = 1;
4845 nfds++;
4846}
4847
4848int
4849fifos_pending ()
4850{
4851 return 0; /* used for cleanup; not needed with /dev/fd */
4852}
4853
4854int
4855num_fifos ()
4856{
4857 return nfds;
4858}
4859
4860void
4861unlink_fifo (fd)
4862 int fd;
4863{
4864 if (dev_fd_list[fd])
4865 {
4866 close (fd);
4867 dev_fd_list[fd] = 0;
4868 nfds--;
4869 }
4870}
4871
4872void
4873unlink_fifo_list ()
4874{
4875 register int i;
4876
4877 if (nfds == 0)
4878 return;
4879
4880 for (i = 0; nfds && i < totfds; i++)
4881 unlink_fifo (i);
4882
4883 nfds = 0;
4884}
4885
4886/* Take LIST, which is a snapshot copy of dev_fd_list from some point in
4887 the past, and close all open fds in dev_fd_list that are not marked
4888 as open in LIST. If LIST is NULL, close everything in dev_fd_list.
4889 LSIZE is the number of elements in LIST, in case it's larger than
4890 totfds (size of dev_fd_list). */
4891void
4892close_new_fifos (list, lsize)
4893 char *list;
4894 int lsize;
4895{
4896 int i;
4897
4898 if (list == 0)
4899 {
4900 unlink_fifo_list ();
4901 return;
4902 }
4903
4904 for (i = 0; i < lsize; i++)
4905 if (list[i] == 0 && i < totfds && dev_fd_list[i])
4906 unlink_fifo (i);
4907
4908 for (i = lsize; i < totfds; i++)
4909 unlink_fifo (i);
4910}
4911
4912#if defined (NOTDEF)
4913print_dev_fd_list ()
4914{
4915 register int i;
4916
4917 fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
4918 fflush (stderr);
4919
4920 for (i = 0; i < totfds; i++)
4921 {
4922 if (dev_fd_list[i])
4923 fprintf (stderr, " %d", i);
4924 }
4925 fprintf (stderr, "\n");
4926}
4927#endif /* NOTDEF */
4928
4929static char *
4930make_dev_fd_filename (fd)
4931 int fd;
4932{
4933 char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
4934
4935 ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
4936
4937 strcpy (ret, DEV_FD_PREFIX);
4938 p = inttostr (fd, intbuf, sizeof (intbuf));
4939 strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
4940
4941 add_fifo_list (fd);
4942 return (ret);
4943}
4944
4945#endif /* HAVE_DEV_FD */
4946
4947/* Return a filename that will open a connection to the process defined by
4948 executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
4949 a filename in /dev/fd corresponding to a descriptor that is one of the
4950 ends of the pipe. If not defined, we use named pipes on systems that have
4951 them. Systems without /dev/fd and named pipes are out of luck.
4952
4953 OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
4954 use the read end of the pipe and dup that file descriptor to fd 0 in
4955 the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
4956 writing or use the write end of the pipe in the child, and dup that
4957 file descriptor to fd 1 in the child. The parent does the opposite. */
4958
4959static char *
4960process_substitute (string, open_for_read_in_child)
4961 char *string;
4962 int open_for_read_in_child;
4963{
4964 char *pathname;
4965 int fd, result;
4966 pid_t old_pid, pid;
4967#if defined (HAVE_DEV_FD)
4968 int parent_pipe_fd, child_pipe_fd;
4969 int fildes[2];
4970#endif /* HAVE_DEV_FD */
4971#if defined (JOB_CONTROL)
4972 pid_t old_pipeline_pgrp;
4973#endif
4974
4975 if (!string || !*string || wordexp_only)
4976 return ((char *)NULL);
4977
4978#if !defined (HAVE_DEV_FD)
4979 pathname = make_named_pipe ();
4980#else /* HAVE_DEV_FD */
4981 if (pipe (fildes) < 0)
4982 {
4983 sys_error (_("cannot make pipe for process substitution"));
4984 return ((char *)NULL);
4985 }
4986 /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
4987 the pipe in the parent, otherwise the read end. */
4988 parent_pipe_fd = fildes[open_for_read_in_child];
4989 child_pipe_fd = fildes[1 - open_for_read_in_child];
4990 /* Move the parent end of the pipe to some high file descriptor, to
4991 avoid clashes with FDs used by the script. */
4992 parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
4993
4994 pathname = make_dev_fd_filename (parent_pipe_fd);
4995#endif /* HAVE_DEV_FD */
4996
4997 if (pathname == 0)
4998 {
4999 sys_error (_("cannot make pipe for process substitution"));
5000 return ((char *)NULL);
5001 }
5002
5003 old_pid = last_made_pid;
5004
5005#if defined (JOB_CONTROL)
5006 old_pipeline_pgrp = pipeline_pgrp;
5007 pipeline_pgrp = shell_pgrp;
5008 save_pipeline (1);
5009#endif /* JOB_CONTROL */
5010
5011 pid = make_child ((char *)NULL, 1);
5012 if (pid == 0)
5013 {
5014 reset_terminating_signals (); /* XXX */
5015 free_pushed_string_input ();
5016 /* Cancel traps, in trap.c. */
5017 restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */
5018 setup_async_signals ();
5019 subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB;
5020 }
5021
5022#if defined (JOB_CONTROL)
5023 set_sigchld_handler ();
5024 stop_making_children ();
5025 /* XXX - should we only do this in the parent? (as in command subst) */
5026 pipeline_pgrp = old_pipeline_pgrp;
5027#endif /* JOB_CONTROL */
5028
5029 if (pid < 0)
5030 {
5031 sys_error (_("cannot make child for process substitution"));
5032 free (pathname);
5033#if defined (HAVE_DEV_FD)
5034 close (parent_pipe_fd);
5035 close (child_pipe_fd);
5036#endif /* HAVE_DEV_FD */
5037 return ((char *)NULL);
5038 }
5039
5040 if (pid > 0)
5041 {
5042#if defined (JOB_CONTROL)
5043 restore_pipeline (1);
5044#endif
5045
5046#if !defined (HAVE_DEV_FD)
5047 fifo_list[nfifo-1].proc = pid;
5048#endif
5049
5050 last_made_pid = old_pid;
5051
5052#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
5053 close_pgrp_pipe ();
5054#endif /* JOB_CONTROL && PGRP_PIPE */
5055
5056#if defined (HAVE_DEV_FD)
5057 close (child_pipe_fd);
5058#endif /* HAVE_DEV_FD */
5059
5060 return (pathname);
5061 }
5062
5063 set_sigint_handler ();
5064
5065#if defined (JOB_CONTROL)
5066 set_job_control (0);
5067#endif /* JOB_CONTROL */
5068
5069#if !defined (HAVE_DEV_FD)
5070 /* Open the named pipe in the child. */
5071 fd = open (pathname, open_for_read_in_child ? O_RDONLY|O_NONBLOCK : O_WRONLY);
5072 if (fd < 0)
5073 {
5074 /* Two separate strings for ease of translation. */
5075 if (open_for_read_in_child)
5076 sys_error (_("cannot open named pipe %s for reading"), pathname);
5077 else
5078 sys_error (_("cannot open named pipe %s for writing"), pathname);
5079
5080 exit (127);
5081 }
5082 if (open_for_read_in_child)
5083 {
5084 if (sh_unset_nodelay_mode (fd) < 0)
5085 {
5086 sys_error (_("cannot reset nodelay mode for fd %d"), fd);
5087 exit (127);
5088 }
5089 }
5090#else /* HAVE_DEV_FD */
5091 fd = child_pipe_fd;
5092#endif /* HAVE_DEV_FD */
5093
5094 if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
5095 {
5096 sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
5097 open_for_read_in_child ? 0 : 1);
5098 exit (127);
5099 }
5100
5101 if (fd != (open_for_read_in_child ? 0 : 1))
5102 close (fd);
5103
5104 /* Need to close any files that this process has open to pipes inherited
5105 from its parent. */
5106 if (current_fds_to_close)
5107 {
5108 close_fd_bitmap (current_fds_to_close);
5109 current_fds_to_close = (struct fd_bitmap *)NULL;
5110 }
5111
5112#if defined (HAVE_DEV_FD)
5113 /* Make sure we close the parent's end of the pipe and clear the slot
5114 in the fd list so it is not closed later, if reallocated by, for
5115 instance, pipe(2). */
5116 close (parent_pipe_fd);
5117 dev_fd_list[parent_pipe_fd] = 0;
5118#endif /* HAVE_DEV_FD */
5119
5120 result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
5121
5122#if !defined (HAVE_DEV_FD)
5123 /* Make sure we close the named pipe in the child before we exit. */
5124 close (open_for_read_in_child ? 0 : 1);
5125#endif /* !HAVE_DEV_FD */
5126
5127 exit (result);
5128 /*NOTREACHED*/
5129}
5130#endif /* PROCESS_SUBSTITUTION */
5131
5132/***********************************/
5133/* */
5134/* Command Substitution */
5135/* */
5136/***********************************/
5137
5138static char *
5139read_comsub (fd, quoted, rflag)
5140 int fd, quoted;
5141 int *rflag;
5142{
5143 char *istring, buf[128], *bufp, *s;
5144 int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul;
5145 ssize_t bufn;
5146
5147 istring = (char *)NULL;
5148 istring_index = istring_size = bufn = tflag = 0;
5149
5150 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
5151 skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
5152
5153 /* Read the output of the command through the pipe. This may need to be
5154 changed to understand multibyte characters in the future. */
5155 while (1)
5156 {
5157 if (fd < 0)
5158 break;
5159 if (--bufn <= 0)
5160 {
5161 bufn = zread (fd, buf, sizeof (buf));
5162 if (bufn <= 0)
5163 break;
5164 bufp = buf;
5165 }
5166 c = *bufp++;
5167
5168 if (c == 0)
5169 {
5170#if 0
5171 internal_warning ("read_comsub: ignored null byte in input");
5172#endif
5173 continue;
5174 }
5175
5176 /* Add the character to ISTRING, possibly after resizing it. */
5177 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
5178
5179 /* This is essentially quote_string inline */
5180 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
5181 istring[istring_index++] = CTLESC;
5182 /* Escape CTLESC and CTLNUL in the output to protect those characters
5183 from the rest of the word expansions (word splitting and globbing.)
5184 This is essentially quote_escapes inline. */
5185 else if (skip_ctlesc == 0 && c == CTLESC)
5186 {
5187 tflag |= W_HASCTLESC;
5188 istring[istring_index++] = CTLESC;
5189 }
5190 else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
5191 istring[istring_index++] = CTLESC;
5192
5193 istring[istring_index++] = c;
5194
5195#if 0
5196#if defined (__CYGWIN__)
5197 if (c == '\n' && istring_index > 1 && istring[istring_index - 2] == '\r')
5198 {
5199 istring_index--;
5200 istring[istring_index - 1] = '\n';
5201 }
5202#endif
5203#endif
5204 }
5205
5206 if (istring)
5207 istring[istring_index] = '\0';
5208
5209 /* If we read no output, just return now and save ourselves some
5210 trouble. */
5211 if (istring_index == 0)
5212 {
5213 FREE (istring);
5214 if (rflag)
5215 *rflag = tflag;
5216 return (char *)NULL;
5217 }
5218
5219 /* Strip trailing newlines from the output of the command. */
5220 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5221 {
5222 while (istring_index > 0)
5223 {
5224 if (istring[istring_index - 1] == '\n')
5225 {
5226 --istring_index;
5227
5228 /* If the newline was quoted, remove the quoting char. */
5229 if (istring[istring_index - 1] == CTLESC)
5230 --istring_index;
5231 }
5232 else
5233 break;
5234 }
5235 istring[istring_index] = '\0';
5236 }
5237 else
5238 strip_trailing (istring, istring_index - 1, 1);
5239
5240 if (rflag)
5241 *rflag = tflag;
5242 return istring;
5243}
5244
5245/* Perform command substitution on STRING. This returns a WORD_DESC * with the
5246 contained string possibly quoted. */
5247WORD_DESC *
5248command_substitute (string, quoted)
5249 char *string;
5250 int quoted;
5251{
5252 pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
5253 char *istring;
5254 int result, fildes[2], function_value, pflags, rc, tflag;
5255 WORD_DESC *ret;
5256
5257 istring = (char *)NULL;
5258
5259 /* Don't fork () if there is no need to. In the case of no command to
5260 run, just return NULL. */
5261 if (!string || !*string || (string[0] == '\n' && !string[1]))
5262 return ((WORD_DESC *)NULL);
5263
5264 if (wordexp_only && read_but_dont_execute)
5265 {
5266 last_command_exit_value = EX_WEXPCOMSUB;
5267 jump_to_top_level (EXITPROG);
5268 }
5269
5270 /* We're making the assumption here that the command substitution will
5271 eventually run a command from the file system. Since we'll run
5272 maybe_make_export_env in this subshell before executing that command,
5273 the parent shell and any other shells it starts will have to remake
5274 the environment. If we make it before we fork, other shells won't
5275 have to. Don't bother if we have any temporary variable assignments,
5276 though, because the export environment will be remade after this
5277 command completes anyway, but do it if all the words to be expanded
5278 are variable assignments. */
5279 if (subst_assign_varlist == 0 || garglist == 0)
5280 maybe_make_export_env (); /* XXX */
5281
5282 /* Flags to pass to parse_and_execute() */
5283 pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
5284
5285 /* Pipe the output of executing STRING into the current shell. */
5286 if (pipe (fildes) < 0)
5287 {
5288 sys_error (_("cannot make pipe for command substitution"));
5289 goto error_exit;
5290 }
5291
5292 old_pid = last_made_pid;
5293#if defined (JOB_CONTROL)
5294 old_pipeline_pgrp = pipeline_pgrp;
5295 /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */
5296 if ((subshell_environment & SUBSHELL_PIPE) == 0)
5297 pipeline_pgrp = shell_pgrp;
5298 cleanup_the_pipeline ();
5299#endif /* JOB_CONTROL */
5300
5301 old_async_pid = last_asynchronous_pid;
5302 pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC);
5303 last_asynchronous_pid = old_async_pid;
5304
5305 if (pid == 0)
5306 {
5307 /* Reset the signal handlers in the child, but don't free the
5308 trap strings. Set a flag noting that we have to free the
5309 trap strings if we run trap to change a signal disposition. */
5310 reset_signal_handlers ();
5311 subshell_environment |= SUBSHELL_RESETTRAP;
5312 }
5313
5314#if defined (JOB_CONTROL)
5315 /* XXX DO THIS ONLY IN PARENT ? XXX */
5316 set_sigchld_handler ();
5317 stop_making_children ();
5318 if (pid != 0)
5319 pipeline_pgrp = old_pipeline_pgrp;
5320#else
5321 stop_making_children ();
5322#endif /* JOB_CONTROL */
5323
5324 if (pid < 0)
5325 {
5326 sys_error (_("cannot make child for command substitution"));
5327 error_exit:
5328
5329 FREE (istring);
5330 close (fildes[0]);
5331 close (fildes[1]);
5332 return ((WORD_DESC *)NULL);
5333 }
5334
5335 if (pid == 0)
5336 {
5337 set_sigint_handler (); /* XXX */
5338
5339 free_pushed_string_input ();
5340
5341 if (dup2 (fildes[1], 1) < 0)
5342 {
5343 sys_error (_("command_substitute: cannot duplicate pipe as fd 1"));
5344 exit (EXECUTION_FAILURE);
5345 }
5346
5347 /* If standard output is closed in the parent shell
5348 (such as after `exec >&-'), file descriptor 1 will be
5349 the lowest available file descriptor, and end up in
5350 fildes[0]. This can happen for stdin and stderr as well,
5351 but stdout is more important -- it will cause no output
5352 to be generated from this command. */
5353 if ((fildes[1] != fileno (stdin)) &&
5354 (fildes[1] != fileno (stdout)) &&
5355 (fildes[1] != fileno (stderr)))
5356 close (fildes[1]);
5357
5358 if ((fildes[0] != fileno (stdin)) &&
5359 (fildes[0] != fileno (stdout)) &&
5360 (fildes[0] != fileno (stderr)))
5361 close (fildes[0]);
5362
5363#ifdef __CYGWIN__
5364 /* Let stdio know the fd may have changed from text to binary mode, and
5365 make sure to preserve stdout line buffering. */
5366 freopen (NULL, "w", stdout);
5367 sh_setlinebuf (stdout);
5368#endif /* __CYGWIN__ */
5369
5370 /* The currently executing shell is not interactive. */
5371 interactive = 0;
5372
5373 /* This is a subshell environment. */
5374 subshell_environment |= SUBSHELL_COMSUB;
5375
5376 /* When not in POSIX mode, command substitution does not inherit
5377 the -e flag. */
5378 if (posixly_correct == 0)
5379 exit_immediately_on_error = 0;
5380
5381 remove_quoted_escapes (string);
5382
5383 startup_state = 2; /* see if we can avoid a fork */
5384 /* Give command substitution a place to jump back to on failure,
5385 so we don't go back up to main (). */
5386 result = setjmp (top_level);
5387
5388 /* If we're running a command substitution inside a shell function,
5389 trap `return' so we don't return from the function in the subshell
5390 and go off to never-never land. */
5391 if (result == 0 && return_catch_flag)
5392 function_value = setjmp (return_catch);
5393 else
5394 function_value = 0;
5395
5396 if (result == ERREXIT)
5397 rc = last_command_exit_value;
5398 else if (result == EXITPROG)
5399 rc = last_command_exit_value;
5400 else if (result)
5401 rc = EXECUTION_FAILURE;
5402 else if (function_value)
5403 rc = return_catch_value;
5404 else
5405 {
5406 subshell_level++;
5407 rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
5408 subshell_level--;
5409 }
5410
5411 last_command_exit_value = rc;
5412 rc = run_exit_trap ();
5413#if defined (PROCESS_SUBSTITUTION)
5414 unlink_fifo_list ();
5415#endif
5416 exit (rc);
5417 }
5418 else
5419 {
5420#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
5421 close_pgrp_pipe ();
5422#endif /* JOB_CONTROL && PGRP_PIPE */
5423
5424 close (fildes[1]);
5425
5426 tflag = 0;
5427 istring = read_comsub (fildes[0], quoted, &tflag);
5428
5429 close (fildes[0]);
5430
5431 current_command_subst_pid = pid;
5432 last_command_exit_value = wait_for (pid);
5433 last_command_subst_pid = pid;
5434 last_made_pid = old_pid;
5435
5436#if defined (JOB_CONTROL)
5437 /* If last_command_exit_value > 128, then the substituted command
5438 was terminated by a signal. If that signal was SIGINT, then send
5439 SIGINT to ourselves. This will break out of loops, for instance. */
5440 if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
5441 kill (getpid (), SIGINT);
5442
5443 /* wait_for gives the terminal back to shell_pgrp. If some other
5444 process group should have it, give it away to that group here.
5445 pipeline_pgrp is non-zero only while we are constructing a
5446 pipline, so what we are concerned about is whether or not that
5447 pipeline was started in the background. A pipeline started in
5448 the background should never get the tty back here. */
5449 if (interactive && pipeline_pgrp != (pid_t)0 && (subshell_environment & SUBSHELL_ASYNC) == 0)
5450 give_terminal_to (pipeline_pgrp, 0);
5451#endif /* JOB_CONTROL */
5452
5453 ret = alloc_word_desc ();
5454 ret->word = istring;
5455 ret->flags = tflag;
5456
5457 return ret;
5458 }
5459}
5460
5461/********************************************************
5462 * *
5463 * Utility functions for parameter expansion *
5464 * *
5465 ********************************************************/
5466
5467#if defined (ARRAY_VARS)
5468
5469static arrayind_t
5470array_length_reference (s)
5471 char *s;
5472{
5473 int len;
5474 arrayind_t ind;
5475 char *akey;
5476 char *t, c;
5477 ARRAY *array;
5478 HASH_TABLE *h;
5479 SHELL_VAR *var;
5480
5481 var = array_variable_part (s, &t, &len);
5482
5483 /* If unbound variables should generate an error, report one and return
5484 failure. */
5485 if ((var == 0 || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
5486 {
5487 c = *--t;
5488 *t = '\0';
5489 last_command_exit_value = EXECUTION_FAILURE;
5490 err_unboundvar (s);
5491 *t = c;
5492 return (-1);
5493 }
5494 else if (var == 0)
5495 return 0;
5496
5497 /* We support a couple of expansions for variables that are not arrays.
5498 We'll return the length of the value for v[0], and 1 for v[@] or
5499 v[*]. Return 0 for everything else. */
5500
5501 array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
5502 h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
5503
5504 if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
5505 {
5506 if (assoc_p (var))
5507 return (h ? assoc_num_elements (h) : 0);
5508 else if (array_p (var))
5509 return (array ? array_num_elements (array) : 0);
5510 else
5511 return (var_isset (var) ? 1 : 0);
5512 }
5513
5514 if (assoc_p (var))
5515 {
5516 t[len - 1] = '\0';
5517 akey = expand_assignment_string_to_string (t, 0); /* [ */
5518 t[len - 1] = ']';
5519 if (akey == 0 || *akey == 0)
5520 {
5521 err_badarraysub (t);
5522 return (-1);
5523 }
5524 t = assoc_reference (assoc_cell (var), akey);
5525 }
5526 else
5527 {
5528 ind = array_expand_index (t, len);
5529 if (ind < 0)
5530 {
5531 err_badarraysub (t);
5532 return (-1);
5533 }
5534 if (array_p (var))
5535 t = array_reference (array, ind);
5536 else
5537 t = (ind == 0) ? value_cell (var) : (char *)NULL;
5538 }
5539
5540 len = MB_STRLEN (t);
5541 return (len);
5542}
5543#endif /* ARRAY_VARS */
5544
5545static int
5546valid_brace_expansion_word (name, var_is_special)
5547 char *name;
5548 int var_is_special;
5549{
5550 if (DIGIT (*name) && all_digits (name))
5551 return 1;
5552 else if (var_is_special)
5553 return 1;
5554#if defined (ARRAY_VARS)
5555 else if (valid_array_reference (name))
5556 return 1;
5557#endif /* ARRAY_VARS */
5558 else if (legal_identifier (name))
5559 return 1;
5560 else
5561 return 0;
5562}
5563
5564static int
5565chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at)
5566 char *name;
5567 int quoted;
5568 int *quoted_dollar_atp, *contains_dollar_at;
5569{
5570 char *temp1;
5571
5572 if (name == 0)
5573 {
5574 if (quoted_dollar_atp)
5575 *quoted_dollar_atp = 0;
5576 if (contains_dollar_at)
5577 *contains_dollar_at = 0;
5578 return 0;
5579 }
5580
5581 /* check for $@ and $* */
5582 if (name[0] == '@' && name[1] == 0)
5583 {
5584 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5585 *quoted_dollar_atp = 1;
5586 if (contains_dollar_at)
5587 *contains_dollar_at = 1;
5588 return 1;
5589 }
5590 else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
5591 {
5592 if (contains_dollar_at)
5593 *contains_dollar_at = 1;
5594 return 1;
5595 }
5596
5597 /* Now check for ${array[@]} and ${array[*]} */
5598#if defined (ARRAY_VARS)
5599 else if (valid_array_reference (name))
5600 {
5601 temp1 = mbschr (name, '[');
5602 if (temp1 && temp1[1] == '@' && temp1[2] == ']')
5603 {
5604 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
5605 *quoted_dollar_atp = 1;
5606 if (contains_dollar_at)
5607 *contains_dollar_at = 1;
5608 return 1;
5609 } /* [ */
5610 /* ${array[*]}, when unquoted, should be treated like ${array[@]},
5611 which should result in separate words even when IFS is unset. */
5612 if (temp1 && temp1[1] == '*' && temp1[2] == ']' && quoted == 0)
5613 {
5614 if (contains_dollar_at)
5615 *contains_dollar_at = 1;
5616 return 1;
5617 }
5618 }
5619#endif
5620 return 0;
5621}
5622
5623/* Parameter expand NAME, and return a new string which is the expansion,
5624 or NULL if there was no expansion.
5625 VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
5626 the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
5627 NAME was found inside of a double-quoted expression. */
5628static WORD_DESC *
5629parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp)
5630 char *name;
5631 int var_is_special, quoted, pflags;
5632 arrayind_t *indp;
5633{
5634 WORD_DESC *ret;
5635 char *temp, *tt;
5636 intmax_t arg_index;
5637 SHELL_VAR *var;
5638 int atype, rflags;
5639 arrayind_t ind;
5640
5641 ret = 0;
5642 temp = 0;
5643 rflags = 0;
5644
5645 if (indp)
5646 *indp = INTMAX_MIN;
5647
5648 /* Handle multiple digit arguments, as in ${11}. */
5649 if (legal_number (name, &arg_index))
5650 {
5651 tt = get_dollar_var_value (arg_index);
5652 if (tt)
5653 temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5654 ? quote_string (tt)
5655 : quote_escapes (tt);
5656 else
5657 temp = (char *)NULL;
5658 FREE (tt);
5659 }
5660 else if (var_is_special) /* ${@} */
5661 {
5662 int sindex;
5663 tt = (char *)xmalloc (2 + strlen (name));
5664 tt[sindex = 0] = '$';
5665 strcpy (tt + 1, name);
5666
5667 ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
5668 (int *)NULL, (int *)NULL, pflags);
5669 free (tt);
5670 }
5671#if defined (ARRAY_VARS)
5672 else if (valid_array_reference (name))
5673 {
5674 temp = array_value (name, quoted, 0, &atype, &ind);
5675 if (atype == 0 && temp)
5676 {
5677 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5678 ? quote_string (temp)
5679 : quote_escapes (temp);
5680 rflags |= W_ARRAYIND;
5681 if (indp)
5682 *indp = ind;
5683 }
5684 else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5685 rflags |= W_HASQUOTEDNULL;
5686 }
5687#endif
5688 else if (var = find_variable (name))
5689 {
5690 if (var_isset (var) && invisible_p (var) == 0)
5691 {
5692#if defined (ARRAY_VARS)
5693 if (assoc_p (var))
5694 temp = assoc_reference (assoc_cell (var), "0");
5695 else if (array_p (var))
5696 temp = array_reference (array_cell (var), 0);
5697 else
5698 temp = value_cell (var);
5699#else
5700 temp = value_cell (var);
5701#endif
5702
5703 if (temp)
5704 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
5705 ? quote_string (temp)
5706 : quote_escapes (temp);
5707 }
5708 else
5709 temp = (char *)NULL;
5710 }
5711 else
5712 temp = (char *)NULL;
5713
5714 if (ret == 0)
5715 {
5716 ret = alloc_word_desc ();
5717 ret->word = temp;
5718 ret->flags |= rflags;
5719 }
5720 return ret;
5721}
5722
5723/* Expand an indirect reference to a variable: ${!NAME} expands to the
5724 value of the variable whose name is the value of NAME. */
5725static WORD_DESC *
5726parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at)
5727 char *name;
5728 int var_is_special, quoted;
5729 int *quoted_dollar_atp, *contains_dollar_at;
5730{
5731 char *temp, *t;
5732 WORD_DESC *w;
5733
5734 w = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND, 0);
5735 t = w->word;
5736 /* Have to dequote here if necessary */
5737 if (t)
5738 {
5739 temp = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
5740 ? dequote_string (t)
5741 : dequote_escapes (t);
5742 free (t);
5743 t = temp;
5744 }
5745 dispose_word_desc (w);
5746
5747 chk_atstar (t, quoted, quoted_dollar_atp, contains_dollar_at);
5748 if (t == 0)
5749 return (WORD_DESC *)NULL;
5750
5751 w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, 0, 0);
5752 free (t);
5753
5754 return w;
5755}
5756
5757/* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
5758 depending on the value of C, the separating character. C can be one of
5759 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
5760 between double quotes. */
5761static WORD_DESC *
5762parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
5763 char *name, *value;
5764 int c, quoted, *qdollaratp, *hasdollarat;
5765{
5766 WORD_DESC *w;
5767 WORD_LIST *l;
5768 char *t, *t1, *temp;
5769 int hasdol;
5770
5771 /* If the entire expression is between double quotes, we want to treat
5772 the value as a double-quoted string, with the exception that we strip
5773 embedded unescaped double quotes (for sh backwards compatibility). */
5774 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
5775 {
5776 hasdol = 0;
5777 temp = string_extract_double_quoted (value, &hasdol, 1);
5778 }
5779 else
5780 temp = value;
5781
5782 w = alloc_word_desc ();
5783 hasdol = 0;
5784 /* XXX was 0 not quoted */
5785 l = *temp ? expand_string_for_rhs (temp, quoted, &hasdol, (int *)NULL)
5786 : (WORD_LIST *)0;
5787 if (hasdollarat)
5788 *hasdollarat = hasdol || (l && l->next);
5789 if (temp != value)
5790 free (temp);
5791 if (l)
5792 {
5793 /* The expansion of TEMP returned something. We need to treat things
5794 slightly differently if HASDOL is non-zero. If we have "$@", the
5795 individual words have already been quoted. We need to turn them
5796 into a string with the words separated by the first character of
5797 $IFS without any additional quoting, so string_list_dollar_at won't
5798 do the right thing. We use string_list_dollar_star instead. */
5799 temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l);
5800
5801 /* If l->next is not null, we know that TEMP contained "$@", since that
5802 is the only expansion that creates more than one word. */
5803 if (qdollaratp && ((hasdol && quoted) || l->next))
5804 *qdollaratp = 1;
5805 dispose_words (l);
5806 }
5807 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol)
5808 {
5809 /* The brace expansion occurred between double quotes and there was
5810 a $@ in TEMP. It does not matter if the $@ is quoted, as long as
5811 it does not expand to anything. In this case, we want to return
5812 a quoted empty string. */
5813 temp = make_quoted_char ('\0');
5814 w->flags |= W_HASQUOTEDNULL;
5815 }
5816 else
5817 temp = (char *)NULL;
5818
5819 if (c == '-' || c == '+')
5820 {
5821 w->word = temp;
5822 return w;
5823 }
5824
5825 /* c == '=' */
5826 t = temp ? savestring (temp) : savestring ("");
5827 t1 = dequote_string (t);
5828 free (t);
5829#if defined (ARRAY_VARS)
5830 if (valid_array_reference (name))
5831 assign_array_element (name, t1, 0);
5832 else
5833#endif /* ARRAY_VARS */
5834 bind_variable (name, t1, 0);
5835
5836 /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
5837 free (temp);
5838
5839 w->word = t1;
5840 return w;
5841}
5842
5843/* Deal with the right hand side of a ${name:?value} expansion in the case
5844 that NAME is null or not set. If VALUE is non-null it is expanded and
5845 used as the error message to print, otherwise a standard message is
5846 printed. */
5847static void
5848parameter_brace_expand_error (name, value)
5849 char *name, *value;
5850{
5851 WORD_LIST *l;
5852 char *temp;
5853
5854 if (value && *value)
5855 {
5856 l = expand_string (value, 0);
5857 temp = string_list (l);
5858 report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
5859 FREE (temp);
5860 dispose_words (l);
5861 }
5862 else
5863 report_error (_("%s: parameter null or not set"), name);
5864
5865 /* Free the data we have allocated during this expansion, since we
5866 are about to longjmp out. */
5867 free (name);
5868 FREE (value);
5869}
5870
5871/* Return 1 if NAME is something for which parameter_brace_expand_length is
5872 OK to do. */
5873static int
5874valid_length_expression (name)
5875 char *name;
5876{
5877 return (name[1] == '\0' || /* ${#} */
5878 ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */
5879 (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
5880#if defined (ARRAY_VARS)
5881 valid_array_reference (name + 1) || /* ${#a[7]} */
5882#endif
5883 legal_identifier (name + 1)); /* ${#PS1} */
5884}
5885
5886/* Handle the parameter brace expansion that requires us to return the
5887 length of a parameter. */
5888static intmax_t
5889parameter_brace_expand_length (name)
5890 char *name;
5891{
5892 char *t, *newname;
5893 intmax_t number, arg_index;
5894 WORD_LIST *list;
5895#if defined (ARRAY_VARS)
5896 SHELL_VAR *var;
5897#endif
5898
5899 if (name[1] == '\0') /* ${#} */
5900 number = number_of_args ();
5901 else if ((name[1] == '@' || name[1] == '*') && name[2] == '\0') /* ${#@}, ${#*} */
5902 number = number_of_args ();
5903 else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
5904 {
5905 /* Take the lengths of some of the shell's special parameters. */
5906 switch (name[1])
5907 {
5908 case '-':
5909 t = which_set_flags ();
5910 break;
5911 case '?':
5912 t = itos (last_command_exit_value);
5913 break;
5914 case '$':
5915 t = itos (dollar_dollar_pid);
5916 break;
5917 case '!':
5918 if (last_asynchronous_pid == NO_PID)
5919 t = (char *)NULL; /* XXX - error if set -u set? */
5920 else
5921 t = itos (last_asynchronous_pid);
5922 break;
5923 case '#':
5924 t = itos (number_of_args ());
5925 break;
5926 }
5927 number = STRLEN (t);
5928 FREE (t);
5929 }
5930#if defined (ARRAY_VARS)
5931 else if (valid_array_reference (name + 1))
5932 number = array_length_reference (name + 1);
5933#endif /* ARRAY_VARS */
5934 else
5935 {
5936 number = 0;
5937
5938 if (legal_number (name + 1, &arg_index)) /* ${#1} */
5939 {
5940 t = get_dollar_var_value (arg_index);
5941 if (t == 0 && unbound_vars_is_error)
5942 return INTMAX_MIN;
5943 number = MB_STRLEN (t);
5944 FREE (t);
5945 }
5946#if defined (ARRAY_VARS)
5947 else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
5948 {
5949 if (assoc_p (var))
5950 t = assoc_reference (assoc_cell (var), "0");
5951 else
5952 t = array_reference (array_cell (var), 0);
5953 if (t == 0 && unbound_vars_is_error)
5954 return INTMAX_MIN;
5955 number = MB_STRLEN (t);
5956 }
5957#endif
5958 else /* ${#PS1} */
5959 {
5960 newname = savestring (name);
5961 newname[0] = '$';
5962 list = expand_string (newname, Q_DOUBLE_QUOTES);
5963 t = list ? string_list (list) : (char *)NULL;
5964 free (newname);
5965 if (list)
5966 dispose_words (list);
5967
5968 number = t ? MB_STRLEN (t) : 0;
5969 FREE (t);
5970 }
5971 }
5972
5973 return (number);
5974}
5975
5976/* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression,
5977 so we do some ad-hoc parsing of an arithmetic expression to find
5978 the first DELIM, instead of using strchr(3). Two rules:
5979 1. If the substring contains a `(', read until closing `)'.
5980 2. If the substring contains a `?', read past one `:' for each `?'.
5981*/
5982
5983static char *
5984skiparith (substr, delim)
5985 char *substr;
5986 int delim;
5987{
5988 size_t sublen;
5989 int skipcol, pcount, i;
5990 DECLARE_MBSTATE;
5991
5992 sublen = strlen (substr);
5993 i = skipcol = pcount = 0;
5994 while (substr[i])
5995 {
5996 /* Balance parens */
5997 if (substr[i] == LPAREN)
5998 {
5999 pcount++;
6000 i++;
6001 continue;
6002 }
6003 if (substr[i] == RPAREN && pcount)
6004 {
6005 pcount--;
6006 i++;
6007 continue;
6008 }
6009 if (pcount)
6010 {
6011 ADVANCE_CHAR (substr, sublen, i);
6012 continue;
6013 }
6014
6015 /* Skip one `:' for each `?' */
6016 if (substr[i] == ':' && skipcol)
6017 {
6018 skipcol--;
6019 i++;
6020 continue;
6021 }
6022 if (substr[i] == delim)
6023 break;
6024 if (substr[i] == '?')
6025 {
6026 skipcol++;
6027 i++;
6028 continue;
6029 }
6030 ADVANCE_CHAR (substr, sublen, i);
6031 }
6032
6033 return (substr + i);
6034}
6035
6036/* Verify and limit the start and end of the desired substring. If
6037 VTYPE == 0, a regular shell variable is being used; if it is 1,
6038 then the positional parameters are being used; if it is 2, then
6039 VALUE is really a pointer to an array variable that should be used.
6040 Return value is 1 if both values were OK, 0 if there was a problem
6041 with an invalid expression, or -1 if the values were out of range. */
6042static int
6043verify_substring_values (v, value, substr, vtype, e1p, e2p)
6044 SHELL_VAR *v;
6045 char *value, *substr;
6046 int vtype;
6047 intmax_t *e1p, *e2p;
6048{
6049 char *t, *temp1, *temp2;
6050 arrayind_t len;
6051 int expok;
6052#if defined (ARRAY_VARS)
6053 ARRAY *a;
6054 HASH_TABLE *h;
6055#endif
6056
6057 /* duplicate behavior of strchr(3) */
6058 t = skiparith (substr, ':');
6059 if (*t && *t == ':')
6060 *t = '\0';
6061 else
6062 t = (char *)0;
6063
6064 temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES);
6065 *e1p = evalexp (temp1, &expok);
6066 free (temp1);
6067 if (expok == 0)
6068 return (0);
6069
6070 len = -1; /* paranoia */
6071 switch (vtype)
6072 {
6073 case VT_VARIABLE:
6074 case VT_ARRAYMEMBER:
6075 len = MB_STRLEN (value);
6076 break;
6077 case VT_POSPARMS:
6078 len = number_of_args () + 1;
6079 if (*e1p == 0)
6080 len++; /* add one arg if counting from $0 */
6081 break;
6082#if defined (ARRAY_VARS)
6083 case VT_ARRAYVAR:
6084 /* For arrays, the first value deals with array indices. Negative
6085 offsets count from one past the array's maximum index. Associative
6086 arrays treat the number of elements as the maximum index. */
6087 if (assoc_p (v))
6088 {
6089 h = assoc_cell (v);
6090 len = assoc_num_elements (h) + (*e1p < 0);
6091 }
6092 else
6093 {
6094 a = (ARRAY *)value;
6095 len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
6096 }
6097 break;
6098#endif
6099 }
6100
6101 if (len == -1) /* paranoia */
6102 return -1;
6103
6104 if (*e1p < 0) /* negative offsets count from end */
6105 *e1p += len;
6106
6107 if (*e1p > len || *e1p < 0)
6108 return (-1);
6109
6110#if defined (ARRAY_VARS)
6111 /* For arrays, the second offset deals with the number of elements. */
6112 if (vtype == VT_ARRAYVAR)
6113 len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
6114#endif
6115
6116 if (t)
6117 {
6118 t++;
6119 temp2 = savestring (t);
6120 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
6121 free (temp2);
6122 t[-1] = ':';
6123 *e2p = evalexp (temp1, &expok);
6124 free (temp1);
6125 if (expok == 0)
6126 return (0);
6127 if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
6128 {
6129 internal_error (_("%s: substring expression < 0"), t);
6130 return (0);
6131 }
6132#if defined (ARRAY_VARS)
6133 /* In order to deal with sparse arrays, push the intelligence about how
6134 to deal with the number of elements desired down to the array-
6135 specific functions. */
6136 if (vtype != VT_ARRAYVAR)
6137#endif
6138 {
6139 if (*e2p < 0)
6140 {
6141 *e2p += len;
6142 if (*e2p < 0 || *e2p < *e1p)
6143 {
6144 internal_error (_("%s: substring expression < 0"), t);
6145 return (0);
6146 }
6147 }
6148 else
6149 *e2p += *e1p; /* want E2 chars starting at E1 */
6150 if (*e2p > len)
6151 *e2p = len;
6152 }
6153 }
6154 else
6155 *e2p = len;
6156
6157 return (1);
6158}
6159
6160/* Return the type of variable specified by VARNAME (simple variable,
6161 positional param, or array variable). Also return the value specified
6162 by VARNAME (value of a variable or a reference to an array element).
6163 QUOTED is the standard description of quoting state, using Q_* defines.
6164 FLAGS is currently a set of flags to pass to array_value. If IND is
6165 non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
6166 passed to array_value so the array index is not computed again.
6167 If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
6168 characters in the value are quoted with CTLESC and takes appropriate
6169 steps. For convenience, *VALP is set to the dequoted VALUE. */
6170static int
6171get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
6172 char *varname, *value;
6173 arrayind_t ind;
6174 int quoted, flags;
6175 SHELL_VAR **varp;
6176 char **valp;
6177{
6178 int vtype;
6179 char *temp;
6180#if defined (ARRAY_VARS)
6181 SHELL_VAR *v;
6182#endif
6183 arrayind_t lind;
6184
6185 /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
6186 vtype = (varname[0] == '@' || varname[0] == '*') && varname[1] == '\0';
6187 if (vtype == VT_POSPARMS && varname[0] == '*')
6188 vtype |= VT_STARSUB;
6189 *varp = (SHELL_VAR *)NULL;
6190
6191#if defined (ARRAY_VARS)
6192 if (valid_array_reference (varname))
6193 {
6194 v = array_variable_part (varname, &temp, (int *)0);
6195 /* If we want to signal array_value to use an already-computed index,
6196 set LIND to that index */
6197 lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0;
6198 if (v && (array_p (v) || assoc_p (v)))
6199 { /* [ */
6200 if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']')
6201 {
6202 /* Callers have to differentiate betwen indexed and associative */
6203 vtype = VT_ARRAYVAR;
6204 if (temp[0] == '*')
6205 vtype |= VT_STARSUB;
6206 *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
6207 }
6208 else
6209 {
6210 vtype = VT_ARRAYMEMBER;
6211 *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
6212 }
6213 *varp = v;
6214 }
6215 else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == ']'))
6216 {
6217 vtype = VT_VARIABLE;
6218 *varp = v;
6219 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6220 *valp = dequote_string (value);
6221 else
6222 *valp = dequote_escapes (value);
6223 }
6224 else
6225 {
6226 vtype = VT_ARRAYMEMBER;
6227 *varp = v;
6228 *valp = array_value (varname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
6229 }
6230 }
6231 else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
6232 {
6233 vtype = VT_ARRAYMEMBER;
6234 *varp = v;
6235 *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
6236 }
6237 else
6238#endif
6239 {
6240 if (value && vtype == VT_VARIABLE)
6241 {
6242 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6243 *valp = dequote_string (value);
6244 else
6245 *valp = dequote_escapes (value);
6246 }
6247 else
6248 *valp = value;
6249 }
6250
6251 return vtype;
6252}
6253
6254/******************************************************/
6255/* */
6256/* Functions to extract substrings of variable values */
6257/* */
6258/******************************************************/
6259
6260#if defined (HANDLE_MULTIBYTE)
6261/* Character-oriented rather than strictly byte-oriented substrings. S and
6262 E, rather being strict indices into STRING, indicate character (possibly
6263 multibyte character) positions that require calculation.
6264 Used by the ${param:offset[:length]} expansion. */
6265static char *
6266mb_substring (string, s, e)
6267 char *string;
6268 int s, e;
6269{
6270 char *tt;
6271 int start, stop, i, slen;
6272 DECLARE_MBSTATE;
6273
6274 start = 0;
6275 /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
6276 slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
6277
6278 i = s;
6279 while (string[start] && i--)
6280 ADVANCE_CHAR (string, slen, start);
6281 stop = start;
6282 i = e - s;
6283 while (string[stop] && i--)
6284 ADVANCE_CHAR (string, slen, stop);
6285 tt = substring (string, start, stop);
6286 return tt;
6287}
6288#endif
6289
6290/* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
6291 is `@', use the positional parameters; otherwise, use the value of
6292 VARNAME. If VARNAME is an array variable, use the array elements. */
6293
6294static char *
6295parameter_brace_substring (varname, value, ind, substr, quoted, flags)
6296 char *varname, *value;
6297 int ind;
6298 char *substr;
6299 int quoted, flags;
6300{
6301 intmax_t e1, e2;
6302 int vtype, r, starsub;
6303 char *temp, *val, *tt, *oname;
6304 SHELL_VAR *v;
6305
6306 if (value == 0)
6307 return ((char *)NULL);
6308
6309 oname = this_command_name;
6310 this_command_name = varname;
6311
6312 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
6313 if (vtype == -1)
6314 {
6315 this_command_name = oname;
6316 return ((char *)NULL);
6317 }
6318
6319 starsub = vtype & VT_STARSUB;
6320 vtype &= ~VT_STARSUB;
6321
6322 r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
6323 this_command_name = oname;
6324 if (r <= 0)
6325 return ((r == 0) ? &expand_param_error : (char *)NULL);
6326
6327 switch (vtype)
6328 {
6329 case VT_VARIABLE:
6330 case VT_ARRAYMEMBER:
6331#if defined (HANDLE_MULTIBYTE)
6332 if (MB_CUR_MAX > 1)
6333 tt = mb_substring (val, e1, e2);
6334 else
6335#endif
6336 tt = substring (val, e1, e2);
6337
6338 if (vtype == VT_VARIABLE)
6339 FREE (val);
6340 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
6341 temp = quote_string (tt);
6342 else
6343 temp = tt ? quote_escapes (tt) : (char *)NULL;
6344 FREE (tt);
6345 break;
6346 case VT_POSPARMS:
6347 tt = pos_params (varname, e1, e2, quoted);
6348 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
6349 {
6350 temp = tt ? quote_escapes (tt) : (char *)NULL;
6351 FREE (tt);
6352 }
6353 else
6354 temp = tt;
6355 break;
6356#if defined (ARRAY_VARS)
6357 case VT_ARRAYVAR:
6358 if (assoc_p (v))
6359 /* we convert to list and take first e2 elements starting at e1th
6360 element -- officially undefined for now */
6361 temp = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted);
6362 else
6363 /* We want E2 to be the number of elements desired (arrays can be sparse,
6364 so verify_substring_values just returns the numbers specified and we
6365 rely on array_subrange to understand how to deal with them). */
6366 temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
6367 /* array_subrange now calls array_quote_escapes as appropriate, so the
6368 caller no longer needs to. */
6369 break;
6370#endif
6371 default:
6372 temp = (char *)NULL;
6373 }
6374
6375 return temp;
6376}
6377
6378/****************************************************************/
6379/* */
6380/* Functions to perform pattern substitution on variable values */
6381/* */
6382/****************************************************************/
6383
6384static int
6385shouldexp_replacement (s)
6386 char *s;
6387{
6388 register char *p;
6389
6390 for (p = s; p && *p; p++)
6391 {
6392 if (*p == '\\')
6393 p++;
6394 else if (*p == '&')
6395 return 1;
6396 }
6397 return 0;
6398}
6399
6400char *
6401pat_subst (string, pat, rep, mflags)
6402 char *string, *pat, *rep;
6403 int mflags;
6404{
6405 char *ret, *s, *e, *str, *rstr, *mstr;
6406 int rsize, rptr, l, replen, mtype, rxpand, rslen, mlen;
6407
6408 if (string == 0)
6409 return (savestring (""));
6410
6411 mtype = mflags & MATCH_TYPEMASK;
6412
6413#if 0 /* bash-4.2 ? */
6414 rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0;
6415#else
6416 rxpand = 0;
6417#endif
6418
6419 /* Special cases:
6420 * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
6421 * with REP and return the result.
6422 * 2. A null pattern with mtype == MATCH_END means to append REP to
6423 * STRING and return the result.
6424 * These don't understand or process `&' in the replacement string.
6425 */
6426 if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
6427 {
6428 replen = STRLEN (rep);
6429 l = STRLEN (string);
6430 ret = (char *)xmalloc (replen + l + 2);
6431 if (replen == 0)
6432 strcpy (ret, string);
6433 else if (mtype == MATCH_BEG)
6434 {
6435 strcpy (ret, rep);
6436 strcpy (ret + replen, string);
6437 }
6438 else
6439 {
6440 strcpy (ret, string);
6441 strcpy (ret + l, rep);
6442 }
6443 return (ret);
6444 }
6445
6446 ret = (char *)xmalloc (rsize = 64);
6447 ret[0] = '\0';
6448
6449 for (replen = STRLEN (rep), rptr = 0, str = string;;)
6450 {
6451 if (match_pattern (str, pat, mtype, &s, &e) == 0)
6452 break;
6453 l = s - str;
6454
6455 if (rxpand)
6456 {
6457 int x;
6458 mlen = e - s;
6459 mstr = xmalloc (mlen + 1);
6460 for (x = 0; x < mlen; x++)
6461 mstr[x] = s[x];
6462 mstr[mlen] = '\0';
6463 rstr = strcreplace (rep, '&', mstr, 0);
6464 rslen = strlen (rstr);
6465 }
6466 else
6467 {
6468 rstr = rep;
6469 rslen = replen;
6470 }
6471
6472 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
6473
6474 /* OK, now copy the leading unmatched portion of the string (from
6475 str to s) to ret starting at rptr (the current offset). Then copy
6476 the replacement string at ret + rptr + (s - str). Increment
6477 rptr (if necessary) and str and go on. */
6478 if (l)
6479 {
6480 strncpy (ret + rptr, str, l);
6481 rptr += l;
6482 }
6483 if (replen)
6484 {
6485 strncpy (ret + rptr, rstr, rslen);
6486 rptr += rslen;
6487 }
6488 str = e; /* e == end of match */
6489
6490 if (rstr != rep)
6491 free (rstr);
6492
6493 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
6494 break;
6495
6496 if (s == e)
6497 {
6498 /* On a zero-length match, make sure we copy one character, since
6499 we increment one character to avoid infinite recursion. */
6500 RESIZE_MALLOCED_BUFFER (ret, rptr, 1, rsize, 64);
6501 ret[rptr++] = *str++;
6502 e++; /* avoid infinite recursion on zero-length match */
6503 }
6504 }
6505
6506 /* Now copy the unmatched portion of the input string */
6507 if (str && *str)
6508 {
6509 RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
6510 strcpy (ret + rptr, str);
6511 }
6512 else
6513 ret[rptr] = '\0';
6514
6515 return ret;
6516}
6517
6518/* Do pattern match and replacement on the positional parameters. */
6519static char *
6520pos_params_pat_subst (string, pat, rep, mflags)
6521 char *string, *pat, *rep;
6522 int mflags;
6523{
6524 WORD_LIST *save, *params;
6525 WORD_DESC *w;
6526 char *ret;
6527 int pchar, qflags;
6528
6529 save = params = list_rest_of_args ();
6530 if (save == 0)
6531 return ((char *)NULL);
6532
6533 for ( ; params; params = params->next)
6534 {
6535 ret = pat_subst (params->word->word, pat, rep, mflags);
6536 w = alloc_word_desc ();
6537 w->word = ret ? ret : savestring ("");
6538 dispose_word (params->word);
6539 params->word = w;
6540 }
6541
6542 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6543 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6544
6545#if 0
6546 if ((mflags & (MATCH_QUOTED|MATCH_STARSUB)) == (MATCH_QUOTED|MATCH_STARSUB))
6547 ret = string_list_dollar_star (quote_list (save));
6548 else if ((mflags & MATCH_STARSUB) == MATCH_STARSUB)
6549 ret = string_list_dollar_star (save);
6550 else if ((mflags & MATCH_QUOTED) == MATCH_QUOTED)
6551 ret = string_list_dollar_at (save, qflags);
6552 else
6553 ret = string_list_dollar_star (save);
6554#else
6555 ret = string_list_pos_params (pchar, save, qflags);
6556#endif
6557
6558 dispose_words (save);
6559
6560 return (ret);
6561}
6562
6563/* Perform pattern substitution on VALUE, which is the expansion of
6564 VARNAME. PATSUB is an expression supplying the pattern to match
6565 and the string to substitute. QUOTED is a flags word containing
6566 the type of quoting currently in effect. */
6567static char *
6568parameter_brace_patsub (varname, value, ind, patsub, quoted, flags)
6569 char *varname, *value;
6570 int ind;
6571 char *patsub;
6572 int quoted, flags;
6573{
6574 int vtype, mflags, starsub, delim;
6575 char *val, *temp, *pat, *rep, *p, *lpatsub, *tt;
6576 SHELL_VAR *v;
6577
6578 if (value == 0)
6579 return ((char *)NULL);
6580
6581 this_command_name = varname;
6582
6583 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
6584 if (vtype == -1)
6585 return ((char *)NULL);
6586
6587 starsub = vtype & VT_STARSUB;
6588 vtype &= ~VT_STARSUB;
6589
6590 mflags = 0;
6591 if (patsub && *patsub == '/')
6592 {
6593 mflags |= MATCH_GLOBREP;
6594 patsub++;
6595 }
6596
6597 /* Malloc this because expand_string_if_necessary or one of the expansion
6598 functions in its call chain may free it on a substitution error. */
6599 lpatsub = savestring (patsub);
6600
6601 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6602 mflags |= MATCH_QUOTED;
6603
6604 if (starsub)
6605 mflags |= MATCH_STARSUB;
6606
6607 /* If the pattern starts with a `/', make sure we skip over it when looking
6608 for the replacement delimiter. */
6609#if 0
6610 if (rep = quoted_strchr ((*patsub == '/') ? lpatsub+1 : lpatsub, '/', ST_BACKSL))
6611 *rep++ = '\0';
6612 else
6613 rep = (char *)NULL;
6614#else
6615 delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
6616 if (lpatsub[delim] == '/')
6617 {
6618 lpatsub[delim] = 0;
6619 rep = lpatsub + delim + 1;
6620 }
6621 else
6622 rep = (char *)NULL;
6623#endif
6624
6625 if (rep && *rep == '\0')
6626 rep = (char *)NULL;
6627
6628 /* Perform the same expansions on the pattern as performed by the
6629 pattern removal expansions. */
6630 pat = getpattern (lpatsub, quoted, 1);
6631
6632 if (rep)
6633 {
6634 if ((mflags & MATCH_QUOTED) == 0)
6635 rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
6636 else
6637 rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
6638 }
6639
6640 /* ksh93 doesn't allow the match specifier to be a part of the expanded
6641 pattern. This is an extension. Make sure we don't anchor the pattern
6642 at the beginning or end of the string if we're doing global replacement,
6643 though. */
6644 p = pat;
6645 if (mflags & MATCH_GLOBREP)
6646 mflags |= MATCH_ANY;
6647 else if (pat && pat[0] == '#')
6648 {
6649 mflags |= MATCH_BEG;
6650 p++;
6651 }
6652 else if (pat && pat[0] == '%')
6653 {
6654 mflags |= MATCH_END;
6655 p++;
6656 }
6657 else
6658 mflags |= MATCH_ANY;
6659
6660 /* OK, we now want to substitute REP for PAT in VAL. If
6661 flags & MATCH_GLOBREP is non-zero, the substitution is done
6662 everywhere, otherwise only the first occurrence of PAT is
6663 replaced. The pattern matching code doesn't understand
6664 CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
6665 values passed in (VT_VARIABLE) so the pattern substitution
6666 code works right. We need to requote special chars after
6667 we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
6668 other cases if QUOTED == 0, since the posparams and arrays
6669 indexed by * or @ do special things when QUOTED != 0. */
6670
6671 switch (vtype)
6672 {
6673 case VT_VARIABLE:
6674 case VT_ARRAYMEMBER:
6675 temp = pat_subst (val, p, rep, mflags);
6676 if (vtype == VT_VARIABLE)
6677 FREE (val);
6678 if (temp)
6679 {
6680 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
6681 free (temp);
6682 temp = tt;
6683 }
6684 break;
6685 case VT_POSPARMS:
6686 temp = pos_params_pat_subst (val, p, rep, mflags);
6687 if (temp && (mflags & MATCH_QUOTED) == 0)
6688 {
6689 tt = quote_escapes (temp);
6690 free (temp);
6691 temp = tt;
6692 }
6693 break;
6694#if defined (ARRAY_VARS)
6695 case VT_ARRAYVAR:
6696 temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags)
6697 : array_patsub (array_cell (v), p, rep, mflags);
6698 /* Don't call quote_escapes anymore; array_patsub calls
6699 array_quote_escapes as appropriate before adding the
6700 space separators; ditto for assoc_patsub. */
6701 break;
6702#endif
6703 }
6704
6705 FREE (pat);
6706 FREE (rep);
6707 free (lpatsub);
6708
6709 return temp;
6710}
6711
6712/****************************************************************/
6713/* */
6714/* Functions to perform case modification on variable values */
6715/* */
6716/****************************************************************/
6717
6718/* Do case modification on the positional parameters. */
6719
6720static char *
6721pos_params_modcase (string, pat, modop, mflags)
6722 char *string, *pat;
6723 int modop;
6724 int mflags;
6725{
6726 WORD_LIST *save, *params;
6727 WORD_DESC *w;
6728 char *ret;
6729 int pchar, qflags;
6730
6731 save = params = list_rest_of_args ();
6732 if (save == 0)
6733 return ((char *)NULL);
6734
6735 for ( ; params; params = params->next)
6736 {
6737 ret = sh_modcase (params->word->word, pat, modop);
6738 w = alloc_word_desc ();
6739 w->word = ret ? ret : savestring ("");
6740 dispose_word (params->word);
6741 params->word = w;
6742 }
6743
6744 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
6745 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
6746
6747 ret = string_list_pos_params (pchar, save, qflags);
6748 dispose_words (save);
6749
6750 return (ret);
6751}
6752
6753/* Perform case modification on VALUE, which is the expansion of
6754 VARNAME. MODSPEC is an expression supplying the type of modification
6755 to perform. QUOTED is a flags word containing the type of quoting
6756 currently in effect. */
6757static char *
6758parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, flags)
6759 char *varname, *value;
6760 int ind, modspec;
6761 char *patspec;
6762 int quoted, flags;
6763{
6764 int vtype, starsub, modop, mflags, x;
6765 char *val, *temp, *pat, *p, *lpat, *tt;
6766 SHELL_VAR *v;
6767
6768 if (value == 0)
6769 return ((char *)NULL);
6770
6771 this_command_name = varname;
6772
6773 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
6774 if (vtype == -1)
6775 return ((char *)NULL);
6776
6777 starsub = vtype & VT_STARSUB;
6778 vtype &= ~VT_STARSUB;
6779
6780 modop = 0;
6781 mflags = 0;
6782 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6783 mflags |= MATCH_QUOTED;
6784 if (starsub)
6785 mflags |= MATCH_STARSUB;
6786
6787 p = patspec;
6788 if (modspec == '^')
6789 {
6790 x = p && p[0] == modspec;
6791 modop = x ? CASE_UPPER : CASE_UPFIRST;
6792 p += x;
6793 }
6794 else if (modspec == ',')
6795 {
6796 x = p && p[0] == modspec;
6797 modop = x ? CASE_LOWER : CASE_LOWFIRST;
6798 p += x;
6799 }
6800 else if (modspec == '~')
6801 {
6802 x = p && p[0] == modspec;
6803 modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
6804 p += x;
6805 }
6806
6807 lpat = p ? savestring (p) : 0;
6808 /* Perform the same expansions on the pattern as performed by the
6809 pattern removal expansions. FOR LATER */
6810 pat = lpat ? getpattern (lpat, quoted, 1) : 0;
6811
6812 /* OK, now we do the case modification. */
6813 switch (vtype)
6814 {
6815 case VT_VARIABLE:
6816 case VT_ARRAYMEMBER:
6817 temp = sh_modcase (val, pat, modop);
6818 if (vtype == VT_VARIABLE)
6819 FREE (val);
6820 if (temp)
6821 {
6822 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
6823 free (temp);
6824 temp = tt;
6825 }
6826 break;
6827
6828 case VT_POSPARMS:
6829 temp = pos_params_modcase (val, pat, modop, mflags);
6830 if (temp && (mflags & MATCH_QUOTED) == 0)
6831 {
6832 tt = quote_escapes (temp);
6833 free (temp);
6834 temp = tt;
6835 }
6836 break;
6837
6838#if defined (ARRAY_VARS)
6839 case VT_ARRAYVAR:
6840 temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
6841 : array_modcase (array_cell (v), pat, modop, mflags);
6842 /* Don't call quote_escapes; array_modcase calls array_quote_escapes
6843 as appropriate before adding the space separators; ditto for
6844 assoc_modcase. */
6845 break;
6846#endif
6847 }
6848
6849 FREE (pat);
6850 free (lpat);
6851
6852 return temp;
6853}
6854
6855/* Check for unbalanced parens in S, which is the contents of $(( ... )). If
6856 any occur, this must be a nested command substitution, so return 0.
6857 Otherwise, return 1. A valid arithmetic expression must always have a
6858 ( before a matching ), so any cases where there are more right parens
6859 means that this must not be an arithmetic expression, though the parser
6860 will not accept it without a balanced total number of parens. */
6861static int
6862chk_arithsub (s, len)
6863 const char *s;
6864 int len;
6865{
6866 int i, count;
6867 DECLARE_MBSTATE;
6868
6869 i = count = 0;
6870 while (i < len)
6871 {
6872 if (s[i] == LPAREN)
6873 count++;
6874 else if (s[i] == RPAREN)
6875 {
6876 count--;
6877 if (count < 0)
6878 return 0;
6879 }
6880
6881 switch (s[i])
6882 {
6883 default:
6884 ADVANCE_CHAR (s, len, i);
6885 break;
6886
6887 case '\\':
6888 i++;
6889 if (s[i])
6890 ADVANCE_CHAR (s, len, i);
6891 break;
6892
6893 case '\'':
6894 i = skip_single_quoted (s, len, ++i);
6895 break;
6896
6897 case '"':
6898 i = skip_double_quoted ((char *)s, len, ++i);
6899 break;
6900 }
6901 }
6902
6903 return (count == 0);
6904}
6905
6906/****************************************************************/
6907/* */
6908/* Functions to perform parameter expansion on a string */
6909/* */
6910/****************************************************************/
6911
6912/* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
6913static WORD_DESC *
6914parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
6915 char *string;
6916 int *indexp, quoted, *quoted_dollar_atp, *contains_dollar_at, pflags;
6917{
6918 int check_nullness, var_is_set, var_is_null, var_is_special;
6919 int want_substring, want_indir, want_patsub, want_casemod;
6920 char *name, *value, *temp, *temp1;
6921 WORD_DESC *tdesc, *ret;
6922 int t_index, sindex, c, tflag, modspec;
6923 intmax_t number;
6924 arrayind_t ind;
6925
6926 temp = temp1 = value = (char *)NULL;
6927 var_is_set = var_is_null = var_is_special = check_nullness = 0;
6928 want_substring = want_indir = want_patsub = want_casemod = 0;
6929
6930 sindex = *indexp;
6931 t_index = ++sindex;
6932 /* ${#var} doesn't have any of the other parameter expansions on it. */
6933 if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
6934 name = string_extract (string, &t_index, "}", SX_VARNAME);
6935 else
6936#if defined (CASEMOD_EXPANSIONS)
6937 /* To enable case-toggling expansions using the `~' operator character
6938 change the 1 to 0. */
6939# if defined (CASEMOD_CAPCASE)
6940 name = string_extract (string, &t_index, "#%^,~:-=?+/}", SX_VARNAME);
6941# else
6942 name = string_extract (string, &t_index, "#%^,:-=?+/}", SX_VARNAME);
6943# endif /* CASEMOD_CAPCASE */
6944#else
6945 name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME);
6946#endif /* CASEMOD_EXPANSIONS */
6947
6948 ret = 0;
6949 tflag = 0;
6950
6951 ind = INTMAX_MIN;
6952
6953 /* If the name really consists of a special variable, then make sure
6954 that we have the entire name. We don't allow indirect references
6955 to special variables except `#', `?', `@' and `*'. */
6956 if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
6957 (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
6958 {
6959 t_index++;
6960 free (name);
6961 temp1 = string_extract (string, &t_index, "#%:-=?+/}", 0);
6962 name = (char *)xmalloc (3 + (strlen (temp1)));
6963 *name = string[sindex];
6964 if (string[sindex] == '!')
6965 {
6966 /* indirect reference of $#, $?, $@, or $* */
6967 name[1] = string[sindex + 1];
6968 strcpy (name + 2, temp1);
6969 }
6970 else
6971 strcpy (name + 1, temp1);
6972 free (temp1);
6973 }
6974 sindex = t_index;
6975
6976 /* Find out what character ended the variable name. Then
6977 do the appropriate thing. */
6978 if (c = string[sindex])
6979 sindex++;
6980
6981 /* If c is followed by one of the valid parameter expansion
6982 characters, move past it as normal. If not, assume that
6983 a substring specification is being given, and do not move
6984 past it. */
6985 if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
6986 {
6987 check_nullness++;
6988 if (c = string[sindex])
6989 sindex++;
6990 }
6991 else if (c == ':' && string[sindex] != RBRACE)
6992 want_substring = 1;
6993 else if (c == '/' && string[sindex] != RBRACE)
6994 want_patsub = 1;
6995#if defined (CASEMOD_EXPANSIONS)
6996 else if (c == '^' || c == ',' || c == '~')
6997 {
6998 modspec = c;
6999 want_casemod = 1;
7000 }
7001#endif
7002
7003 /* Catch the valid and invalid brace expressions that made it through the
7004 tests above. */
7005 /* ${#-} is a valid expansion and means to take the length of $-.
7006 Similarly for ${#?} and ${##}... */
7007 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
7008 VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
7009 {
7010 name = (char *)xrealloc (name, 3);
7011 name[1] = c;
7012 name[2] = '\0';
7013 c = string[sindex++];
7014 }
7015
7016 /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
7017 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
7018 member (c, "%:=+/") && string[sindex] == RBRACE)
7019 {
7020 temp = (char *)NULL;
7021 goto bad_substitution;
7022 }
7023
7024 /* Indirect expansion begins with a `!'. A valid indirect expansion is
7025 either a variable name, one of the positional parameters or a special
7026 variable that expands to one of the positional parameters. */
7027 want_indir = *name == '!' &&
7028 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
7029 || VALID_INDIR_PARAM (name[1]));
7030
7031 /* Determine the value of this variable. */
7032
7033 /* Check for special variables, directly referenced. */
7034 if (SPECIAL_VAR (name, want_indir))
7035 var_is_special++;
7036
7037 /* Check for special expansion things, like the length of a parameter */
7038 if (*name == '#' && name[1])
7039 {
7040 /* If we are not pointing at the character just after the
7041 closing brace, then we haven't gotten all of the name.
7042 Since it begins with a special character, this is a bad
7043 substitution. Also check NAME for validity before trying
7044 to go on. */
7045 if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
7046 {
7047 temp = (char *)NULL;
7048 goto bad_substitution;
7049 }
7050
7051 number = parameter_brace_expand_length (name);
7052 if (number == INTMAX_MIN && unbound_vars_is_error)
7053 {
7054 last_command_exit_value = EXECUTION_FAILURE;
7055 err_unboundvar (name+1);
7056 free (name);
7057 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7058 }
7059 free (name);
7060
7061 *indexp = sindex;
7062 if (number < 0)
7063 return (&expand_wdesc_error);
7064 else
7065 {
7066 ret = alloc_word_desc ();
7067 ret->word = itos (number);
7068 return ret;
7069 }
7070 }
7071
7072 /* ${@} is identical to $@. */
7073 if (name[0] == '@' && name[1] == '\0')
7074 {
7075 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7076 *quoted_dollar_atp = 1;
7077
7078 if (contains_dollar_at)
7079 *contains_dollar_at = 1;
7080 }
7081
7082 /* Process ${!PREFIX*} expansion. */
7083 if (want_indir && string[sindex - 1] == RBRACE &&
7084 (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
7085 legal_variable_starter ((unsigned char) name[1]))
7086 {
7087 char **x;
7088 WORD_LIST *xlist;
7089
7090 temp1 = savestring (name + 1);
7091 number = strlen (temp1);
7092 temp1[number - 1] = '\0';
7093 x = all_variables_matching_prefix (temp1);
7094 xlist = strvec_to_word_list (x, 0, 0);
7095 if (string[sindex - 2] == '*')
7096 temp = string_list_dollar_star (xlist);
7097 else
7098 {
7099 temp = string_list_dollar_at (xlist, quoted);
7100 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7101 *quoted_dollar_atp = 1;
7102 if (contains_dollar_at)
7103 *contains_dollar_at = 1;
7104 }
7105 free (x);
7106 dispose_words (xlist);
7107 free (temp1);
7108 *indexp = sindex;
7109
7110 ret = alloc_word_desc ();
7111 ret->word = temp;
7112 return ret;
7113 }
7114
7115#if defined (ARRAY_VARS)
7116 /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */ /* [ */
7117 if (want_indir && string[sindex - 1] == RBRACE &&
7118 string[sindex - 2] == ']' && valid_array_reference (name+1))
7119 {
7120 char *x, *x1;
7121
7122 temp1 = savestring (name + 1);
7123 x = array_variable_name (temp1, &x1, (int *)0); /* [ */
7124 FREE (x);
7125 if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == ']')
7126 {
7127 temp = array_keys (temp1, quoted); /* handles assoc vars too */
7128 if (x1[0] == '@')
7129 {
7130 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7131 *quoted_dollar_atp = 1;
7132 if (contains_dollar_at)
7133 *contains_dollar_at = 1;
7134 }
7135
7136 free (temp1);
7137 *indexp = sindex;
7138
7139 ret = alloc_word_desc ();
7140 ret->word = temp;
7141 return ret;
7142 }
7143
7144 free (temp1);
7145 }
7146#endif /* ARRAY_VARS */
7147
7148 /* Make sure that NAME is valid before trying to go on. */
7149 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
7150 var_is_special) == 0)
7151 {
7152 temp = (char *)NULL;
7153 goto bad_substitution;
7154 }
7155
7156 if (want_indir)
7157 tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, quoted_dollar_atp, contains_dollar_at);
7158 else
7159 tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&PF_NOSPLIT2), &ind);
7160
7161 if (tdesc)
7162 {
7163 temp = tdesc->word;
7164 tflag = tdesc->flags;
7165 dispose_word_desc (tdesc);
7166 }
7167 else
7168 temp = (char *)0;
7169
7170#if defined (ARRAY_VARS)
7171 if (valid_array_reference (name))
7172 chk_atstar (name, quoted, quoted_dollar_atp, contains_dollar_at);
7173#endif
7174
7175 var_is_set = temp != (char *)0;
7176 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
7177
7178 /* Get the rest of the stuff inside the braces. */
7179 if (c && c != RBRACE)
7180 {
9c2db999
CR
7181 /* Extract the contents of the ${ ... } expansion
7182 according to the Posix.2 rules. */
7183 value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
e192f341
CR
7184 if (string[sindex] == RBRACE)
7185 sindex++;
7186 else
7187 goto bad_substitution;
7188 }
7189 else
7190 value = (char *)NULL;
7191
7192 *indexp = sindex;
7193
7194 /* All the cases where an expansion can possibly generate an unbound
7195 variable error. */
7196 if (want_substring || want_patsub || want_casemod || c == '#' || c == '%' || c == RBRACE)
7197 {
7198 if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
7199 {
7200 last_command_exit_value = EXECUTION_FAILURE;
7201 err_unboundvar (name);
7202 FREE (value);
7203 FREE (temp);
7204 free (name);
7205 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7206 }
7207 }
7208
7209 /* If this is a substring spec, process it and add the result. */
7210 if (want_substring)
7211 {
7212 temp1 = parameter_brace_substring (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7213 FREE (name);
7214 FREE (value);
7215 FREE (temp);
7216
7217 if (temp1 == &expand_param_error)
7218 return (&expand_wdesc_error);
7219 else if (temp1 == &expand_param_fatal)
7220 return (&expand_wdesc_fatal);
7221
7222 ret = alloc_word_desc ();
7223 ret->word = temp1;
7224 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7225 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7226 return ret;
7227 }
7228 else if (want_patsub)
7229 {
7230 temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7231 FREE (name);
7232 FREE (value);
7233 FREE (temp);
7234
7235 if (temp1 == &expand_param_error)
7236 return (&expand_wdesc_error);
7237 else if (temp1 == &expand_param_fatal)
7238 return (&expand_wdesc_fatal);
7239
7240 ret = alloc_word_desc ();
7241 ret->word = temp1;
7242 ret = alloc_word_desc ();
7243 ret->word = temp1;
7244 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7245 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7246 return ret;
7247 }
7248#if defined (CASEMOD_EXPANSIONS)
7249 else if (want_casemod)
7250 {
7251 temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7252 FREE (name);
7253 FREE (value);
7254 FREE (temp);
7255
7256 if (temp1 == &expand_param_error)
7257 return (&expand_wdesc_error);
7258 else if (temp1 == &expand_param_fatal)
7259 return (&expand_wdesc_fatal);
7260
7261 ret = alloc_word_desc ();
7262 ret->word = temp1;
7263 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7264 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7265 return ret;
7266 }
7267#endif
7268
7269 /* Do the right thing based on which character ended the variable name. */
7270 switch (c)
7271 {
7272 default:
7273 case '\0':
7274 bad_substitution:
7275 report_error (_("%s: bad substitution"), string ? string : "??");
7276 FREE (value);
7277 FREE (temp);
7278 free (name);
7279 return &expand_wdesc_error;
7280
7281 case RBRACE:
7282 break;
7283
7284 case '#': /* ${param#[#]pattern} */
7285 case '%': /* ${param%[%]pattern} */
7286 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
7287 {
7288 FREE (value);
7289 break;
7290 }
7291 temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
7292 free (temp);
7293 free (value);
7294 free (name);
7295
7296 ret = alloc_word_desc ();
7297 ret->word = temp1;
7298 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7299 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
7300 return ret;
7301
7302 case '-':
7303 case '=':
7304 case '?':
7305 case '+':
7306 if (var_is_set && var_is_null == 0)
7307 {
7308 /* If the operator is `+', we don't want the value of the named
7309 variable for anything, just the value of the right hand side. */
7310 if (c == '+')
7311 {
7312 /* XXX -- if we're double-quoted and the named variable is "$@",
7313 we want to turn off any special handling of "$@" --
7314 we're not using it, so whatever is on the rhs applies. */
7315 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7316 *quoted_dollar_atp = 0;
7317 if (contains_dollar_at)
7318 *contains_dollar_at = 0;
7319
7320 FREE (temp);
7321 if (value)
7322 {
7323 /* From Posix discussion on austin-group list. Issue 221
7324 requires that backslashes escaping `}' inside
7325 double-quoted ${...} be removed. */
7326 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7327 quoted |= Q_DOLBRACE;
7328 ret = parameter_brace_expand_rhs (name, value, c,
7329 quoted,
7330 quoted_dollar_atp,
7331 contains_dollar_at);
7332 /* XXX - fix up later, esp. noting presence of
7333 W_HASQUOTEDNULL in ret->flags */
7334 free (value);
7335 }
7336 else
7337 temp = (char *)NULL;
7338 }
7339 else
7340 {
7341 FREE (value);
7342 }
7343 /* Otherwise do nothing; just use the value in TEMP. */
7344 }
7345 else /* VAR not set or VAR is NULL. */
7346 {
7347 FREE (temp);
7348 temp = (char *)NULL;
7349 if (c == '=' && var_is_special)
7350 {
7351 report_error (_("$%s: cannot assign in this way"), name);
7352 free (name);
7353 free (value);
7354 return &expand_wdesc_error;
7355 }
7356 else if (c == '?')
7357 {
7358 parameter_brace_expand_error (name, value);
7359 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7360 }
7361 else if (c != '+')
7362 {
7363 /* XXX -- if we're double-quoted and the named variable is "$@",
7364 we want to turn off any special handling of "$@" --
7365 we're not using it, so whatever is on the rhs applies. */
7366 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7367 *quoted_dollar_atp = 0;
7368 if (contains_dollar_at)
7369 *contains_dollar_at = 0;
7370
7371 /* From Posix discussion on austin-group list. Issue 221 requires
7372 that backslashes escaping `}' inside double-quoted ${...} be
7373 removed. */
7374 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7375 quoted |= Q_DOLBRACE;
7376 ret = parameter_brace_expand_rhs (name, value, c, quoted,
7377 quoted_dollar_atp,
7378 contains_dollar_at);
7379 /* XXX - fix up later, esp. noting presence of
7380 W_HASQUOTEDNULL in tdesc->flags */
7381 }
7382 free (value);
7383 }
7384
7385 break;
7386 }
7387 free (name);
7388
7389 if (ret == 0)
7390 {
7391 ret = alloc_word_desc ();
7392 ret->flags = tflag;
7393 ret->word = temp;
7394 }
7395 return (ret);
7396}
7397
7398/* Expand a single ${xxx} expansion. The braces are optional. When
7399 the braces are used, parameter_brace_expand() does the work,
7400 possibly calling param_expand recursively. */
7401static WORD_DESC *
7402param_expand (string, sindex, quoted, expanded_something,
7403 contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
7404 pflags)
7405 char *string;
7406 int *sindex, quoted, *expanded_something, *contains_dollar_at;
7407 int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
7408{
7409 char *temp, *temp1, uerror[3];
7410 int zindex, t_index, expok;
7411 unsigned char c;
7412 intmax_t number;
7413 SHELL_VAR *var;
7414 WORD_LIST *list;
7415 WORD_DESC *tdesc, *ret;
7416 int tflag;
7417
7418 zindex = *sindex;
7419 c = string[++zindex];
7420
7421 temp = (char *)NULL;
7422 ret = tdesc = (WORD_DESC *)NULL;
7423 tflag = 0;
7424
7425 /* Do simple cases first. Switch on what follows '$'. */
7426 switch (c)
7427 {
7428 /* $0 .. $9? */
7429 case '0':
7430 case '1':
7431 case '2':
7432 case '3':
7433 case '4':
7434 case '5':
7435 case '6':
7436 case '7':
7437 case '8':
7438 case '9':
7439 temp1 = dollar_vars[TODIGIT (c)];
7440 if (unbound_vars_is_error && temp1 == (char *)NULL)
7441 {
7442 uerror[0] = '$';
7443 uerror[1] = c;
7444 uerror[2] = '\0';
7445 last_command_exit_value = EXECUTION_FAILURE;
7446 err_unboundvar (uerror);
7447 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7448 }
7449 if (temp1)
7450 temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7451 ? quote_string (temp1)
7452 : quote_escapes (temp1);
7453 else
7454 temp = (char *)NULL;
7455
7456 break;
7457
7458 /* $$ -- pid of the invoking shell. */
7459 case '$':
7460 temp = itos (dollar_dollar_pid);
7461 break;
7462
7463 /* $# -- number of positional parameters. */
7464 case '#':
7465 temp = itos (number_of_args ());
7466 break;
7467
7468 /* $? -- return value of the last synchronous command. */
7469 case '?':
7470 temp = itos (last_command_exit_value);
7471 break;
7472
7473 /* $- -- flags supplied to the shell on invocation or by `set'. */
7474 case '-':
7475 temp = which_set_flags ();
7476 break;
7477
7478 /* $! -- Pid of the last asynchronous command. */
7479 case '!':
7480 /* If no asynchronous pids have been created, expand to nothing.
7481 If `set -u' has been executed, and no async processes have
7482 been created, this is an expansion error. */
7483 if (last_asynchronous_pid == NO_PID)
7484 {
7485 if (expanded_something)
7486 *expanded_something = 0;
7487 temp = (char *)NULL;
7488 if (unbound_vars_is_error)
7489 {
7490 uerror[0] = '$';
7491 uerror[1] = c;
7492 uerror[2] = '\0';
7493 last_command_exit_value = EXECUTION_FAILURE;
7494 err_unboundvar (uerror);
7495 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7496 }
7497 }
7498 else
7499 temp = itos (last_asynchronous_pid);
7500 break;
7501
7502 /* The only difference between this and $@ is when the arg is quoted. */
7503 case '*': /* `$*' */
7504 list = list_rest_of_args ();
7505
7506#if 0
7507 /* According to austin-group posix proposal by Geoff Clare in
7508 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
7509
7510 "The shell shall write a message to standard error and
7511 immediately exit when it tries to expand an unset parameter
7512 other than the '@' and '*' special parameters."
7513 */
7514
7515 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
7516 {
7517 uerror[0] = '$';
7518 uerror[1] = '*';
7519 uerror[2] = '\0';
7520 last_command_exit_value = EXECUTION_FAILURE;
7521 err_unboundvar (uerror);
7522 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7523 }
7524#endif
7525
7526 /* If there are no command-line arguments, this should just
7527 disappear if there are other characters in the expansion,
7528 even if it's quoted. */
7529 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
7530 temp = (char *)NULL;
7531 else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
7532 {
7533 /* If we have "$*" we want to make a string of the positional
7534 parameters, separated by the first character of $IFS, and
7535 quote the whole string, including the separators. If IFS
7536 is unset, the parameters are separated by ' '; if $IFS is
7537 null, the parameters are concatenated. */
7538 temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list) : string_list (list);
7539 if (temp)
7540 {
7541 temp1 = quote_string (temp);
7542 if (*temp == 0)
7543 tflag |= W_HASQUOTEDNULL;
7544 free (temp);
7545 temp = temp1;
7546 }
7547 }
7548 else
7549 {
7550 /* We check whether or not we're eventually going to split $* here,
7551 for example when IFS is empty and we are processing the rhs of
7552 an assignment statement. In that case, we don't separate the
7553 arguments at all. Otherwise, if the $* is not quoted it is
7554 identical to $@ */
7555#if 1
7556# if defined (HANDLE_MULTIBYTE)
7557 if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
7558# else
7559 if (expand_no_split_dollar_star && ifs_firstc == 0)
7560# endif
7561 temp = string_list_dollar_star (list);
7562 else
7563 temp = string_list_dollar_at (list, quoted);
7564#else
7565 temp = string_list_dollar_at (list, quoted);
7566#endif
7567 if (expand_no_split_dollar_star == 0 && contains_dollar_at)
7568 *contains_dollar_at = 1;
7569 }
7570
7571 dispose_words (list);
7572 break;
7573
7574 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
7575 means that we have to turn quoting off after we split into
7576 the individually quoted arguments so that the final split
7577 on the first character of $IFS is still done. */
7578 case '@': /* `$@' */
7579 list = list_rest_of_args ();
7580
7581#if 0
7582 /* According to austin-group posix proposal by Geoff Clare in
7583 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
7584
7585 "The shell shall write a message to standard error and
7586 immediately exit when it tries to expand an unset parameter
7587 other than the '@' and '*' special parameters."
7588 */
7589
7590 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
7591 {
7592 uerror[0] = '$';
7593 uerror[1] = '@';
7594 uerror[2] = '\0';
7595 last_command_exit_value = EXECUTION_FAILURE;
7596 err_unboundvar (uerror);
7597 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
7598 }
7599#endif
7600
7601 /* We want to flag the fact that we saw this. We can't turn
7602 off quoting entirely, because other characters in the
7603 string might need it (consider "\"$@\""), but we need some
7604 way to signal that the final split on the first character
7605 of $IFS should be done, even though QUOTED is 1. */
7606 /* XXX - should this test include Q_PATQUOTE? */
7607 if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7608 *quoted_dollar_at_p = 1;
7609 if (contains_dollar_at)
7610 *contains_dollar_at = 1;
7611
7612#if 0
7613 if (pflags & PF_NOSPLIT2)
7614 temp = string_list_internal (quoted ? quote_list (list) : list, " ");
7615 else
7616#endif
7617 /* We want to separate the positional parameters with the first
7618 character of $IFS in case $IFS is something other than a space.
7619 We also want to make sure that splitting is done no matter what --
7620 according to POSIX.2, this expands to a list of the positional
7621 parameters no matter what IFS is set to. */
7622 temp = string_list_dollar_at (list, quoted);
7623
7624 dispose_words (list);
7625 break;
7626
7627 case LBRACE:
7628 tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
7629 quoted_dollar_at_p,
7630 contains_dollar_at);
7631
7632 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
7633 return (tdesc);
7634 temp = tdesc ? tdesc->word : (char *)0;
7635
7636 /* XXX */
7637 /* Quoted nulls should be removed if there is anything else
7638 in the string. */
7639 /* Note that we saw the quoted null so we can add one back at
7640 the end of this function if there are no other characters
7641 in the string, discard TEMP, and go on. The exception to
7642 this is when we have "${@}" and $1 is '', since $@ needs
7643 special handling. */
7644 if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
7645 {
7646 if (had_quoted_null_p)
7647 *had_quoted_null_p = 1;
7648 if (*quoted_dollar_at_p == 0)
7649 {
7650 free (temp);
7651 tdesc->word = temp = (char *)NULL;
7652 }
7653
7654 }
7655
7656 ret = tdesc;
7657 goto return0;
7658
7659 /* Do command or arithmetic substitution. */
7660 case LPAREN:
7661 /* We have to extract the contents of this paren substitution. */
7662 t_index = zindex + 1;
7663 temp = extract_command_subst (string, &t_index, 0);
7664 zindex = t_index;
7665
7666 /* For Posix.2-style `$(( ))' arithmetic substitution,
7667 extract the expression and pass it to the evaluator. */
7668 if (temp && *temp == LPAREN)
7669 {
7670 char *temp2;
7671 temp1 = temp + 1;
7672 temp2 = savestring (temp1);
7673 t_index = strlen (temp2) - 1;
7674
7675 if (temp2[t_index] != RPAREN)
7676 {
7677 free (temp2);
7678 goto comsub;
7679 }
7680
7681 /* Cut off ending `)' */
7682 temp2[t_index] = '\0';
7683
7684 if (chk_arithsub (temp2, t_index) == 0)
7685 {
7686 free (temp2);
7687#if 0
7688 internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
7689#endif
7690 goto comsub;
7691 }
7692
7693 /* Expand variables found inside the expression. */
7694 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
7695 free (temp2);
7696
7697arithsub:
7698 /* No error messages. */
7699 this_command_name = (char *)NULL;
7700 number = evalexp (temp1, &expok);
7701 free (temp);
7702 free (temp1);
7703 if (expok == 0)
7704 {
7705 if (interactive_shell == 0 && posixly_correct)
7706 {
7707 last_command_exit_value = EXECUTION_FAILURE;
7708 return (&expand_wdesc_fatal);
7709 }
7710 else
7711 return (&expand_wdesc_error);
7712 }
7713 temp = itos (number);
7714 break;
7715 }
7716
7717comsub:
7718 if (pflags & PF_NOCOMSUB)
7719 /* we need zindex+1 because string[zindex] == RPAREN */
7720 temp1 = substring (string, *sindex, zindex+1);
7721 else
7722 {
7723 tdesc = command_substitute (temp, quoted);
7724 temp1 = tdesc ? tdesc->word : (char *)NULL;
7725 if (tdesc)
7726 dispose_word_desc (tdesc);
7727 }
7728 FREE (temp);
7729 temp = temp1;
7730 break;
7731
7732 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
7733 away in a future bash release. */
7734 case '[':
7735 /* Extract the contents of this arithmetic substitution. */
7736 t_index = zindex + 1;
7737 temp = extract_arithmetic_subst (string, &t_index);
7738 zindex = t_index;
7739 if (temp == 0)
7740 {
7741 temp = savestring (string);
7742 if (expanded_something)
7743 *expanded_something = 0;
7744 goto return0;
7745 }
7746
7747 /* Do initial variable expansion. */
7748 temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES);
7749
7750 goto arithsub;
7751
7752 default:
7753 /* Find the variable in VARIABLE_LIST. */
7754 temp = (char *)NULL;
7755
7756 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
7757 ;
7758 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
7759
7760 /* If this isn't a variable name, then just output the `$'. */
7761 if (temp1 == 0 || *temp1 == '\0')
7762 {
7763 FREE (temp1);
7764 temp = (char *)xmalloc (2);
7765 temp[0] = '$';
7766 temp[1] = '\0';
7767 if (expanded_something)
7768 *expanded_something = 0;
7769 goto return0;
7770 }
7771
7772 /* If the variable exists, return its value cell. */
7773 var = find_variable (temp1);
7774
7775 if (var && invisible_p (var) == 0 && var_isset (var))
7776 {
7777#if defined (ARRAY_VARS)
7778 if (assoc_p (var) || array_p (var))
7779 {
7780 temp = array_p (var) ? array_reference (array_cell (var), 0)
7781 : assoc_reference (assoc_cell (var), "0");
7782 if (temp)
7783 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7784 ? quote_string (temp)
7785 : quote_escapes (temp);
7786 else if (unbound_vars_is_error)
7787 goto unbound_variable;
7788 }
7789 else
7790#endif
7791 {
7792 temp = value_cell (var);
7793
7794 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
7795 ? quote_string (temp)
7796 : quote_escapes (temp);
7797 }
7798
7799 free (temp1);
7800
7801 goto return0;
7802 }
7803
7804 temp = (char *)NULL;
7805
7806unbound_variable:
7807 if (unbound_vars_is_error)
7808 {
7809 last_command_exit_value = EXECUTION_FAILURE;
7810 err_unboundvar (temp1);
7811 }
7812 else
7813 {
7814 free (temp1);
7815 goto return0;
7816 }
7817
7818 free (temp1);
7819 last_command_exit_value = EXECUTION_FAILURE;
7820 return ((unbound_vars_is_error && interactive_shell == 0)
7821 ? &expand_wdesc_fatal
7822 : &expand_wdesc_error);
7823 }
7824
7825 if (string[zindex])
7826 zindex++;
7827
7828return0:
7829 *sindex = zindex;
7830
7831 if (ret == 0)
7832 {
7833 ret = alloc_word_desc ();
7834 ret->flags = tflag; /* XXX */
7835 ret->word = temp;
7836 }
7837 return ret;
7838}
7839
7840/* Make a word list which is the result of parameter and variable
7841 expansion, command substitution, arithmetic substitution, and
7842 quote removal of WORD. Return a pointer to a WORD_LIST which is
7843 the result of the expansion. If WORD contains a null word, the
7844 word list returned is also null.
7845
7846 QUOTED contains flag values defined in shell.h.
7847
7848 ISEXP is used to tell expand_word_internal that the word should be
7849 treated as the result of an expansion. This has implications for
7850 how IFS characters in the word are treated.
7851
7852 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
7853 they point to an integer value which receives information about expansion.
7854 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
7855 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
7856 else zero.
7857
7858 This only does word splitting in the case of $@ expansion. In that
7859 case, we split on ' '. */
7860
7861/* Values for the local variable quoted_state. */
7862#define UNQUOTED 0
7863#define PARTIALLY_QUOTED 1
7864#define WHOLLY_QUOTED 2
7865
7866static WORD_LIST *
7867expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
7868 WORD_DESC *word;
7869 int quoted, isexp;
7870 int *contains_dollar_at;
7871 int *expanded_something;
7872{
7873 WORD_LIST *list;
7874 WORD_DESC *tword;
7875
7876 /* The intermediate string that we build while expanding. */
7877 char *istring;
7878
7879 /* The current size of the above object. */
7880 int istring_size;
7881
7882 /* Index into ISTRING. */
7883 int istring_index;
7884
7885 /* Temporary string storage. */
7886 char *temp, *temp1;
7887
7888 /* The text of WORD. */
7889 register char *string;
7890
7891 /* The size of STRING. */
7892 size_t string_size;
7893
7894 /* The index into STRING. */
7895 int sindex;
7896
7897 /* This gets 1 if we see a $@ while quoted. */
7898 int quoted_dollar_at;
7899
7900 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
7901 whether WORD contains no quoting characters, a partially quoted
7902 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
7903 int quoted_state;
7904
7905 /* State flags */
7906 int had_quoted_null;
7907 int has_dollar_at;
7908 int tflag;
7909 int pflags; /* flags passed to param_expand */
7910
7911 int assignoff; /* If assignment, offset of `=' */
7912
7913 register unsigned char c; /* Current character. */
7914 int t_index; /* For calls to string_extract_xxx. */
7915
7916 char twochars[2];
7917
7918 DECLARE_MBSTATE;
7919
7920 istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
7921 istring[istring_index = 0] = '\0';
7922 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
7923 quoted_state = UNQUOTED;
7924
7925 string = word->word;
7926 if (string == 0)
7927 goto finished_with_string;
7928 /* Don't need the string length for the SADD... and COPY_ macros unless
7929 multibyte characters are possible. */
7930 string_size = (MB_CUR_MAX > 1) ? strlen (string) : 1;
7931
7932 if (contains_dollar_at)
7933 *contains_dollar_at = 0;
7934
7935 assignoff = -1;
7936
7937 /* Begin the expansion. */
7938
7939 for (sindex = 0; ;)
7940 {
7941 c = string[sindex];
7942
7943 /* Case on toplevel character. */
7944 switch (c)
7945 {
7946 case '\0':
7947 goto finished_with_string;
7948
7949 case CTLESC:
7950 sindex++;
7951#if HANDLE_MULTIBYTE
7952 if (MB_CUR_MAX > 1 && string[sindex])
7953 {
7954 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
7955 }
7956 else
7957#endif
7958 {
7959 temp = (char *)xmalloc (3);
7960 temp[0] = CTLESC;
7961 temp[1] = c = string[sindex];
7962 temp[2] = '\0';
7963 }
7964
7965dollar_add_string:
7966 if (string[sindex])
7967 sindex++;
7968
7969add_string:
7970 if (temp)
7971 {
7972 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
7973 temp = (char *)0;
7974 }
7975
7976 break;
7977
7978#if defined (PROCESS_SUBSTITUTION)
7979 /* Process substitution. */
7980 case '<':
7981 case '>':
7982 {
7983 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)) || posixly_correct)
7984 {
7985 sindex--; /* add_character: label increments sindex */
7986 goto add_character;
7987 }
7988 else
7989 t_index = sindex + 1; /* skip past both '<' and LPAREN */
7990
7991 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index); /*))*/
7992 sindex = t_index;
7993
7994 /* If the process substitution specification is `<()', we want to
7995 open the pipe for writing in the child and produce output; if
7996 it is `>()', we want to open the pipe for reading in the child
7997 and consume input. */
7998 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
7999
8000 FREE (temp1);
8001
8002 goto dollar_add_string;
8003 }
8004#endif /* PROCESS_SUBSTITUTION */
8005
8006 case '=':
8007 /* Posix.2 section 3.6.1 says that tildes following `=' in words
8008 which are not assignment statements are not expanded. If the
8009 shell isn't in posix mode, though, we perform tilde expansion
8010 on `likely candidate' unquoted assignment statements (flags
8011 include W_ASSIGNMENT but not W_QUOTED). A likely candidate
8012 contains an unquoted :~ or =~. Something to think about: we
8013 now have a flag that says to perform tilde expansion on arguments
8014 to `assignment builtins' like declare and export that look like
8015 assignment statements. We now do tilde expansion on such words
8016 even in POSIX mode. */
8017 if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
8018 {
8019 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8020 goto add_ifs_character;
8021 else
8022 goto add_character;
8023 }
8024 /* If we're not in posix mode or forcing assignment-statement tilde
8025 expansion, note where the `=' appears in the word and prepare to
8026 do tilde expansion following the first `='. */
8027 if ((word->flags & W_ASSIGNMENT) &&
8028 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
8029 assignoff == -1 && sindex > 0)
8030 assignoff = sindex;
8031 if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
8032 word->flags |= W_ITILDE;
8033#if 0
8034 else if ((word->flags & W_ASSIGNMENT) &&
8035 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
8036 string[sindex+1] == '~')
8037 word->flags |= W_ITILDE;
8038#endif
8039 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8040 goto add_ifs_character;
8041 else
8042 goto add_character;
8043
8044 case ':':
8045 if (word->flags & W_NOTILDE)
8046 {
8047 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8048 goto add_ifs_character;
8049 else
8050 goto add_character;
8051 }
8052
8053 if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) &&
8054 string[sindex+1] == '~')
8055 word->flags |= W_ITILDE;
8056
8057 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
8058 goto add_ifs_character;
8059 else
8060 goto add_character;
8061
8062 case '~':
8063 /* If the word isn't supposed to be tilde expanded, or we're not
8064 at the start of a word or after an unquoted : or = in an
8065 assignment statement, we don't do tilde expansion. */
8066 if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
8067 (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
8068 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8069 {
8070 word->flags &= ~W_ITILDE;
8071 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
8072 goto add_ifs_character;
8073 else
8074 goto add_character;
8075 }
8076
8077 if (word->flags & W_ASSIGNRHS)
8078 tflag = 2;
8079 else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
8080 tflag = 1;
8081 else
8082 tflag = 0;
8083
8084 temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
8085
8086 word->flags &= ~W_ITILDE;
8087
8088 if (temp && *temp && t_index > 0)
8089 {
8090 temp1 = bash_tilde_expand (temp, tflag);
8091 if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
8092 {
8093 FREE (temp);
8094 FREE (temp1);
8095 goto add_character; /* tilde expansion failed */
8096 }
8097 free (temp);
8098 temp = temp1;
8099 sindex += t_index;
8100 goto add_quoted_string; /* XXX was add_string */
8101 }
8102 else
8103 {
8104 FREE (temp);
8105 goto add_character;
8106 }
8107
8108 case '$':
8109 if (expanded_something)
8110 *expanded_something = 1;
8111
8112 has_dollar_at = 0;
8113 pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
8114 if (word->flags & W_NOSPLIT2)
8115 pflags |= PF_NOSPLIT2;
8116 tword = param_expand (string, &sindex, quoted, expanded_something,
8117 &has_dollar_at, &quoted_dollar_at,
8118 &had_quoted_null, pflags);
8119
8120 if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
8121 {
8122 free (string);
8123 free (istring);
8124 return ((tword == &expand_wdesc_error) ? &expand_word_error
8125 : &expand_word_fatal);
8126 }
8127 if (contains_dollar_at && has_dollar_at)
8128 *contains_dollar_at = 1;
8129
8130 if (tword && (tword->flags & W_HASQUOTEDNULL))
8131 had_quoted_null = 1;
8132
8133 temp = tword->word;
8134 dispose_word_desc (tword);
8135
8136 goto add_string;
8137 break;
8138
8139 case '`': /* Backquoted command substitution. */
8140 {
8141 t_index = sindex++;
8142
8143 temp = string_extract (string, &sindex, "`", SX_REQMATCH);
8144 /* The test of sindex against t_index is to allow bare instances of
8145 ` to pass through, for backwards compatibility. */
8146 if (temp == &extract_string_error || temp == &extract_string_fatal)
8147 {
8148 if (sindex - 1 == t_index)
8149 {
8150 sindex = t_index;
8151 goto add_character;
8152 }
8153 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
8154 free (string);
8155 free (istring);
8156 return ((temp == &extract_string_error) ? &expand_word_error
8157 : &expand_word_fatal);
8158 }
8159
8160 if (expanded_something)
8161 *expanded_something = 1;
8162
8163 if (word->flags & W_NOCOMSUB)
8164 /* sindex + 1 because string[sindex] == '`' */
8165 temp1 = substring (string, t_index, sindex + 1);
8166 else
8167 {
8168 de_backslash (temp);
8169 tword = command_substitute (temp, quoted);
8170 temp1 = tword ? tword->word : (char *)NULL;
8171 if (tword)
8172 dispose_word_desc (tword);
8173 }
8174 FREE (temp);
8175 temp = temp1;
8176 goto dollar_add_string;
8177 }
8178
8179 case '\\':
8180 if (string[sindex + 1] == '\n')
8181 {
8182 sindex += 2;
8183 continue;
8184 }
8185
8186 c = string[++sindex];
8187
8188 if (quoted & Q_HERE_DOCUMENT)
8189 tflag = CBSHDOC;
8190 else if (quoted & Q_DOUBLE_QUOTES)
8191 tflag = CBSDQUOTE;
8192 else
8193 tflag = 0;
8194
8195 /* From Posix discussion on austin-group list: Backslash escaping
8196 a } in ${...} is removed. Issue 0000221 */
8197 if ((quoted & Q_DOLBRACE) && c == RBRACE)
8198 {
8199 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
8200 }
8201 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
8202 {
8203 SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
8204 }
8205 else if (c == 0)
8206 {
8207 c = CTLNUL;
8208 sindex--; /* add_character: label increments sindex */
8209 goto add_character;
8210 }
8211 else
8212 {
8213 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
8214 }
8215
8216 sindex++;
8217add_twochars:
8218 /* BEFORE jumping here, we need to increment sindex if appropriate */
8219 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
8220 DEFAULT_ARRAY_SIZE);
8221 istring[istring_index++] = twochars[0];
8222 istring[istring_index++] = twochars[1];
8223 istring[istring_index] = '\0';
8224
8225 break;
8226
8227 case '"':
8228#if 0
8229 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
8230#else
8231 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8232#endif
8233 goto add_character;
8234
8235 t_index = ++sindex;
8236 temp = string_extract_double_quoted (string, &sindex, 0);
8237
8238 /* If the quotes surrounded the entire string, then the
8239 whole word was quoted. */
8240 quoted_state = (t_index == 1 && string[sindex] == '\0')
8241 ? WHOLLY_QUOTED
8242 : PARTIALLY_QUOTED;
8243
8244 if (temp && *temp)
8245 {
8246 tword = alloc_word_desc ();
8247 tword->word = temp;
8248
8249 temp = (char *)NULL;
8250
8251 has_dollar_at = 0;
8252 /* Need to get W_HASQUOTEDNULL flag through this function. */
8253 list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL);
8254
8255 if (list == &expand_word_error || list == &expand_word_fatal)
8256 {
8257 free (istring);
8258 free (string);
8259 /* expand_word_internal has already freed temp_word->word
8260 for us because of the way it prints error messages. */
8261 tword->word = (char *)NULL;
8262 dispose_word (tword);
8263 return list;
8264 }
8265
8266 dispose_word (tword);
8267
8268 /* "$@" (a double-quoted dollar-at) expands into nothing,
8269 not even a NULL word, when there are no positional
8270 parameters. */
8271 if (list == 0 && has_dollar_at)
8272 {
8273 quoted_dollar_at++;
8274 break;
8275 }
8276
8277 /* If we get "$@", we know we have expanded something, so we
8278 need to remember it for the final split on $IFS. This is
8279 a special case; it's the only case where a quoted string
8280 can expand into more than one word. It's going to come back
8281 from the above call to expand_word_internal as a list with
8282 a single word, in which all characters are quoted and
8283 separated by blanks. What we want to do is to turn it back
8284 into a list for the next piece of code. */
8285 if (list)
8286 dequote_list (list);
8287
8288 if (list && list->word && (list->word->flags & W_HASQUOTEDNULL))
8289 had_quoted_null = 1;
8290
8291 if (has_dollar_at)
8292 {
8293 quoted_dollar_at++;
8294 if (contains_dollar_at)
8295 *contains_dollar_at = 1;
8296 if (expanded_something)
8297 *expanded_something = 1;
8298 }
8299 }
8300 else
8301 {
8302 /* What we have is "". This is a minor optimization. */
8303 FREE (temp);
8304 list = (WORD_LIST *)NULL;
8305 }
8306
8307 /* The code above *might* return a list (consider the case of "$@",
8308 where it returns "$1", "$2", etc.). We can't throw away the
8309 rest of the list, and we have to make sure each word gets added
8310 as quoted. We test on tresult->next: if it is non-NULL, we
8311 quote the whole list, save it to a string with string_list, and
8312 add that string. We don't need to quote the results of this
8313 (and it would be wrong, since that would quote the separators
8314 as well), so we go directly to add_string. */
8315 if (list)
8316 {
8317 if (list->next)
8318 {
8319#if 0
8320 if (quoted_dollar_at && (word->flags & W_NOSPLIT2))
8321 temp = string_list_internal (quote_list (list), " ");
8322 else
8323#endif
8324 /* Testing quoted_dollar_at makes sure that "$@" is
8325 split correctly when $IFS does not contain a space. */
8326 temp = quoted_dollar_at
8327 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES)
8328 : string_list (quote_list (list));
8329 dispose_words (list);
8330 goto add_string;
8331 }
8332 else
8333 {
8334 temp = savestring (list->word->word);
8335 tflag = list->word->flags;
8336 dispose_words (list);
8337
8338 /* If the string is not a quoted null string, we want
8339 to remove any embedded unquoted CTLNUL characters.
8340 We do not want to turn quoted null strings back into
8341 the empty string, though. We do this because we
8342 want to remove any quoted nulls from expansions that
8343 contain other characters. For example, if we have
8344 x"$*"y or "x$*y" and there are no positional parameters,
8345 the $* should expand into nothing. */
8346 /* We use the W_HASQUOTEDNULL flag to differentiate the
8347 cases: a quoted null character as above and when
8348 CTLNUL is contained in the (non-null) expansion
8349 of some variable. We use the had_quoted_null flag to
8350 pass the value through this function to its caller. */
8351 if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
8352 remove_quoted_nulls (temp); /* XXX */
8353 }
8354 }
8355 else
8356 temp = (char *)NULL;
8357
8358 /* We do not want to add quoted nulls to strings that are only
8359 partially quoted; we can throw them away. */
8360 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
8361 continue;
8362
8363 add_quoted_string:
8364
8365 if (temp)
8366 {
8367 temp1 = temp;
8368 temp = quote_string (temp);
8369 free (temp1);
8370 goto add_string;
8371 }
8372 else
8373 {
8374 /* Add NULL arg. */
8375 c = CTLNUL;
8376 sindex--; /* add_character: label increments sindex */
8377 goto add_character;
8378 }
8379
8380 /* break; */
8381
8382 case '\'':
8383#if 0
8384 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (word->flags & W_DQUOTE))
8385#else
8386 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
8387#endif
8388 goto add_character;
8389
8390 t_index = ++sindex;
8391 temp = string_extract_single_quoted (string, &sindex);
8392
8393 /* If the entire STRING was surrounded by single quotes,
8394 then the string is wholly quoted. */
8395 quoted_state = (t_index == 1 && string[sindex] == '\0')
8396 ? WHOLLY_QUOTED
8397 : PARTIALLY_QUOTED;
8398
8399 /* If all we had was '', it is a null expansion. */
8400 if (*temp == '\0')
8401 {
8402 free (temp);
8403 temp = (char *)NULL;
8404 }
8405 else
8406 remove_quoted_escapes (temp); /* ??? */
8407
8408 /* We do not want to add quoted nulls to strings that are only
8409 partially quoted; such nulls are discarded. */
8410 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED))
8411 continue;
8412
8413 /* If we have a quoted null expansion, add a quoted NULL to istring. */
8414 if (temp == 0)
8415 {
8416 c = CTLNUL;
8417 sindex--; /* add_character: label increments sindex */
8418 goto add_character;
8419 }
8420 else
8421 goto add_quoted_string;
8422
8423 /* break; */
8424
8425 default:
8426 /* This is the fix for " $@ " */
8427 add_ifs_character:
8428 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c)))
8429 {
8430 if (string[sindex]) /* from old goto dollar_add_string */
8431 sindex++;
8432 if (c == 0)
8433 {
8434 c = CTLNUL;
8435 goto add_character;
8436 }
8437 else
8438 {
8439#if HANDLE_MULTIBYTE
8440 if (MB_CUR_MAX > 1)
8441 sindex--;
8442
8443 if (MB_CUR_MAX > 1)
8444 {
8445 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
8446 }
8447 else
8448#endif
8449 {
8450 twochars[0] = CTLESC;
8451 twochars[1] = c;
8452 goto add_twochars;
8453 }
8454 }
8455 }
8456
8457 SADD_MBCHAR (temp, string, sindex, string_size);
8458
8459 add_character:
8460 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
8461 DEFAULT_ARRAY_SIZE);
8462 istring[istring_index++] = c;
8463 istring[istring_index] = '\0';
8464
8465 /* Next character. */
8466 sindex++;
8467 }
8468 }
8469
8470finished_with_string:
8471 /* OK, we're ready to return. If we have a quoted string, and
8472 quoted_dollar_at is not set, we do no splitting at all; otherwise
8473 we split on ' '. The routines that call this will handle what to
8474 do if nothing has been expanded. */
8475
8476 /* Partially and wholly quoted strings which expand to the empty
8477 string are retained as an empty arguments. Unquoted strings
8478 which expand to the empty string are discarded. The single
8479 exception is the case of expanding "$@" when there are no
8480 positional parameters. In that case, we discard the expansion. */
8481
8482 /* Because of how the code that handles "" and '' in partially
8483 quoted strings works, we need to make ISTRING into a QUOTED_NULL
8484 if we saw quoting characters, but the expansion was empty.
8485 "" and '' are tossed away before we get to this point when
8486 processing partially quoted strings. This makes "" and $xxx""
8487 equivalent when xxx is unset. We also look to see whether we
8488 saw a quoted null from a ${} expansion and add one back if we
8489 need to. */
8490
8491 /* If we expand to nothing and there were no single or double quotes
8492 in the word, we throw it away. Otherwise, we return a NULL word.
8493 The single exception is for $@ surrounded by double quotes when
8494 there are no positional parameters. In that case, we also throw
8495 the word away. */
8496
8497 if (*istring == '\0')
8498 {
8499 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
8500 {
8501 istring[0] = CTLNUL;
8502 istring[1] = '\0';
8503 tword = make_bare_word (istring);
8504 tword->flags |= W_HASQUOTEDNULL; /* XXX */
8505 list = make_word_list (tword, (WORD_LIST *)NULL);
8506 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8507 tword->flags |= W_QUOTED;
8508 }
8509 /* According to sh, ksh, and Posix.2, if a word expands into nothing
8510 and a double-quoted "$@" appears anywhere in it, then the entire
8511 word is removed. */
8512 else if (quoted_state == UNQUOTED || quoted_dollar_at)
8513 list = (WORD_LIST *)NULL;
8514#if 0
8515 else
8516 {
8517 tword = make_bare_word (istring);
8518 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8519 tword->flags |= W_QUOTED;
8520 list = make_word_list (tword, (WORD_LIST *)NULL);
8521 }
8522#else
8523 else
8524 list = (WORD_LIST *)NULL;
8525#endif
8526 }
8527 else if (word->flags & W_NOSPLIT)
8528 {
8529 tword = make_bare_word (istring);
8530 if (word->flags & W_ASSIGNMENT)
8531 tword->flags |= W_ASSIGNMENT; /* XXX */
8532 if (word->flags & W_COMPASSIGN)
8533 tword->flags |= W_COMPASSIGN; /* XXX */
8534 if (word->flags & W_NOGLOB)
8535 tword->flags |= W_NOGLOB; /* XXX */
8536 if (word->flags & W_NOEXPAND)
8537 tword->flags |= W_NOEXPAND; /* XXX */
8538 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8539 tword->flags |= W_QUOTED;
8540 if (had_quoted_null)
8541 tword->flags |= W_HASQUOTEDNULL;
8542 list = make_word_list (tword, (WORD_LIST *)NULL);
8543 }
8544 else
8545 {
8546 char *ifs_chars;
8547
8548 ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
8549
8550 /* If we have $@, we need to split the results no matter what. If
8551 IFS is unset or NULL, string_list_dollar_at has separated the
8552 positional parameters with a space, so we split on space (we have
8553 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
8554 string_list_dollar_at has separated the positional parameters
8555 with the first character of $IFS, so we split on $IFS. */
8556 if (has_dollar_at && ifs_chars)
8557 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
8558 else
8559 {
8560 tword = make_bare_word (istring);
8561 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
8562 tword->flags |= W_QUOTED;
8563 if (word->flags & W_ASSIGNMENT)
8564 tword->flags |= W_ASSIGNMENT;
8565 if (word->flags & W_COMPASSIGN)
8566 tword->flags |= W_COMPASSIGN;
8567 if (word->flags & W_NOGLOB)
8568 tword->flags |= W_NOGLOB;
8569 if (word->flags & W_NOEXPAND)
8570 tword->flags |= W_NOEXPAND;
8571 if (had_quoted_null)
8572 tword->flags |= W_HASQUOTEDNULL; /* XXX */
8573 list = make_word_list (tword, (WORD_LIST *)NULL);
8574 }
8575 }
8576
8577 free (istring);
8578 return (list);
8579}
8580
8581/* **************************************************************** */
8582/* */
8583/* Functions for Quote Removal */
8584/* */
8585/* **************************************************************** */
8586
8587/* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
8588 backslash quoting rules for within double quotes or a here document. */
8589char *
8590string_quote_removal (string, quoted)
8591 char *string;
8592 int quoted;
8593{
8594 size_t slen;
8595 char *r, *result_string, *temp, *send;
8596 int sindex, tindex, dquote;
8597 unsigned char c;
8598 DECLARE_MBSTATE;
8599
8600 /* The result can be no longer than the original string. */
8601 slen = strlen (string);
8602 send = string + slen;
8603
8604 r = result_string = (char *)xmalloc (slen + 1);
8605
8606 for (dquote = sindex = 0; c = string[sindex];)
8607 {
8608 switch (c)
8609 {
8610 case '\\':
8611 c = string[++sindex];
8612 if (c == 0)
8613 {
8614 *r++ = '\\';
8615 break;
8616 }
8617 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
8618 *r++ = '\\';
8619 /* FALLTHROUGH */
8620
8621 default:
8622 SCOPY_CHAR_M (r, string, send, sindex);
8623 break;
8624
8625 case '\'':
8626 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
8627 {
8628 *r++ = c;
8629 sindex++;
8630 break;
8631 }
8632 tindex = sindex + 1;
8633 temp = string_extract_single_quoted (string, &tindex);
8634 if (temp)
8635 {
8636 strcpy (r, temp);
8637 r += strlen (r);
8638 free (temp);
8639 }
8640 sindex = tindex;
8641 break;
8642
8643 case '"':
8644 dquote = 1 - dquote;
8645 sindex++;
8646 break;
8647 }
8648 }
8649 *r = '\0';
8650 return (result_string);
8651}
8652
8653#if 0
8654/* UNUSED */
8655/* Perform quote removal on word WORD. This allocates and returns a new
8656 WORD_DESC *. */
8657WORD_DESC *
8658word_quote_removal (word, quoted)
8659 WORD_DESC *word;
8660 int quoted;
8661{
8662 WORD_DESC *w;
8663 char *t;
8664
8665 t = string_quote_removal (word->word, quoted);
8666 w = alloc_word_desc ();
8667 w->word = t ? t : savestring ("");
8668 return (w);
8669}
8670
8671/* Perform quote removal on all words in LIST. If QUOTED is non-zero,
8672 the members of the list are treated as if they are surrounded by
8673 double quotes. Return a new list, or NULL if LIST is NULL. */
8674WORD_LIST *
8675word_list_quote_removal (list, quoted)
8676 WORD_LIST *list;
8677 int quoted;
8678{
8679 WORD_LIST *result, *t, *tresult, *e;
8680
8681 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
8682 {
8683 tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
8684#if 0
8685 result = (WORD_LIST *) list_append (result, tresult);
8686#else
8687 if (result == 0)
8688 result = e = tresult;
8689 else
8690 {
8691 e->next = tresult;
8692 while (e->next)
8693 e = e->next;
8694 }
8695#endif
8696 }
8697 return (result);
8698}
8699#endif
8700
8701/*******************************************
8702 * *
8703 * Functions to perform word splitting *
8704 * *
8705 *******************************************/
8706
8707void
8708setifs (v)
8709 SHELL_VAR *v;
8710{
8711 char *t;
8712 unsigned char uc;
8713
8714 ifs_var = v;
8715 ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
8716
8717 /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
8718 handle multibyte chars in IFS */
8719 memset (ifs_cmap, '\0', sizeof (ifs_cmap));
8720 for (t = ifs_value ; t && *t; t++)
8721 {
8722 uc = *t;
8723 ifs_cmap[uc] = 1;
8724 }
8725
8726#if defined (HANDLE_MULTIBYTE)
8727 if (ifs_value == 0)
8728 {
8729 ifs_firstc[0] = '\0';
8730 ifs_firstc_len = 1;
8731 }
8732 else
8733 {
8734 size_t ifs_len;
8735 ifs_len = strnlen (ifs_value, MB_CUR_MAX);
8736 ifs_firstc_len = MBLEN (ifs_value, ifs_len);
8737 if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
8738 {
8739 ifs_firstc[0] = ifs_value[0];
8740 ifs_firstc[1] = '\0';
8741 ifs_firstc_len = 1;
8742 }
8743 else
8744 memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
8745 }
8746#else
8747 ifs_firstc = ifs_value ? *ifs_value : 0;
8748#endif
8749}
8750
8751char *
8752getifs ()
8753{
8754 return ifs_value;
8755}
8756
8757/* This splits a single word into a WORD LIST on $IFS, but only if the word
8758 is not quoted. list_string () performs quote removal for us, even if we
8759 don't do any splitting. */
8760WORD_LIST *
8761word_split (w, ifs_chars)
8762 WORD_DESC *w;
8763 char *ifs_chars;
8764{
8765 WORD_LIST *result;
8766
8767 if (w)
8768 {
8769 char *xifs;
8770
8771 xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
8772 result = list_string (w->word, xifs, w->flags & W_QUOTED);
8773 }
8774 else
8775 result = (WORD_LIST *)NULL;
8776
8777 return (result);
8778}
8779
8780/* Perform word splitting on LIST and return the RESULT. It is possible
8781 to return (WORD_LIST *)NULL. */
8782static WORD_LIST *
8783word_list_split (list)
8784 WORD_LIST *list;
8785{
8786 WORD_LIST *result, *t, *tresult, *e;
8787
8788 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
8789 {
8790 tresult = word_split (t->word, ifs_value);
8791 if (result == 0)
8792 result = e = tresult;
8793 else
8794 {
8795 e->next = tresult;
8796 while (e->next)
8797 e = e->next;
8798 }
8799 }
8800 return (result);
8801}
8802
8803/**************************************************
8804 * *
8805 * Functions to expand an entire WORD_LIST *
8806 * *
8807 **************************************************/
8808
8809/* Do any word-expansion-specific cleanup and jump to top_level */
8810static void
8811exp_jump_to_top_level (v)
8812 int v;
8813{
8814 set_pipestatus_from_exit (last_command_exit_value);
8815
8816 /* Cleanup code goes here. */
8817 expand_no_split_dollar_star = 0; /* XXX */
8818 expanding_redir = 0;
8819 assigning_in_environment = 0;
8820
8821 if (parse_and_execute_level == 0)
8822 top_level_cleanup (); /* from sig.c */
8823
8824 jump_to_top_level (v);
8825}
8826
8827/* Put NLIST (which is a WORD_LIST * of only one element) at the front of
8828 ELIST, and set ELIST to the new list. */
8829#define PREPEND_LIST(nlist, elist) \
8830 do { nlist->next = elist; elist = nlist; } while (0)
8831
8832/* Separate out any initial variable assignments from TLIST. If set -k has
8833 been executed, remove all assignment statements from TLIST. Initial
8834 variable assignments and other environment assignments are placed
8835 on SUBST_ASSIGN_VARLIST. */
8836static WORD_LIST *
8837separate_out_assignments (tlist)
8838 WORD_LIST *tlist;
8839{
8840 register WORD_LIST *vp, *lp;
8841
8842 if (tlist == 0)
8843 return ((WORD_LIST *)NULL);
8844
8845 if (subst_assign_varlist)
8846 dispose_words (subst_assign_varlist); /* Clean up after previous error */
8847
8848 subst_assign_varlist = (WORD_LIST *)NULL;
8849 vp = lp = tlist;
8850
8851 /* Separate out variable assignments at the start of the command.
8852 Loop invariant: vp->next == lp
8853 Loop postcondition:
8854 lp = list of words left after assignment statements skipped
8855 tlist = original list of words
8856 */
8857 while (lp && (lp->word->flags & W_ASSIGNMENT))
8858 {
8859 vp = lp;
8860 lp = lp->next;
8861 }
8862
8863 /* If lp != tlist, we have some initial assignment statements.
8864 We make SUBST_ASSIGN_VARLIST point to the list of assignment
8865 words and TLIST point to the remaining words. */
8866 if (lp != tlist)
8867 {
8868 subst_assign_varlist = tlist;
8869 /* ASSERT(vp->next == lp); */
8870 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
8871 tlist = lp; /* remainder of word list */
8872 }
8873
8874 /* vp == end of variable list */
8875 /* tlist == remainder of original word list without variable assignments */
8876 if (!tlist)
8877 /* All the words in tlist were assignment statements */
8878 return ((WORD_LIST *)NULL);
8879
8880 /* ASSERT(tlist != NULL); */
8881 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
8882
8883 /* If the -k option is in effect, we need to go through the remaining
8884 words, separate out the assignment words, and place them on
8885 SUBST_ASSIGN_VARLIST. */
8886 if (place_keywords_in_env)
8887 {
8888 WORD_LIST *tp; /* tp == running pointer into tlist */
8889
8890 tp = tlist;
8891 lp = tlist->next;
8892
8893 /* Loop Invariant: tp->next == lp */
8894 /* Loop postcondition: tlist == word list without assignment statements */
8895 while (lp)
8896 {
8897 if (lp->word->flags & W_ASSIGNMENT)
8898 {
8899 /* Found an assignment statement, add this word to end of
8900 subst_assign_varlist (vp). */
8901 if (!subst_assign_varlist)
8902 subst_assign_varlist = vp = lp;
8903 else
8904 {
8905 vp->next = lp;
8906 vp = lp;
8907 }
8908
8909 /* Remove the word pointed to by LP from TLIST. */
8910 tp->next = lp->next;
8911 /* ASSERT(vp == lp); */
8912 lp->next = (WORD_LIST *)NULL;
8913 lp = tp->next;
8914 }
8915 else
8916 {
8917 tp = lp;
8918 lp = lp->next;
8919 }
8920 }
8921 }
8922 return (tlist);
8923}
8924
8925#define WEXP_VARASSIGN 0x001
8926#define WEXP_BRACEEXP 0x002
8927#define WEXP_TILDEEXP 0x004
8928#define WEXP_PARAMEXP 0x008
8929#define WEXP_PATHEXP 0x010
8930
8931/* All of the expansions, including variable assignments at the start of
8932 the list. */
8933#define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
8934
8935/* All of the expansions except variable assignments at the start of
8936 the list. */
8937#define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
8938
8939/* All of the `shell expansions': brace expansion, tilde expansion, parameter
8940 expansion, command substitution, arithmetic expansion, word splitting, and
8941 quote removal. */
8942#define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
8943
8944/* Take the list of words in LIST and do the various substitutions. Return
8945 a new list of words which is the expanded list, and without things like
8946 variable assignments. */
8947
8948WORD_LIST *
8949expand_words (list)
8950 WORD_LIST *list;
8951{
8952 return (expand_word_list_internal (list, WEXP_ALL));
8953}
8954
8955/* Same as expand_words (), but doesn't hack variable or environment
8956 variables. */
8957WORD_LIST *
8958expand_words_no_vars (list)
8959 WORD_LIST *list;
8960{
8961 return (expand_word_list_internal (list, WEXP_NOVARS));
8962}
8963
8964WORD_LIST *
8965expand_words_shellexp (list)
8966 WORD_LIST *list;
8967{
8968 return (expand_word_list_internal (list, WEXP_SHELLEXP));
8969}
8970
8971static WORD_LIST *
8972glob_expand_word_list (tlist, eflags)
8973 WORD_LIST *tlist;
8974 int eflags;
8975{
8976 char **glob_array, *temp_string;
8977 register int glob_index;
8978 WORD_LIST *glob_list, *output_list, *disposables, *next;
8979 WORD_DESC *tword;
8980
8981 output_list = disposables = (WORD_LIST *)NULL;
8982 glob_array = (char **)NULL;
8983 while (tlist)
8984 {
8985 /* For each word, either globbing is attempted or the word is
8986 added to orig_list. If globbing succeeds, the results are
8987 added to orig_list and the word (tlist) is added to the list
8988 of disposable words. If globbing fails and failed glob
8989 expansions are left unchanged (the shell default), the
8990 original word is added to orig_list. If globbing fails and
8991 failed glob expansions are removed, the original word is
8992 added to the list of disposable words. orig_list ends up
8993 in reverse order and requires a call to REVERSE_LIST to
8994 be set right. After all words are examined, the disposable
8995 words are freed. */
8996 next = tlist->next;
8997
8998 /* If the word isn't an assignment and contains an unquoted
8999 pattern matching character, then glob it. */
9000 if ((tlist->word->flags & W_NOGLOB) == 0 &&
9001 unquoted_glob_pattern_p (tlist->word->word))
9002 {
9003 glob_array = shell_glob_filename (tlist->word->word);
9004
9005 /* Handle error cases.
9006 I don't think we should report errors like "No such file
9007 or directory". However, I would like to report errors
9008 like "Read failed". */
9009
9010 if (glob_array == 0 || GLOB_FAILED (glob_array))
9011 {
9012 glob_array = (char **)xmalloc (sizeof (char *));
9013 glob_array[0] = (char *)NULL;
9014 }
9015
9016 /* Dequote the current word in case we have to use it. */
9017 if (glob_array[0] == NULL)
9018 {
9019 temp_string = dequote_string (tlist->word->word);
9020 free (tlist->word->word);
9021 tlist->word->word = temp_string;
9022 }
9023
9024 /* Make the array into a word list. */
9025 glob_list = (WORD_LIST *)NULL;
9026 for (glob_index = 0; glob_array[glob_index]; glob_index++)
9027 {
9028 tword = make_bare_word (glob_array[glob_index]);
9029 tword->flags |= W_GLOBEXP; /* XXX */
9030 glob_list = make_word_list (tword, glob_list);
9031 }
9032
9033 if (glob_list)
9034 {
9035 output_list = (WORD_LIST *)list_append (glob_list, output_list);
9036 PREPEND_LIST (tlist, disposables);
9037 }
9038 else if (fail_glob_expansion != 0)
9039 {
9040 report_error (_("no match: %s"), tlist->word->word);
9041 exp_jump_to_top_level (DISCARD);
9042 }
9043 else if (allow_null_glob_expansion == 0)
9044 {
9045 /* Failed glob expressions are left unchanged. */
9046 PREPEND_LIST (tlist, output_list);
9047 }
9048 else
9049 {
9050 /* Failed glob expressions are removed. */
9051 PREPEND_LIST (tlist, disposables);
9052 }
9053 }
9054 else
9055 {
9056 /* Dequote the string. */
9057 temp_string = dequote_string (tlist->word->word);
9058 free (tlist->word->word);
9059 tlist->word->word = temp_string;
9060 PREPEND_LIST (tlist, output_list);
9061 }
9062
9063 strvec_dispose (glob_array);
9064 glob_array = (char **)NULL;
9065
9066 tlist = next;
9067 }
9068
9069 if (disposables)
9070 dispose_words (disposables);
9071
9072 if (output_list)
9073 output_list = REVERSE_LIST (output_list, WORD_LIST *);
9074
9075 return (output_list);
9076}
9077
9078#if defined (BRACE_EXPANSION)
9079static WORD_LIST *
9080brace_expand_word_list (tlist, eflags)
9081 WORD_LIST *tlist;
9082 int eflags;
9083{
9084 register char **expansions;
9085 char *temp_string;
9086 WORD_LIST *disposables, *output_list, *next;
9087 WORD_DESC *w;
9088 int eindex;
9089
9090 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
9091 {
9092 next = tlist->next;
9093
9094 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
9095 {
9096/*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
9097 PREPEND_LIST (tlist, output_list);
9098 continue;
9099 }
9100
9101 /* Only do brace expansion if the word has a brace character. If
9102 not, just add the word list element to BRACES and continue. In
9103 the common case, at least when running shell scripts, this will
9104 degenerate to a bunch of calls to `mbschr', and then what is
9105 basically a reversal of TLIST into BRACES, which is corrected
9106 by a call to REVERSE_LIST () on BRACES when the end of TLIST
9107 is reached. */
9108 if (mbschr (tlist->word->word, LBRACE))
9109 {
9110 expansions = brace_expand (tlist->word->word);
9111
9112 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
9113 {
9114 w = make_word (temp_string);
9115 /* If brace expansion didn't change the word, preserve
9116 the flags. We may want to preserve the flags
9117 unconditionally someday -- XXX */
9118 if (STREQ (temp_string, tlist->word->word))
9119 w->flags = tlist->word->flags;
9120 output_list = make_word_list (w, output_list);
9121 free (expansions[eindex]);
9122 }
9123 free (expansions);
9124
9125 /* Add TLIST to the list of words to be freed after brace
9126 expansion has been performed. */
9127 PREPEND_LIST (tlist, disposables);
9128 }
9129 else
9130 PREPEND_LIST (tlist, output_list);
9131 }
9132
9133 if (disposables)
9134 dispose_words (disposables);
9135
9136 if (output_list)
9137 output_list = REVERSE_LIST (output_list, WORD_LIST *);
9138
9139 return (output_list);
9140}
9141#endif
9142
9143#if defined (ARRAY_VARS)
9144/* Take WORD, a compound associative array assignment, and internally run
9145 'declare -A w', where W is the variable name portion of WORD. */
9146static int
9147make_internal_declare (word, option)
9148 char *word;
9149 char *option;
9150{
9151 int t;
9152 WORD_LIST *wl;
9153 WORD_DESC *w;
9154
9155 w = make_word (word);
9156
9157 t = assignment (w->word, 0);
9158 w->word[t] = '\0';
9159
9160 wl = make_word_list (w, (WORD_LIST *)NULL);
9161 wl = make_word_list (make_word (option), wl);
9162
9163 return (declare_builtin (wl));
9164}
9165#endif
9166
9167static WORD_LIST *
9168shell_expand_word_list (tlist, eflags)
9169 WORD_LIST *tlist;
9170 int eflags;
9171{
9172 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list;
9173 int expanded_something, has_dollar_at;
9174 char *temp_string;
9175
9176 /* We do tilde expansion all the time. This is what 1003.2 says. */
9177 new_list = (WORD_LIST *)NULL;
9178 for (orig_list = tlist; tlist; tlist = next)
9179 {
9180 temp_string = tlist->word->word;
9181
9182 next = tlist->next;
9183
9184#if defined (ARRAY_VARS)
9185 /* If this is a compound array assignment to a builtin that accepts
9186 such assignments (e.g., `declare'), take the assignment and perform
9187 it separately, handling the semantics of declarations inside shell
9188 functions. This avoids the double-evaluation of such arguments,
9189 because `declare' does some evaluation of compound assignments on
9190 its own. */
9191 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
9192 {
9193 int t;
9194
9195 if (tlist->word->flags & W_ASSIGNASSOC)
9196 make_internal_declare (tlist->word->word, "-A");
9197
9198 t = do_word_assignment (tlist->word, 0);
9199 if (t == 0)
9200 {
9201 last_command_exit_value = EXECUTION_FAILURE;
9202 exp_jump_to_top_level (DISCARD);
9203 }
9204
9205 /* Now transform the word as ksh93 appears to do and go on */
9206 t = assignment (tlist->word->word, 0);
9207 tlist->word->word[t] = '\0';
9208 tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC);
9209 }
9210#endif
9211
9212 expanded_something = 0;
9213 expanded = expand_word_internal
9214 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
9215
9216 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
9217 {
9218 /* By convention, each time this error is returned,
9219 tlist->word->word has already been freed. */
9220 tlist->word->word = (char *)NULL;
9221
9222 /* Dispose our copy of the original list. */
9223 dispose_words (orig_list);
9224 /* Dispose the new list we're building. */
9225 dispose_words (new_list);
9226
9227 last_command_exit_value = EXECUTION_FAILURE;
9228 if (expanded == &expand_word_error)
9229 exp_jump_to_top_level (DISCARD);
9230 else
9231 exp_jump_to_top_level (FORCE_EOF);
9232 }
9233
9234 /* Don't split words marked W_NOSPLIT. */
9235 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
9236 {
9237 temp_list = word_list_split (expanded);
9238 dispose_words (expanded);
9239 }
9240 else
9241 {
9242 /* If no parameter expansion, command substitution, process
9243 substitution, or arithmetic substitution took place, then
9244 do not do word splitting. We still have to remove quoted
9245 null characters from the result. */
9246 word_list_remove_quoted_nulls (expanded);
9247 temp_list = expanded;
9248 }
9249
9250 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
9251 new_list = (WORD_LIST *)list_append (expanded, new_list);
9252 }
9253
9254 if (orig_list)
9255 dispose_words (orig_list);
9256
9257 if (new_list)
9258 new_list = REVERSE_LIST (new_list, WORD_LIST *);
9259
9260 return (new_list);
9261}
9262
9263/* The workhorse for expand_words () and expand_words_no_vars ().
9264 First arg is LIST, a WORD_LIST of words.
9265 Second arg EFLAGS is a flags word controlling which expansions are
9266 performed.
9267
9268 This does all of the substitutions: brace expansion, tilde expansion,
9269 parameter expansion, command substitution, arithmetic expansion,
9270 process substitution, word splitting, and pathname expansion, according
9271 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
9272 set, or for which no expansion is done, do not undergo word splitting.
9273 Words with the W_NOGLOB bit set do not undergo pathname expansion. */
9274static WORD_LIST *
9275expand_word_list_internal (list, eflags)
9276 WORD_LIST *list;
9277 int eflags;
9278{
9279 WORD_LIST *new_list, *temp_list;
9280 int tint;
9281
9282 if (list == 0)
9283 return ((WORD_LIST *)NULL);
9284
9285 garglist = new_list = copy_word_list (list);
9286 if (eflags & WEXP_VARASSIGN)
9287 {
9288 garglist = new_list = separate_out_assignments (new_list);
9289 if (new_list == 0)
9290 {
9291 if (subst_assign_varlist)
9292 {
9293 /* All the words were variable assignments, so they are placed
9294 into the shell's environment. */
9295 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
9296 {
9297 this_command_name = (char *)NULL; /* no arithmetic errors */
9298 tint = do_word_assignment (temp_list->word, 0);
9299 /* Variable assignment errors in non-interactive shells
9300 running in Posix.2 mode cause the shell to exit. */
9301 if (tint == 0)
9302 {
9303 last_command_exit_value = EXECUTION_FAILURE;
9304 if (interactive_shell == 0 && posixly_correct)
9305 exp_jump_to_top_level (FORCE_EOF);
9306 else
9307 exp_jump_to_top_level (DISCARD);
9308 }
9309 }
9310 dispose_words (subst_assign_varlist);
9311 subst_assign_varlist = (WORD_LIST *)NULL;
9312 }
9313 return ((WORD_LIST *)NULL);
9314 }
9315 }
9316
9317 /* Begin expanding the words that remain. The expansions take place on
9318 things that aren't really variable assignments. */
9319
9320#if defined (BRACE_EXPANSION)
9321 /* Do brace expansion on this word if there are any brace characters
9322 in the string. */
9323 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
9324 new_list = brace_expand_word_list (new_list, eflags);
9325#endif /* BRACE_EXPANSION */
9326
9327 /* Perform the `normal' shell expansions: tilde expansion, parameter and
9328 variable substitution, command substitution, arithmetic expansion,
9329 and word splitting. */
9330 new_list = shell_expand_word_list (new_list, eflags);
9331
9332 /* Okay, we're almost done. Now let's just do some filename
9333 globbing. */
9334 if (new_list)
9335 {
9336 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
9337 /* Glob expand the word list unless globbing has been disabled. */
9338 new_list = glob_expand_word_list (new_list, eflags);
9339 else
9340 /* Dequote the words, because we're not performing globbing. */
9341 new_list = dequote_list (new_list);
9342 }
9343
9344 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
9345 {
9346 sh_wassign_func_t *assign_func;
9347 int is_special_builtin, is_builtin_or_func;
9348
9349 /* If the remainder of the words expand to nothing, Posix.2 requires
9350 that the variable and environment assignments affect the shell's
9351 environment. */
9352 assign_func = new_list ? assign_in_env : do_word_assignment;
9353 tempenv_assign_error = 0;
9354
9355 is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
9356 /* Posix says that special builtins exit if a variable assignment error
9357 occurs in an assignment preceding it. */
9358 is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
9359
9360 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
9361 {
9362 this_command_name = (char *)NULL;
9363 assigning_in_environment = (assign_func == assign_in_env);
9364 tint = (*assign_func) (temp_list->word, is_builtin_or_func);
9365 assigning_in_environment = 0;
9366 /* Variable assignment errors in non-interactive shells running
9367 in Posix.2 mode cause the shell to exit. */
9368 if (tint == 0)
9369 {
9370 if (assign_func == do_word_assignment)
9371 {
9372 last_command_exit_value = EXECUTION_FAILURE;
9373 if (interactive_shell == 0 && posixly_correct && is_special_builtin)
9374 exp_jump_to_top_level (FORCE_EOF);
9375 else
9376 exp_jump_to_top_level (DISCARD);
9377 }
9378 else
9379 tempenv_assign_error++;
9380 }
9381 }
9382
9383 dispose_words (subst_assign_varlist);
9384 subst_assign_varlist = (WORD_LIST *)NULL;
9385 }
9386
9387#if 0
9388 tint = list_length (new_list) + 1;
9389 RESIZE_MALLOCED_BUFFER (glob_argv_flags, 0, tint, glob_argv_flags_size, 16);
9390 for (tint = 0, temp_list = new_list; temp_list; temp_list = temp_list->next)
9391 glob_argv_flags[tint++] = (temp_list->word->flags & W_GLOBEXP) ? '1' : '0';
9392 glob_argv_flags[tint] = '\0';
9393#endif
9394
9395 return (new_list);
9396}