improve of cmpl.
[bush.git] / mydoc / vname / subst.c
blobf6e84ad57b1d9167d2e51f51ea9a5d201990c842
1 /* subst.c -- The part of the shell that does parameter, command, arithmetic,
2 and globbing substitutions. */
4 /* ``Have a little faith, there's magic in the night. You ain't a
5 beauty, but, hey, you're alright.'' */
7 /* Copyright (C) 1987-2020 Free Software Foundation, Inc.
9 This file is part of GNU Bush, the Bourne Again SHell.
11 Bush 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.
16 Bush 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.
21 You should have received a copy of the GNU General Public License
22 along with Bush. If not, see <http://www.gnu.org/licenses/>.
25 #include "config.h"
27 #include "bushtypes.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>
36 #if defined (HAVE_UNISTD_H)
37 # include <unistd.h>
38 #endif
40 #define NEED_FPURGE_DECL
42 #include "bushansi.h"
43 #include "posixstat.h"
44 #include "bushintl.h"
46 #include "shell.h"
47 #include "lxrgmr/parser.h"
48 #include "flags.h"
49 #include "jobs.h"
50 #include "runner/execute_cmd.h"
51 #include "filecntl.h"
52 #include "trap.h"
53 #include "impl/pathexp.h"
54 #include "mailcheck.h"
56 #include "shmbutil.h"
57 #if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
58 # include <mbstr.h> /* mbschr */
59 #endif
60 #include "typemax.h"
62 #include "builtins/getopt.h"
63 #include "builtins/common.h"
65 #include "builtins/builtext.h"
67 #include <tilde/tilde.h>
68 #include <glob/strmatch.h>
70 #if !defined (errno)
71 extern int errno;
72 #endif /* !errno */
74 /* The size that strings change by. */
75 #define DEFAULT_INITIAL_ARRAY_SIZE 112
76 #define DEFAULT_ARRAY_SIZE 128
78 /* Variable types. */
79 #define VT_VARIABLE 0
80 #define VT_POSPARMS 1
81 #define VT_ARRAYVAR 2
82 #define VT_ARRAYMEMBER 3
83 #define VT_ASSOCVAR 4
85 #define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
87 /* Flags for quoted_strchr */
88 #define ST_BACKSL 0x01
89 #define ST_CTLESC 0x02
90 #define ST_SQUOTE 0x04 /* unused yet */
91 #define ST_DQUOTE 0x08 /* unused yet */
93 /* These defs make it easier to use the editor. */
94 #define LBRACE '{'
95 #define RBRACE '}'
96 #define LPAREN '('
97 #define RPAREN ')'
98 #define LBRACK '['
99 #define RBRACK ']'
101 #if defined (HANDLE_MULTIBYTE)
102 #define WLPAREN L'('
103 #define WRPAREN L')'
104 #endif
106 #define DOLLAR_AT_STAR(c) ((c) == '@' || (c) == '*')
107 #define STR_DOLLAR_AT_STAR(s) (DOLLAR_AT_STAR ((s)[0]) && (s)[1] == '\0')
109 /* Evaluates to 1 if C is one of the shell's special parameters whose length
110 can be taken, but is also one of the special expansion characters. */
111 #define VALID_SPECIAL_LENGTH_PARAM(c) \
112 ((c) == '-' || (c) == '?' || (c) == '#' || (c) == '@')
114 /* Evaluates to 1 if C is one of the shell's special parameters for which an
115 indirect variable reference may be made. */
116 #define VALID_INDIR_PARAM(c) \
117 ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
119 /* Evaluates to 1 if C is one of the OP characters that follows the parameter
120 in ${parameter[:]OPword}. */
121 #define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)
123 /* Evaluates to 1 if this is one of the shell's special variables. */
124 #define SPECIAL_VAR(name, wi) \
125 (*name && ((DIGIT (*name) && all_digits (name)) || \
126 (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \
127 (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))))
129 /* This can be used by all of the *_extract_* functions that have a similar
130 structure. It can't just be wrapped in a do...while(0) loop because of
131 the embedded `break'. The dangling else accommodates a trailing semicolon;
132 we could also put in a do ; while (0) */
134 #define CHECK_STRING_OVERRUN(oind, ind, len, ch) \
135 if (ind >= len) \
137 oind = len; \
138 ch = 0; \
139 break; \
141 else \
143 /* An expansion function that takes a string and a quoted flag and returns
144 a WORD_LIST *. Used as the type of the third argument to
145 expand_string_if_necessary(). */
146 typedef WORD_LIST *EXPFUNC PARAMS((char *, int));
148 /* Process ID of the last command executed within command substitution. */
149 pid_t last_command_subst_pid = NO_PID;
150 pid_t current_command_subst_pid = NO_PID;
152 /* Variables used to keep track of the characters in IFS. */
153 SHELL_VAR *ifs_var;
154 char *ifs_value;
155 unsigned char ifs_cmap[UCHAR_MAX + 1];
156 int ifs_is_set, ifs_is_null;
158 #if defined (HANDLE_MULTIBYTE)
159 unsigned char ifs_firstc[MB_LEN_MAX];
160 size_t ifs_firstc_len;
161 #else
162 unsigned char ifs_firstc;
163 #endif
165 /* If non-zero, command substitution inherits the value of errexit option */
166 int inherit_errexit = 0;
168 /* Sentinel to tell when we are performing variable assignments preceding a
169 command name and putting them into the environment. Used to make sure
170 we use the temporary environment when looking up variable values. */
171 int assigning_in_environment;
173 /* Used to hold a list of variable assignments preceding a command. Global
174 so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
175 SIGCHLD trap and so it can be saved and restored by the trap handlers. */
176 WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
178 /* Tell the expansion functions to not longjmp back to top_level on fatal
179 errors. Enabled when doing completion and prompt string expansion. */
180 int no_longjmp_on_fatal_error = 0;
182 /* Non-zero means to allow unmatched globbed filenames to expand to
183 a null file. */
184 int allow_null_glob_expansion;
186 /* Non-zero means to throw an error when globbing fails to match anything. */
187 int fail_glob_expansion;
189 /* Extern functions and variables from different files. */
190 extern struct fd_bitmap *current_fds_to_close;
191 extern int wordexp_only;
193 #if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION)
194 extern PROCESS *last_procsub_child;
195 #endif
197 #if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)
198 extern wchar_t *wcsdup PARAMS((const wchar_t *));
199 #endif
201 #if 0
202 /* Variables to keep track of which words in an expanded word list (the
203 output of expand_word_list_internal) are the result of globbing
204 expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c.
205 (CURRENTLY UNUSED). */
206 char *glob_argv_flags;
207 static int glob_argv_flags_size;
208 #endif
210 static WORD_LIST *cached_quoted_dollar_at = 0;
212 /* Distinguished error values to return from expansion functions */
213 static WORD_LIST expand_word_error, expand_word_fatal;
214 static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
215 static char expand_param_error, expand_param_fatal, expand_param_unset;
216 static char extract_string_error, extract_string_fatal;
218 /* Set by expand_word_unsplit and several of the expand_string_XXX functions;
219 used to inhibit splitting and re-joining $* on $IFS, primarily when doing
220 assignment statements. The idea is that if we're in a context where this
221 is set, we're not going to be performing word splitting, so we use the same
222 rules to expand $* as we would if it appeared within double quotes. */
223 static int expand_no_split_dollar_star = 0;
225 /* A WORD_LIST of words to be expanded by expand_word_list_internal,
226 without any leading variable assignments. */
227 static WORD_LIST *garglist = (WORD_LIST *)NULL;
229 static char *quoted_substring PARAMS((char *, int, int));
230 static int quoted_strlen PARAMS((char *));
231 static char *quoted_strchr PARAMS((char *, int, int));
233 static char *expand_string_if_necessary PARAMS((char *, int, EXPFUNC *));
234 static inline char *expand_string_to_string_internal PARAMS((char *, int, EXPFUNC *));
235 static WORD_LIST *call_expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *));
236 static WORD_LIST *expand_string_internal PARAMS((char *, int));
237 static WORD_LIST *expand_string_leave_quoted PARAMS((char *, int));
238 static WORD_LIST *expand_string_for_rhs PARAMS((char *, int, int, int, int *, int *));
239 static WORD_LIST *expand_string_for_pat PARAMS((char *, int, int *, int *));
241 static char *quote_escapes_internal PARAMS((const char *, int));
243 static WORD_LIST *list_quote_escapes PARAMS((WORD_LIST *));
244 static WORD_LIST *list_dequote_escapes PARAMS((WORD_LIST *));
246 static char *make_quoted_char PARAMS((int));
247 static WORD_LIST *quote_list PARAMS((WORD_LIST *));
249 static int unquoted_substring PARAMS((char *, char *));
250 static int unquoted_member PARAMS((int, char *));
252 #if defined (ARRAY_VARS)
253 static SHELL_VAR *do_compound_assignment PARAMS((char *, char *, int));
254 #endif
255 static int do_assignment_internal PARAMS((const WORD_DESC *, int));
257 static char *string_extract_verbatim PARAMS((char *, size_t, int *, char *, int));
258 static char *string_extract PARAMS((char *, int *, char *, int));
259 static char *string_extract_double_quoted PARAMS((char *, int *, int));
260 static inline char *string_extract_single_quoted PARAMS((char *, int *));
261 static inline int skip_single_quoted PARAMS((const char *, size_t, int, int));
262 static int skip_double_quoted PARAMS((char *, size_t, int, int));
263 static char *extract_delimited_string PARAMS((char *, int *, char *, char *, char *, int));
264 static char *extract_dollar_brace_string PARAMS((char *, int *, int, int));
265 static int skip_matched_pair PARAMS((const char *, int, int, int, int));
267 static char *pos_params PARAMS((char *, int, int, int, int));
269 static unsigned char *mb_getcharlens PARAMS((char *, int));
271 static char *remove_upattern PARAMS((char *, char *, int));
272 #if defined (HANDLE_MULTIBYTE)
273 static wchar_t *remove_wpattern PARAMS((wchar_t *, size_t, wchar_t *, int));
274 #endif
275 static char *remove_pattern PARAMS((char *, char *, int));
277 static int match_upattern PARAMS((char *, char *, int, char **, char **));
278 #if defined (HANDLE_MULTIBYTE)
279 static int match_wpattern PARAMS((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
280 #endif
281 static int match_pattern PARAMS((char *, char *, int, char **, char **));
282 static int getpatspec PARAMS((int, char *));
283 static char *getpattern PARAMS((char *, int, int));
284 static char *variable_remove_pattern PARAMS((char *, char *, int, int));
285 static char *list_remove_pattern PARAMS((WORD_LIST *, char *, int, int, int));
286 static char *parameter_list_remove_pattern PARAMS((int, char *, int, int));
287 #ifdef ARRAY_VARS
288 static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int));
289 #endif
290 static char *parameter_brace_remove_pattern PARAMS((char *, char *, int, char *, int, int, int));
292 static char *string_var_assignment PARAMS((SHELL_VAR *, char *));
293 #if defined (ARRAY_VARS)
294 static char *array_var_assignment PARAMS((SHELL_VAR *, int, int, int));
295 #endif
296 static char *pos_params_assignment PARAMS((WORD_LIST *, int, int));
297 static char *string_transform PARAMS((int, SHELL_VAR *, char *));
298 static char *list_transform PARAMS((int, SHELL_VAR *, WORD_LIST *, int, int));
299 static char *parameter_list_transform PARAMS((int, int, int));
300 #if defined ARRAY_VARS
301 static char *array_transform PARAMS((int, SHELL_VAR *, int, int));
302 #endif
303 static char *parameter_brace_transform PARAMS((char *, char *, int, char *, int, int, int, int));
304 static int valid_parameter_transform PARAMS((char *));
306 static char *process_substitute PARAMS((char *, int));
308 static char *read_comsub PARAMS((int, int, int, int *));
310 #ifdef ARRAY_VARS
311 static arrayind_t array_length_reference PARAMS((char *));
312 #endif
314 static int valid_brace_expansion_word PARAMS((char *, int));
315 static int chk_atstar PARAMS((char *, int, int, int *, int *));
316 static int chk_arithsub PARAMS((const char *, int));
318 static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, arrayind_t *));
319 static char *parameter_brace_find_indir PARAMS((char *, int, int, int));
320 static WORD_DESC *parameter_brace_expand_indir PARAMS((char *, int, int, int, int *, int *));
321 static WORD_DESC *parameter_brace_expand_rhs PARAMS((char *, char *, int, int, int, int *, int *));
322 static void parameter_brace_expand_error PARAMS((char *, char *, int));
324 static int valid_length_expression PARAMS((char *));
325 static intmax_t parameter_brace_expand_length PARAMS((char *));
327 static char *skiparith PARAMS((char *, int));
328 static int verify_substring_values PARAMS((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
329 static int get_var_and_type PARAMS((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **));
330 static char *mb_substring PARAMS((char *, int, int));
331 static char *parameter_brace_substring PARAMS((char *, char *, int, char *, int, int, int));
333 static int shouldexp_replacement PARAMS((char *));
335 static char *pos_params_pat_subst PARAMS((char *, char *, char *, int));
337 static char *parameter_brace_patsub PARAMS((char *, char *, int, char *, int, int, int));
339 static char *pos_params_casemod PARAMS((char *, char *, int, int));
340 static char *parameter_brace_casemod PARAMS((char *, char *, int, int, char *, int, int, int));
342 static WORD_DESC *parameter_brace_expand PARAMS((char *, int *, int, int, int *, int *));
343 static WORD_DESC *param_expand PARAMS((char *, int *, int, int *, int *, int *, int *, int));
345 static WORD_LIST *expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *));
347 static WORD_LIST *word_list_split PARAMS((WORD_LIST *));
349 static void exp_jump_to_top_level PARAMS((int));
351 static WORD_LIST *separate_out_assignments PARAMS((WORD_LIST *));
352 static WORD_LIST *glob_expand_word_list PARAMS((WORD_LIST *, int));
353 #ifdef BRACE_EXPANSION
354 static WORD_LIST *brace_expand_word_list PARAMS((WORD_LIST *, int));
355 #endif
356 #if defined (ARRAY_VARS)
357 static int make_internal_declare PARAMS((char *, char *, char *));
358 static void expand_compound_assignment_word PARAMS((WORD_LIST *, int));
359 static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *));
360 #endif
361 static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int));
362 static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int));
364 /* **************************************************************** */
365 /* */
366 /* Utility Functions */
367 /* */
368 /* **************************************************************** */
370 #if defined (DEBUG)
371 void
372 dump_word_flags (flags)
373 int flags;
375 int f;
377 f = flags;
378 fprintf (stderr, "%d -> ", f);
379 if (f & W_ARRAYIND)
381 f &= ~W_ARRAYIND;
382 fprintf (stderr, "W_ARRAYIND%s", f ? "|" : "");
384 if (f & W_ASSIGNASSOC)
386 f &= ~W_ASSIGNASSOC;
387 fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
389 if (f & W_ASSIGNARRAY)
391 f &= ~W_ASSIGNARRAY;
392 fprintf (stderr, "W_ASSIGNARRAY%s", f ? "|" : "");
394 if (f & W_SAWQUOTEDNULL)
396 f &= ~W_SAWQUOTEDNULL;
397 fprintf (stderr, "W_SAWQUOTEDNULL%s", f ? "|" : "");
399 if (f & W_NOPROCSUB)
401 f &= ~W_NOPROCSUB;
402 fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
404 if (f & W_DQUOTE)
406 f &= ~W_DQUOTE;
407 fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
409 if (f & W_HASQUOTEDNULL)
411 f &= ~W_HASQUOTEDNULL;
412 fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
414 if (f & W_ASSIGNARG)
416 f &= ~W_ASSIGNARG;
417 fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
419 if (f & W_ASSNBLTIN)
421 f &= ~W_ASSNBLTIN;
422 fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
424 if (f & W_ASSNGLOBAL)
426 f &= ~W_ASSNGLOBAL;
427 fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : "");
429 if (f & W_COMPASSIGN)
431 f &= ~W_COMPASSIGN;
432 fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
434 if (f & W_EXPANDRHS)
436 f &= ~W_EXPANDRHS;
437 fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : "");
439 if (f & W_ITILDE)
441 f &= ~W_ITILDE;
442 fprintf (stderr, "W_ITILDE%s", f ? "|" : "");
444 if (f & W_NOTILDE)
446 f &= ~W_NOTILDE;
447 fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
449 if (f & W_ASSIGNRHS)
451 f &= ~W_ASSIGNRHS;
452 fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
454 if (f & W_NOASSNTILDE)
456 f &= ~W_NOASSNTILDE;
457 fprintf (stderr, "W_NOASSNTILDE%s", f ? "|" : "");
459 if (f & W_NOCOMSUB)
461 f &= ~W_NOCOMSUB;
462 fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
464 if (f & W_DOLLARSTAR)
466 f &= ~W_DOLLARSTAR;
467 fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : "");
469 if (f & W_DOLLARAT)
471 f &= ~W_DOLLARAT;
472 fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
474 if (f & W_TILDEEXP)
476 f &= ~W_TILDEEXP;
477 fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
479 if (f & W_NOSPLIT2)
481 f &= ~W_NOSPLIT2;
482 fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
484 if (f & W_NOSPLIT)
486 f &= ~W_NOSPLIT;
487 fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
489 if (f & W_NOBRACE)
491 f &= ~W_NOBRACE;
492 fprintf (stderr, "W_NOBRACE%s", f ? "|" : "");
494 if (f & W_NOGLOB)
496 f &= ~W_NOGLOB;
497 fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
499 if (f & W_SPLITSPACE)
501 f &= ~W_SPLITSPACE;
502 fprintf (stderr, "W_SPLITSPACE%s", f ? "|" : "");
504 if (f & W_ASSIGNMENT)
506 f &= ~W_ASSIGNMENT;
507 fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
509 if (f & W_QUOTED)
511 f &= ~W_QUOTED;
512 fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
514 if (f & W_HASDOLLAR)
516 f &= ~W_HASDOLLAR;
517 fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
519 if (f & W_COMPLETE)
521 f &= ~W_COMPLETE;
522 fprintf (stderr, "W_COMPLETE%s", f ? "|" : "");
524 if (f & W_CHKLOCAL)
526 f &= ~W_CHKLOCAL;
527 fprintf (stderr, "W_CHKLOCAL%s", f ? "|" : "");
529 if (f & W_FORCELOCAL)
531 f &= ~W_FORCELOCAL;
532 fprintf (stderr, "W_FORCELOCAL%s", f ? "|" : "");
535 fprintf (stderr, "\n");
536 fflush (stderr);
538 #endif
540 #ifdef INCLUDE_UNUSED
541 static char *
542 quoted_substring (string, start, end)
543 char *string;
544 int start, end;
546 register int len, l;
547 register char *result, *s, *r;
549 len = end - start;
551 /* Move to string[start], skipping quoted characters. */
552 for (s = string, l = 0; *s && l < start; )
554 if (*s == CTLESC)
556 s++;
557 continue;
559 l++;
560 if (*s == 0)
561 break;
564 r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */
566 /* Copy LEN characters, including quote characters. */
567 s = string + l;
568 for (l = 0; l < len; s++)
570 if (*s == CTLESC)
571 *r++ = *s++;
572 *r++ = *s;
573 l++;
574 if (*s == 0)
575 break;
577 *r = '\0';
578 return result;
580 #endif
582 #ifdef INCLUDE_UNUSED
583 /* Return the length of S, skipping over quoted characters */
584 static int
585 quoted_strlen (s)
586 char *s;
588 register char *p;
589 int i;
591 i = 0;
592 for (p = s; *p; p++)
594 if (*p == CTLESC)
596 p++;
597 if (*p == 0)
598 return (i + 1);
600 i++;
603 return i;
605 #endif
607 #ifdef INCLUDE_UNUSED
608 /* Find the first occurrence of character C in string S, obeying shell
609 quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
610 characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters
611 escaped with CTLESC are skipped. */
612 static char *
613 quoted_strchr (s, c, flags)
614 char *s;
615 int c, flags;
617 register char *p;
619 for (p = s; *p; p++)
621 if (((flags & ST_BACKSL) && *p == '\\')
622 || ((flags & ST_CTLESC) && *p == CTLESC))
624 p++;
625 if (*p == '\0')
626 return ((char *)NULL);
627 continue;
629 else if (*p == c)
630 return p;
632 return ((char *)NULL);
635 /* Return 1 if CHARACTER appears in an unquoted portion of
636 STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */
637 static int
638 unquoted_member (character, string)
639 int character;
640 char *string;
642 size_t slen;
643 int sindex, c;
644 DECLARE_MBSTATE;
646 slen = strlen (string);
647 sindex = 0;
648 while (c = string[sindex])
650 if (c == character)
651 return (1);
653 switch (c)
655 default:
656 ADVANCE_CHAR (string, slen, sindex);
657 break;
659 case '\\':
660 sindex++;
661 if (string[sindex])
662 ADVANCE_CHAR (string, slen, sindex);
663 break;
665 case '\'':
666 sindex = skip_single_quoted (string, slen, ++sindex, 0);
667 break;
669 case '"':
670 sindex = skip_double_quoted (string, slen, ++sindex, 0);
671 break;
674 return (0);
677 /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
678 static int
679 unquoted_substring (substr, string)
680 char *substr, *string;
682 size_t slen;
683 int sindex, c, sublen;
684 DECLARE_MBSTATE;
686 if (substr == 0 || *substr == '\0')
687 return (0);
689 slen = strlen (string);
690 sublen = strlen (substr);
691 for (sindex = 0; c = string[sindex]; )
693 if (STREQN (string + sindex, substr, sublen))
694 return (1);
696 switch (c)
698 case '\\':
699 sindex++;
700 if (string[sindex])
701 ADVANCE_CHAR (string, slen, sindex);
702 break;
704 case '\'':
705 sindex = skip_single_quoted (string, slen, ++sindex, 0);
706 break;
708 case '"':
709 sindex = skip_double_quoted (string, slen, ++sindex, 0);
710 break;
712 default:
713 ADVANCE_CHAR (string, slen, sindex);
714 break;
717 return (0);
719 #endif
721 /* Most of the substitutions must be done in parallel. In order
722 to avoid using tons of unclear goto's, I have some functions
723 for manipulating malloc'ed strings. They all take INDX, a
724 pointer to an integer which is the offset into the string
725 where manipulation is taking place. They also take SIZE, a
726 pointer to an integer which is the current length of the
727 character array for this string. */
729 /* Append SOURCE to TARGET at INDEX. SIZE is the current amount
730 of space allocated to TARGET. SOURCE can be NULL, in which
731 case nothing happens. Gets rid of SOURCE by freeing it.
732 Returns TARGET in case the location has changed. */
733 INLINE char *
734 sub_append_string (source, target, indx, size)
735 char *source, *target;
736 int *indx;
737 size_t *size;
739 if (source)
741 int n;
742 size_t srclen;
744 srclen = STRLEN (source);
745 if (srclen >= (int)(*size - *indx))
747 n = srclen + *indx;
748 n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
749 target = (char *)xrealloc (target, (*size = n));
752 FASTCOPY (source, target + *indx, srclen);
753 *indx += srclen;
754 target[*indx] = '\0';
756 free (source);
758 return (target);
761 #if 0
762 /* UNUSED */
763 /* Append the textual representation of NUMBER to TARGET.
764 INDX and SIZE are as in SUB_APPEND_STRING. */
765 char *
766 sub_append_number (number, target, indx, size)
767 intmax_t number;
768 char *target;
769 int *indx;
770 size_t *size;
772 char *temp;
774 temp = itos (number);
775 return (sub_append_string (temp, target, indx, size));
777 #endif
779 /* Extract a substring from STRING, starting at SINDEX and ending with
780 one of the characters in CHARLIST. Don't make the ending character
781 part of the string. Leave SINDEX pointing at the ending character.
782 Understand about backslashes in the string. If (flags & SX_VARNAME)
783 is non-zero, and array variables have been compiled into the shell,
784 everything between a `[' and a corresponding `]' is skipped over.
785 If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
786 update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must
787 contain a closing character from CHARLIST. */
788 static char *
789 string_extract (string, sindex, charlist, flags)
790 char *string;
791 int *sindex;
792 char *charlist;
793 int flags;
795 register int c, i;
796 int found;
797 size_t slen;
798 char *temp;
799 DECLARE_MBSTATE;
801 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
802 i = *sindex;
803 found = 0;
804 while (c = string[i])
806 if (c == '\\')
808 if (string[i + 1])
809 i++;
810 else
811 break;
813 #if defined (ARRAY_VARS)
814 else if ((flags & SX_VARNAME) && c == LBRACK)
816 int ni;
817 /* If this is an array subscript, skip over it and continue. */
818 ni = skipsubscript (string, i, 0);
819 if (string[ni] == RBRACK)
820 i = ni;
822 #endif
823 // else if (c == ':' && string[i+1] == ':' && legal_variable_starter(string[i+2]))
824 else if (c == ':' && string[i+1] == ':' && org_legal_variable_starter(string[i+2]) )
826 i+=2;
827 continue;
829 else if (MEMBER (c, charlist))
831 found = 1;
832 break;
835 ADVANCE_CHAR (string, slen, i);
838 /* If we had to have a matching delimiter and didn't find one, return an
839 error and let the caller deal with it. */
840 if ((flags & SX_REQMATCH) && found == 0)
842 *sindex = i;
843 return (&extract_string_error);
846 temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
847 *sindex = i;
849 return (temp);
852 /* Extract the contents of STRING as if it is enclosed in double quotes.
853 SINDEX, when passed in, is the offset of the character immediately
854 following the opening double quote; on exit, SINDEX is left pointing after
855 the closing double quote. If STRIPDQ is non-zero, unquoted double
856 quotes are stripped and the string is terminated by a null byte.
857 Backslashes between the embedded double quotes are processed. If STRIPDQ
858 is zero, an unquoted `"' terminates the string. */
859 static char *
860 string_extract_double_quoted (string, sindex, flags)
861 char *string;
862 int *sindex, flags;
864 size_t slen;
865 char *send;
866 int j, i, t;
867 unsigned char c;
868 char *temp, *ret; /* The new string we return. */
869 int pass_next, backquote, si; /* State variables for the machine. */
870 int dquote;
871 int stripdq;
872 DECLARE_MBSTATE;
874 slen = strlen (string + *sindex) + *sindex;
875 send = string + slen;
877 stripdq = (flags & SX_STRIPDQ);
879 pass_next = backquote = dquote = 0;
880 temp = (char *)xmalloc (1 + slen - *sindex);
882 j = 0;
883 i = *sindex;
884 while (c = string[i])
886 /* Process a character that was quoted by a backslash. */
887 if (pass_next)
889 /* XXX - take another look at this in light of Interp 221 */
890 /* Posix.2 sez:
892 ``The backslash shall retain its special meaning as an escape
893 character only when followed by one of the characters:
894 $ ` " \ <newline>''.
896 If STRIPDQ is zero, we handle the double quotes here and let
897 expand_word_internal handle the rest. If STRIPDQ is non-zero,
898 we have already been through one round of backslash stripping,
899 and want to strip these backslashes only if DQUOTE is non-zero,
900 indicating that we are inside an embedded double-quoted string. */
902 /* If we are in an embedded quoted string, then don't strip
903 backslashes before characters for which the backslash
904 retains its special meaning, but remove backslashes in
905 front of other characters. If we are not in an
906 embedded quoted string, don't strip backslashes at all.
907 This mess is necessary because the string was already
908 surrounded by double quotes (and sh has some really weird
909 quoting rules).
910 The returned string will be run through expansion as if
911 it were double-quoted. */
912 if ((stripdq == 0 && c != '"') ||
913 (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0)))
914 temp[j++] = '\\';
915 pass_next = 0;
917 add_one_character:
918 COPY_CHAR_I (temp, j, string, send, i);
919 continue;
922 /* A backslash protects the next character. The code just above
923 handles preserving the backslash in front of any character but
924 a double quote. */
925 if (c == '\\')
927 pass_next++;
928 i++;
929 continue;
932 /* Inside backquotes, ``the portion of the quoted string from the
933 initial backquote and the characters up to the next backquote
934 that is not preceded by a backslash, having escape characters
935 removed, defines that command''. */
936 if (backquote)
938 if (c == '`')
939 backquote = 0;
940 temp[j++] = c; /* COPY_CHAR_I? */
941 i++;
942 continue;
945 if (c == '`')
947 temp[j++] = c;
948 backquote++;
949 i++;
950 continue;
953 /* Pass everything between `$(' and the matching `)' or a quoted
954 ${ ... } pair through according to the Posix.2 specification. */
955 if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
957 int free_ret = 1;
959 si = i + 2;
960 if (string[i + 1] == LPAREN)
961 ret = extract_command_subst (string, &si, (flags & SX_COMPLETE));
962 else
963 ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0);
965 temp[j++] = '$';
966 temp[j++] = string[i + 1];
968 /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error
969 is set. */
970 if (ret == 0 && no_longjmp_on_fatal_error)
972 free_ret = 0;
973 ret = string + i + 2;
976 /* XXX - CHECK_STRING_OVERRUN here? */
977 for (t = 0; ret[t]; t++, j++)
978 temp[j] = ret[t];
979 temp[j] = string[si];
981 if (si < i + 2) /* we went back? */
982 i += 2;
983 else if (string[si])
985 j++;
986 i = si + 1;
988 else
989 i = si;
991 if (free_ret)
992 free (ret);
993 continue;
996 /* Add any character but a double quote to the quoted string we're
997 accumulating. */
998 if (c != '"')
999 goto add_one_character;
1001 /* c == '"' */
1002 if (stripdq)
1004 dquote ^= 1;
1005 i++;
1006 continue;
1009 break;
1011 temp[j] = '\0';
1013 /* Point to after the closing quote. */
1014 if (c)
1015 i++;
1016 *sindex = i;
1018 return (temp);
1021 /* This should really be another option to string_extract_double_quoted. */
1022 static int
1023 skip_double_quoted (string, slen, sind, flags)
1024 char *string;
1025 size_t slen;
1026 int sind;
1027 int flags;
1029 int c, i;
1030 char *ret;
1031 int pass_next, backquote, si;
1032 DECLARE_MBSTATE;
1034 pass_next = backquote = 0;
1035 i = sind;
1036 while (c = string[i])
1038 if (pass_next)
1040 pass_next = 0;
1041 ADVANCE_CHAR (string, slen, i);
1042 continue;
1044 else if (c == '\\')
1046 pass_next++;
1047 i++;
1048 continue;
1050 else if (backquote)
1052 if (c == '`')
1053 backquote = 0;
1054 ADVANCE_CHAR (string, slen, i);
1055 continue;
1057 else if (c == '`')
1059 backquote++;
1060 i++;
1061 continue;
1063 else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
1065 si = i + 2;
1066 if (string[i + 1] == LPAREN)
1067 ret = extract_command_subst (string, &si, SX_NOALLOC|(flags&SX_COMPLETE));
1068 else
1069 ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC);
1071 /* These can consume the entire string if they are unterminated */
1072 CHECK_STRING_OVERRUN (i, si, slen, c);
1074 i = si + 1;
1075 continue;
1077 else if (c != '"')
1079 ADVANCE_CHAR (string, slen, i);
1080 continue;
1082 else
1083 break;
1086 if (c)
1087 i++;
1089 return (i);
1092 /* Extract the contents of STRING as if it is enclosed in single quotes.
1093 SINDEX, when passed in, is the offset of the character immediately
1094 following the opening single quote; on exit, SINDEX is left pointing after
1095 the closing single quote. */
1096 static inline char *
1097 string_extract_single_quoted (string, sindex)
1098 char *string;
1099 int *sindex;
1101 register int i;
1102 size_t slen;
1103 char *t;
1104 DECLARE_MBSTATE;
1106 /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */
1107 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
1108 i = *sindex;
1109 while (string[i] && string[i] != '\'')
1110 ADVANCE_CHAR (string, slen, i);
1112 t = substring (string, *sindex, i);
1114 if (string[i])
1115 i++;
1116 *sindex = i;
1118 return (t);
1121 /* Skip over a single-quoted string. We overload the SX_COMPLETE flag to mean
1122 that we are splitting out words for completion and have encountered a $'...'
1123 string, which allows backslash-escaped single quotes. */
1124 static inline int
1125 skip_single_quoted (string, slen, sind, flags)
1126 const char *string;
1127 size_t slen;
1128 int sind;
1129 int flags;
1131 register int c;
1132 DECLARE_MBSTATE;
1134 c = sind;
1135 while (string[c] && string[c] != '\'')
1137 if ((flags & SX_COMPLETE) && string[c] == '\\' && string[c+1] == '\'' && string[c+2])
1138 ADVANCE_CHAR (string, slen, c);
1139 ADVANCE_CHAR (string, slen, c);
1142 if (string[c])
1143 c++;
1144 return c;
1147 /* Just like string_extract, but doesn't hack backslashes or any of
1148 that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */
1149 static char *
1150 string_extract_verbatim (string, slen, sindex, charlist, flags)
1151 char *string;
1152 size_t slen;
1153 int *sindex;
1154 char *charlist;
1155 int flags;
1157 register int i;
1158 #if defined (HANDLE_MULTIBYTE)
1159 wchar_t *wcharlist;
1160 #endif
1161 int c;
1162 char *temp;
1163 DECLARE_MBSTATE;
1165 if ((flags & SX_NOCTLESC) && charlist[0] == '\'' && charlist[1] == '\0')
1167 temp = string_extract_single_quoted (string, sindex);
1168 --*sindex; /* leave *sindex at separator character */
1169 return temp;
1172 /* This can never be called with charlist == NULL. If *charlist == NULL,
1173 we can skip the loop and just return a copy of the string, updating
1174 *sindex */
1175 if (*charlist == 0)
1177 temp = string + *sindex;
1178 c = (*sindex == 0) ? slen : STRLEN (temp);
1179 temp = savestring (temp);
1180 *sindex += c;
1181 return temp;
1184 i = *sindex;
1185 #if defined (HANDLE_MULTIBYTE)
1186 wcharlist = 0;
1187 #endif
1188 while (c = string[i])
1190 #if defined (HANDLE_MULTIBYTE)
1191 size_t mblength;
1192 #endif
1193 if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
1195 i += 2;
1196 CHECK_STRING_OVERRUN (i, i, slen, c);
1197 continue;
1199 /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
1200 through, to protect the CTLNULs from later calls to
1201 remove_quoted_nulls. */
1202 else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
1204 i += 2;
1205 CHECK_STRING_OVERRUN (i, i, slen, c);
1206 continue;
1209 #if defined (HANDLE_MULTIBYTE)
1210 if (locale_utf8locale && slen > i && UTF8_SINGLEBYTE (string[i]))
1211 mblength = (string[i] != 0) ? 1 : 0;
1212 else
1213 mblength = MBLEN (string + i, slen - i);
1214 if (mblength > 1)
1216 wchar_t wc;
1217 mblength = mbtowc (&wc, string + i, slen - i);
1218 if (MB_INVALIDCH (mblength))
1220 if (MEMBER (c, charlist))
1221 break;
1223 else
1225 if (wcharlist == 0)
1227 size_t len;
1228 len = mbstowcs (wcharlist, charlist, 0);
1229 if (len == -1)
1230 len = 0;
1231 wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
1232 mbstowcs (wcharlist, charlist, len + 1);
1235 if (wcschr (wcharlist, wc))
1236 break;
1239 else
1240 #endif
1241 if (MEMBER (c, charlist))
1242 break;
1244 ADVANCE_CHAR (string, slen, i);
1247 #if defined (HANDLE_MULTIBYTE)
1248 FREE (wcharlist);
1249 #endif
1251 temp = substring (string, *sindex, i);
1252 *sindex = i;
1254 return (temp);
1257 /* Extract the $( construct in STRING, and return a new string.
1258 Start extracting at (SINDEX) as if we had just seen "$(".
1259 Make (SINDEX) get the position of the matching ")". )
1260 XFLAGS is additional flags to pass to other extraction functions. */
1261 char *
1262 extract_command_subst (string, sindex, xflags)
1263 char *string;
1264 int *sindex;
1265 int xflags;
1267 char *ret;
1269 if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE))
1270 return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
1271 else
1273 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1274 ret = xparse_dolparen (string, string+*sindex, sindex, xflags);
1275 return ret;
1279 /* Extract the $[ construct in STRING, and return a new string. (])
1280 Start extracting at (SINDEX) as if we had just seen "$[".
1281 Make (SINDEX) get the position of the matching "]". */
1282 char *
1283 extract_arithmetic_subst (string, sindex)
1284 char *string;
1285 int *sindex;
1287 return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/
1290 #if defined (PROCESS_SUBSTITUTION)
1291 /* Extract the <( or >( construct in STRING, and return a new string.
1292 Start extracting at (SINDEX) as if we had just seen "<(".
1293 Make (SINDEX) get the position of the matching ")". */ /*))*/
1294 char *
1295 extract_process_subst (string, starter, sindex, xflags)
1296 char *string;
1297 char *starter;
1298 int *sindex;
1299 int xflags;
1301 #if 0
1302 /* XXX - check xflags&SX_COMPLETE here? */
1303 return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND));
1304 #else
1305 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1306 return (xparse_dolparen (string, string+*sindex, sindex, xflags));
1307 #endif
1309 #endif /* PROCESS_SUBSTITUTION */
1311 #if defined (ARRAY_VARS)
1312 /* This can be fooled by unquoted right parens in the passed string. If
1313 each caller verifies that the last character in STRING is a right paren,
1314 we don't even need to call extract_delimited_string. */
1315 char *
1316 extract_array_assignment_list (string, sindex)
1317 char *string;
1318 int *sindex;
1320 int slen;
1321 char *ret;
1323 slen = strlen (string);
1324 if (string[slen - 1] == RPAREN)
1326 ret = substring (string, *sindex, slen - 1);
1327 *sindex = slen - 1;
1328 return ret;
1330 return 0;
1332 #endif
1334 /* Extract and create a new string from the contents of STRING, a
1335 character string delimited with OPENER and CLOSER. SINDEX is
1336 the address of an int describing the current offset in STRING;
1337 it should point to just after the first OPENER found. On exit,
1338 SINDEX gets the position of the last character of the matching CLOSER.
1339 If OPENER is more than a single character, ALT_OPENER, if non-null,
1340 contains a character string that can also match CLOSER and thus
1341 needs to be skipped. */
1342 static char *
1343 extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
1344 char *string;
1345 int *sindex;
1346 char *opener, *alt_opener, *closer;
1347 int flags;
1349 int i, c, si;
1350 size_t slen;
1351 char *t, *result;
1352 int pass_character, nesting_level, in_comment;
1353 int len_closer, len_opener, len_alt_opener;
1354 DECLARE_MBSTATE;
1356 slen = strlen (string + *sindex) + *sindex;
1357 len_opener = STRLEN (opener);
1358 len_alt_opener = STRLEN (alt_opener);
1359 len_closer = STRLEN (closer);
1361 pass_character = in_comment = 0;
1363 nesting_level = 1;
1364 i = *sindex;
1366 while (nesting_level)
1368 c = string[i];
1370 /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond
1371 the end of the string, catch it and cut the loop. */
1372 if (i > slen)
1374 i = slen;
1375 c = string[i = slen];
1376 break;
1379 if (c == 0)
1380 break;
1382 if (in_comment)
1384 if (c == '\n')
1385 in_comment = 0;
1386 ADVANCE_CHAR (string, slen, i);
1387 continue;
1390 if (pass_character) /* previous char was backslash */
1392 pass_character = 0;
1393 ADVANCE_CHAR (string, slen, i);
1394 continue;
1397 /* Not exactly right yet; should handle shell metacharacters and
1398 multibyte characters, too. See COMMENT_BEGIN define in parse.y */
1399 if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
1401 in_comment = 1;
1402 ADVANCE_CHAR (string, slen, i);
1403 continue;
1406 if (c == CTLESC || c == '\\')
1408 pass_character++;
1409 i++;
1410 continue;
1413 /* Process a nested command substitution, but only if we're parsing an
1414 arithmetic substitution. */
1415 if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
1417 si = i + 2;
1418 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1419 CHECK_STRING_OVERRUN (i, si, slen, c);
1420 i = si + 1;
1421 continue;
1424 /* Process a nested OPENER. */
1425 if (STREQN (string + i, opener, len_opener))
1427 si = i + len_opener;
1428 t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
1429 CHECK_STRING_OVERRUN (i, si, slen, c);
1430 i = si + 1;
1431 continue;
1434 /* Process a nested ALT_OPENER */
1435 if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
1437 si = i + len_alt_opener;
1438 t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
1439 CHECK_STRING_OVERRUN (i, si, slen, c);
1440 i = si + 1;
1441 continue;
1444 /* If the current substring terminates the delimited string, decrement
1445 the nesting level. */
1446 if (STREQN (string + i, closer, len_closer))
1448 i += len_closer - 1; /* move to last byte of the closer */
1449 nesting_level--;
1450 if (nesting_level == 0)
1451 break;
1454 /* Pass old-style command substitution through verbatim. */
1455 if (c == '`')
1457 si = i + 1;
1458 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1459 CHECK_STRING_OVERRUN (i, si, slen, c);
1460 i = si + 1;
1461 continue;
1464 /* Pass single-quoted and double-quoted strings through verbatim. */
1465 if (c == '\'' || c == '"')
1467 si = i + 1;
1468 i = (c == '\'') ? skip_single_quoted (string, slen, si, 0)
1469 : skip_double_quoted (string, slen, si, 0);
1470 continue;
1473 /* move past this character, which was not special. */
1474 ADVANCE_CHAR (string, slen, i);
1477 if (c == 0 && nesting_level)
1479 if (no_longjmp_on_fatal_error == 0)
1481 last_command_exit_value = EXECUTION_FAILURE;
1482 report_error (_("bad substitution: no closing `%s' in %s"), closer, string);
1483 exp_jump_to_top_level (DISCARD);
1485 else
1487 *sindex = i;
1488 return (char *)NULL;
1492 si = i - *sindex - len_closer + 1;
1493 if (flags & SX_NOALLOC)
1494 result = (char *)NULL;
1495 else
1497 result = (char *)xmalloc (1 + si);
1498 strncpy (result, string + *sindex, si);
1499 result[si] = '\0';
1501 *sindex = i;
1503 return (result);
1506 /* Extract a parameter expansion expression within ${ and } from STRING.
1507 Obey the Posix.2 rules for finding the ending `}': count braces while
1508 skipping over enclosed quoted strings and command substitutions.
1509 SINDEX is the address of an int describing the current offset in STRING;
1510 it should point to just after the first `{' found. On exit, SINDEX
1511 gets the position of the matching `}'. QUOTED is non-zero if this
1512 occurs inside double quotes. */
1513 /* XXX -- this is very similar to extract_delimited_string -- XXX */
1514 static char *
1515 extract_dollar_brace_string (string, sindex, quoted, flags)
1516 char *string;
1517 int *sindex, quoted, flags;
1519 register int i, c;
1520 size_t slen;
1521 int pass_character, nesting_level, si, dolbrace_state;
1522 char *result, *t;
1523 DECLARE_MBSTATE;
1525 pass_character = 0;
1526 nesting_level = 1;
1527 slen = strlen (string + *sindex) + *sindex;
1529 /* The handling of dolbrace_state needs to agree with the code in parse.y:
1530 parse_matched_pair(). The different initial value is to handle the
1531 case where this function is called to parse the word in
1532 ${param op word} (SX_WORD). */
1533 dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM;
1534 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP))
1535 dolbrace_state = DOLBRACE_QUOTE;
1537 i = *sindex;
1538 while (c = string[i])
1540 if (pass_character)
1542 pass_character = 0;
1543 ADVANCE_CHAR (string, slen, i);
1544 continue;
1547 /* CTLESCs and backslashes quote the next character. */
1548 if (c == CTLESC || c == '\\')
1550 pass_character++;
1551 i++;
1552 continue;
1555 if (string[i] == '$' && string[i+1] == LBRACE)
1557 nesting_level++;
1558 i += 2;
1559 continue;
1562 if (c == RBRACE)
1564 nesting_level--;
1565 if (nesting_level == 0)
1566 break;
1567 i++;
1568 continue;
1571 /* Pass the contents of old-style command substitutions through
1572 verbatim. */
1573 if (c == '`')
1575 si = i + 1;
1576 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1578 CHECK_STRING_OVERRUN (i, si, slen, c);
1580 i = si + 1;
1581 continue;
1584 /* Pass the contents of new-style command substitutions and
1585 arithmetic substitutions through verbatim. */
1586 if (string[i] == '$' && string[i+1] == LPAREN)
1588 si = i + 2;
1589 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1591 CHECK_STRING_OVERRUN (i, si, slen, c);
1593 i = si + 1;
1594 continue;
1597 #if defined (PROCESS_SUBSTITUTION)
1598 /* Technically this should only work at the start of a word */
1599 if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN)
1601 si = i + 2;
1602 t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags|SX_NOALLOC);
1604 CHECK_STRING_OVERRUN (i, si, slen, c);
1606 i = si + 1;
1607 continue;
1609 #endif
1611 /* Pass the contents of double-quoted strings through verbatim. */
1612 if (c == '"')
1614 si = i + 1;
1615 i = skip_double_quoted (string, slen, si, 0);
1616 /* skip_XXX_quoted leaves index one past close quote */
1617 continue;
1620 if (c == '\'')
1622 /*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
1623 if (posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1624 ADVANCE_CHAR (string, slen, i);
1625 else
1627 si = i + 1;
1628 i = skip_single_quoted (string, slen, si, 0);
1631 continue;
1634 #if defined (ARRAY_VARS)
1635 if (c == LBRACK && dolbrace_state == DOLBRACE_PARAM)
1637 si = skipsubscript (string, i, 0);
1638 CHECK_STRING_OVERRUN (i, si, slen, c);
1639 if (string[si] == RBRACK)
1640 c = string[i = si];
1642 #endif
1644 /* move past this character, which was not special. */
1645 ADVANCE_CHAR (string, slen, i);
1647 /* This logic must agree with parse.y:parse_matched_pair, since they
1648 share the same defines. */
1649 if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
1650 dolbrace_state = DOLBRACE_QUOTE;
1651 else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
1652 dolbrace_state = DOLBRACE_QUOTE;
1653 else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
1654 dolbrace_state = DOLBRACE_QUOTE2; /* XXX */
1655 else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
1656 dolbrace_state = DOLBRACE_QUOTE;
1657 else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
1658 dolbrace_state = DOLBRACE_QUOTE;
1659 /* This is intended to handle all of the [:]op expansions and the substring/
1660 length/pattern removal/pattern substitution expansions. */
1661 else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
1662 dolbrace_state = DOLBRACE_OP;
1663 else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
1664 dolbrace_state = DOLBRACE_WORD;
1667 if (c == 0 && nesting_level)
1669 if (no_longjmp_on_fatal_error == 0)
1670 { /* { */
1671 last_command_exit_value = EXECUTION_FAILURE;
1672 report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
1673 exp_jump_to_top_level (DISCARD);
1675 else
1677 *sindex = i;
1678 return ((char *)NULL);
1682 result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
1683 *sindex = i;
1685 return (result);
1688 /* Remove backslashes which are quoting backquotes from STRING. Modifies
1689 STRING, and returns a pointer to it. */
1690 char *
1691 de_backslash (string)
1692 char *string;
1694 register size_t slen;
1695 register int i, j, prev_i;
1696 DECLARE_MBSTATE;
1698 slen = strlen (string);
1699 i = j = 0;
1701 /* Loop copying string[i] to string[j], i >= j. */
1702 while (i < slen)
1704 if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
1705 string[i + 1] == '$'))
1706 i++;
1707 prev_i = i;
1708 ADVANCE_CHAR (string, slen, i);
1709 if (j < prev_i)
1710 do string[j++] = string[prev_i++]; while (prev_i < i);
1711 else
1712 j = i;
1714 string[j] = '\0';
1716 return (string);
1719 #if 0
1720 /*UNUSED*/
1721 /* Replace instances of \! in a string with !. */
1722 void
1723 unquote_bang (string)
1724 char *string;
1726 register int i, j;
1727 register char *temp;
1729 temp = (char *)xmalloc (1 + strlen (string));
1731 for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
1733 if (string[i] == '\\' && string[i + 1] == '!')
1735 temp[j] = '!';
1736 i++;
1739 strcpy (string, temp);
1740 free (temp);
1742 #endif
1744 #define CQ_RETURN(x) do { no_longjmp_on_fatal_error = oldjmp; return (x); } while (0)
1746 /* This function assumes s[i] == open; returns with s[ret] == close; used to
1747 parse array subscripts. FLAGS & 1 means to not attempt to skip over
1748 matched pairs of quotes or backquotes, or skip word expansions; it is
1749 intended to be used after expansion has been performed and during final
1750 assignment parsing (see arrayfunc.c:assign_compound_array_list()) or
1751 during execution by a builtin which has already undergone word expansion. */
1752 static int
1753 skip_matched_pair (string, start, open, close, flags)
1754 const char *string;
1755 int start, open, close, flags;
1757 int i, pass_next, backq, si, c, count, oldjmp;
1758 size_t slen;
1759 char *temp, *ss;
1760 DECLARE_MBSTATE;
1762 slen = strlen (string + start) + start;
1763 oldjmp = no_longjmp_on_fatal_error;
1764 no_longjmp_on_fatal_error = 1;
1766 i = start + 1; /* skip over leading bracket */
1767 count = 1;
1768 pass_next = backq = 0;
1769 ss = (char *)string;
1770 while (c = string[i])
1772 if (pass_next)
1774 pass_next = 0;
1775 if (c == 0)
1776 CQ_RETURN(i);
1777 ADVANCE_CHAR (string, slen, i);
1778 continue;
1780 else if ((flags & 1) == 0 && c == '\\')
1782 pass_next = 1;
1783 i++;
1784 continue;
1786 else if (backq)
1788 if (c == '`')
1789 backq = 0;
1790 ADVANCE_CHAR (string, slen, i);
1791 continue;
1793 else if ((flags & 1) == 0 && c == '`')
1795 backq = 1;
1796 i++;
1797 continue;
1799 else if ((flags & 1) == 0 && c == open)
1801 count++;
1802 i++;
1803 continue;
1805 else if (c == close)
1807 count--;
1808 if (count == 0)
1809 break;
1810 i++;
1811 continue;
1813 else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
1815 i = (c == '\'') ? skip_single_quoted (ss, slen, ++i, 0)
1816 : skip_double_quoted (ss, slen, ++i, 0);
1817 /* no increment, the skip functions increment past the closing quote. */
1819 else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
1821 si = i + 2;
1822 if (string[si] == '\0')
1823 CQ_RETURN(si);
1825 /* XXX - extract_command_subst here? */
1826 if (string[i+1] == LPAREN)
1827 temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
1828 else
1829 temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
1831 CHECK_STRING_OVERRUN (i, si, slen, c);
1833 i = si;
1834 if (string[i] == '\0') /* don't increment i past EOS in loop */
1835 break;
1836 i++;
1837 continue;
1839 else
1840 ADVANCE_CHAR (string, slen, i);
1843 CQ_RETURN(i);
1846 #if defined (ARRAY_VARS)
1847 /* Flags has 1 as a reserved value, since skip_matched_pair uses it for
1848 skipping over quoted strings and taking the first instance of the
1849 closing character. */
1851 skipsubscript (string, start, flags)
1852 const char *string;
1853 int start, flags;
1855 return (skip_matched_pair (string, start, '[', ']', flags));
1857 #endif
1859 /* Skip characters in STRING until we find a character in DELIMS, and return
1860 the index of that character. START is the index into string at which we
1861 begin. This is similar in spirit to strpbrk, but it returns an index into
1862 STRING and takes a starting index. This little piece of code knows quite
1863 a lot of shell syntax. It's very similar to skip_double_quoted and other
1864 functions of that ilk. */
1866 skip_to_delim (string, start, delims, flags)
1867 char *string;
1868 int start;
1869 char *delims;
1870 int flags;
1872 int i, pass_next, backq, dquote, si, c, oldjmp;
1873 int invert, skipquote, skipcmd, noprocsub, completeflag;
1874 int arithexp, skipcol;
1875 size_t slen;
1876 char *temp, open[3];
1877 DECLARE_MBSTATE;
1879 slen = strlen (string + start) + start;
1880 oldjmp = no_longjmp_on_fatal_error;
1881 if (flags & SD_NOJMP)
1882 no_longjmp_on_fatal_error = 1;
1883 invert = (flags & SD_INVERT);
1884 skipcmd = (flags & SD_NOSKIPCMD) == 0;
1885 noprocsub = (flags & SD_NOPROCSUB);
1886 completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0;
1888 arithexp = (flags & SD_ARITHEXP);
1889 skipcol = 0;
1891 i = start;
1892 pass_next = backq = dquote = 0;
1893 while (c = string[i])
1895 /* If this is non-zero, we should not let quote characters be delimiters
1896 and the current character is a single or double quote. We should not
1897 test whether or not it's a delimiter until after we skip single- or
1898 double-quoted strings. */
1899 skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
1900 if (pass_next)
1902 pass_next = 0;
1903 if (c == 0)
1904 CQ_RETURN(i);
1905 ADVANCE_CHAR (string, slen, i);
1906 continue;
1908 else if (c == '\\')
1910 pass_next = 1;
1911 i++;
1912 continue;
1914 else if (backq)
1916 if (c == '`')
1917 backq = 0;
1918 ADVANCE_CHAR (string, slen, i);
1919 continue;
1921 else if (c == '`')
1923 backq = 1;
1924 i++;
1925 continue;
1927 else if (arithexp && skipcol && c == ':')
1929 skipcol--;
1930 i++;
1931 continue;
1933 else if (arithexp && c == '?')
1935 skipcol++;
1936 i++;
1937 continue;
1939 else if (skipquote == 0 && invert == 0 && member (c, delims))
1940 break;
1941 /* the usual case is to use skip_xxx_quoted, but we don't skip over double
1942 quoted strings when looking for the history expansion character as a
1943 delimiter. */
1944 /* special case for programmable completion which takes place before
1945 parser converts backslash-escaped single quotes between $'...' to
1946 `regular' single-quoted strings. */
1947 else if (completeflag && i > 0 && string[i-1] == '$' && c == '\'')
1948 i = skip_single_quoted (string, slen, ++i, SX_COMPLETE);
1949 else if (c == '\'')
1950 i = skip_single_quoted (string, slen, ++i, 0);
1951 else if (c == '"')
1952 i = skip_double_quoted (string, slen, ++i, completeflag);
1953 else if (c == LPAREN && arithexp)
1955 si = i + 1;
1956 if (string[si] == '\0')
1957 CQ_RETURN(si);
1959 temp = extract_delimited_string (string, &si, "(", "(", ")", SX_NOALLOC); /* ) */
1960 i = si;
1961 if (string[i] == '\0') /* don't increment i past EOS in loop */
1962 break;
1963 i++;
1964 continue;
1966 else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
1968 si = i + 2;
1969 if (string[si] == '\0')
1970 CQ_RETURN(si);
1972 if (string[i+1] == LPAREN)
1973 temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
1974 else
1975 temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
1976 CHECK_STRING_OVERRUN (i, si, slen, c);
1977 i = si;
1978 if (string[i] == '\0') /* don't increment i past EOS in loop */
1979 break;
1980 i++;
1981 continue;
1983 #if defined (PROCESS_SUBSTITUTION)
1984 else if (skipcmd && noprocsub == 0 && (c == '<' || c == '>') && string[i+1] == LPAREN)
1986 si = i + 2;
1987 if (string[si] == '\0')
1988 CQ_RETURN(si);
1990 temp = extract_delimited_string (string, &si, (c == '<') ? "<(" : ">(", "(", ")", SX_COMMAND|SX_NOALLOC); /* )) */
1991 CHECK_STRING_OVERRUN (i, si, slen, c);
1992 i = si;
1993 if (string[i] == '\0')
1994 break;
1995 i++;
1996 continue;
1998 #endif /* PROCESS_SUBSTITUTION */
1999 #if defined (EXTENDED_GLOB)
2000 else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@"))
2002 si = i + 2;
2003 if (string[si] == '\0')
2004 CQ_RETURN(si);
2006 open[0] = c;
2007 open[1] = LPAREN;
2008 open[2] = '\0';
2009 temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */
2011 CHECK_STRING_OVERRUN (i, si, slen, c);
2012 i = si;
2013 if (string[i] == '\0') /* don't increment i past EOS in loop */
2014 break;
2015 i++;
2016 continue;
2018 #endif
2019 else if ((flags & SD_GLOB) && c == LBRACK)
2021 si = i + 1;
2022 if (string[si] == '\0')
2023 CQ_RETURN(si);
2025 temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */
2027 i = si;
2028 if (string[i] == '\0') /* don't increment i past EOS in loop */
2029 break;
2030 i++;
2031 continue;
2033 else if ((skipquote || invert) && (member (c, delims) == 0))
2034 break;
2035 else
2036 ADVANCE_CHAR (string, slen, i);
2039 CQ_RETURN(i);
2042 #if defined (BANG_HISTORY)
2043 /* Skip to the history expansion character (delims[0]), paying attention to
2044 quoted strings and command and process substitution. This is a stripped-
2045 down version of skip_to_delims. The essential difference is that this
2046 resets the quoting state when starting a command substitution */
2048 skip_to_histexp (string, start, delims, flags)
2049 char *string;
2050 int start;
2051 char *delims;
2052 int flags;
2054 int i, pass_next, backq, dquote, c, oldjmp;
2055 int histexp_comsub, histexp_backq, old_dquote;
2056 size_t slen;
2057 DECLARE_MBSTATE;
2059 slen = strlen (string + start) + start;
2060 oldjmp = no_longjmp_on_fatal_error;
2061 if (flags & SD_NOJMP)
2062 no_longjmp_on_fatal_error = 1;
2064 histexp_comsub = histexp_backq = old_dquote = 0;
2066 i = start;
2067 pass_next = backq = dquote = 0;
2068 while (c = string[i])
2070 if (pass_next)
2072 pass_next = 0;
2073 if (c == 0)
2074 CQ_RETURN(i);
2075 ADVANCE_CHAR (string, slen, i);
2076 continue;
2078 else if (c == '\\')
2080 pass_next = 1;
2081 i++;
2082 continue;
2084 else if (backq && c == '`')
2086 backq = 0;
2087 histexp_backq--;
2088 dquote = old_dquote;
2089 i++;
2090 continue;
2092 else if (c == '`')
2094 backq = 1;
2095 histexp_backq++;
2096 old_dquote = dquote; /* simple - one level for now */
2097 dquote = 0;
2098 i++;
2099 continue;
2101 /* When in double quotes, act as if the double quote is a member of
2102 history_no_expand_chars, like the history library does */
2103 else if (dquote && c == delims[0] && string[i+1] == '"')
2105 i++;
2106 continue;
2108 else if (c == delims[0])
2109 break;
2110 /* the usual case is to use skip_xxx_quoted, but we don't skip over double
2111 quoted strings when looking for the history expansion character as a
2112 delimiter. */
2113 else if (dquote && c == '\'')
2115 i++;
2116 continue;
2118 else if (c == '\'')
2119 i = skip_single_quoted (string, slen, ++i, 0);
2120 /* The posixly_correct test makes posix-mode shells allow double quotes
2121 to quote the history expansion character */
2122 else if (posixly_correct == 0 && c == '"')
2124 dquote = 1 - dquote;
2125 i++;
2126 continue;
2128 else if (c == '"')
2129 i = skip_double_quoted (string, slen, ++i, 0);
2130 #if defined (PROCESS_SUBSTITUTION)
2131 else if ((c == '$' || c == '<' || c == '>') && string[i+1] == LPAREN && string[i+2] != LPAREN)
2132 #else
2133 else if (c == '$' && string[i+1] == LPAREN && string[i+2] != LPAREN)
2134 #endif
2136 if (string[i+2] == '\0')
2137 CQ_RETURN(i+2);
2138 i += 2;
2139 histexp_comsub++;
2140 old_dquote = dquote;
2141 dquote = 0;
2143 else if (histexp_comsub && c == RPAREN)
2145 histexp_comsub--;
2146 dquote = old_dquote;
2147 i++;
2148 continue;
2150 else if (backq) /* placeholder */
2152 ADVANCE_CHAR (string, slen, i);
2153 continue;
2155 else
2156 ADVANCE_CHAR (string, slen, i);
2159 CQ_RETURN(i);
2161 #endif /* BANG_HISTORY */
2163 #if defined (READLINE)
2164 /* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
2165 an unclosed quoted string), or if the character at EINDEX is quoted
2166 by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various
2167 single and double-quoted string parsing functions should not return an
2168 error if there are unclosed quotes or braces. The characters that this
2169 recognizes need to be the same as the contents of
2170 rl_completer_quote_characters. */
2173 char_is_quoted (string, eindex)
2174 char *string;
2175 int eindex;
2177 int i, pass_next, c, oldjmp;
2178 size_t slen;
2179 DECLARE_MBSTATE;
2181 slen = strlen (string);
2182 oldjmp = no_longjmp_on_fatal_error;
2183 no_longjmp_on_fatal_error = 1;
2184 i = pass_next = 0;
2185 while (i <= eindex)
2187 c = string[i];
2189 if (pass_next)
2191 pass_next = 0;
2192 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
2193 CQ_RETURN(1);
2194 ADVANCE_CHAR (string, slen, i);
2195 continue;
2197 else if (c == '\\')
2199 pass_next = 1;
2200 i++;
2201 continue;
2203 else if (c == '$' && string[i+1] == '\'' && string[i+2])
2205 i += 2;
2206 i = skip_single_quoted (string, slen, i, SX_COMPLETE);
2207 if (i > eindex)
2208 CQ_RETURN (i);
2210 else if (c == '\'' || c == '"')
2212 i = (c == '\'') ? skip_single_quoted (string, slen, ++i, 0)
2213 : skip_double_quoted (string, slen, ++i, SX_COMPLETE);
2214 if (i > eindex)
2215 CQ_RETURN(1);
2216 /* no increment, the skip_xxx functions go one past end */
2218 else
2219 ADVANCE_CHAR (string, slen, i);
2222 CQ_RETURN(0);
2226 unclosed_pair (string, eindex, openstr)
2227 char *string;
2228 int eindex;
2229 char *openstr;
2231 int i, pass_next, openc, olen;
2232 size_t slen;
2233 DECLARE_MBSTATE;
2235 slen = strlen (string);
2236 olen = strlen (openstr);
2237 i = pass_next = openc = 0;
2238 while (i <= eindex)
2240 if (pass_next)
2242 pass_next = 0;
2243 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
2244 return 0;
2245 ADVANCE_CHAR (string, slen, i);
2246 continue;
2248 else if (string[i] == '\\')
2250 pass_next = 1;
2251 i++;
2252 continue;
2254 else if (STREQN (string + i, openstr, olen))
2256 openc = 1 - openc;
2257 i += olen;
2259 /* XXX - may want to handle $'...' specially here */
2260 else if (string[i] == '\'' || string[i] == '"')
2262 i = (string[i] == '\'') ? skip_single_quoted (string, slen, i, 0)
2263 : skip_double_quoted (string, slen, i, SX_COMPLETE);
2264 if (i > eindex)
2265 return 0;
2267 else
2268 ADVANCE_CHAR (string, slen, i);
2270 return (openc);
2273 /* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
2274 individual words. If DELIMS is NULL, the current value of $IFS is used
2275 to split the string, and the function follows the shell field splitting
2276 rules. SENTINEL is an index to look for. NWP, if non-NULL,
2277 gets the number of words in the returned list. CWP, if non-NULL, gets
2278 the index of the word containing SENTINEL. Non-whitespace chars in
2279 DELIMS delimit separate fields. This is used by programmable completion. */
2280 WORD_LIST *
2281 split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
2282 char *string;
2283 int slen;
2284 char *delims;
2285 int sentinel, flags;
2286 int *nwp, *cwp;
2288 int ts, te, i, nw, cw, ifs_split, dflags;
2289 char *token, *d, *d2;
2290 WORD_LIST *ret, *tl;
2292 if (string == 0 || *string == '\0')
2294 if (nwp)
2295 *nwp = 0;
2296 if (cwp)
2297 *cwp = 0;
2298 return ((WORD_LIST *)NULL);
2301 d = (delims == 0) ? ifs_value : delims;
2302 ifs_split = delims == 0;
2304 /* Make d2 the non-whitespace characters in delims */
2305 d2 = 0;
2306 if (delims)
2308 size_t slength;
2309 #if defined (HANDLE_MULTIBYTE)
2310 size_t mblength = 1;
2311 #endif
2312 DECLARE_MBSTATE;
2314 slength = strlen (delims);
2315 d2 = (char *)xmalloc (slength + 1);
2316 i = ts = 0;
2317 while (delims[i])
2319 #if defined (HANDLE_MULTIBYTE)
2320 mbstate_t state_bak;
2321 state_bak = state;
2322 mblength = MBRLEN (delims + i, slength, &state);
2323 if (MB_INVALIDCH (mblength))
2324 state = state_bak;
2325 else if (mblength > 1)
2327 memcpy (d2 + ts, delims + i, mblength);
2328 ts += mblength;
2329 i += mblength;
2330 slength -= mblength;
2331 continue;
2333 #endif
2334 if (whitespace (delims[i]) == 0)
2335 d2[ts++] = delims[i];
2337 i++;
2338 slength--;
2340 d2[ts] = '\0';
2343 ret = (WORD_LIST *)NULL;
2345 /* Remove sequences of whitespace characters at the start of the string, as
2346 long as those characters are delimiters. */
2347 for (i = 0; member (string[i], d) && spctabnl (string[i]); i++)
2349 if (string[i] == '\0')
2351 FREE (d2);
2352 return (ret);
2355 ts = i;
2356 nw = 0;
2357 cw = -1;
2358 dflags = flags|SD_NOJMP;
2359 while (1)
2361 te = skip_to_delim (string, ts, d, dflags);
2363 /* If we have a non-whitespace delimiter character, use it to make a
2364 separate field. This is just about what $IFS splitting does and
2365 is closer to the behavior of the shell parser. */
2366 if (ts == te && d2 && member (string[ts], d2))
2368 te = ts + 1;
2369 /* If we're using IFS splitting, the non-whitespace delimiter char
2370 and any additional IFS whitespace delimits a field. */
2371 if (ifs_split)
2372 while (member (string[te], d) && spctabnl (string[te]) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2373 te++;
2374 else
2375 while (member (string[te], d2) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2376 te++;
2379 token = substring (string, ts, te);
2381 ret = add_string_to_list (token, ret); /* XXX */
2382 free (token);
2383 nw++;
2385 if (sentinel >= ts && sentinel <= te)
2386 cw = nw;
2388 /* If the cursor is at whitespace just before word start, set the
2389 sentinel word to the current word. */
2390 if (cwp && cw == -1 && sentinel == ts-1)
2391 cw = nw;
2393 /* If the cursor is at whitespace between two words, make a new, empty
2394 word, add it before (well, after, since the list is in reverse order)
2395 the word we just added, and set the current word to that one. */
2396 if (cwp && cw == -1 && sentinel < ts)
2398 tl = make_word_list (make_word (""), ret->next);
2399 ret->next = tl;
2400 cw = nw;
2401 nw++;
2404 if (string[te] == 0)
2405 break;
2407 i = te;
2408 /* XXX - honor SD_NOQUOTEDELIM here */
2409 while (member (string[i], d) && (ifs_split || spctabnl(string[i])) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2410 i++;
2412 if (string[i])
2413 ts = i;
2414 else
2415 break;
2418 /* Special case for SENTINEL at the end of STRING. If we haven't found
2419 the word containing SENTINEL yet, and the index we're looking for is at
2420 the end of STRING (or past the end of the previously-found token,
2421 possible if the end of the line is composed solely of IFS whitespace)
2422 add an additional null argument and set the current word pointer to that. */
2423 if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
2425 if (whitespace (string[sentinel - 1]))
2427 token = "";
2428 ret = add_string_to_list (token, ret);
2429 nw++;
2431 cw = nw;
2434 if (nwp)
2435 *nwp = nw;
2436 if (cwp)
2437 *cwp = cw;
2439 FREE (d2);
2441 return (REVERSE_LIST (ret, WORD_LIST *));
2443 #endif /* READLINE */
2445 #if 0
2446 /* UNUSED */
2447 /* Extract the name of the variable to bind to from the assignment string. */
2448 char *
2449 assignment_name (string)
2450 char *string;
2452 int offset;
2453 char *temp;
2455 offset = assignment (string, 0);
2456 if (offset == 0)
2457 return (char *)NULL;
2458 temp = substring (string, 0, offset);
2459 return (temp);
2461 #endif
2463 /* **************************************************************** */
2464 /* */
2465 /* Functions to convert strings to WORD_LISTs and vice versa */
2466 /* */
2467 /* **************************************************************** */
2469 /* Return a single string of all the words in LIST. SEP is the separator
2470 to put between individual elements of LIST in the output string. */
2471 char *
2472 string_list_internal (list, sep)
2473 WORD_LIST *list;
2474 char *sep;
2476 register WORD_LIST *t;
2477 char *result, *r;
2478 size_t word_len, sep_len, result_size;
2480 if (list == 0)
2481 return ((char *)NULL);
2483 /* Short-circuit quickly if we don't need to separate anything. */
2484 if (list->next == 0)
2485 return (savestring (list->word->word));
2487 /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
2488 sep_len = STRLEN (sep);
2489 result_size = 0;
2491 for (t = list; t; t = t->next)
2493 if (t != list)
2494 result_size += sep_len;
2495 result_size += strlen (t->word->word);
2498 r = result = (char *)xmalloc (result_size + 1);
2500 for (t = list; t; t = t->next)
2502 if (t != list && sep_len)
2504 if (sep_len > 1)
2506 FASTCOPY (sep, r, sep_len);
2507 r += sep_len;
2509 else
2510 *r++ = sep[0];
2513 word_len = strlen (t->word->word);
2514 FASTCOPY (t->word->word, r, word_len);
2515 r += word_len;
2518 *r = '\0';
2519 return (result);
2522 /* Return a single string of all the words present in LIST, separating
2523 each word with a space. */
2524 char *
2525 string_list (list)
2526 WORD_LIST *list;
2528 return (string_list_internal (list, " "));
2531 /* An external interface that can be used by the rest of the shell to
2532 obtain a string containing the first character in $IFS. Handles all
2533 the multibyte complications. If LENP is non-null, it is set to the
2534 length of the returned string. */
2535 char *
2536 ifs_firstchar (lenp)
2537 int *lenp;
2539 char *ret;
2540 int len;
2542 ret = xmalloc (MB_LEN_MAX + 1);
2543 #if defined (HANDLE_MULTIBYTE)
2544 if (ifs_firstc_len == 1)
2546 ret[0] = ifs_firstc[0];
2547 ret[1] = '\0';
2548 len = ret[0] ? 1 : 0;
2550 else
2552 memcpy (ret, ifs_firstc, ifs_firstc_len);
2553 ret[len = ifs_firstc_len] = '\0';
2555 #else
2556 ret[0] = ifs_firstc;
2557 ret[1] = '\0';
2558 len = ret[0] ? 0 : 1;
2559 #endif
2561 if (lenp)
2562 *lenp = len;
2564 return ret;
2567 /* Return a single string of all the words present in LIST, obeying the
2568 quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
2569 expansion [of $*] appears within a double quoted string, it expands
2570 to a single field with the value of each parameter separated by the
2571 first character of the IFS variable, or by a <space> if IFS is unset." */
2572 /* Posix interpretation 888 changes this when IFS is null by specifying
2573 that when unquoted, this expands to separate arguments */
2574 char *
2575 string_list_dollar_star (list, quoted, flags)
2576 WORD_LIST *list;
2577 int quoted, flags;
2579 char *ret;
2580 #if defined (HANDLE_MULTIBYTE)
2581 # if defined (__GNUC__)
2582 char sep[MB_CUR_MAX + 1];
2583 # else
2584 char *sep = 0;
2585 # endif
2586 #else
2587 char sep[2];
2588 #endif
2590 #if defined (HANDLE_MULTIBYTE)
2591 # if !defined (__GNUC__)
2592 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2593 # endif /* !__GNUC__ */
2594 if (ifs_firstc_len == 1)
2596 sep[0] = ifs_firstc[0];
2597 sep[1] = '\0';
2599 else
2601 memcpy (sep, ifs_firstc, ifs_firstc_len);
2602 sep[ifs_firstc_len] = '\0';
2604 #else
2605 sep[0] = ifs_firstc;
2606 sep[1] = '\0';
2607 #endif
2609 ret = string_list_internal (list, sep);
2610 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2611 free (sep);
2612 #endif
2613 return ret;
2616 /* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
2617 is non-zero, the $@ appears within double quotes, and we should quote
2618 the list before converting it into a string. If IFS is unset, and the
2619 word is not quoted, we just need to quote CTLESC and CTLNUL characters
2620 in the words in the list, because the default value of $IFS is
2621 <space><tab><newline>, IFS characters in the words in the list should
2622 also be split. If IFS is null, and the word is not quoted, we need
2623 to quote the words in the list to preserve the positional parameters
2624 exactly.
2625 Valid values for the FLAGS argument are the PF_ flags in command.h,
2626 the only one we care about is PF_ASSIGNRHS. $@ is supposed to expand
2627 to the positional parameters separated by spaces no matter what IFS is
2628 set to if in a context where word splitting is not performed. The only
2629 one that we didn't handle before is assignment statement arguments to
2630 declaration builtins like `declare'. */
2631 char *
2632 string_list_dollar_at (list, quoted, flags)
2633 WORD_LIST *list;
2634 int quoted;
2635 int flags;
2637 char *ifs, *ret;
2638 #if defined (HANDLE_MULTIBYTE)
2639 # if defined (__GNUC__)
2640 char sep[MB_CUR_MAX + 1];
2641 # else
2642 char *sep = 0;
2643 # endif /* !__GNUC__ */
2644 #else
2645 char sep[2];
2646 #endif
2647 WORD_LIST *tlist;
2649 /* XXX this could just be ifs = ifs_value; */
2650 ifs = ifs_var ? value_cell (ifs_var) : (char *)0;
2652 #if defined (HANDLE_MULTIBYTE)
2653 # if !defined (__GNUC__)
2654 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2655 # endif /* !__GNUC__ */
2656 /* XXX - testing PF_ASSIGNRHS to make sure positional parameters are
2657 separated with a space even when word splitting will not occur. */
2658 if (flags & PF_ASSIGNRHS)
2660 sep[0] = ' ';
2661 sep[1] = '\0';
2663 else if (ifs && *ifs)
2665 if (ifs_firstc_len == 1)
2667 sep[0] = ifs_firstc[0];
2668 sep[1] = '\0';
2670 else
2672 memcpy (sep, ifs_firstc, ifs_firstc_len);
2673 sep[ifs_firstc_len] = '\0';
2676 else
2678 sep[0] = ' ';
2679 sep[1] = '\0';
2681 #else /* !HANDLE_MULTIBYTE */
2682 /* XXX - PF_ASSIGNRHS means no word splitting, so we want positional
2683 parameters separated by a space. */
2684 sep[0] = ((flags & PF_ASSIGNRHS) || ifs == 0 || *ifs == 0) ? ' ' : *ifs;
2685 sep[1] = '\0';
2686 #endif /* !HANDLE_MULTIBYTE */
2688 /* XXX -- why call quote_list if ifs == 0? we can get away without doing
2689 it now that quote_escapes quotes spaces */
2690 tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
2691 ? quote_list (list)
2692 : list_quote_escapes (list);
2694 ret = string_list_internal (tlist, sep);
2695 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2696 free (sep);
2697 #endif
2698 return ret;
2701 /* Turn the positional parameters into a string, understanding quoting and
2702 the various subtleties of using the first character of $IFS as the
2703 separator. Calls string_list_dollar_at, string_list_dollar_star, and
2704 string_list as appropriate. */
2705 /* This needs to fully understand the additional contexts where word
2706 splitting does not occur (W_ASSIGNRHS, etc.) */
2707 char *
2708 string_list_pos_params (pchar, list, quoted, pflags)
2709 int pchar;
2710 WORD_LIST *list;
2711 int quoted, pflags;
2713 char *ret;
2714 WORD_LIST *tlist;
2716 if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
2718 tlist = quote_list (list);
2719 word_list_remove_quoted_nulls (tlist);
2720 ret = string_list_dollar_star (tlist, 0, 0);
2722 else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
2724 tlist = quote_list (list);
2725 word_list_remove_quoted_nulls (tlist);
2726 ret = string_list (tlist);
2728 else if (pchar == '*' && quoted == 0 && ifs_is_null) /* XXX */
2729 ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
2730 else if (pchar == '*' && quoted == 0 && (pflags & PF_ASSIGNRHS)) /* XXX */
2731 ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
2732 else if (pchar == '*')
2734 /* Even when unquoted, string_list_dollar_star does the right thing
2735 making sure that the first character of $IFS is used as the
2736 separator. */
2737 ret = string_list_dollar_star (list, quoted, 0);
2739 else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
2740 /* We use string_list_dollar_at, but only if the string is quoted, since
2741 that quotes the escapes if it's not, which we don't want. We could
2742 use string_list (the old code did), but that doesn't do the right
2743 thing if the first character of $IFS is not a space. We use
2744 string_list_dollar_star if the string is unquoted so we make sure that
2745 the elements of $@ are separated by the first character of $IFS for
2746 later splitting. */
2747 ret = string_list_dollar_at (list, quoted, 0);
2748 else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */
2749 ret = string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
2750 else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS))
2751 ret = string_list_dollar_at (list, quoted, pflags); /* Posix interp 888 */
2752 else if (pchar == '@')
2753 ret = string_list_dollar_star (list, quoted, 0);
2754 else
2755 ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
2757 return ret;
2760 /* Return the list of words present in STRING. Separate the string into
2761 words at any of the characters found in SEPARATORS. If QUOTED is
2762 non-zero then word in the list will have its quoted flag set, otherwise
2763 the quoted flag is left as make_word () deemed fit.
2765 This obeys the P1003.2 word splitting semantics. If `separators' is
2766 exactly <space><tab><newline>, then the splitting algorithm is that of
2767 the Bourne shell, which treats any sequence of characters from `separators'
2768 as a delimiter. If IFS is unset, which results in `separators' being set
2769 to "", no splitting occurs. If separators has some other value, the
2770 following rules are applied (`IFS white space' means zero or more
2771 occurrences of <space>, <tab>, or <newline>, as long as those characters
2772 are in `separators'):
2774 1) IFS white space is ignored at the start and the end of the
2775 string.
2776 2) Each occurrence of a character in `separators' that is not
2777 IFS white space, along with any adjacent occurrences of
2778 IFS white space delimits a field.
2779 3) Any nonzero-length sequence of IFS white space delimits a field.
2782 /* BEWARE! list_string strips null arguments. Don't call it twice and
2783 expect to have "" preserved! */
2785 /* This performs word splitting and quoted null character removal on
2786 STRING. */
2787 #define issep(c) \
2788 (((separators)[0]) ? ((separators)[1] ? isifs(c) \
2789 : (c) == (separators)[0]) \
2790 : 0)
2792 /* member of the space character class in the current locale */
2793 #define ifs_whitespace(c) ISSPACE(c)
2795 /* "adjacent IFS white space" */
2796 #define ifs_whitesep(c) ((sh_style_split || separators == 0) ? spctabnl (c) \
2797 : ifs_whitespace (c))
2799 WORD_LIST *
2800 list_string (string, separators, quoted)
2801 register char *string, *separators;
2802 int quoted;
2804 WORD_LIST *result;
2805 WORD_DESC *t;
2806 char *current_word, *s;
2807 int sindex, sh_style_split, whitesep, xflags, free_word;
2808 size_t slen;
2810 if (!string || !*string)
2811 return ((WORD_LIST *)NULL);
2813 sh_style_split = separators && separators[0] == ' ' &&
2814 separators[1] == '\t' &&
2815 separators[2] == '\n' &&
2816 separators[3] == '\0';
2817 for (xflags = 0, s = ifs_value; s && *s; s++)
2819 if (*s == CTLESC) xflags |= SX_NOCTLESC;
2820 else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
2823 slen = 0;
2824 /* Remove sequences of whitespace at the beginning of STRING, as
2825 long as those characters appear in IFS. Do not do this if
2826 STRING is quoted or if there are no separator characters. We use the
2827 Posix definition of whitespace as a member of the space character
2828 class in the current locale. */
2829 #if 0
2830 if (!quoted || !separators || !*separators)
2831 #else
2832 /* issep() requires that separators be non-null, and always returns 0 if
2833 separator is the empty string, so don't bother if we get an empty string
2834 for separators. We already returned NULL above if STRING is empty. */
2835 if (!quoted && separators && *separators)
2836 #endif
2838 for (s = string; *s && issep (*s) && ifs_whitespace (*s); s++);
2840 if (!*s)
2841 return ((WORD_LIST *)NULL);
2843 string = s;
2846 /* OK, now STRING points to a word that does not begin with white space.
2847 The splitting algorithm is:
2848 extract a word, stopping at a separator
2849 skip sequences of whitespace characters as long as they are separators
2850 This obeys the field splitting rules in Posix.2. */
2851 slen = STRLEN (string);
2852 for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
2854 /* Don't need string length in ADVANCE_CHAR unless multibyte chars are
2855 possible, but need it in string_extract_verbatim for bounds checking */
2856 current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
2857 if (current_word == 0)
2858 break;
2860 free_word = 1; /* If non-zero, we free current_word */
2862 /* If we have a quoted empty string, add a quoted null argument. We
2863 want to preserve the quoted null character iff this is a quoted
2864 empty string; otherwise the quoted null characters are removed
2865 below. */
2866 if (QUOTED_NULL (current_word))
2868 t = alloc_word_desc ();
2869 t->word = make_quoted_char ('\0');
2870 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
2871 result = make_word_list (t, result);
2873 else if (current_word[0] != '\0')
2875 /* If we have something, then add it regardless. However,
2876 perform quoted null character removal on the current word. */
2877 remove_quoted_nulls (current_word);
2879 /* We don't want to set the word flags based on the string contents
2880 here -- that's mostly for the parser -- so we just allocate a
2881 WORD_DESC *, assign current_word (noting that we don't want to
2882 free it), and skip all of make_word. */
2883 t = alloc_word_desc ();
2884 t->word = current_word;
2885 result = make_word_list (t, result);
2886 free_word = 0;
2887 result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */
2888 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
2889 result->word->flags |= W_QUOTED;
2890 /* If removing quoted null characters leaves an empty word, note
2891 that we saw this for the caller to act on. */
2892 if (current_word == 0 || current_word[0] == '\0')
2893 result->word->flags |= W_SAWQUOTEDNULL;
2896 /* If we're not doing sequences of separators in the traditional
2897 Bourne shell style, then add a quoted null argument. */
2898 else if (!sh_style_split && !ifs_whitespace (string[sindex]))
2900 t = alloc_word_desc ();
2901 t->word = make_quoted_char ('\0');
2902 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
2903 result = make_word_list (t, result);
2906 if (free_word)
2907 free (current_word);
2909 /* Note whether or not the separator is IFS whitespace, used later. */
2910 whitesep = string[sindex] && ifs_whitesep (string[sindex]);
2912 /* Move past the current separator character. */
2913 if (string[sindex])
2915 DECLARE_MBSTATE;
2916 ADVANCE_CHAR (string, slen, sindex);
2919 /* Now skip sequences of whitespace characters if they are
2920 in the list of separators. */
2921 while (string[sindex] && ifs_whitesep (string[sindex]) && issep (string[sindex]))
2922 sindex++;
2924 /* If the first separator was IFS whitespace and the current character
2925 is a non-whitespace IFS character, it should be part of the current
2926 field delimiter, not a separate delimiter that would result in an
2927 empty field. Look at POSIX.2, 3.6.5, (3)(b). */
2928 if (string[sindex] && whitesep && issep (string[sindex]) && !ifs_whitesep (string[sindex]))
2930 sindex++;
2931 /* An IFS character that is not IFS white space, along with any
2932 adjacent IFS white space, shall delimit a field. (SUSv3) */
2933 while (string[sindex] && ifs_whitesep (string[sindex]) && isifs (string[sindex]))
2934 sindex++;
2937 return (REVERSE_LIST (result, WORD_LIST *));
2940 /* Parse a single word from STRING, using SEPARATORS to separate fields.
2941 ENDPTR is set to the first character after the word. This is used by
2942 the `read' builtin.
2944 This is never called with SEPARATORS != $IFS, and takes advantage of that.
2946 XXX - this function is very similar to list_string; they should be
2947 combined - XXX */
2949 /* character is in $IFS */
2950 #define islocalsep(c) (local_cmap[(unsigned char)(c)] != 0)
2952 char *
2953 get_word_from_string (stringp, separators, endptr)
2954 char **stringp, *separators, **endptr;
2956 register char *s;
2957 char *current_word;
2958 int sindex, sh_style_split, whitesep, xflags;
2959 unsigned char local_cmap[UCHAR_MAX+1]; /* really only need single-byte chars here */
2960 size_t slen;
2962 if (!stringp || !*stringp || !**stringp)
2963 return ((char *)NULL);
2965 sh_style_split = separators && separators[0] == ' ' &&
2966 separators[1] == '\t' &&
2967 separators[2] == '\n' &&
2968 separators[3] == '\0';
2969 memset (local_cmap, '\0', sizeof (local_cmap));
2970 for (xflags = 0, s = separators; s && *s; s++)
2972 if (*s == CTLESC) xflags |= SX_NOCTLESC;
2973 if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
2974 local_cmap[(unsigned char)*s] = 1; /* local charmap of separators */
2977 s = *stringp;
2978 slen = 0;
2980 /* Remove sequences of whitespace at the beginning of STRING, as
2981 long as those characters appear in SEPARATORS. This happens if
2982 SEPARATORS == $' \t\n' or if IFS is unset. */
2983 if (sh_style_split || separators == 0)
2984 for (; *s && spctabnl (*s) && islocalsep (*s); s++);
2985 else
2986 for (; *s && ifs_whitespace (*s) && islocalsep (*s); s++);
2988 /* If the string is nothing but whitespace, update it and return. */
2989 if (!*s)
2991 *stringp = s;
2992 if (endptr)
2993 *endptr = s;
2994 return ((char *)NULL);
2997 /* OK, S points to a word that does not begin with white space.
2998 Now extract a word, stopping at a separator, save a pointer to
2999 the first character after the word, then skip sequences of spc,
3000 tab, or nl as long as they are separators.
3002 This obeys the field splitting rules in Posix.2. */
3003 sindex = 0;
3004 /* Don't need string length in ADVANCE_CHAR unless multibyte chars are
3005 possible, but need it in string_extract_verbatim for bounds checking */
3006 slen = STRLEN (s);
3007 current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
3009 /* Set ENDPTR to the first character after the end of the word. */
3010 if (endptr)
3011 *endptr = s + sindex;
3013 /* Note whether or not the separator is IFS whitespace, used later. */
3014 whitesep = s[sindex] && ifs_whitesep (s[sindex]);
3016 /* Move past the current separator character. */
3017 if (s[sindex])
3019 DECLARE_MBSTATE;
3020 ADVANCE_CHAR (s, slen, sindex);
3023 /* Now skip sequences of space, tab, or newline characters if they are
3024 in the list of separators. */
3025 while (s[sindex] && spctabnl (s[sindex]) && islocalsep (s[sindex]))
3026 sindex++;
3028 /* If the first separator was IFS whitespace and the current character is
3029 a non-whitespace IFS character, it should be part of the current field
3030 delimiter, not a separate delimiter that would result in an empty field.
3031 Look at POSIX.2, 3.6.5, (3)(b). */
3032 if (s[sindex] && whitesep && islocalsep (s[sindex]) && !ifs_whitesep (s[sindex]))
3034 sindex++;
3035 /* An IFS character that is not IFS white space, along with any adjacent
3036 IFS white space, shall delimit a field. */
3037 while (s[sindex] && ifs_whitesep (s[sindex]) && islocalsep(s[sindex]))
3038 sindex++;
3041 /* Update STRING to point to the next field. */
3042 *stringp = s + sindex;
3043 return (current_word);
3046 /* Remove IFS white space at the end of STRING. Start at the end
3047 of the string and walk backwards until the beginning of the string
3048 or we find a character that's not IFS white space and not CTLESC.
3049 Only let CTLESC escape a white space character if SAW_ESCAPE is
3050 non-zero. */
3051 char *
3052 strip_trailing_ifs_whitespace (string, separators, saw_escape)
3053 char *string, *separators;
3054 int saw_escape;
3056 char *s;
3058 s = string + STRLEN (string) - 1;
3059 while (s > string && ((spctabnl (*s) && isifs (*s)) ||
3060 (saw_escape && *s == CTLESC && spctabnl (s[1]))))
3061 s--;
3062 *++s = '\0';
3063 return string;
3066 #if 0
3067 /* UNUSED */
3068 /* Split STRING into words at whitespace. Obeys shell-style quoting with
3069 backslashes, single and double quotes. */
3070 WORD_LIST *
3071 list_string_with_quotes (string)
3072 char *string;
3074 WORD_LIST *list;
3075 char *token, *s;
3076 size_t s_len;
3077 int c, i, tokstart, len;
3079 for (s = string; s && *s && spctabnl (*s); s++)
3081 if (s == 0 || *s == 0)
3082 return ((WORD_LIST *)NULL);
3084 s_len = strlen (s);
3085 tokstart = i = 0;
3086 list = (WORD_LIST *)NULL;
3087 while (1)
3089 c = s[i];
3090 if (c == '\\')
3092 i++;
3093 if (s[i])
3094 i++;
3096 else if (c == '\'')
3097 i = skip_single_quoted (s, s_len, ++i, 0);
3098 else if (c == '"')
3099 i = skip_double_quoted (s, s_len, ++i, 0);
3100 else if (c == 0 || spctabnl (c))
3102 /* We have found the end of a token. Make a word out of it and
3103 add it to the word list. */
3104 token = substring (s, tokstart, i);
3105 list = add_string_to_list (token, list);
3106 free (token);
3107 while (spctabnl (s[i]))
3108 i++;
3109 if (s[i])
3110 tokstart = i;
3111 else
3112 break;
3114 else
3115 i++; /* normal character */
3117 return (REVERSE_LIST (list, WORD_LIST *));
3119 #endif
3121 /********************************************************/
3122 /* */
3123 /* Functions to perform assignment statements */
3124 /* */
3125 /********************************************************/
3127 #if defined (ARRAY_VARS)
3128 static SHELL_VAR *
3129 do_compound_assignment (name, value, flags)
3130 char *name, *value;
3131 int flags;
3133 SHELL_VAR *v;
3134 int mklocal, mkassoc, mkglobal, chklocal;
3135 WORD_LIST *list;
3136 char *newname; /* used for local nameref references */
3138 mklocal = flags & ASS_MKLOCAL;
3139 mkassoc = flags & ASS_MKASSOC;
3140 mkglobal = flags & ASS_MKGLOBAL;
3141 chklocal = flags & ASS_CHKLOCAL;
3143 if (mklocal && variable_context)
3145 v = find_variable (name); /* follows namerefs */
3146 newname = (v == 0) ? nameref_transform_name (name, flags) : v->name;
3147 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3149 if (readonly_p (v))
3150 err_readonly (name);
3151 return (v); /* XXX */
3153 list = expand_compound_array_assignment (v, value, flags);
3154 if (mkassoc)
3155 v = make_local_assoc_variable (newname, 0);
3156 else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context)
3157 v = make_local_array_variable (newname, 0);
3158 if (v)
3159 assign_compound_array_list (v, list, flags);
3160 if (list)
3161 dispose_words (list);
3163 /* In a function but forcing assignment in global context. CHKLOCAL means to
3164 check for an existing local variable first. */
3165 else if (mkglobal && variable_context)
3167 v = chklocal ? find_variable (name) : 0;
3168 if (v && (local_p (v) == 0 || v->context != variable_context))
3169 v = 0;
3170 if (v == 0)
3171 v = find_global_variable (name);
3172 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3174 if (readonly_p (v))
3175 err_readonly (name);
3176 return (v); /* XXX */
3178 /* sanity check */
3179 newname = (v == 0) ? nameref_transform_name (name, flags) : name;
3180 list = expand_compound_array_assignment (v, value, flags);
3181 if (v == 0 && mkassoc)
3182 v = make_new_assoc_variable (newname);
3183 else if (v && mkassoc && assoc_p (v) == 0)
3184 v = convert_var_to_assoc (v);
3185 else if (v == 0)
3186 v = make_new_array_variable (newname);
3187 else if (v && mkassoc == 0 && array_p (v) == 0)
3188 v = convert_var_to_array (v);
3189 if (v)
3190 assign_compound_array_list (v, list, flags);
3191 if (list)
3192 dispose_words (list);
3194 else
3196 v = assign_array_from_string (name, value, flags);
3197 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3199 if (readonly_p (v))
3200 err_readonly (name);
3201 return (v); /* XXX */
3205 return (v);
3207 #endif
3209 /* Given STRING, an assignment string, get the value of the right side
3210 of the `=', and bind it to the left side. If EXPAND is true, then
3211 perform parameter expansion, command substitution, and arithmetic
3212 expansion on the right-hand side. Perform tilde expansion in any
3213 case. Do not perform word splitting on the result of expansion. */
3214 static int
3215 do_assignment_internal (word, expand)
3216 const WORD_DESC *word;
3217 int expand;
3219 int offset, appendop, assign_list, aflags, retval;
3220 char *name, *value, *temp;
3221 SHELL_VAR *entry;
3222 #if defined (ARRAY_VARS)
3223 char *t;
3224 int ni;
3225 #endif
3226 const char *string;
3228 if (word == 0 || word->word == 0)
3229 return 0;
3231 appendop = assign_list = aflags = 0;
3232 string = word->word;
3233 offset = assignment (string, 0);
3234 name = savestring (string);
3235 value = (char *)NULL;
3237 if (name[offset] == '=')
3239 if (name[offset - 1] == '+')
3241 appendop = 1;
3242 name[offset - 1] = '\0';
3245 name[offset] = 0; /* might need this set later */
3246 temp = name + offset + 1;
3248 #if defined (ARRAY_VARS)
3249 if (expand && (word->flags & W_COMPASSIGN))
3251 assign_list = ni = 1;
3252 value = extract_array_assignment_list (temp, &ni);
3254 else
3255 #endif
3256 if (expand && temp[0])
3257 value = expand_string_if_necessary (temp, 0, expand_string_assignment);
3258 else
3259 value = savestring (temp);
3262 if (value == 0)
3264 value = (char *)xmalloc (1);
3265 value[0] = '\0';
3268 if (echo_command_at_execute || debug_info)
3270 if (appendop)
3271 name[offset - 1] = '+';
3272 xtrace_print_assignment (name, value, assign_list, 1);
3273 if (appendop)
3274 name[offset - 1] = '\0';
3277 #define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
3279 if (appendop)
3280 aflags |= ASS_APPEND;
3282 #if defined (ARRAY_VARS)
3283 if (t = mbschr (name, LBRACK))
3285 if (assign_list)
3287 report_error (_("%s: cannot assign list to array member"), name);
3288 ASSIGN_RETURN (0);
3290 entry = assign_array_element (name, value, aflags);
3291 if (entry == 0)
3292 ASSIGN_RETURN (0);
3294 else if (assign_list)
3296 if ((word->flags & W_ASSIGNARG) && (word->flags & W_CHKLOCAL))
3297 aflags |= ASS_CHKLOCAL;
3298 if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0)
3299 aflags |= ASS_MKLOCAL;
3300 if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL))
3301 aflags |= ASS_MKGLOBAL;
3302 if (word->flags & W_ASSIGNASSOC)
3303 aflags |= ASS_MKASSOC;
3304 entry = do_compound_assignment (name, value, aflags);
3306 else
3307 #endif /* ARRAY_VARS */
3308 entry = bind_variable (name, value, aflags);
3310 if (entry)
3311 stupidly_hack_special_variables (entry->name); /* might be a nameref */
3312 else
3313 stupidly_hack_special_variables (name);
3315 /* Return 1 if the assignment seems to have been performed correctly. */
3316 if (entry == 0 || readonly_p (entry))
3317 retval = 0; /* assignment failure */
3318 else if (noassign_p (entry))
3320 set_exit_status (EXECUTION_FAILURE);
3321 retval = 1; /* error status, but not assignment failure */
3323 else
3324 retval = 1;
3326 if (entry && retval != 0 && noassign_p (entry) == 0)
3327 VUNSETATTR (entry, att_invisible);
3329 ASSIGN_RETURN (retval);
3332 /* Perform the assignment statement in STRING, and expand the
3333 right side by doing tilde, command and parameter expansion. */
3335 do_assignment (string)
3336 char *string;
3338 WORD_DESC td;
3340 td.flags = W_ASSIGNMENT;
3341 td.word = string;
3343 return do_assignment_internal (&td, 1);
3347 do_word_assignment (word, flags)
3348 WORD_DESC *word;
3349 int flags;
3351 return do_assignment_internal (word, 1);
3354 /* Given STRING, an assignment string, get the value of the right side
3355 of the `=', and bind it to the left side. Do not perform any word
3356 expansions on the right hand side. */
3358 do_assignment_no_expand (string)
3359 char *string;
3361 WORD_DESC td;
3363 td.flags = W_ASSIGNMENT;
3364 td.word = string;
3366 return (do_assignment_internal (&td, 0));
3369 /***************************************************
3371 * Functions to manage the positional parameters *
3373 ***************************************************/
3375 /* Return the word list that corresponds to `$*'. */
3376 WORD_LIST *
3377 list_rest_of_args ()
3379 register WORD_LIST *list, *args;
3380 int i;
3382 /* Break out of the loop as soon as one of the dollar variables is null. */
3383 for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
3384 list = make_word_list (make_bare_word (dollar_vars[i]), list);
3386 for (args = rest_of_args; args; args = args->next)
3387 list = make_word_list (make_bare_word (args->word->word), list);
3389 return (REVERSE_LIST (list, WORD_LIST *));
3392 /* Return the value of a positional parameter. This handles values > 10. */
3393 char *
3394 get_dollar_var_value (ind)
3395 intmax_t ind;
3397 char *temp;
3398 WORD_LIST *p;
3400 if (ind < 10)
3401 temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
3402 else /* We want something like ${11} */
3404 ind -= 10;
3405 for (p = rest_of_args; p && ind--; p = p->next)
3407 temp = p ? savestring (p->word->word) : (char *)NULL;
3409 return (temp);
3412 /* Make a single large string out of the dollar digit variables,
3413 and the rest_of_args. If DOLLAR_STAR is 1, then obey the special
3414 case of "$*" with respect to IFS. */
3415 char *
3416 string_rest_of_args (dollar_star)
3417 int dollar_star;
3419 register WORD_LIST *list;
3420 char *string;
3422 list = list_rest_of_args ();
3423 string = dollar_star ? string_list_dollar_star (list, 0, 0) : string_list (list);
3424 dispose_words (list);
3425 return (string);
3428 /* Return a string containing the positional parameters from START to
3429 END, inclusive. If STRING[0] == '*', we obey the rules for $*,
3430 which only makes a difference if QUOTED is non-zero. If QUOTED includes
3431 Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise
3432 no quoting chars are added. */
3433 static char *
3434 pos_params (string, start, end, quoted, pflags)
3435 char *string;
3436 int start, end, quoted, pflags;
3438 WORD_LIST *save, *params, *h, *t;
3439 char *ret;
3440 int i;
3442 /* see if we can short-circuit. if start == end, we want 0 parameters. */
3443 if (start == end)
3444 return ((char *)NULL);
3446 save = params = list_rest_of_args ();
3447 if (save == 0 && start > 0)
3448 return ((char *)NULL);
3450 if (start == 0) /* handle ${@:0[:x]} specially */
3452 t = make_word_list (make_word (dollar_vars[0]), params);
3453 save = params = t;
3456 for (i = start ? 1 : 0; params && i < start; i++)
3457 params = params->next;
3458 if (params == 0)
3460 dispose_words (save);
3461 return ((char *)NULL);
3463 for (h = t = params; params && i < end; i++)
3465 t = params;
3466 params = params->next;
3468 t->next = (WORD_LIST *)NULL;
3470 ret = string_list_pos_params (string[0], h, quoted, pflags);
3472 if (t != params)
3473 t->next = params;
3475 dispose_words (save);
3476 return (ret);
3479 /******************************************************************/
3480 /* */
3481 /* Functions to expand strings to strings or WORD_LISTs */
3482 /* */
3483 /******************************************************************/
3485 #if defined (PROCESS_SUBSTITUTION)
3486 #define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~')
3487 #else
3488 #define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
3489 #endif
3491 /* If there are any characters in STRING that require full expansion,
3492 then call FUNC to expand STRING; otherwise just perform quote
3493 removal if necessary. This returns a new string. */
3494 static char *
3495 expand_string_if_necessary (string, quoted, func)
3496 char *string;
3497 int quoted;
3498 EXPFUNC *func;
3500 WORD_LIST *list;
3501 size_t slen;
3502 int i, saw_quote;
3503 char *ret;
3504 DECLARE_MBSTATE;
3506 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3507 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
3508 i = saw_quote = 0;
3509 while (string[i])
3511 if (EXP_CHAR (string[i]))
3512 break;
3513 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3514 saw_quote = 1;
3515 ADVANCE_CHAR (string, slen, i);
3518 if (string[i])
3520 list = (*func) (string, quoted);
3521 if (list)
3523 ret = string_list (list);
3524 dispose_words (list);
3526 else
3527 ret = (char *)NULL;
3529 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3530 ret = string_quote_removal (string, quoted);
3531 else
3532 ret = savestring (string);
3534 return ret;
3537 static inline char *
3538 expand_string_to_string_internal (string, quoted, func)
3539 char *string;
3540 int quoted;
3541 EXPFUNC *func;
3543 WORD_LIST *list;
3544 char *ret;
3546 if (string == 0 || *string == '\0')
3547 return ((char *)NULL);
3549 list = (*func) (string, quoted);
3550 if (list)
3552 ret = string_list (list);
3553 dispose_words (list);
3555 else
3556 ret = (char *)NULL;
3558 return (ret);
3561 char *
3562 expand_string_to_string (string, quoted)
3563 char *string;
3564 int quoted;
3566 return (expand_string_to_string_internal (string, quoted, expand_string));
3569 char *
3570 expand_string_unsplit_to_string (string, quoted)
3571 char *string;
3572 int quoted;
3574 return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
3577 char *
3578 expand_assignment_string_to_string (string, quoted)
3579 char *string;
3580 int quoted;
3582 return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
3585 char *
3586 expand_arith_string (string, quoted)
3587 char *string;
3588 int quoted;
3590 WORD_DESC td;
3591 WORD_LIST *list, *tlist;
3592 size_t slen;
3593 int i, saw_quote;
3594 char *ret;
3595 DECLARE_MBSTATE;
3597 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3598 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
3599 i = saw_quote = 0;
3600 while (string[i])
3602 if (EXP_CHAR (string[i]))
3603 break;
3604 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3605 saw_quote = 1;
3606 ADVANCE_CHAR (string, slen, i);
3609 if (string[i])
3611 /* This is expanded version of expand_string_internal as it's called by
3612 expand_string_leave_quoted */
3613 td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */
3614 #if 0 /* TAG: bush-5.2 */
3615 if (quoted & Q_ARRAYSUB)
3616 td.flags |= W_NOCOMSUB;
3617 #endif
3618 td.word = savestring (string);
3619 list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3620 /* This takes care of the calls from expand_string_leave_quoted and
3621 expand_string */
3622 if (list)
3624 tlist = word_list_split (list);
3625 dispose_words (list);
3626 list = tlist;
3627 if (list)
3628 dequote_list (list);
3630 /* This comes from expand_string_if_necessary */
3631 if (list)
3633 ret = string_list (list);
3634 dispose_words (list);
3636 else
3637 ret = (char *)NULL;
3638 FREE (td.word);
3640 else if (saw_quote && (quoted & Q_ARITH))
3641 ret = string_quote_removal (string, quoted);
3642 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3643 ret = string_quote_removal (string, quoted);
3644 else
3645 ret = savestring (string);
3647 return ret;
3650 #if defined (COND_COMMAND)
3651 /* Just remove backslashes in STRING. Returns a new string. */
3652 char *
3653 remove_backslashes (string)
3654 char *string;
3656 char *r, *ret, *s;
3658 r = ret = (char *)xmalloc (strlen (string) + 1);
3659 for (s = string; s && *s; )
3661 if (*s == '\\')
3662 s++;
3663 if (*s == 0)
3664 break;
3665 *r++ = *s++;
3667 *r = '\0';
3668 return ret;
3671 /* This needs better error handling. */
3672 /* Expand W for use as an argument to a unary or binary operator in a
3673 [[...]] expression. If SPECIAL is 1, this is the rhs argument
3674 to the != or == operator, and should be treated as a pattern. In
3675 this case, we quote the string specially for the globbing code. If
3676 SPECIAL is 2, this is an rhs argument for the =~ operator, and should
3677 be quoted appropriately for regcomp/regexec. The caller is responsible
3678 for removing the backslashes if the unquoted word is needed later. In
3679 any case, since we don't perform word splitting, we need to do quoted
3680 null character removal. */
3681 char *
3682 cond_expand_word (w, special)
3683 WORD_DESC *w;
3684 int special;
3686 char *r, *p;
3687 WORD_LIST *l;
3688 int qflags;
3690 if (w->word == 0 || w->word[0] == '\0')
3691 return ((char *)NULL);
3693 expand_no_split_dollar_star = 1;
3694 w->flags |= W_NOSPLIT2;
3695 l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
3696 expand_no_split_dollar_star = 0;
3697 if (l)
3699 if (special == 0) /* LHS */
3701 if (l->word)
3702 word_list_remove_quoted_nulls (l);
3703 dequote_list (l);
3704 r = string_list (l);
3706 else
3708 /* Need to figure out whether or not we should call dequote_escapes
3709 or a new dequote_ctlnul function here, and under what
3710 circumstances. */
3711 qflags = QGLOB_CVTNULL|QGLOB_CTLESC;
3712 if (special == 2)
3713 qflags |= QGLOB_REGEXP;
3714 word_list_remove_quoted_nulls (l);
3715 p = string_list (l);
3716 r = quote_string_for_globbing (p, qflags);
3717 free (p);
3719 dispose_words (l);
3721 else
3722 r = (char *)NULL;
3724 return r;
3726 #endif
3728 /* Call expand_word_internal to expand W and handle error returns.
3729 A convenience function for functions that don't want to handle
3730 any errors or free any memory before aborting. */
3731 static WORD_LIST *
3732 call_expand_word_internal (w, q, i, c, e)
3733 WORD_DESC *w;
3734 int q, i, *c, *e;
3736 WORD_LIST *result;
3738 result = expand_word_internal (w, q, i, c, e);
3739 if (result == &expand_word_error || result == &expand_word_fatal)
3741 /* By convention, each time this error is returned, w->word has
3742 already been freed (it sometimes may not be in the fatal case,
3743 but that doesn't result in a memory leak because we're going
3744 to exit in most cases). */
3745 w->word = (char *)NULL;
3746 last_command_exit_value = EXECUTION_FAILURE;
3747 exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
3748 /* NOTREACHED */
3749 return (NULL);
3751 else
3752 return (result);
3755 /* Perform parameter expansion, command substitution, and arithmetic
3756 expansion on STRING, as if it were a word. Leave the result quoted.
3757 Since this does not perform word splitting, it leaves quoted nulls
3758 in the result. */
3759 static WORD_LIST *
3760 expand_string_internal (string, quoted)
3761 char *string;
3762 int quoted;
3764 WORD_DESC td;
3765 WORD_LIST *tresult;
3767 if (string == 0 || *string == 0)
3768 return ((WORD_LIST *)NULL);
3770 td.flags = 0;
3771 td.word = savestring (string);
3773 tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3775 FREE (td.word);
3776 return (tresult);
3779 /* Expand STRING by performing parameter expansion, command substitution,
3780 and arithmetic expansion. Dequote the resulting WORD_LIST before
3781 returning it, but do not perform word splitting. The call to
3782 remove_quoted_nulls () is in here because word splitting normally
3783 takes care of quote removal. */
3784 WORD_LIST *
3785 expand_string_unsplit (string, quoted)
3786 char *string;
3787 int quoted;
3789 WORD_LIST *value;
3791 if (string == 0 || *string == '\0')
3792 return ((WORD_LIST *)NULL);
3794 expand_no_split_dollar_star = 1;
3795 value = expand_string_internal (string, quoted);
3796 expand_no_split_dollar_star = 0;
3798 if (value)
3800 if (value->word)
3802 remove_quoted_nulls (value->word->word); /* XXX */
3803 value->word->flags &= ~W_HASQUOTEDNULL;
3805 dequote_list (value);
3807 return (value);
3810 /* Expand the rhs of an assignment statement */
3811 WORD_LIST *
3812 expand_string_assignment (string, quoted)
3813 char *string;
3814 int quoted;
3816 WORD_DESC td;
3817 WORD_LIST *value;
3819 if (string == 0 || *string == '\0')
3820 return ((WORD_LIST *)NULL);
3822 expand_no_split_dollar_star = 1;
3824 #if 0
3825 /* Other shells (ksh93) do it this way, which affects how $@ is expanded
3826 in constructs like bar=${@#0} (preserves the spaces resulting from the
3827 expansion of $@ in a context where you don't do word splitting); Posix
3828 interp 888 makes the expansion of $@ in contexts where word splitting
3829 is not performed unspecified. */
3830 td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */
3831 #else
3832 td.flags = W_ASSIGNRHS;
3833 #endif
3834 td.word = savestring (string);
3835 value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3836 FREE (td.word);
3838 expand_no_split_dollar_star = 0;
3840 if (value)
3842 if (value->word)
3844 remove_quoted_nulls (value->word->word); /* XXX */
3845 value->word->flags &= ~W_HASQUOTEDNULL;
3847 dequote_list (value);
3849 return (value);
3853 /* Expand one of the PS? prompt strings. This is a sort of combination of
3854 expand_string_unsplit and expand_string_internal, but returns the
3855 passed string when an error occurs. Might want to trap other calls
3856 to jump_to_top_level here so we don't endlessly loop. */
3857 WORD_LIST *
3858 expand_prompt_string (string, quoted, wflags)
3859 char *string;
3860 int quoted;
3861 int wflags;
3863 WORD_LIST *value;
3864 WORD_DESC td;
3866 if (string == 0 || *string == 0)
3867 return ((WORD_LIST *)NULL);
3869 td.flags = wflags;
3870 td.word = savestring (string);
3872 no_longjmp_on_fatal_error = 1;
3873 value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3874 no_longjmp_on_fatal_error = 0;
3876 if (value == &expand_word_error || value == &expand_word_fatal)
3878 value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
3879 return value;
3881 FREE (td.word);
3882 if (value)
3884 if (value->word)
3886 remove_quoted_nulls (value->word->word); /* XXX */
3887 value->word->flags &= ~W_HASQUOTEDNULL;
3889 dequote_list (value);
3891 return (value);
3894 /* Expand STRING just as if you were expanding a word, but do not dequote
3895 the resultant WORD_LIST. This is called only from within this file,
3896 and is used to correctly preserve quoted characters when expanding
3897 things like ${1+"$@"}. This does parameter expansion, command
3898 substitution, arithmetic expansion, and word splitting. */
3899 static WORD_LIST *
3900 expand_string_leave_quoted (string, quoted)
3901 char *string;
3902 int quoted;
3904 WORD_LIST *tlist;
3905 WORD_LIST *tresult;
3907 if (string == 0 || *string == '\0')
3908 return ((WORD_LIST *)NULL);
3910 tlist = expand_string_internal (string, quoted);
3912 if (tlist)
3914 tresult = word_list_split (tlist);
3915 dispose_words (tlist);
3916 return (tresult);
3918 return ((WORD_LIST *)NULL);
3921 /* This does not perform word splitting or dequote the WORD_LIST
3922 it returns. */
3923 static WORD_LIST *
3924 expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p)
3925 char *string;
3926 int quoted, op, pflags;
3927 int *dollar_at_p, *expanded_p;
3929 WORD_DESC td;
3930 WORD_LIST *tresult;
3931 int old_nosplit;
3933 if (string == 0 || *string == '\0')
3934 return (WORD_LIST *)NULL;
3936 /* We want field splitting to be determined by what is going to be done with
3937 the entire ${parameterOPword} expansion, so we don't want to split the RHS
3938 we expand here. However, the expansion of $* is determined by whether we
3939 are going to eventually perform word splitting, so we want to set this
3940 depending on whether or not are are going to be splitting: if the expansion
3941 is quoted, if the OP is `=', or if IFS is set to the empty string, we
3942 are not going to be splitting, so we set expand_no_split_dollar_star to
3943 note this to callees.
3944 We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an
3945 assignment statement. */
3946 /* The updated treatment of $* is the result of Posix interp 888 */
3947 /* This was further clarified on the austin-group list in March, 2017 and
3948 in Posix bug 1129 */
3949 old_nosplit = expand_no_split_dollar_star;
3950 expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */
3951 td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */
3952 td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */
3953 if (pflags & PF_ASSIGNRHS) /* pass through */
3954 td.flags |= W_ASSIGNRHS;
3955 if (op == '=')
3956 #if 0
3957 td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */
3958 #else
3959 td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */
3960 #endif
3961 td.word = string;
3962 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
3963 expand_no_split_dollar_star = old_nosplit;
3965 return (tresult);
3968 /* This does not perform word splitting or dequote the WORD_LIST
3969 it returns and it treats $* as if it were quoted. */
3970 static WORD_LIST *
3971 expand_string_for_pat (string, quoted, dollar_at_p, expanded_p)
3972 char *string;
3973 int quoted, *dollar_at_p, *expanded_p;
3975 WORD_DESC td;
3976 WORD_LIST *tresult;
3977 int oexp;
3979 if (string == 0 || *string == '\0')
3980 return (WORD_LIST *)NULL;
3982 oexp = expand_no_split_dollar_star;
3983 expand_no_split_dollar_star = 1;
3984 td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */
3985 td.word = string;
3986 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
3987 expand_no_split_dollar_star = oexp;
3989 return (tresult);
3992 /* Expand STRING just as if you were expanding a word. This also returns
3993 a list of words. Note that filename globbing is *NOT* done for word
3994 or string expansion, just when the shell is expanding a command. This
3995 does parameter expansion, command substitution, arithmetic expansion,
3996 and word splitting. Dequote the resultant WORD_LIST before returning. */
3997 WORD_LIST *
3998 expand_string (string, quoted)
3999 char *string;
4000 int quoted;
4002 WORD_LIST *result;
4004 if (string == 0 || *string == '\0')
4005 return ((WORD_LIST *)NULL);
4007 result = expand_string_leave_quoted (string, quoted);
4008 return (result ? dequote_list (result) : result);
4011 /*******************************************
4013 * Functions to expand WORD_DESCs *
4015 *******************************************/
4017 /* Expand WORD, performing word splitting on the result. This does
4018 parameter expansion, command substitution, arithmetic expansion,
4019 word splitting, and quote removal. */
4021 WORD_LIST *
4022 expand_word (word, quoted)
4023 WORD_DESC *word;
4024 int quoted;
4026 WORD_LIST *result, *tresult;
4028 tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4029 result = word_list_split (tresult);
4030 dispose_words (tresult);
4031 return (result ? dequote_list (result) : result);
4034 /* Expand WORD, but do not perform word splitting on the result. This
4035 does parameter expansion, command substitution, arithmetic expansion,
4036 and quote removal. */
4037 WORD_LIST *
4038 expand_word_unsplit (word, quoted)
4039 WORD_DESC *word;
4040 int quoted;
4042 WORD_LIST *result;
4044 result = expand_word_leave_quoted (word, quoted);
4045 return (result ? dequote_list (result) : result);
4048 /* Perform shell expansions on WORD, but do not perform word splitting or
4049 quote removal on the result. Virtually identical to expand_word_unsplit;
4050 could be combined if implementations don't diverge. */
4051 WORD_LIST *
4052 expand_word_leave_quoted (word, quoted)
4053 WORD_DESC *word;
4054 int quoted;
4056 WORD_LIST *result;
4058 expand_no_split_dollar_star = 1;
4059 if (ifs_is_null)
4060 word->flags |= W_NOSPLIT;
4061 word->flags |= W_NOSPLIT2;
4062 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4063 expand_no_split_dollar_star = 0;
4065 return result;
4068 /***************************************************
4070 * Functions to handle quoting chars *
4072 ***************************************************/
4074 /* Conventions:
4076 A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
4077 The parser passes CTLNUL as CTLESC CTLNUL. */
4079 /* Quote escape characters in string s, but no other characters. This is
4080 used to protect CTLESC and CTLNUL in variable values from the rest of
4081 the word expansion process after the variable is expanded (word splitting
4082 and filename generation). If IFS is null, we quote spaces as well, just
4083 in case we split on spaces later (in the case of unquoted $@, we will
4084 eventually attempt to split the entire word on spaces). Corresponding
4085 code exists in dequote_escapes. Even if we don't end up splitting on
4086 spaces, quoting spaces is not a problem. This should never be called on
4087 a string that is quoted with single or double quotes or part of a here
4088 document (effectively double-quoted).
4089 FLAGS says whether or not we are going to split the result. If we are not,
4090 and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL,
4091 respectively, to prevent them from being removed as part of dequoting. */
4092 static char *
4093 quote_escapes_internal (string, flags)
4094 const char *string;
4095 int flags;
4097 const char *s, *send;
4098 char *t, *result;
4099 size_t slen;
4100 int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit;
4101 DECLARE_MBSTATE;
4103 slen = strlen (string);
4104 send = string + slen;
4106 quote_spaces = (ifs_value && *ifs_value == 0);
4107 nosplit = (flags & PF_NOSPLIT2);
4109 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
4111 skip_ctlesc |= (nosplit == 0 && *s == CTLESC);
4112 skip_ctlnul |= (nosplit == 0 && *s == CTLNUL);
4115 t = result = (char *)xmalloc ((slen * 2) + 1);
4116 s = string;
4118 while (*s)
4120 if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
4121 *t++ = CTLESC;
4122 COPY_CHAR_P (t, s, send);
4124 *t = '\0';
4126 return (result);
4129 char *
4130 quote_escapes (string)
4131 const char *string;
4133 return (quote_escapes_internal (string, 0));
4136 char *
4137 quote_rhs (string)
4138 const char *string;
4140 return (quote_escapes_internal (string, PF_NOSPLIT2));
4143 static WORD_LIST *
4144 list_quote_escapes (list)
4145 WORD_LIST *list;
4147 register WORD_LIST *w;
4148 char *t;
4150 for (w = list; w; w = w->next)
4152 t = w->word->word;
4153 w->word->word = quote_escapes (t);
4154 free (t);
4156 return list;
4159 /* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
4161 The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
4162 This is necessary to make unquoted CTLESC and CTLNUL characters in the
4163 data stream pass through properly.
4165 We need to remove doubled CTLESC characters inside quoted strings before
4166 quoting the entire string, so we do not double the number of CTLESC
4167 characters.
4169 Also used by parts of the pattern substitution code. */
4170 char *
4171 dequote_escapes (string)
4172 const char *string;
4174 const char *s, *send;
4175 char *t, *result;
4176 size_t slen;
4177 int quote_spaces;
4178 DECLARE_MBSTATE;
4180 if (string == 0)
4181 return (char *)0;
4183 slen = strlen (string);
4184 send = string + slen;
4186 t = result = (char *)xmalloc (slen + 1);
4188 if (strchr (string, CTLESC) == 0)
4189 return (strcpy (result, string));
4191 quote_spaces = (ifs_value && *ifs_value == 0);
4193 s = string;
4194 while (*s)
4196 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
4198 s++;
4199 if (*s == '\0')
4200 break;
4202 COPY_CHAR_P (t, s, send);
4204 *t = '\0';
4206 return result;
4209 #if defined (INCLUDE_UNUSED)
4210 static WORD_LIST *
4211 list_dequote_escapes (list)
4212 WORD_LIST *list;
4214 register WORD_LIST *w;
4215 char *t;
4217 for (w = list; w; w = w->next)
4219 t = w->word->word;
4220 w->word->word = dequote_escapes (t);
4221 free (t);
4223 return list;
4225 #endif
4227 /* Return a new string with the quoted representation of character C.
4228 This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
4229 set in any resultant WORD_DESC where this value is the word. */
4230 static char *
4231 make_quoted_char (c)
4232 int c;
4234 char *temp;
4236 temp = (char *)xmalloc (3);
4237 if (c == 0)
4239 temp[0] = CTLNUL;
4240 temp[1] = '\0';
4242 else
4244 temp[0] = CTLESC;
4245 temp[1] = c;
4246 temp[2] = '\0';
4248 return (temp);
4251 /* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so
4252 the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
4253 this value is the word. */
4254 char *
4255 quote_string (string)
4256 char *string;
4258 register char *t;
4259 size_t slen;
4260 char *result, *send;
4262 if (*string == 0)
4264 result = (char *)xmalloc (2);
4265 result[0] = CTLNUL;
4266 result[1] = '\0';
4268 else
4270 DECLARE_MBSTATE;
4272 slen = strlen (string);
4273 send = string + slen;
4275 result = (char *)xmalloc ((slen * 2) + 1);
4277 for (t = result; string < send; )
4279 *t++ = CTLESC;
4280 COPY_CHAR_P (t, string, send);
4282 *t = '\0';
4284 return (result);
4287 /* De-quote quoted characters in STRING. */
4288 char *
4289 dequote_string (string)
4290 char *string;
4292 register char *s, *t;
4293 size_t slen;
4294 char *result, *send;
4295 DECLARE_MBSTATE;
4297 #if defined (DEBUG)
4298 if (string[0] == CTLESC && string[1] == 0)
4299 internal_inform ("dequote_string: string with bare CTLESC");
4300 #endif
4302 slen = STRLEN (string);
4304 t = result = (char *)xmalloc (slen + 1);
4306 if (QUOTED_NULL (string))
4308 result[0] = '\0';
4309 return (result);
4312 /* A string consisting of only a single CTLESC should pass through unchanged */
4313 if (string[0] == CTLESC && string[1] == 0)
4315 result[0] = CTLESC;
4316 result[1] = '\0';
4317 return (result);
4320 /* If no character in the string can be quoted, don't bother examining
4321 each character. Just return a copy of the string passed to us. */
4322 if (strchr (string, CTLESC) == NULL)
4323 return (strcpy (result, string));
4325 send = string + slen;
4326 s = string;
4327 while (*s)
4329 if (*s == CTLESC)
4331 s++;
4332 if (*s == '\0')
4333 break;
4335 COPY_CHAR_P (t, s, send);
4338 *t = '\0';
4339 return (result);
4342 /* Quote the entire WORD_LIST list. */
4343 static WORD_LIST *
4344 quote_list (list)
4345 WORD_LIST *list;
4347 register WORD_LIST *w;
4348 char *t;
4350 for (w = list; w; w = w->next)
4352 t = w->word->word;
4353 w->word->word = quote_string (t);
4354 if (*t == 0)
4355 w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
4356 w->word->flags |= W_QUOTED;
4357 free (t);
4359 return list;
4362 WORD_DESC *
4363 dequote_word (word)
4364 WORD_DESC *word;
4366 register char *s;
4368 s = dequote_string (word->word);
4369 if (QUOTED_NULL (word->word))
4370 word->flags &= ~W_HASQUOTEDNULL;
4371 free (word->word);
4372 word->word = s;
4374 return word;
4377 /* De-quote quoted characters in each word in LIST. */
4378 WORD_LIST *
4379 dequote_list (list)
4380 WORD_LIST *list;
4382 register char *s;
4383 register WORD_LIST *tlist;
4385 for (tlist = list; tlist; tlist = tlist->next)
4387 s = dequote_string (tlist->word->word);
4388 if (QUOTED_NULL (tlist->word->word))
4389 tlist->word->flags &= ~W_HASQUOTEDNULL;
4390 free (tlist->word->word);
4391 tlist->word->word = s;
4393 return list;
4396 /* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
4397 string. */
4398 char *
4399 remove_quoted_escapes (string)
4400 char *string;
4402 char *t;
4404 if (string)
4406 t = dequote_escapes (string);
4407 strcpy (string, t);
4408 free (t);
4411 return (string);
4414 /* Remove quoted $IFS characters from STRING. Quoted IFS characters are
4415 added to protect them from word splitting, but we need to remove them
4416 if no word splitting takes place. This returns newly-allocated memory,
4417 so callers can use it to replace savestring(). */
4418 char *
4419 remove_quoted_ifs (string)
4420 char *string;
4422 register size_t slen;
4423 register int i, j;
4424 char *ret, *send;
4425 DECLARE_MBSTATE;
4427 slen = strlen (string);
4428 send = string + slen;
4430 i = j = 0;
4431 ret = (char *)xmalloc (slen + 1);
4433 while (i < slen)
4435 if (string[i] == CTLESC)
4437 i++;
4438 if (string[i] == 0 || isifs (string[i]) == 0)
4439 ret[j++] = CTLESC;
4440 if (i == slen)
4441 break;
4444 COPY_CHAR_I (ret, j, string, send, i);
4446 ret[j] = '\0';
4448 return (ret);
4451 char *
4452 remove_quoted_nulls (string)
4453 char *string;
4455 register size_t slen;
4456 register int i, j, prev_i;
4457 DECLARE_MBSTATE;
4459 if (strchr (string, CTLNUL) == 0) /* XXX */
4460 return string; /* XXX */
4462 slen = strlen (string);
4463 i = j = 0;
4465 while (i < slen)
4467 if (string[i] == CTLESC)
4469 /* Old code had j++, but we cannot assume that i == j at this
4470 point -- what if a CTLNUL has already been removed from the
4471 string? We don't want to drop the CTLESC or recopy characters
4472 that we've already copied down. */
4473 i++;
4474 string[j++] = CTLESC;
4475 if (i == slen)
4476 break;
4478 else if (string[i] == CTLNUL)
4480 i++;
4481 continue;
4484 prev_i = i;
4485 ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */
4486 if (j < prev_i)
4488 do string[j++] = string[prev_i++]; while (prev_i < i);
4490 else
4491 j = i;
4493 string[j] = '\0';
4495 return (string);
4498 /* Perform quoted null character removal on each element of LIST.
4499 This modifies LIST. */
4500 void
4501 word_list_remove_quoted_nulls (list)
4502 WORD_LIST *list;
4504 register WORD_LIST *t;
4506 for (t = list; t; t = t->next)
4508 remove_quoted_nulls (t->word->word);
4509 t->word->flags &= ~W_HASQUOTEDNULL;
4513 /* **************************************************************** */
4514 /* */
4515 /* Functions for Matching and Removing Patterns */
4516 /* */
4517 /* **************************************************************** */
4519 #if defined (HANDLE_MULTIBYTE)
4520 # ifdef INCLUDE_UNUSED
4521 static unsigned char *
4522 mb_getcharlens (string, len)
4523 char *string;
4524 int len;
4526 int i, offset, last;
4527 unsigned char *ret;
4528 char *p;
4529 DECLARE_MBSTATE;
4531 i = offset = 0;
4532 last = 0;
4533 ret = (unsigned char *)xmalloc (len);
4534 memset (ret, 0, len);
4535 while (string[last])
4537 ADVANCE_CHAR (string, len, offset);
4538 ret[last] = offset - last;
4539 last = offset;
4541 return ret;
4543 # endif
4544 #endif
4546 /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
4547 can have one of 4 values:
4548 RP_LONG_LEFT remove longest matching portion at start of PARAM
4549 RP_SHORT_LEFT remove shortest matching portion at start of PARAM
4550 RP_LONG_RIGHT remove longest matching portion at end of PARAM
4551 RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
4554 #define RP_LONG_LEFT 1
4555 #define RP_SHORT_LEFT 2
4556 #define RP_LONG_RIGHT 3
4557 #define RP_SHORT_RIGHT 4
4559 /* Returns its first argument if nothing matched; new memory otherwise */
4560 static char *
4561 remove_upattern (param, pattern, op)
4562 char *param, *pattern;
4563 int op;
4565 register size_t len;
4566 register char *end;
4567 register char *p, *ret, c;
4569 len = STRLEN (param);
4570 end = param + len;
4572 switch (op)
4574 case RP_LONG_LEFT: /* remove longest match at start */
4575 for (p = end; p >= param; p--)
4577 c = *p; *p = '\0';
4578 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4580 *p = c;
4581 return (savestring (p));
4583 *p = c;
4586 break;
4588 case RP_SHORT_LEFT: /* remove shortest match at start */
4589 for (p = param; p <= end; p++)
4591 c = *p; *p = '\0';
4592 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4594 *p = c;
4595 return (savestring (p));
4597 *p = c;
4599 break;
4601 case RP_LONG_RIGHT: /* remove longest match at end */
4602 for (p = param; p <= end; p++)
4604 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4606 c = *p; *p = '\0';
4607 ret = savestring (param);
4608 *p = c;
4609 return (ret);
4612 break;
4614 case RP_SHORT_RIGHT: /* remove shortest match at end */
4615 for (p = end; p >= param; p--)
4617 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4619 c = *p; *p = '\0';
4620 ret = savestring (param);
4621 *p = c;
4622 return (ret);
4625 break;
4628 return (param); /* no match, return original string */
4631 #if defined (HANDLE_MULTIBYTE)
4632 /* Returns its first argument if nothing matched; new memory otherwise */
4633 static wchar_t *
4634 remove_wpattern (wparam, wstrlen, wpattern, op)
4635 wchar_t *wparam;
4636 size_t wstrlen;
4637 wchar_t *wpattern;
4638 int op;
4640 wchar_t wc, *ret;
4641 int n;
4643 switch (op)
4645 case RP_LONG_LEFT: /* remove longest match at start */
4646 for (n = wstrlen; n >= 0; n--)
4648 wc = wparam[n]; wparam[n] = L'\0';
4649 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4651 wparam[n] = wc;
4652 return (wcsdup (wparam + n));
4654 wparam[n] = wc;
4656 break;
4658 case RP_SHORT_LEFT: /* remove shortest match at start */
4659 for (n = 0; n <= wstrlen; n++)
4661 wc = wparam[n]; wparam[n] = L'\0';
4662 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4664 wparam[n] = wc;
4665 return (wcsdup (wparam + n));
4667 wparam[n] = wc;
4669 break;
4671 case RP_LONG_RIGHT: /* remove longest match at end */
4672 for (n = 0; n <= wstrlen; n++)
4674 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4676 wc = wparam[n]; wparam[n] = L'\0';
4677 ret = wcsdup (wparam);
4678 wparam[n] = wc;
4679 return (ret);
4682 break;
4684 case RP_SHORT_RIGHT: /* remove shortest match at end */
4685 for (n = wstrlen; n >= 0; n--)
4687 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4689 wc = wparam[n]; wparam[n] = L'\0';
4690 ret = wcsdup (wparam);
4691 wparam[n] = wc;
4692 return (ret);
4695 break;
4698 return (wparam); /* no match, return original string */
4700 #endif /* HANDLE_MULTIBYTE */
4702 static char *
4703 remove_pattern (param, pattern, op)
4704 char *param, *pattern;
4705 int op;
4707 char *xret;
4709 if (param == NULL)
4710 return (param);
4711 if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
4712 return (savestring (param));
4714 #if defined (HANDLE_MULTIBYTE)
4715 if (MB_CUR_MAX > 1)
4717 wchar_t *ret, *oret;
4718 size_t n;
4719 wchar_t *wparam, *wpattern;
4720 mbstate_t ps;
4722 /* XXX - could optimize here by checking param and pattern for multibyte
4723 chars with mbsmbchar and calling remove_upattern. */
4725 n = xdupmbstowcs (&wpattern, NULL, pattern);
4726 if (n == (size_t)-1)
4728 xret = remove_upattern (param, pattern, op);
4729 return ((xret == param) ? savestring (param) : xret);
4731 n = xdupmbstowcs (&wparam, NULL, param);
4733 if (n == (size_t)-1)
4735 free (wpattern);
4736 xret = remove_upattern (param, pattern, op);
4737 return ((xret == param) ? savestring (param) : xret);
4739 oret = ret = remove_wpattern (wparam, n, wpattern, op);
4740 /* Don't bother to convert wparam back to multibyte string if nothing
4741 matched; just return copy of original string */
4742 if (ret == wparam)
4744 free (wparam);
4745 free (wpattern);
4746 return (savestring (param));
4749 free (wparam);
4750 free (wpattern);
4752 n = strlen (param);
4753 xret = (char *)xmalloc (n + 1);
4754 memset (&ps, '\0', sizeof (mbstate_t));
4755 n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
4756 xret[n] = '\0'; /* just to make sure */
4757 free (oret);
4758 return xret;
4760 else
4761 #endif
4763 xret = remove_upattern (param, pattern, op);
4764 return ((xret == param) ? savestring (param) : xret);
4768 /* Match PAT anywhere in STRING and return the match boundaries.
4769 This returns 1 in case of a successful match, 0 otherwise. SP
4770 and EP are pointers into the string where the match begins and
4771 ends, respectively. MTYPE controls what kind of match is attempted.
4772 MATCH_BEG and MATCH_END anchor the match at the beginning and end
4773 of the string, respectively. The longest match is returned. */
4774 static int
4775 match_upattern (string, pat, mtype, sp, ep)
4776 char *string, *pat;
4777 int mtype;
4778 char **sp, **ep;
4780 int c, mlen;
4781 size_t len;
4782 register char *p, *p1, *npat;
4783 char *end;
4785 /* If the pattern doesn't match anywhere in the string, go ahead and
4786 short-circuit right away. A minor optimization, saves a bunch of
4787 unnecessary calls to strmatch (up to N calls for a string of N
4788 characters) if the match is unsuccessful. To preserve the semantics
4789 of the substring matches below, we make sure that the pattern has
4790 `*' as first and last character, making a new pattern if necessary. */
4791 /* XXX - check this later if I ever implement `**' with special meaning,
4792 since this will potentially result in `**' at the beginning or end */
4793 len = STRLEN (pat);
4794 if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
4796 int unescaped_backslash;
4797 char *pp;
4799 p = npat = (char *)xmalloc (len + 3);
4800 p1 = pat;
4801 if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob)))
4802 *p++ = '*';
4803 while (*p1)
4804 *p++ = *p1++;
4805 #if 1
4806 /* Need to also handle a pattern that ends with an unescaped backslash.
4807 For right now, we ignore it because the pattern matching code will
4808 fail the match anyway */
4809 /* If the pattern ends with a `*' we leave it alone if it's preceded by
4810 an even number of backslashes, but if it's escaped by a backslash
4811 we need to add another `*'. */
4812 if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\')))
4814 pp = p1 - 3;
4815 while (pp >= pat && *pp-- == '\\')
4816 unescaped_backslash = 1 - unescaped_backslash;
4817 if (unescaped_backslash)
4818 *p++ = '*';
4820 else if (mtype != MATCH_END && p1[-1] != '*')
4821 *p++ = '*';
4822 #else
4823 if (p1[-1] != '*' || p1[-2] == '\\')
4824 *p++ = '*';
4825 #endif
4826 *p = '\0';
4828 else
4829 npat = pat;
4830 c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
4831 if (npat != pat)
4832 free (npat);
4833 if (c == FNM_NOMATCH)
4834 return (0);
4836 len = STRLEN (string);
4837 end = string + len;
4839 mlen = umatchlen (pat, len);
4840 if (mlen > (int)len)
4841 return (0);
4843 switch (mtype)
4845 case MATCH_ANY:
4846 for (p = string; p <= end; p++)
4848 if (match_pattern_char (pat, p, FNMATCH_IGNCASE))
4850 p1 = (mlen == -1) ? end : p + mlen;
4851 /* p1 - p = length of portion of string to be considered
4852 p = current position in string
4853 mlen = number of characters consumed by match (-1 for entire string)
4854 end = end of string
4855 we want to break immediately if the potential match len
4856 is greater than the number of characters remaining in the
4857 string
4859 if (p1 > end)
4860 break;
4861 for ( ; p1 >= p; p1--)
4863 c = *p1; *p1 = '\0';
4864 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
4866 *p1 = c;
4867 *sp = p;
4868 *ep = p1;
4869 return 1;
4871 *p1 = c;
4872 #if 1
4873 /* If MLEN != -1, we have a fixed length pattern. */
4874 if (mlen != -1)
4875 break;
4876 #endif
4881 return (0);
4883 case MATCH_BEG:
4884 if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0)
4885 return (0);
4887 for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
4889 c = *p; *p = '\0';
4890 if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
4892 *p = c;
4893 *sp = string;
4894 *ep = p;
4895 return 1;
4897 *p = c;
4898 /* If MLEN != -1, we have a fixed length pattern. */
4899 if (mlen != -1)
4900 break;
4903 return (0);
4905 case MATCH_END:
4906 for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
4908 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
4910 *sp = p;
4911 *ep = end;
4912 return 1;
4914 /* If MLEN != -1, we have a fixed length pattern. */
4915 if (mlen != -1)
4916 break;
4919 return (0);
4922 return (0);
4925 #if defined (HANDLE_MULTIBYTE)
4927 #define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c))
4929 /* Match WPAT anywhere in WSTRING and return the match boundaries.
4930 This returns 1 in case of a successful match, 0 otherwise. Wide
4931 character version. */
4932 static int
4933 match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
4934 wchar_t *wstring;
4935 char **indices;
4936 size_t wstrlen;
4937 wchar_t *wpat;
4938 int mtype;
4939 char **sp, **ep;
4941 wchar_t wc, *wp, *nwpat, *wp1;
4942 size_t len;
4943 int mlen;
4944 int n, n1, n2, simple;
4946 simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
4947 #if defined (EXTENDED_GLOB)
4948 if (extended_glob)
4949 simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
4950 #endif
4952 /* If the pattern doesn't match anywhere in the string, go ahead and
4953 short-circuit right away. A minor optimization, saves a bunch of
4954 unnecessary calls to strmatch (up to N calls for a string of N
4955 characters) if the match is unsuccessful. To preserve the semantics
4956 of the substring matches below, we make sure that the pattern has
4957 `*' as first and last character, making a new pattern if necessary. */
4958 len = wcslen (wpat);
4959 if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
4961 int unescaped_backslash;
4962 wchar_t *wpp;
4964 wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
4965 wp1 = wpat;
4966 if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
4967 *wp++ = L'*';
4968 while (*wp1 != L'\0')
4969 *wp++ = *wp1++;
4970 #if 1
4971 /* See comments above in match_upattern. */
4972 if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\'))
4974 wpp = wp1 - 3;
4975 while (wpp >= wpat && *wpp-- == L'\\')
4976 unescaped_backslash = 1 - unescaped_backslash;
4977 if (unescaped_backslash)
4978 *wp++ = L'*';
4980 else if (wp1[-1] != L'*')
4981 *wp++ = L'*';
4982 #else
4983 if (wp1[-1] != L'*' || wp1[-2] == L'\\')
4984 *wp++ = L'*';
4985 #endif
4986 *wp = '\0';
4988 else
4989 nwpat = wpat;
4990 len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
4991 if (nwpat != wpat)
4992 free (nwpat);
4993 if (len == FNM_NOMATCH)
4994 return (0);
4996 mlen = wmatchlen (wpat, wstrlen);
4997 if (mlen > (int)wstrlen)
4998 return (0);
5000 /* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
5001 switch (mtype)
5003 case MATCH_ANY:
5004 for (n = 0; n <= wstrlen; n++)
5006 n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE);
5007 if (n2)
5009 n1 = (mlen == -1) ? wstrlen : n + mlen;
5010 if (n1 > wstrlen)
5011 break;
5013 for ( ; n1 >= n; n1--)
5015 wc = wstring[n1]; wstring[n1] = L'\0';
5016 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5018 wstring[n1] = wc;
5019 *sp = indices[n];
5020 *ep = indices[n1];
5021 return 1;
5023 wstring[n1] = wc;
5024 /* If MLEN != -1, we have a fixed length pattern. */
5025 if (mlen != -1)
5026 break;
5031 return (0);
5033 case MATCH_BEG:
5034 if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0)
5035 return (0);
5037 for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
5039 wc = wstring[n]; wstring[n] = L'\0';
5040 if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5042 wstring[n] = wc;
5043 *sp = indices[0];
5044 *ep = indices[n];
5045 return 1;
5047 wstring[n] = wc;
5048 /* If MLEN != -1, we have a fixed length pattern. */
5049 if (mlen != -1)
5050 break;
5053 return (0);
5055 case MATCH_END:
5056 for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
5058 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5060 *sp = indices[n];
5061 *ep = indices[wstrlen];
5062 return 1;
5064 /* If MLEN != -1, we have a fixed length pattern. */
5065 if (mlen != -1)
5066 break;
5069 return (0);
5072 return (0);
5074 #undef WFOLD
5075 #endif /* HANDLE_MULTIBYTE */
5077 static int
5078 match_pattern (string, pat, mtype, sp, ep)
5079 char *string, *pat;
5080 int mtype;
5081 char **sp, **ep;
5083 #if defined (HANDLE_MULTIBYTE)
5084 int ret;
5085 size_t n;
5086 wchar_t *wstring, *wpat;
5087 char **indices;
5088 #endif
5090 if (string == 0 || pat == 0 || *pat == 0)
5091 return (0);
5093 #if defined (HANDLE_MULTIBYTE)
5094 if (MB_CUR_MAX > 1)
5096 if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
5097 return (match_upattern (string, pat, mtype, sp, ep));
5099 n = xdupmbstowcs (&wpat, NULL, pat);
5100 if (n == (size_t)-1)
5101 return (match_upattern (string, pat, mtype, sp, ep));
5102 n = xdupmbstowcs (&wstring, &indices, string);
5103 if (n == (size_t)-1)
5105 free (wpat);
5106 return (match_upattern (string, pat, mtype, sp, ep));
5108 ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
5110 free (wpat);
5111 free (wstring);
5112 free (indices);
5114 return (ret);
5116 else
5117 #endif
5118 return (match_upattern (string, pat, mtype, sp, ep));
5121 static int
5122 getpatspec (c, value)
5123 int c;
5124 char *value;
5126 if (c == '#')
5127 return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
5128 else /* c == '%' */
5129 return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
5132 /* Posix.2 says that the WORD should be run through tilde expansion,
5133 parameter expansion, command substitution and arithmetic expansion.
5134 This leaves the result quoted, so quote_string_for_globbing () has
5135 to be called to fix it up for strmatch (). If QUOTED is non-zero,
5136 it means that the entire expression was enclosed in double quotes.
5137 This means that quoting characters in the pattern do not make any
5138 special pattern characters quoted. For example, the `*' in the
5139 following retains its special meaning: "${foo#'*'}". */
5140 static char *
5141 getpattern (value, quoted, expandpat)
5142 char *value;
5143 int quoted, expandpat;
5145 char *pat, *tword;
5146 WORD_LIST *l;
5147 #if 0
5148 int i;
5149 #endif
5150 /* There is a problem here: how to handle single or double quotes in the
5151 pattern string when the whole expression is between double quotes?
5152 POSIX.2 says that enclosing double quotes do not cause the pattern to
5153 be quoted, but does that leave us a problem with @ and array[@] and their
5154 expansions inside a pattern? */
5155 #if 0
5156 if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
5158 i = 0;
5159 pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ);
5160 free (tword);
5161 tword = pat;
5163 #endif
5165 /* expand_string_for_pat () leaves WORD quoted and does not perform
5166 word splitting. */
5167 l = *value ? expand_string_for_pat (value,
5168 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
5169 (int *)NULL, (int *)NULL)
5170 : (WORD_LIST *)0;
5171 if (l)
5172 word_list_remove_quoted_nulls (l);
5173 pat = string_list (l);
5174 dispose_words (l);
5175 if (pat)
5177 tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
5178 free (pat);
5179 pat = tword;
5181 return (pat);
5184 #if 0
5185 /* Handle removing a pattern from a string as a result of ${name%[%]value}
5186 or ${name#[#]value}. */
5187 static char *
5188 variable_remove_pattern (value, pattern, patspec, quoted)
5189 char *value, *pattern;
5190 int patspec, quoted;
5192 char *tword;
5194 tword = remove_pattern (value, pattern, patspec);
5196 return (tword);
5198 #endif
5200 static char *
5201 list_remove_pattern (list, pattern, patspec, itype, quoted)
5202 WORD_LIST *list;
5203 char *pattern;
5204 int patspec, itype, quoted;
5206 WORD_LIST *new, *l;
5207 WORD_DESC *w;
5208 char *tword;
5210 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
5212 tword = remove_pattern (l->word->word, pattern, patspec);
5213 w = alloc_word_desc ();
5214 w->word = tword ? tword : savestring ("");
5215 new = make_word_list (w, new);
5218 l = REVERSE_LIST (new, WORD_LIST *);
5219 tword = string_list_pos_params (itype, l, quoted, 0);
5220 dispose_words (l);
5222 return (tword);
5225 static char *
5226 parameter_list_remove_pattern (itype, pattern, patspec, quoted)
5227 int itype;
5228 char *pattern;
5229 int patspec, quoted;
5231 char *ret;
5232 WORD_LIST *list;
5234 list = list_rest_of_args ();
5235 if (list == 0)
5236 return ((char *)NULL);
5237 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5238 dispose_words (list);
5239 return (ret);
5242 #if defined (ARRAY_VARS)
5243 static char *
5244 array_remove_pattern (var, pattern, patspec, starsub, quoted)
5245 SHELL_VAR *var;
5246 char *pattern;
5247 int patspec;
5248 int starsub; /* so we can figure out how it's indexed */
5249 int quoted;
5251 ARRAY *a;
5252 HASH_TABLE *h;
5253 int itype;
5254 char *ret;
5255 WORD_LIST *list;
5256 SHELL_VAR *v;
5258 v = var; /* XXX - for now */
5260 itype = starsub ? '*' : '@';
5262 a = (v && array_p (v)) ? array_cell (v) : 0;
5263 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
5265 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
5266 if (list == 0)
5267 return ((char *)NULL);
5268 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5269 dispose_words (list);
5271 return ret;
5273 #endif /* ARRAY_VARS */
5275 static char *
5276 parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags)
5277 char *varname, *value;
5278 int ind;
5279 char *patstr;
5280 int rtype, quoted, flags;
5282 int vtype, patspec, starsub;
5283 char *temp1, *val, *pattern, *oname;
5284 SHELL_VAR *v;
5286 if (value == 0)
5287 return ((char *)NULL);
5289 oname = this_command_name;
5290 this_command_name = varname;
5292 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
5293 if (vtype == -1)
5295 this_command_name = oname;
5296 return ((char *)NULL);
5299 starsub = vtype & VT_STARSUB;
5300 vtype &= ~VT_STARSUB;
5302 patspec = getpatspec (rtype, patstr);
5303 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
5304 patstr++;
5306 /* Need to pass getpattern newly-allocated memory in case of expansion --
5307 the expansion code will free the passed string on an error. */
5308 temp1 = savestring (patstr);
5309 pattern = getpattern (temp1, quoted, 1);
5310 free (temp1);
5312 temp1 = (char *)NULL; /* shut up gcc */
5313 switch (vtype)
5315 case VT_VARIABLE:
5316 case VT_ARRAYMEMBER:
5317 temp1 = remove_pattern (val, pattern, patspec);
5318 if (vtype == VT_VARIABLE)
5319 FREE (val);
5320 if (temp1)
5322 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5323 ? quote_string (temp1)
5324 : quote_escapes (temp1);
5325 free (temp1);
5326 temp1 = val;
5328 break;
5329 #if defined (ARRAY_VARS)
5330 case VT_ARRAYVAR:
5331 temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted);
5332 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5334 val = quote_escapes (temp1);
5335 free (temp1);
5336 temp1 = val;
5338 break;
5339 #endif
5340 case VT_POSPARMS:
5341 temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
5342 if (temp1 && quoted == 0 && ifs_is_null)
5344 /* Posix interp 888 */
5346 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5348 val = quote_escapes (temp1);
5349 free (temp1);
5350 temp1 = val;
5352 break;
5355 this_command_name = oname;
5357 FREE (pattern);
5358 return temp1;
5361 #if defined (PROCESS_SUBSTITUTION)
5363 static void reap_some_procsubs PARAMS((int));
5365 /*****************************************************************/
5366 /* */
5367 /* Hacking Process Substitution */
5368 /* */
5369 /*****************************************************************/
5371 #if !defined (HAVE_DEV_FD)
5372 /* Named pipes must be removed explicitly with `unlink'. This keeps a list
5373 of FIFOs the shell has open. unlink_fifo_list will walk the list and
5374 unlink the ones that don't have a living process on the other end.
5375 unlink_all_fifos will walk the list and unconditionally unlink them, trying
5376 to open and close the FIFO first to release any child processes sleeping on
5377 the FIFO. add_fifo_list adds the name of an open FIFO to the list.
5378 NFIFO is a count of the number of FIFOs in the list. */
5379 #define FIFO_INCR 20
5381 /* PROC value of -1 means the process has been reaped and the FIFO needs to
5382 be removed. PROC value of 0 means the slot is unused. */
5383 struct temp_fifo {
5384 char *file;
5385 pid_t proc;
5388 static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
5389 static int nfifo;
5390 static int fifo_list_size;
5392 void
5393 clear_fifo_list ()
5395 int i;
5397 for (i = 0; i < fifo_list_size; i++)
5399 if (fifo_list[i].file)
5400 free (fifo_list[i].file);
5401 fifo_list[i].file = NULL;
5402 fifo_list[i].proc = 0;
5404 nfifo = 0;
5407 void *
5408 copy_fifo_list (sizep)
5409 int *sizep;
5411 if (sizep)
5412 *sizep = 0;
5413 return (void *)NULL;
5416 static void
5417 add_fifo_list (pathname)
5418 char *pathname;
5420 int osize, i;
5422 if (nfifo >= fifo_list_size - 1)
5424 osize = fifo_list_size;
5425 fifo_list_size += FIFO_INCR;
5426 fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
5427 fifo_list_size * sizeof (struct temp_fifo));
5428 for (i = osize; i < fifo_list_size; i++)
5430 fifo_list[i].file = (char *)NULL;
5431 fifo_list[i].proc = 0; /* unused */
5435 fifo_list[nfifo].file = savestring (pathname);
5436 nfifo++;
5439 void
5440 unlink_fifo (i)
5441 int i;
5443 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
5445 unlink (fifo_list[i].file);
5446 free (fifo_list[i].file);
5447 fifo_list[i].file = (char *)NULL;
5448 fifo_list[i].proc = 0;
5452 void
5453 unlink_fifo_list ()
5455 int saved, i, j;
5457 if (nfifo == 0)
5458 return;
5460 for (i = saved = 0; i < nfifo; i++)
5462 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
5464 unlink (fifo_list[i].file);
5465 free (fifo_list[i].file);
5466 fifo_list[i].file = (char *)NULL;
5467 fifo_list[i].proc = 0;
5469 else
5470 saved++;
5473 /* If we didn't remove some of the FIFOs, compact the list. */
5474 if (saved)
5476 for (i = j = 0; i < nfifo; i++)
5477 if (fifo_list[i].file)
5479 if (i != j)
5481 fifo_list[j].file = fifo_list[i].file;
5482 fifo_list[j].proc = fifo_list[i].proc;
5483 fifo_list[i].file = (char *)NULL;
5484 fifo_list[i].proc = 0;
5486 j++;
5488 nfifo = j;
5490 else
5491 nfifo = 0;
5494 void
5495 unlink_all_fifos ()
5497 int i, fd;
5499 if (nfifo == 0)
5500 return;
5502 for (i = 0; i < nfifo; i++)
5504 fifo_list[i].proc = (pid_t)-1;
5505 fd = open (fifo_list[i].file, O_RDWR|O_NONBLOCK);
5506 unlink_fifo (i);
5507 if (fd >= 0)
5508 close (fd);
5511 nfifo = 0;
5514 /* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
5515 from some point in the past, and close all open FIFOs in fifo_list
5516 that are not marked as active in LIST. If LIST is NULL, close
5517 everything in fifo_list. LSIZE is the number of elements in LIST, in
5518 case it's larger than fifo_list_size (size of fifo_list). */
5519 void
5520 close_new_fifos (list, lsize)
5521 void *list;
5522 int lsize;
5524 int i;
5525 char *plist;
5527 if (list == 0)
5529 unlink_fifo_list ();
5530 return;
5533 for (plist = (char *)list, i = 0; i < lsize; i++)
5534 if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
5535 unlink_fifo (i);
5537 for (i = lsize; i < fifo_list_size; i++)
5538 unlink_fifo (i);
5542 find_procsub_child (pid)
5543 pid_t pid;
5545 int i;
5547 for (i = 0; i < nfifo; i++)
5548 if (fifo_list[i].proc == pid)
5549 return i;
5550 return -1;
5553 void
5554 set_procsub_status (ind, pid, status)
5555 int ind;
5556 pid_t pid;
5557 int status;
5559 if (ind >= 0 && ind < nfifo)
5560 fifo_list[ind].proc = (pid_t)-1; /* sentinel */
5563 /* If we've marked the process for this procsub as dead, close the
5564 associated file descriptor and delete the FIFO. */
5565 static void
5566 reap_some_procsubs (max)
5567 int max;
5569 int i;
5571 for (i = 0; i < max; i++)
5572 if (fifo_list[i].proc == (pid_t)-1) /* reaped */
5573 unlink_fifo (i);
5576 void
5577 reap_procsubs ()
5579 reap_some_procsubs (nfifo);
5582 #if 0
5583 /* UNUSED */
5584 void
5585 wait_procsubs ()
5587 int i, r;
5589 for (i = 0; i < nfifo; i++)
5591 if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0)
5593 r = wait_for (fifo_list[i].proc, 0);
5594 save_proc_status (fifo_list[i].proc, r);
5595 fifo_list[i].proc = (pid_t)-1;
5599 #endif
5602 fifos_pending ()
5604 return nfifo;
5608 num_fifos ()
5610 return nfifo;
5613 static char *
5614 make_named_pipe ()
5616 char *tname;
5618 tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
5619 if (mkfifo (tname, 0600) < 0)
5621 free (tname);
5622 return ((char *)NULL);
5625 add_fifo_list (tname);
5626 return (tname);
5629 #else /* HAVE_DEV_FD */
5631 /* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
5632 has open to children. NFDS is a count of the number of bits currently
5633 set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
5634 of open files. */
5635 /* dev_fd_list[I] value of -1 means the process has been reaped and file
5636 descriptor I needs to be closed. Value of 0 means the slot is unused. */
5638 static pid_t *dev_fd_list = (pid_t *)NULL;
5639 static int nfds;
5640 static int totfds; /* The highest possible number of open files. */
5642 void
5643 clear_fifo (i)
5644 int i;
5646 if (dev_fd_list[i])
5648 dev_fd_list[i] = 0;
5649 nfds--;
5653 void
5654 clear_fifo_list ()
5656 register int i;
5658 if (nfds == 0)
5659 return;
5661 for (i = 0; nfds && i < totfds; i++)
5662 clear_fifo (i);
5664 nfds = 0;
5667 void *
5668 copy_fifo_list (sizep)
5669 int *sizep;
5671 void *ret;
5673 if (nfds == 0 || totfds == 0)
5675 if (sizep)
5676 *sizep = 0;
5677 return (void *)NULL;
5680 if (sizep)
5681 *sizep = totfds;
5682 ret = xmalloc (totfds * sizeof (pid_t));
5683 return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t)));
5686 static void
5687 add_fifo_list (fd)
5688 int fd;
5690 if (dev_fd_list == 0 || fd >= totfds)
5692 int ofds;
5694 ofds = totfds;
5695 totfds = getdtablesize ();
5696 if (totfds < 0 || totfds > 256)
5697 totfds = 256;
5698 if (fd >= totfds)
5699 totfds = fd + 2;
5701 dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0]));
5702 /* XXX - might need a loop for this */
5703 memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t));
5706 dev_fd_list[fd] = 1; /* marker; updated later */
5707 nfds++;
5711 fifos_pending ()
5713 return 0; /* used for cleanup; not needed with /dev/fd */
5717 num_fifos ()
5719 return nfds;
5722 void
5723 unlink_fifo (fd)
5724 int fd;
5726 if (dev_fd_list[fd])
5728 close (fd);
5729 dev_fd_list[fd] = 0;
5730 nfds--;
5734 void
5735 unlink_fifo_list ()
5737 register int i;
5739 if (nfds == 0)
5740 return;
5742 for (i = totfds-1; nfds && i >= 0; i--)
5743 unlink_fifo (i);
5745 nfds = 0;
5748 void
5749 unlink_all_fifos ()
5751 unlink_fifo_list ();
5754 /* Take LIST, which is a snapshot copy of dev_fd_list from some point in
5755 the past, and close all open fds in dev_fd_list that are not marked
5756 as open in LIST. If LIST is NULL, close everything in dev_fd_list.
5757 LSIZE is the number of elements in LIST, in case it's larger than
5758 totfds (size of dev_fd_list). */
5759 void
5760 close_new_fifos (list, lsize)
5761 void *list;
5762 int lsize;
5764 int i;
5765 pid_t *plist;
5767 if (list == 0)
5769 unlink_fifo_list ();
5770 return;
5773 for (plist = (pid_t *)list, i = 0; i < lsize; i++)
5774 if (plist[i] == 0 && i < totfds && dev_fd_list[i])
5775 unlink_fifo (i);
5777 for (i = lsize; i < totfds; i++)
5778 unlink_fifo (i);
5782 find_procsub_child (pid)
5783 pid_t pid;
5785 int i;
5787 if (nfds == 0)
5788 return -1;
5790 for (i = 0; i < totfds; i++)
5791 if (dev_fd_list[i] == pid)
5792 return i;
5794 return -1;
5797 void
5798 set_procsub_status (ind, pid, status)
5799 int ind;
5800 pid_t pid;
5801 int status;
5803 if (ind >= 0 && ind < totfds)
5804 dev_fd_list[ind] = (pid_t)-1; /* sentinel */
5807 /* If we've marked the process for this procsub as dead, close the
5808 associated file descriptor. */
5809 static void
5810 reap_some_procsubs (max)
5811 int max;
5813 int i;
5815 for (i = 0; nfds > 0 && i < max; i++)
5816 if (dev_fd_list[i] == (pid_t)-1)
5817 unlink_fifo (i);
5820 void
5821 reap_procsubs ()
5823 reap_some_procsubs (totfds);
5826 #if 0
5827 /* UNUSED */
5828 void
5829 wait_procsubs ()
5831 int i, r;
5833 for (i = 0; nfds > 0 && i < totfds; i++)
5835 if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0)
5837 r = wait_for (dev_fd_list[i], 0);
5838 save_proc_status (dev_fd_list[i], r);
5839 dev_fd_list[i] = (pid_t)-1;
5843 #endif
5845 #if defined (NOTDEF)
5846 print_dev_fd_list ()
5848 register int i;
5850 fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
5851 fflush (stderr);
5853 for (i = 0; i < totfds; i++)
5855 if (dev_fd_list[i])
5856 fprintf (stderr, " %d", i);
5858 fprintf (stderr, "\n");
5860 #endif /* NOTDEF */
5862 static char *
5863 make_dev_fd_filename (fd)
5864 int fd;
5866 char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
5868 ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
5870 strcpy (ret, DEV_FD_PREFIX);
5871 p = inttostr (fd, intbuf, sizeof (intbuf));
5872 strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
5874 add_fifo_list (fd);
5875 return (ret);
5878 #endif /* HAVE_DEV_FD */
5880 /* Return a filename that will open a connection to the process defined by
5881 executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
5882 a filename in /dev/fd corresponding to a descriptor that is one of the
5883 ends of the pipe. If not defined, we use named pipes on systems that have
5884 them. Systems without /dev/fd and named pipes are out of luck.
5886 OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
5887 use the read end of the pipe and dup that file descriptor to fd 0 in
5888 the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
5889 writing or use the write end of the pipe in the child, and dup that
5890 file descriptor to fd 1 in the child. The parent does the opposite. */
5892 static char *
5893 process_substitute (string, open_for_read_in_child)
5894 char *string;
5895 int open_for_read_in_child;
5897 char *pathname;
5898 int fd, result, rc, function_value;
5899 pid_t old_pid, pid;
5900 #if defined (HAVE_DEV_FD)
5901 int parent_pipe_fd, child_pipe_fd;
5902 int fildes[2];
5903 #endif /* HAVE_DEV_FD */
5904 #if defined (JOB_CONTROL)
5905 pid_t old_pipeline_pgrp;
5906 #endif
5908 if (!string || !*string || wordexp_only)
5909 return ((char *)NULL);
5911 #if !defined (HAVE_DEV_FD)
5912 pathname = make_named_pipe ();
5913 #else /* HAVE_DEV_FD */
5914 if (pipe (fildes) < 0)
5916 sys_error ("%s", _("cannot make pipe for process substitution"));
5917 return ((char *)NULL);
5919 /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
5920 the pipe in the parent, otherwise the read end. */
5921 parent_pipe_fd = fildes[open_for_read_in_child];
5922 child_pipe_fd = fildes[1 - open_for_read_in_child];
5923 /* Move the parent end of the pipe to some high file descriptor, to
5924 avoid clashes with FDs used by the script. */
5925 parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
5927 pathname = make_dev_fd_filename (parent_pipe_fd);
5928 #endif /* HAVE_DEV_FD */
5930 if (pathname == 0)
5932 sys_error ("%s", _("cannot make pipe for process substitution"));
5933 return ((char *)NULL);
5936 old_pid = last_made_pid;
5938 #if defined (JOB_CONTROL)
5939 old_pipeline_pgrp = pipeline_pgrp;
5940 if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0)
5941 pipeline_pgrp = shell_pgrp;
5942 save_pipeline (1);
5943 #endif /* JOB_CONTROL */
5945 pid = make_child ((char *)NULL, FORK_ASYNC);
5946 if (pid == 0)
5948 #if 0
5949 int old_interactive;
5951 old_interactive = interactive;
5952 #endif
5953 /* The currently-executing shell is not interactive */
5954 interactive = 0;
5956 reset_terminating_signals (); /* XXX */
5957 free_pushed_string_input ();
5958 /* Cancel traps, in trap.c. */
5959 restore_original_signals (); /* XXX - what about special builtins? bush-4.2 */
5960 QUIT; /* catch any interrupts we got post-fork */
5961 setup_async_signals ();
5962 #if 0
5963 if (open_for_read_in_child == 0 && old_interactive && (bush_input.type == st_stdin || bush_input.type == st_stream))
5964 async_redirect_stdin ();
5965 #endif
5967 subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB|SUBSHELL_ASYNC;
5969 /* We don't inherit the verbose option for command substitutions now, so
5970 let's try it for process substitutions. */
5971 change_flag ('v', FLAG_OFF);
5973 /* if we're expanding a redirection, we shouldn't have access to the
5974 temporary environment, but commands in the subshell should have
5975 access to their own temporary environment. */
5976 if (expanding_redir)
5977 flush_temporary_env ();
5980 #if defined (JOB_CONTROL)
5981 set_sigchld_handler ();
5982 stop_making_children ();
5983 /* XXX - should we only do this in the parent? (as in command subst) */
5984 pipeline_pgrp = old_pipeline_pgrp;
5985 #else
5986 stop_making_children ();
5987 #endif /* JOB_CONTROL */
5989 if (pid < 0)
5991 sys_error ("%s", _("cannot make child for process substitution"));
5992 free (pathname);
5993 #if defined (HAVE_DEV_FD)
5994 close (parent_pipe_fd);
5995 close (child_pipe_fd);
5996 #endif /* HAVE_DEV_FD */
5997 #if defined (JOB_CONTROL)
5998 restore_pipeline (1);
5999 #endif
6000 return ((char *)NULL);
6003 if (pid > 0)
6005 #if defined (JOB_CONTROL)
6006 last_procsub_child = restore_pipeline (0);
6007 /* We assume that last_procsub_child->next == last_procsub_child because
6008 of how jobs.c:add_process() works. */
6009 last_procsub_child->next = 0;
6010 procsub_add (last_procsub_child);
6011 #endif
6013 #if defined (HAVE_DEV_FD)
6014 dev_fd_list[parent_pipe_fd] = pid;
6015 #else
6016 fifo_list[nfifo-1].proc = pid;
6017 #endif
6019 last_made_pid = old_pid;
6021 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
6022 close_pgrp_pipe ();
6023 #endif /* JOB_CONTROL && PGRP_PIPE */
6025 #if defined (HAVE_DEV_FD)
6026 close (child_pipe_fd);
6027 #endif /* HAVE_DEV_FD */
6029 return (pathname);
6032 set_sigint_handler ();
6034 #if defined (JOB_CONTROL)
6035 /* make sure we don't have any job control */
6036 set_job_control (0);
6038 /* Clear out any existing list of process substitutions */
6039 procsub_clear ();
6041 /* The idea is that we want all the jobs we start from an async process
6042 substitution to be in the same process group, but not the same pgrp
6043 as our parent shell, since we don't want to affect our parent shell's
6044 jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example.
6045 If pipeline_pgrp != shell_pgrp, we assume that there is a job control
6046 shell somewhere in our parent process chain (since make_child initializes
6047 pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this
6048 case is to set pipeline_pgrp to our PID, so all jobs started by this
6049 process have that same pgrp and we are basically the process group leader.
6050 This should not have negative effects on child processes surviving
6051 after we exit, since we wait for the children we create, but that is
6052 something to watch for. */
6054 if (pipeline_pgrp != shell_pgrp)
6055 pipeline_pgrp = getpid ();
6056 #endif /* JOB_CONTROL */
6058 #if !defined (HAVE_DEV_FD)
6059 /* Open the named pipe in the child. */
6060 fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY);
6061 if (fd < 0)
6063 /* Two separate strings for ease of translation. */
6064 if (open_for_read_in_child)
6065 sys_error (_("cannot open named pipe %s for reading"), pathname);
6066 else
6067 sys_error (_("cannot open named pipe %s for writing"), pathname);
6069 exit (127);
6071 if (open_for_read_in_child)
6073 if (sh_unset_nodelay_mode (fd) < 0)
6075 sys_error (_("cannot reset nodelay mode for fd %d"), fd);
6076 exit (127);
6079 #else /* HAVE_DEV_FD */
6080 fd = child_pipe_fd;
6081 #endif /* HAVE_DEV_FD */
6083 /* Discard buffered stdio output before replacing the underlying file
6084 descriptor. */
6085 if (open_for_read_in_child == 0)
6086 fpurge (stdout);
6088 if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
6090 sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
6091 open_for_read_in_child ? 0 : 1);
6092 exit (127);
6095 if (fd != (open_for_read_in_child ? 0 : 1))
6096 close (fd);
6098 /* Need to close any files that this process has open to pipes inherited
6099 from its parent. */
6100 if (current_fds_to_close)
6102 close_fd_bitmap (current_fds_to_close);
6103 current_fds_to_close = (struct fd_bitmap *)NULL;
6106 #if defined (HAVE_DEV_FD)
6107 /* Make sure we close the parent's end of the pipe and clear the slot
6108 in the fd list so it is not closed later, if reallocated by, for
6109 instance, pipe(2). */
6110 close (parent_pipe_fd);
6111 dev_fd_list[parent_pipe_fd] = 0;
6112 #endif /* HAVE_DEV_FD */
6114 /* subshells shouldn't have this flag, which controls using the temporary
6115 environment for variable lookups. We have already flushed the temporary
6116 environment above in the case we're expanding a redirection, so processes
6117 executed by this command need to be able to set it independently of their
6118 parent. */
6119 expanding_redir = 0;
6121 remove_quoted_escapes (string);
6123 #if 0 /* TAG: bush-5.2 */
6124 startup_state = 2; /* see if we can avoid a fork */
6125 parse_and_execute_level = 0;
6126 #endif
6128 /* Give process substitution a place to jump back to on failure,
6129 so we don't go back up to main (). */
6130 result = setjmp_nosigs (top_level);
6132 /* If we're running a process substitution inside a shell function,
6133 trap `return' so we don't return from the function in the subshell
6134 and go off to never-never land. */
6135 if (result == 0 && return_catch_flag)
6136 function_value = setjmp_nosigs (return_catch);
6137 else
6138 function_value = 0;
6140 if (result == ERREXIT)
6141 rc = last_command_exit_value;
6142 else if (result == EXITPROG)
6143 rc = last_command_exit_value;
6144 else if (result)
6145 rc = EXECUTION_FAILURE;
6146 else if (function_value)
6147 rc = return_catch_value;
6148 else
6150 subshell_level++;
6151 rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
6152 /* leave subshell level intact for any exit trap */
6155 #if !defined (HAVE_DEV_FD)
6156 /* Make sure we close the named pipe in the child before we exit. */
6157 close (open_for_read_in_child ? 0 : 1);
6158 #endif /* !HAVE_DEV_FD */
6160 last_command_exit_value = rc;
6161 rc = run_exit_trap ();
6162 exit (rc);
6163 /*NOTREACHED*/
6165 #endif /* PROCESS_SUBSTITUTION */
6167 /***********************************/
6168 /* */
6169 /* Command Substitution */
6170 /* */
6171 /***********************************/
6173 static char *
6174 read_comsub (fd, quoted, flags, rflag)
6175 int fd, quoted, flags;
6176 int *rflag;
6178 char *istring, buf[512], *bufp;
6179 int istring_index, c, tflag, skip_ctlesc, skip_ctlnul;
6180 int mb_cur_max;
6181 size_t istring_size;
6182 ssize_t bufn;
6183 int nullbyte;
6184 #if defined (HANDLE_MULTIBYTE)
6185 mbstate_t ps;
6186 wchar_t wc;
6187 size_t mblen;
6188 int i;
6189 #endif
6191 istring = (char *)NULL;
6192 istring_index = istring_size = bufn = tflag = 0;
6194 skip_ctlesc = ifs_cmap[CTLESC];
6195 skip_ctlnul = ifs_cmap[CTLNUL];
6197 mb_cur_max = MB_CUR_MAX;
6198 nullbyte = 0;
6200 /* Read the output of the command through the pipe. */
6201 while (1)
6203 if (fd < 0)
6204 break;
6205 if (--bufn <= 0)
6207 bufn = zread (fd, buf, sizeof (buf));
6208 if (bufn <= 0)
6209 break;
6210 bufp = buf;
6212 c = *bufp++;
6214 if (c == 0)
6216 #if 1
6217 if (nullbyte == 0)
6219 internal_warning ("%s", _("command substitution: ignored null byte in input"));
6220 nullbyte = 1;
6222 #endif
6223 continue;
6226 /* Add the character to ISTRING, possibly after resizing it. */
6227 RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512);
6229 /* This is essentially quote_string inline */
6230 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
6231 istring[istring_index++] = CTLESC;
6232 else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC)
6233 istring[istring_index++] = CTLESC;
6234 /* Escape CTLESC and CTLNUL in the output to protect those characters
6235 from the rest of the word expansions (word splitting and globbing.)
6236 This is essentially quote_escapes inline. */
6237 else if (skip_ctlesc == 0 && c == CTLESC)
6238 istring[istring_index++] = CTLESC;
6239 else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
6240 istring[istring_index++] = CTLESC;
6242 #if defined (HANDLE_MULTIBYTE)
6243 if ((locale_utf8locale && (c & 0x80)) ||
6244 (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127))
6246 /* read a multibyte character from buf */
6247 /* punt on the hard case for now */
6248 memset (&ps, '\0', sizeof (mbstate_t));
6249 mblen = mbrtowc (&wc, bufp-1, bufn+1, &ps);
6250 if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1)
6251 istring[istring_index++] = c;
6252 else
6254 istring[istring_index++] = c;
6255 for (i = 0; i < mblen-1; i++)
6256 istring[istring_index++] = *bufp++;
6257 bufn -= mblen - 1;
6259 continue;
6261 #endif
6263 istring[istring_index++] = c;
6266 if (istring)
6267 istring[istring_index] = '\0';
6269 /* If we read no output, just return now and save ourselves some
6270 trouble. */
6271 if (istring_index == 0)
6273 FREE (istring);
6274 if (rflag)
6275 *rflag = tflag;
6276 return (char *)NULL;
6279 /* Strip trailing newlines from the output of the command. */
6280 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6282 while (istring_index > 0)
6284 if (istring[istring_index - 1] == '\n')
6286 --istring_index;
6288 /* If the newline was quoted, remove the quoting char. */
6289 if (istring[istring_index - 1] == CTLESC)
6290 --istring_index;
6292 else
6293 break;
6295 istring[istring_index] = '\0';
6297 else
6298 strip_trailing (istring, istring_index - 1, 1);
6300 if (rflag)
6301 *rflag = tflag;
6302 return istring;
6305 /* Perform command substitution on STRING. This returns a WORD_DESC * with the
6306 contained string possibly quoted. */
6307 WORD_DESC *
6308 command_substitute (string, quoted, flags)
6309 char *string;
6310 int quoted;
6311 int flags;
6313 pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
6314 char *istring, *s;
6315 int result, fildes[2], function_value, pflags, rc, tflag, fork_flags;
6316 WORD_DESC *ret;
6317 sigset_t set, oset;
6319 istring = (char *)NULL;
6321 /* Don't fork () if there is no need to. In the case of no command to
6322 run, just return NULL. */
6323 #if 1
6324 for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++)
6326 if (s == 0 || *s == 0)
6327 return ((WORD_DESC *)NULL);
6328 #else
6329 if (!string || !*string || (string[0] == '\n' && !string[1]))
6330 return ((WORD_DESC *)NULL);
6331 #endif
6333 if (wordexp_only && read_but_dont_execute)
6335 last_command_exit_value = EX_WEXPCOMSUB;
6336 jump_to_top_level (EXITPROG);
6339 /* We're making the assumption here that the command substitution will
6340 eventually run a command from the file system. Since we'll run
6341 maybe_make_export_env in this subshell before executing that command,
6342 the parent shell and any other shells it starts will have to remake
6343 the environment. If we make it before we fork, other shells won't
6344 have to. Don't bother if we have any temporary variable assignments,
6345 though, because the export environment will be remade after this
6346 command completes anyway, but do it if all the words to be expanded
6347 are variable assignments. */
6348 if (subst_assign_varlist == 0 || garglist == 0)
6349 maybe_make_export_env (); /* XXX */
6351 /* Flags to pass to parse_and_execute() */
6352 pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
6354 old_pid = last_made_pid;
6356 /* Pipe the output of executing STRING into the current shell. */
6357 if (pipe (fildes) < 0)
6359 sys_error ("%s", _("cannot make pipe for command substitution"));
6360 goto error_exit;
6363 #if defined (JOB_CONTROL)
6364 old_pipeline_pgrp = pipeline_pgrp;
6365 /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */
6366 if ((subshell_environment & SUBSHELL_PIPE) == 0)
6367 pipeline_pgrp = shell_pgrp;
6368 cleanup_the_pipeline ();
6369 #endif /* JOB_CONTROL */
6371 old_async_pid = last_asynchronous_pid;
6372 fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0;
6373 pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM);
6374 last_asynchronous_pid = old_async_pid;
6376 if (pid == 0)
6378 /* Reset the signal handlers in the child, but don't free the
6379 trap strings. Set a flag noting that we have to free the
6380 trap strings if we run trap to change a signal disposition. */
6381 reset_signal_handlers ();
6382 if (ISINTERRUPT)
6384 kill (getpid (), SIGINT);
6385 CLRINTERRUPT; /* if we're ignoring SIGINT somehow */
6387 QUIT; /* catch any interrupts we got post-fork */
6388 subshell_environment |= SUBSHELL_RESETTRAP;
6391 #if defined (JOB_CONTROL)
6392 /* XXX DO THIS ONLY IN PARENT ? XXX */
6393 set_sigchld_handler ();
6394 stop_making_children ();
6395 if (pid != 0)
6396 pipeline_pgrp = old_pipeline_pgrp;
6397 #else
6398 stop_making_children ();
6399 #endif /* JOB_CONTROL */
6401 if (pid < 0)
6403 sys_error (_("cannot make child for command substitution"));
6404 error_exit:
6406 last_made_pid = old_pid;
6408 FREE (istring);
6409 close (fildes[0]);
6410 close (fildes[1]);
6411 return ((WORD_DESC *)NULL);
6414 if (pid == 0)
6416 /* The currently executing shell is not interactive. */
6417 interactive = 0;
6419 set_sigint_handler (); /* XXX */
6421 free_pushed_string_input ();
6423 /* Discard buffered stdio output before replacing the underlying file
6424 descriptor. */
6425 fpurge (stdout);
6427 if (dup2 (fildes[1], 1) < 0)
6429 sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1"));
6430 exit (EXECUTION_FAILURE);
6433 /* If standard output is closed in the parent shell
6434 (such as after `exec >&-'), file descriptor 1 will be
6435 the lowest available file descriptor, and end up in
6436 fildes[0]. This can happen for stdin and stderr as well,
6437 but stdout is more important -- it will cause no output
6438 to be generated from this command. */
6439 if ((fildes[1] != fileno (stdin)) &&
6440 (fildes[1] != fileno (stdout)) &&
6441 (fildes[1] != fileno (stderr)))
6442 close (fildes[1]);
6444 if ((fildes[0] != fileno (stdin)) &&
6445 (fildes[0] != fileno (stdout)) &&
6446 (fildes[0] != fileno (stderr)))
6447 close (fildes[0]);
6449 #ifdef __CYGWIN__
6450 /* Let stdio know the fd may have changed from text to binary mode, and
6451 make sure to preserve stdout line buffering. */
6452 freopen (NULL, "w", stdout);
6453 sh_setlinebuf (stdout);
6454 #endif /* __CYGWIN__ */
6456 /* This is a subshell environment. */
6457 subshell_environment |= SUBSHELL_COMSUB;
6459 /* Many shells do not appear to inherit the -v option for command
6460 substitutions. */
6461 change_flag ('v', FLAG_OFF);
6463 /* When inherit_errexit option is not enabled, command substitution does
6464 not inherit the -e flag. It is enabled when Posix mode is enabled */
6465 if (inherit_errexit == 0)
6467 builtin_ignoring_errexit = 0;
6468 change_flag ('e', FLAG_OFF);
6470 set_shellopts ();
6472 /* If we are expanding a redirection, we can dispose of any temporary
6473 environment we received, since redirections are not supposed to have
6474 access to the temporary environment. We will have to see whether this
6475 affects temporary environments supplied to `eval', but the temporary
6476 environment gets copied to builtin_env at some point. */
6477 if (expanding_redir)
6479 flush_temporary_env ();
6480 expanding_redir = 0;
6483 remove_quoted_escapes (string);
6485 startup_state = 2; /* see if we can avoid a fork */
6486 parse_and_execute_level = 0;
6488 /* Give command substitution a place to jump back to on failure,
6489 so we don't go back up to main (). */
6490 result = setjmp_nosigs (top_level);
6492 /* If we're running a command substitution inside a shell function,
6493 trap `return' so we don't return from the function in the subshell
6494 and go off to never-never land. */
6495 if (result == 0 && return_catch_flag)
6496 function_value = setjmp_nosigs (return_catch);
6497 else
6498 function_value = 0;
6500 if (result == ERREXIT)
6501 rc = last_command_exit_value;
6502 else if (result == EXITPROG)
6503 rc = last_command_exit_value;
6504 else if (result)
6505 rc = EXECUTION_FAILURE;
6506 else if (function_value)
6507 rc = return_catch_value;
6508 else
6510 subshell_level++;
6511 rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
6512 /* leave subshell level intact for any exit trap */
6515 last_command_exit_value = rc;
6516 rc = run_exit_trap ();
6517 #if defined (PROCESS_SUBSTITUTION)
6518 unlink_fifo_list ();
6519 #endif
6520 exit (rc);
6522 else
6524 int dummyfd;
6526 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
6527 close_pgrp_pipe ();
6528 #endif /* JOB_CONTROL && PGRP_PIPE */
6530 close (fildes[1]);
6532 begin_unwind_frame ("read-comsub");
6533 dummyfd = fildes[0];
6534 add_unwind_protect (close, dummyfd);
6536 /* Block SIGINT while we're reading from the pipe. If the child
6537 process gets a SIGINT, it will either handle it or die, and the
6538 read will return. */
6539 BLOCK_SIGNAL (SIGINT, set, oset);
6540 tflag = 0;
6541 istring = read_comsub (fildes[0], quoted, flags, &tflag);
6543 close (fildes[0]);
6544 discard_unwind_frame ("read-comsub");
6545 UNBLOCK_SIGNAL (oset);
6547 current_command_subst_pid = pid;
6548 last_command_exit_value = wait_for (pid, JWAIT_NOTERM);
6549 last_command_subst_pid = pid;
6550 last_made_pid = old_pid;
6552 #if defined (JOB_CONTROL)
6553 /* If last_command_exit_value > 128, then the substituted command
6554 was terminated by a signal. If that signal was SIGINT, then send
6555 SIGINT to ourselves. This will break out of loops, for instance. */
6556 if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
6557 kill (getpid (), SIGINT);
6558 #endif /* JOB_CONTROL */
6560 ret = alloc_word_desc ();
6561 ret->word = istring;
6562 ret->flags = tflag;
6564 return ret;
6568 /********************************************************
6570 * Utility functions for parameter expansion *
6572 ********************************************************/
6574 #if defined (ARRAY_VARS)
6576 static arrayind_t
6577 array_length_reference (s)
6578 char *s;
6580 int len;
6581 arrayind_t ind;
6582 char *akey;
6583 char *t, c;
6584 ARRAY *array;
6585 HASH_TABLE *h;
6586 SHELL_VAR *var;
6588 var = array_variable_part (s, 0, &t, &len);
6590 /* If unbound variables should generate an error, report one and return
6591 failure. */
6592 if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
6594 c = *--t;
6595 *t = '\0';
6596 set_exit_status (EXECUTION_FAILURE);
6597 err_unboundvar (s);
6598 *t = c;
6599 return (-1);
6601 else if (var == 0 || invisible_p (var))
6602 return 0;
6604 /* We support a couple of expansions for variables that are not arrays.
6605 We'll return the length of the value for v[0], and 1 for v[@] or
6606 v[*]. Return 0 for everything else. */
6608 array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
6609 h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
6611 if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK)
6613 if (assoc_p (var))
6614 return (h ? assoc_num_elements (h) : 0);
6615 else if (array_p (var))
6616 return (array ? array_num_elements (array) : 0);
6617 else
6618 return (var_isset (var) ? 1 : 0);
6621 if (assoc_p (var))
6623 t[len - 1] = '\0';
6624 akey = expand_assignment_string_to_string (t, 0); /* [ */
6625 t[len - 1] = RBRACK;
6626 if (akey == 0 || *akey == 0)
6628 err_badarraysub (t);
6629 FREE (akey);
6630 return (-1);
6632 t = assoc_reference (assoc_cell (var), akey);
6633 free (akey);
6635 else
6637 ind = array_expand_index (var, t, len, 0);
6638 /* negative subscripts to indexed arrays count back from end */
6639 if (var && array_p (var) && ind < 0)
6640 ind = array_max_index (array_cell (var)) + 1 + ind;
6641 if (ind < 0)
6643 err_badarraysub (t);
6644 return (-1);
6646 if (array_p (var))
6647 t = array_reference (array, ind);
6648 else
6649 t = (ind == 0) ? value_cell (var) : (char *)NULL;
6652 len = MB_STRLEN (t);
6653 return (len);
6655 #endif /* ARRAY_VARS */
6657 static int
6658 valid_brace_expansion_word (name, var_is_special)
6659 char *name;
6660 int var_is_special;
6662 if (DIGIT (*name) && all_digits (name))
6663 return 1;
6664 else if (var_is_special)
6665 return 1;
6666 #if defined (ARRAY_VARS)
6667 else if (valid_array_reference (name, 0))
6668 return 1;
6669 #endif /* ARRAY_VARS */
6670 else if (legal_identifier (name))
6671 return 1;
6672 else
6673 return 0;
6676 static int
6677 chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
6678 char *name;
6679 int quoted, pflags;
6680 int *quoted_dollar_atp, *contains_dollar_at;
6682 char *temp1;
6684 if (name == 0)
6686 if (quoted_dollar_atp)
6687 *quoted_dollar_atp = 0;
6688 if (contains_dollar_at)
6689 *contains_dollar_at = 0;
6690 return 0;
6693 /* check for $@ and $* */
6694 if (name[0] == '@' && name[1] == 0)
6696 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
6697 *quoted_dollar_atp = 1;
6698 if (contains_dollar_at)
6699 *contains_dollar_at = 1;
6700 return 1;
6702 else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
6704 /* Need more checks here that parallel what string_list_pos_params and
6705 param_expand do. Check expand_no_split_dollar_star and ??? */
6706 if (contains_dollar_at && expand_no_split_dollar_star == 0)
6707 *contains_dollar_at = 1;
6708 return 1;
6711 /* Now check for ${array[@]} and ${array[*]} */
6712 #if defined (ARRAY_VARS)
6713 else if (valid_array_reference (name, 0))
6715 temp1 = mbschr (name, LBRACK);
6716 if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK)
6718 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
6719 *quoted_dollar_atp = 1;
6720 if (contains_dollar_at)
6721 *contains_dollar_at = 1;
6722 return 1;
6724 /* ${array[*]}, when unquoted, should be treated like ${array[@]},
6725 which should result in separate words even when IFS is unset. */
6726 if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0)
6728 if (contains_dollar_at)
6729 *contains_dollar_at = 1;
6730 return 1;
6733 #endif
6734 return 0;
6737 /* Parameter expand NAME, and return a new string which is the expansion,
6738 or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}.
6739 VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
6740 the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
6741 NAME was found inside of a double-quoted expression. */
6742 static WORD_DESC *
6743 parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp)
6744 char *name;
6745 int var_is_special, quoted, pflags;
6746 arrayind_t *indp;
6748 WORD_DESC *ret;
6749 char *temp, *tt;
6750 intmax_t arg_index;
6751 SHELL_VAR *var;
6752 int atype, rflags;
6753 arrayind_t ind;
6755 ret = 0;
6756 temp = 0;
6757 rflags = 0;
6759 if (indp)
6760 *indp = INTMAX_MIN;
6762 /* Handle multiple digit arguments, as in ${11}. */
6763 if (legal_number (name, &arg_index))
6765 tt = get_dollar_var_value (arg_index);
6766 if (tt)
6767 temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
6768 ? quote_string (tt)
6769 : quote_escapes (tt);
6770 else
6771 temp = (char *)NULL;
6772 FREE (tt);
6774 else if (var_is_special) /* ${@} */
6776 int sindex;
6777 tt = (char *)xmalloc (2 + strlen (name));
6778 tt[sindex = 0] = '$';
6779 strcpy (tt + 1, name);
6781 ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
6782 (int *)NULL, (int *)NULL, pflags);
6783 free (tt);
6785 #if defined (ARRAY_VARS)
6786 else if (valid_array_reference (name, 0))
6788 expand_arrayref:
6789 var = array_variable_part (name, 0, &tt, (int *)0);
6790 /* These are the cases where word splitting will not be performed */
6791 if (pflags & PF_ASSIGNRHS)
6793 if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK)
6795 /* Only treat as double quoted if array variable */
6796 if (var && (array_p (var) || assoc_p (var)))
6797 temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind);
6798 else
6799 temp = array_value (name, quoted, 0, &atype, &ind);
6801 else
6802 temp = array_value (name, quoted, 0, &atype, &ind);
6804 /* Posix interp 888 */
6805 else if (pflags & PF_NOSPLIT2)
6807 /* Special cases, then general case, for each of A[@], A[*], A[n] */
6808 #if defined (HANDLE_MULTIBYTE)
6809 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
6810 #else
6811 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
6812 #endif
6813 temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind);
6814 else if (tt[0] == '@' && tt[1] == RBRACK)
6815 temp = array_value (name, quoted, 0, &atype, &ind);
6816 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
6817 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind);
6818 else if (tt[0] == '*' && tt[1] == RBRACK)
6819 temp = array_value (name, quoted, 0, &atype, &ind);
6820 else
6821 temp = array_value (name, quoted, 0, &atype, &ind);
6823 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
6824 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind);
6825 else
6826 temp = array_value (name, quoted, 0, &atype, &ind);
6827 if (atype == 0 && temp)
6829 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
6830 ? quote_string (temp)
6831 : quote_escapes (temp);
6832 rflags |= W_ARRAYIND;
6833 if (indp)
6834 *indp = ind;
6836 else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
6837 rflags |= W_HASQUOTEDNULL;
6839 #endif
6840 else if (var = find_variable (name))
6842 if (var_isset (var) && invisible_p (var) == 0)
6844 #if defined (ARRAY_VARS)
6845 /* We avoid a memory leak by saving TT as the memory allocated by
6846 assoc_to_string or array_to_string and leaving it 0 otherwise,
6847 then freeing TT after quoting temp. */
6848 tt = (char *)NULL;
6849 if ((pflags & PF_ALLINDS) && assoc_p (var))
6850 tt = temp = assoc_empty (assoc_cell (var)) ? (char *)NULL : assoc_to_string (assoc_cell (var), " ", quoted);
6851 else if ((pflags & PF_ALLINDS) && array_p (var))
6852 tt = temp = array_empty (array_cell (var)) ? (char *)NULL : array_to_string (array_cell (var), " ", quoted);
6853 else if (assoc_p (var))
6854 temp = assoc_reference (assoc_cell (var), "0");
6855 else if (array_p (var))
6856 temp = array_reference (array_cell (var), 0);
6857 else
6858 temp = value_cell (var);
6859 #else
6860 temp = value_cell (var);
6861 #endif
6863 if (temp)
6864 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
6865 ? quote_string (temp)
6866 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
6867 : quote_escapes (temp));
6868 FREE (tt);
6870 else
6871 temp = (char *)NULL;
6873 else if (var = find_variable_last_nameref (name, 0))
6875 temp = nameref_cell (var);
6876 #if defined (ARRAY_VARS)
6877 /* Handle expanding nameref whose value is x[n] */
6878 if (temp && *temp && valid_array_reference (temp, 0))
6880 name = temp;
6881 goto expand_arrayref;
6883 else
6884 #endif
6885 /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */
6886 if (temp && *temp && legal_identifier (temp) == 0)
6888 set_exit_status (EXECUTION_FAILURE);
6889 report_error (_("%s: invalid variable name for name reference"), temp);
6890 temp = &expand_param_error;
6892 else
6893 temp = (char *)NULL;
6895 else
6896 temp = (char *)NULL;
6898 if (ret == 0)
6900 ret = alloc_word_desc ();
6901 ret->word = temp;
6902 ret->flags |= rflags;
6904 return ret;
6907 static char *
6908 parameter_brace_find_indir (name, var_is_special, quoted, find_nameref)
6909 char *name;
6910 int var_is_special, quoted, find_nameref;
6912 char *temp, *t;
6913 WORD_DESC *w;
6914 SHELL_VAR *v;
6915 int pflags, oldex;
6917 if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) &&
6918 nameref_p (v) && (t = nameref_cell (v)) && *t)
6919 return (savestring (t));
6921 /* If var_is_special == 0, and name is not an array reference, this does
6922 more expansion than necessary. It should really look up the variable's
6923 value and not try to expand it. */
6924 pflags = PF_IGNUNBOUND;
6925 /* Note that we're not going to be doing word splitting here */
6926 if (var_is_special)
6928 pflags |= PF_ASSIGNRHS; /* suppresses word splitting */
6929 oldex = expand_no_split_dollar_star;
6930 expand_no_split_dollar_star = 1;
6932 w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0);
6933 if (var_is_special)
6934 expand_no_split_dollar_star = oldex;
6936 t = w->word;
6937 /* Have to dequote here if necessary */
6938 if (t)
6940 temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special)
6941 ? dequote_string (t)
6942 : dequote_escapes (t);
6943 free (t);
6944 t = temp;
6946 dispose_word_desc (w);
6948 return t;
6951 /* Expand an indirect reference to a variable: ${!NAME} expands to the
6952 value of the variable whose name is the value of NAME. */
6953 static WORD_DESC *
6954 parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
6955 char *name;
6956 int var_is_special, quoted, pflags;
6957 int *quoted_dollar_atp, *contains_dollar_at;
6959 char *t;
6960 WORD_DESC *w;
6961 SHELL_VAR *v;
6963 /* See if it's a nameref first, behave in ksh93-compatible fashion.
6964 There is at least one incompatibility: given ${!foo[0]} where foo=bar,
6965 bush performs an indirect lookup on foo[0] and expands the result;
6966 ksh93 expands bar[0]. We could do that here -- there are enough usable
6967 primitives to do that -- but do not at this point. */
6968 if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0)))
6970 if (nameref_p (v) && (t = nameref_cell (v)) && *t)
6972 w = alloc_word_desc ();
6973 w->word = savestring (t);
6974 w->flags = 0;
6975 return w;
6979 /* An indirect reference to a positional parameter or a special parameter
6980 is ok. Indirect references to array references, as explained above, are
6981 ok (currently). Only references to unset variables are errors at this
6982 point. */
6983 if (legal_identifier (name) && v == 0)
6985 report_error (_("%s: invalid indirect expansion"), name);
6986 w = alloc_word_desc ();
6987 w->word = &expand_param_error;
6988 w->flags = 0;
6989 return (w);
6992 t = parameter_brace_find_indir (name, var_is_special, quoted, 0);
6994 chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at);
6996 #if defined (ARRAY_VARS)
6997 /* Array references to unset variables are also an error */
6998 if (t == 0 && valid_array_reference (name, 0))
7000 v = array_variable_part (name, 0, (char **)0, (int *)0);
7001 if (v == 0)
7003 report_error (_("%s: invalid indirect expansion"), name);
7004 w = alloc_word_desc ();
7005 w->word = &expand_param_error;
7006 w->flags = 0;
7007 return (w);
7009 else
7010 return (WORD_DESC *)NULL;
7012 #endif
7014 if (t == 0)
7015 return (WORD_DESC *)NULL;
7017 if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0)
7019 report_error (_("%s: invalid variable name"), t);
7020 free (t);
7021 w = alloc_word_desc ();
7022 w->word = &expand_param_error;
7023 w->flags = 0;
7024 return (w);
7027 w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0);
7028 free (t);
7030 return w;
7033 /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
7034 depending on the value of C, the separating character. C can be one of
7035 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
7036 between double quotes. */
7037 static WORD_DESC *
7038 parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat)
7039 char *name, *value;
7040 int op, quoted, pflags, *qdollaratp, *hasdollarat;
7042 WORD_DESC *w;
7043 WORD_LIST *l, *tl;
7044 char *t, *t1, *temp, *vname;
7045 int l_hasdollat, sindex;
7046 SHELL_VAR *v;
7048 /*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/
7049 /* If the entire expression is between double quotes, we want to treat
7050 the value as a double-quoted string, with the exception that we strip
7051 embedded unescaped double quotes (for sh backwards compatibility). */
7052 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
7054 sindex = 0;
7055 temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ);
7057 else
7058 temp = value;
7060 w = alloc_word_desc ();
7061 l_hasdollat = 0;
7062 l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL)
7063 : (WORD_LIST *)0;
7064 if (hasdollarat)
7065 *hasdollarat = l_hasdollat || (l && l->next);
7066 if (temp != value)
7067 free (temp);
7069 /* list_string takes multiple CTLNULs and turns them into an empty word
7070 with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the
7071 rest of this function and the caller. */
7072 for (tl = l; tl; tl = tl->next)
7074 if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) &&
7075 (tl->word->flags | W_SAWQUOTEDNULL))
7077 t = make_quoted_char ('\0');
7078 FREE (tl->word->word);
7079 tl->word->word = t;
7080 tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL;
7081 tl->word->flags &= ~W_SAWQUOTEDNULL;
7085 if (l)
7087 /* If l->next is not null, we know that TEMP contained "$@", since that
7088 is the only expansion that creates more than one word. */
7089 if (qdollaratp && ((l_hasdollat && quoted) || l->next))
7091 /*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/
7092 *qdollaratp = 1;
7095 /* The expansion of TEMP returned something. We need to treat things
7096 slightly differently if L_HASDOLLAT is non-zero. If we have "$@",
7097 the individual words have already been quoted. We need to turn them
7098 into a string with the words separated by the first character of
7099 $IFS without any additional quoting, so string_list_dollar_at won't
7100 do the right thing. If IFS is null, we want "$@" to split into
7101 separate arguments, not be concatenated, so we use string_list_internal
7102 and mark the word to be split on spaces later. We use
7103 string_list_dollar_star for "$@" otherwise. */
7104 if (l->next && ifs_is_null)
7106 temp = string_list_internal (l, " ");
7107 w->flags |= W_SPLITSPACE;
7109 else if (l_hasdollat || l->next)
7110 temp = string_list_dollar_star (l, quoted, 0);
7111 else
7113 temp = string_list (l);
7114 if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL))
7115 w->flags |= W_SAWQUOTEDNULL; /* XXX */
7118 /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
7119 a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
7120 flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
7121 expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7122 (which is more paranoia than anything else), we need to return the
7123 quoted null string and set the flags to indicate it. */
7124 if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL))
7126 w->flags |= W_HASQUOTEDNULL;
7127 /*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/
7128 /* If we return a quoted null with L_HASDOLLARAT, we either have a
7129 construct like "${@-$@}" or "${@-${@-$@}}" with no positional
7130 parameters or a quoted expansion of "$@" with $1 == ''. In either
7131 case, we don't want to enable special handling of $@. */
7132 if (qdollaratp && l_hasdollat)
7133 *qdollaratp = 0;
7135 dispose_words (l);
7137 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat)
7139 /* Posix interp 221 changed the rules on this. The idea is that
7140 something like "$xxx$@" should expand the same as "${foo-$xxx$@}"
7141 when foo and xxx are unset. The problem is that it's not in any
7142 way backwards compatible and few other shells do it. We're eventually
7143 going to try and split the difference (heh) a little bit here. */
7144 /* l_hasdollat == 1 means we saw a quoted dollar at. */
7146 /* The brace expansion occurred between double quotes and there was
7147 a $@ in TEMP. It does not matter if the $@ is quoted, as long as
7148 it does not expand to anything. In this case, we want to return
7149 a quoted empty string. Posix interp 888 */
7150 temp = make_quoted_char ('\0');
7151 w->flags |= W_HASQUOTEDNULL;
7152 /*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/
7154 else
7155 temp = (char *)NULL;
7157 if (op == '-' || op == '+')
7159 w->word = temp;
7160 return w;
7163 /* op == '=' */
7164 t1 = temp ? dequote_string (temp) : savestring ("");
7165 free (temp);
7167 /* bush-4.4/5.0 */
7168 vname = name;
7169 if (*name == '!' &&
7170 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1])))
7172 vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1);
7173 if (vname == 0 || *vname == 0)
7175 report_error (_("%s: invalid indirect expansion"), name);
7176 free (vname);
7177 free (t1);
7178 dispose_word (w);
7179 return &expand_wdesc_error;
7181 if (legal_identifier (vname) == 0)
7183 report_error (_("%s: invalid variable name"), vname);
7184 free (vname);
7185 free (t1);
7186 dispose_word (w);
7187 return &expand_wdesc_error;
7191 #if defined (ARRAY_VARS)
7192 if (valid_array_reference (vname, 0))
7193 v = assign_array_element (vname, t1, 0);
7194 else
7195 #endif /* ARRAY_VARS */
7196 v = bind_variable (vname, t1, 0);
7198 if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */
7200 if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct)
7202 last_command_exit_value = EXECUTION_FAILURE;
7203 exp_jump_to_top_level (FORCE_EOF);
7205 else
7207 if (vname != name)
7208 free (vname);
7209 last_command_exit_value = EX_BADUSAGE;
7210 exp_jump_to_top_level (DISCARD);
7214 stupidly_hack_special_variables (vname);
7216 if (vname != name)
7217 free (vname);
7219 /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
7221 /* If we are double-quoted or if we are not going to be performing word
7222 splitting, we want to quote the value we return appropriately, like
7223 the other expansions this function handles. */
7224 w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1);
7225 /* If we have something that's non-null, that's not a quoted null string,
7226 and we're not going to be performing word splitting (we know we're not
7227 because the operator is `='), we can forget we saw a quoted null. */
7228 if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0)
7229 w->flags &= ~W_SAWQUOTEDNULL;
7230 free (t1);
7232 /* If we convert a null string into a quoted null, make sure the caller
7233 knows it. */
7234 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word))
7235 w->flags |= W_HASQUOTEDNULL;
7237 return w;
7240 /* Deal with the right hand side of a ${name:?value} expansion in the case
7241 that NAME is null or not set. If VALUE is non-null it is expanded and
7242 used as the error message to print, otherwise a standard message is
7243 printed. */
7244 static void
7245 parameter_brace_expand_error (name, value, check_null)
7246 char *name, *value;
7247 int check_null;
7249 WORD_LIST *l;
7250 char *temp;
7252 set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */
7253 if (value && *value)
7255 l = expand_string (value, 0);
7256 temp = string_list (l);
7257 report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
7258 FREE (temp);
7259 dispose_words (l);
7261 else if (check_null == 0)
7262 report_error (_("%s: parameter not set"), name);
7263 else
7264 report_error (_("%s: parameter null or not set"), name);
7266 /* Free the data we have allocated during this expansion, since we
7267 are about to longjmp out. */
7268 free (name);
7269 FREE (value);
7272 /* Return 1 if NAME is something for which parameter_brace_expand_length is
7273 OK to do. */
7274 static int
7275 valid_length_expression (name)
7276 char *name;
7278 return (name[1] == '\0' || /* ${#} */
7279 ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */
7280 (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
7281 #if defined (ARRAY_VARS)
7282 valid_array_reference (name + 1, 0) || /* ${#a[7]} */
7283 #endif
7284 legal_identifier (name + 1)); /* ${#PS1} */
7287 /* Handle the parameter brace expansion that requires us to return the
7288 length of a parameter. */
7289 static intmax_t
7290 parameter_brace_expand_length (name)
7291 char *name;
7293 char *t, *newname;
7294 intmax_t number, arg_index;
7295 WORD_LIST *list;
7296 SHELL_VAR *var;
7298 var = (SHELL_VAR *)NULL;
7300 if (name[1] == '\0') /* ${#} */
7301 number = number_of_args ();
7302 else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */
7303 number = number_of_args ();
7304 else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
7306 /* Take the lengths of some of the shell's special parameters. */
7307 switch (name[1])
7309 case '-':
7310 t = which_set_flags ();
7311 break;
7312 case '?':
7313 t = itos (last_command_exit_value);
7314 break;
7315 case '$':
7316 t = itos (dollar_dollar_pid);
7317 break;
7318 case '!':
7319 if (last_asynchronous_pid == NO_PID)
7320 t = (char *)NULL; /* XXX - error if set -u set? */
7321 else
7322 t = itos (last_asynchronous_pid);
7323 break;
7324 case '#':
7325 t = itos (number_of_args ());
7326 break;
7328 number = STRLEN (t);
7329 FREE (t);
7331 #if defined (ARRAY_VARS)
7332 else if (valid_array_reference (name + 1, 0))
7333 number = array_length_reference (name + 1);
7334 #endif /* ARRAY_VARS */
7335 else
7337 number = 0;
7339 if (legal_number (name + 1, &arg_index)) /* ${#1} */
7341 t = get_dollar_var_value (arg_index);
7342 if (t == 0 && unbound_vars_is_error)
7343 return INTMAX_MIN;
7344 number = MB_STRLEN (t);
7345 FREE (t);
7347 #if defined (ARRAY_VARS)
7348 else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
7350 if (assoc_p (var))
7351 t = assoc_reference (assoc_cell (var), "0");
7352 else
7353 t = array_reference (array_cell (var), 0);
7354 if (t == 0 && unbound_vars_is_error)
7355 return INTMAX_MIN;
7356 number = MB_STRLEN (t);
7358 #endif
7359 /* Fast path for the common case of taking the length of a non-dynamic
7360 scalar variable value. */
7361 else if ((var || (var = find_variable (name + 1))) &&
7362 invisible_p (var) == 0 &&
7363 array_p (var) == 0 && assoc_p (var) == 0 &&
7364 var->dynamic_value == 0)
7365 number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0;
7366 else if (var == 0 && unbound_vars_is_error == 0)
7367 number = 0;
7368 else /* ${#PS1} */
7370 newname = savestring (name);
7371 newname[0] = '$';
7372 list = expand_string (newname, Q_DOUBLE_QUOTES);
7373 t = list ? string_list (list) : (char *)NULL;
7374 free (newname);
7375 if (list)
7376 dispose_words (list);
7378 number = t ? MB_STRLEN (t) : 0;
7379 FREE (t);
7383 return (number);
7386 /* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression,
7387 so we do some ad-hoc parsing of an arithmetic expression to find
7388 the first DELIM, instead of using strchr(3). Two rules:
7389 1. If the substring contains a `(', read until closing `)'.
7390 2. If the substring contains a `?', read past one `:' for each `?'.
7391 The SD_ARITHEXP flag to skip_to_delim takes care of doing this.
7394 static char *
7395 skiparith (substr, delim)
7396 char *substr;
7397 int delim;
7399 int i;
7400 char delims[2];
7402 delims[0] = delim;
7403 delims[1] = '\0';
7405 i = skip_to_delim (substr, 0, delims, SD_ARITHEXP);
7406 return (substr + i);
7409 /* Verify and limit the start and end of the desired substring. If
7410 VTYPE == 0, a regular shell variable is being used; if it is 1,
7411 then the positional parameters are being used; if it is 2, then
7412 VALUE is really a pointer to an array variable that should be used.
7413 Return value is 1 if both values were OK, 0 if there was a problem
7414 with an invalid expression, or -1 if the values were out of range. */
7415 static int
7416 verify_substring_values (v, value, substr, vtype, e1p, e2p)
7417 SHELL_VAR *v;
7418 char *value, *substr;
7419 int vtype;
7420 intmax_t *e1p, *e2p;
7422 char *t, *temp1, *temp2;
7423 arrayind_t len;
7424 int expok;
7425 #if defined (ARRAY_VARS)
7426 ARRAY *a;
7427 HASH_TABLE *h;
7428 #endif
7430 /* duplicate behavior of strchr(3) */
7431 t = skiparith (substr, ':');
7432 if (*t && *t == ':')
7433 *t = '\0';
7434 else
7435 t = (char *)0;
7437 temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES);
7438 *e1p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */
7439 free (temp1);
7440 if (expok == 0)
7441 return (0);
7443 len = -1; /* paranoia */
7444 switch (vtype)
7446 case VT_VARIABLE:
7447 case VT_ARRAYMEMBER:
7448 len = MB_STRLEN (value);
7449 break;
7450 case VT_POSPARMS:
7451 len = number_of_args () + 1;
7452 if (*e1p == 0)
7453 len++; /* add one arg if counting from $0 */
7454 break;
7455 #if defined (ARRAY_VARS)
7456 case VT_ARRAYVAR:
7457 /* For arrays, the first value deals with array indices. Negative
7458 offsets count from one past the array's maximum index. Associative
7459 arrays treat the number of elements as the maximum index. */
7460 if (assoc_p (v))
7462 h = assoc_cell (v);
7463 len = assoc_num_elements (h) + (*e1p < 0);
7465 else
7467 a = (ARRAY *)value;
7468 len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
7470 break;
7471 #endif
7474 if (len == -1) /* paranoia */
7475 return -1;
7477 if (*e1p < 0) /* negative offsets count from end */
7478 *e1p += len;
7480 if (*e1p > len || *e1p < 0)
7481 return (-1);
7483 #if defined (ARRAY_VARS)
7484 /* For arrays, the second offset deals with the number of elements. */
7485 if (vtype == VT_ARRAYVAR)
7486 len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
7487 #endif
7489 if (t)
7491 t++;
7492 temp2 = savestring (t);
7493 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
7494 free (temp2);
7495 t[-1] = ':';
7496 *e2p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */
7497 free (temp1);
7498 if (expok == 0)
7499 return (0);
7501 /* Should we allow positional parameter length < 0 to count backwards
7502 from end of positional parameters? */
7503 #if 1
7504 if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
7505 #else /* TAG: bush-5.2 */
7506 if (vtype == VT_ARRAYVAR && *e2p < 0)
7507 #endif
7509 internal_error (_("%s: substring expression < 0"), t);
7510 return (0);
7512 #if defined (ARRAY_VARS)
7513 /* In order to deal with sparse arrays, push the intelligence about how
7514 to deal with the number of elements desired down to the array-
7515 specific functions. */
7516 if (vtype != VT_ARRAYVAR)
7517 #endif
7519 if (*e2p < 0)
7521 *e2p += len;
7522 if (*e2p < 0 || *e2p < *e1p)
7524 internal_error (_("%s: substring expression < 0"), t);
7525 return (0);
7528 else
7529 *e2p += *e1p; /* want E2 chars starting at E1 */
7530 if (*e2p > len)
7531 *e2p = len;
7534 else
7535 *e2p = len;
7537 return (1);
7540 /* Return the type of variable specified by VARNAME (simple variable,
7541 positional param, or array variable). Also return the value specified
7542 by VARNAME (value of a variable or a reference to an array element).
7543 QUOTED is the standard description of quoting state, using Q_* defines.
7544 FLAGS is currently a set of flags to pass to array_value. If IND is
7545 non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
7546 passed to array_value so the array index is not computed again.
7547 If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
7548 characters in the value are quoted with CTLESC and takes appropriate
7549 steps. For convenience, *VALP is set to the dequoted VALUE. */
7550 static int
7551 get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
7552 char *varname, *value;
7553 arrayind_t ind;
7554 int quoted, flags;
7555 SHELL_VAR **varp;
7556 char **valp;
7558 int vtype, want_indir;
7559 char *temp, *vname;
7560 SHELL_VAR *v;
7561 arrayind_t lind;
7563 want_indir = *varname == '!' &&
7564 (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1])
7565 || VALID_INDIR_PARAM (varname[1]));
7566 if (want_indir)
7567 vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1);
7568 /* XXX - what if vname == 0 || *vname == 0 ? */
7569 else
7570 vname = varname;
7572 if (vname == 0)
7574 vtype = VT_VARIABLE;
7575 *varp = (SHELL_VAR *)NULL;
7576 *valp = (char *)NULL;
7577 return (vtype);
7580 /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
7581 vtype = STR_DOLLAR_AT_STAR (vname);
7582 if (vtype == VT_POSPARMS && vname[0] == '*')
7583 vtype |= VT_STARSUB;
7584 *varp = (SHELL_VAR *)NULL;
7586 #if defined (ARRAY_VARS)
7587 if (valid_array_reference (vname, 0))
7589 v = array_variable_part (vname, 0, &temp, (int *)0);
7590 /* If we want to signal array_value to use an already-computed index,
7591 set LIND to that index */
7592 lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0;
7593 if (v && invisible_p (v))
7595 vtype = VT_ARRAYMEMBER;
7596 *varp = (SHELL_VAR *)NULL;
7597 *valp = (char *)NULL;
7599 if (v && (array_p (v) || assoc_p (v)))
7601 if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)
7603 /* Callers have to differentiate between indexed and associative */
7604 vtype = VT_ARRAYVAR;
7605 if (temp[0] == '*')
7606 vtype |= VT_STARSUB;
7607 *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
7609 else
7611 vtype = VT_ARRAYMEMBER;
7612 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
7614 *varp = v;
7616 else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK))
7618 vtype = VT_VARIABLE;
7619 *varp = v;
7620 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
7621 *valp = value ? dequote_string (value) : (char *)NULL;
7622 else
7623 *valp = value ? dequote_escapes (value) : (char *)NULL;
7625 else
7627 vtype = VT_ARRAYMEMBER;
7628 *varp = v;
7629 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
7632 else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
7634 vtype = VT_ARRAYMEMBER;
7635 *varp = v;
7636 *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
7638 else
7639 #endif
7641 if (value && vtype == VT_VARIABLE)
7643 *varp = find_variable (vname);
7644 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
7645 *valp = dequote_string (value);
7646 else
7647 *valp = dequote_escapes (value);
7649 else
7650 *valp = value;
7653 if (want_indir)
7654 free (vname);
7656 return vtype;
7659 /***********************************************************/
7660 /* */
7661 /* Functions to perform transformations on variable values */
7662 /* */
7663 /***********************************************************/
7665 static char *
7666 string_var_assignment (v, s)
7667 SHELL_VAR *v;
7668 char *s;
7670 char flags[MAX_ATTRIBUTES], *ret, *val;
7671 int i;
7673 val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0);
7674 i = var_attribute_string (v, 0, flags);
7675 if (i == 0 && val == 0)
7676 return (char *)NULL;
7678 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES);
7679 if (i > 0 && val == 0)
7680 sprintf (ret, "declare -%s %s", flags, v->name);
7681 else if (i > 0)
7682 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
7683 else
7684 sprintf (ret, "%s=%s", v->name, val);
7685 free (val);
7686 return ret;
7689 #if defined (ARRAY_VARS)
7690 static char *
7691 array_var_assignment (v, itype, quoted, atype)
7692 SHELL_VAR *v;
7693 int itype, quoted, atype;
7695 char *ret, *val, flags[MAX_ATTRIBUTES];
7696 int i;
7698 if (v == 0)
7699 return (char *)NULL;
7700 if (atype == 2)
7701 val = array_p (v) ? array_to_kvpair (array_cell (v), 0)
7702 : assoc_to_kvpair (assoc_cell (v), 0);
7703 else
7704 val = array_p (v) ? array_to_assign (array_cell (v), 0)
7705 : assoc_to_assign (assoc_cell (v), 0);
7707 if (val == 0 && (invisible_p (v) || var_isset (v) == 0))
7708 ; /* placeholder */
7709 else if (val == 0)
7711 val = (char *)xmalloc (3);
7712 val[0] = LPAREN;
7713 val[1] = RPAREN;
7714 val[2] = 0;
7716 else
7718 ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val);
7719 free (val);
7720 val = ret;
7723 if (atype == 2)
7724 return val;
7726 i = var_attribute_string (v, 0, flags);
7727 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16);
7728 if (val)
7729 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
7730 else
7731 sprintf (ret, "declare -%s %s", flags, v->name);
7732 free (val);
7733 return ret;
7735 #endif
7737 static char *
7738 pos_params_assignment (list, itype, quoted)
7739 WORD_LIST *list;
7740 int itype;
7741 int quoted;
7743 char *temp, *ret;
7745 /* first, we transform the list to quote each word. */
7746 temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted);
7747 ret = (char *)xmalloc (strlen (temp) + 8);
7748 strcpy (ret, "set -- ");
7749 strcpy (ret + 7, temp);
7750 free (temp);
7751 return ret;
7754 static char *
7755 string_transform (xc, v, s)
7756 int xc;
7757 SHELL_VAR *v;
7758 char *s;
7760 char *ret, flags[MAX_ATTRIBUTES], *t;
7761 int i;
7763 if (((xc == 'A' || xc == 'a') && v == 0))
7764 return (char *)NULL;
7765 else if (xc != 'a' && xc != 'A' && s == 0)
7766 return (char *)NULL;
7768 switch (xc)
7770 /* Transformations that interrogate the variable */
7771 case 'a':
7772 i = var_attribute_string (v, 0, flags);
7773 ret = (i > 0) ? savestring (flags) : (char *)NULL;
7774 break;
7775 case 'A':
7776 ret = string_var_assignment (v, s);
7777 break;
7778 case 'K':
7779 ret = sh_quote_reusable (s, 0);
7780 break;
7781 /* Transformations that modify the variable's value */
7782 case 'E':
7783 t = ansiexpand (s, 0, strlen (s), (int *)0);
7784 ret = dequote_escapes (t);
7785 free (t);
7786 break;
7787 case 'P':
7788 ret = decode_prompt_string (s);
7789 break;
7790 case 'Q':
7791 ret = sh_quote_reusable (s, 0);
7792 break;
7793 case 'U':
7794 ret = sh_modcase (s, 0, CASE_UPPER);
7795 break;
7796 case 'u':
7797 ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */
7798 break;
7799 case 'L':
7800 ret = sh_modcase (s, 0, CASE_LOWER);
7801 break;
7802 default:
7803 ret = (char *)NULL;
7804 break;
7806 return ret;
7809 static char *
7810 list_transform (xc, v, list, itype, quoted)
7811 int xc;
7812 SHELL_VAR *v;
7813 WORD_LIST *list;
7814 int itype, quoted;
7816 WORD_LIST *new, *l;
7817 WORD_DESC *w;
7818 char *tword;
7819 int qflags;
7821 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
7823 tword = string_transform (xc, v, l->word->word);
7824 w = alloc_word_desc ();
7825 w->word = tword ? tword : savestring (""); /* XXX */
7826 new = make_word_list (w, new);
7828 l = REVERSE_LIST (new, WORD_LIST *);
7830 qflags = quoted;
7831 /* If we are expanding in a context where word splitting will not be
7832 performed, treat as quoted. This changes how $* will be expanded. */
7833 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
7834 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
7836 tword = string_list_pos_params (itype, l, qflags, 0);
7837 dispose_words (l);
7839 return (tword);
7842 static char *
7843 parameter_list_transform (xc, itype, quoted)
7844 int xc;
7845 int itype;
7846 int quoted;
7848 char *ret;
7849 WORD_LIST *list;
7851 list = list_rest_of_args ();
7852 if (list == 0)
7853 return ((char *)NULL);
7854 if (xc == 'A')
7855 ret = pos_params_assignment (list, itype, quoted);
7856 else
7857 ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted);
7858 dispose_words (list);
7859 return (ret);
7862 #if defined (ARRAY_VARS)
7863 static char *
7864 array_transform (xc, var, starsub, quoted)
7865 int xc;
7866 SHELL_VAR *var;
7867 int starsub; /* so we can figure out how it's indexed */
7868 int quoted;
7870 ARRAY *a;
7871 HASH_TABLE *h;
7872 int itype;
7873 char *ret;
7874 WORD_LIST *list;
7875 SHELL_VAR *v;
7877 v = var; /* XXX - for now */
7879 itype = starsub ? '*' : '@';
7881 if (xc == 'A')
7882 return (array_var_assignment (v, itype, quoted, 1));
7883 else if (xc == 'K')
7884 return (array_var_assignment (v, itype, quoted, 2));
7886 /* special case for unset arrays and attributes */
7887 if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0))
7889 char flags[MAX_ATTRIBUTES];
7890 int i;
7892 i = var_attribute_string (v, 0, flags);
7893 return ((i > 0) ? savestring (flags) : (char *)NULL);
7896 a = (v && array_p (v)) ? array_cell (v) : 0;
7897 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
7899 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
7900 if (list == 0)
7901 return ((char *)NULL);
7902 ret = list_transform (xc, v, list, itype, quoted);
7903 dispose_words (list);
7905 return ret;
7907 #endif /* ARRAY_VARS */
7909 static int
7910 valid_parameter_transform (xform)
7911 char *xform;
7913 if (xform[1])
7914 return 0;
7916 /* check for valid values of xform[0] */
7917 switch (xform[0])
7919 case 'a': /* expand to a string with just attributes */
7920 case 'A': /* expand as an assignment statement with attributes */
7921 case 'K': /* expand assoc array to list of key/value pairs */
7922 case 'E': /* expand like $'...' */
7923 case 'P': /* expand like prompt string */
7924 case 'Q': /* quote reusably */
7925 case 'U': /* transform to uppercase */
7926 case 'u': /* tranform by capitalizing */
7927 case 'L': /* transform to lowercase */
7928 return 1;
7929 default:
7930 return 0;
7934 static char *
7935 parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, flags)
7936 char *varname, *value;
7937 int ind;
7938 char *xform;
7939 int rtype, quoted, pflags, flags;
7941 int vtype, xc, starsub;
7942 char *temp1, *val, *oname;
7943 SHELL_VAR *v;
7945 xc = xform[0];
7946 if (value == 0 && xc != 'A' && xc != 'a')
7947 return ((char *)NULL);
7949 oname = this_command_name;
7950 this_command_name = varname;
7952 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
7953 if (vtype == -1)
7955 this_command_name = oname;
7956 return ((char *)NULL);
7959 if (valid_parameter_transform (xform) == 0)
7961 this_command_name = oname;
7962 #if 0 /* TAG: bush-5.2 Martin Schulte <gnu@schrader-schulte.de> 10/2020 */
7963 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
7964 #else
7965 return &expand_param_error;
7966 #endif
7969 starsub = vtype & VT_STARSUB;
7970 vtype &= ~VT_STARSUB;
7972 /* If we are asked to display the attributes of an unset variable, V will
7973 be NULL after the call to get_var_and_type. Double-check here. */
7974 if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0)
7975 v = find_variable (varname);
7977 temp1 = (char *)NULL; /* shut up gcc */
7978 switch (vtype)
7980 case VT_VARIABLE:
7981 case VT_ARRAYMEMBER:
7982 temp1 = string_transform (xc, v, val);
7983 if (vtype == VT_VARIABLE)
7984 FREE (val);
7985 if (temp1)
7987 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7988 ? quote_string (temp1)
7989 : quote_escapes (temp1);
7990 free (temp1);
7991 temp1 = val;
7993 break;
7994 #if defined (ARRAY_VARS)
7995 case VT_ARRAYVAR:
7996 temp1 = array_transform (xc, v, starsub, quoted);
7997 if (temp1 && quoted == 0 && ifs_is_null)
7999 /* Posix interp 888 */
8001 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
8003 val = quote_escapes (temp1);
8004 free (temp1);
8005 temp1 = val;
8007 break;
8008 #endif
8009 case VT_POSPARMS:
8010 temp1 = parameter_list_transform (xc, varname[0], quoted);
8011 if (temp1 && quoted == 0 && ifs_is_null)
8013 /* Posix interp 888 */
8015 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
8017 val = quote_escapes (temp1);
8018 free (temp1);
8019 temp1 = val;
8021 break;
8024 this_command_name = oname;
8025 return temp1;
8028 /******************************************************/
8029 /* */
8030 /* Functions to extract substrings of variable values */
8031 /* */
8032 /******************************************************/
8034 #if defined (HANDLE_MULTIBYTE)
8035 /* Character-oriented rather than strictly byte-oriented substrings. S and
8036 E, rather being strict indices into STRING, indicate character (possibly
8037 multibyte character) positions that require calculation.
8038 Used by the ${param:offset[:length]} expansion. */
8039 static char *
8040 mb_substring (string, s, e)
8041 char *string;
8042 int s, e;
8044 char *tt;
8045 int start, stop, i;
8046 size_t slen;
8047 DECLARE_MBSTATE;
8049 start = 0;
8050 /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
8051 slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
8053 i = s;
8054 while (string[start] && i--)
8055 ADVANCE_CHAR (string, slen, start);
8056 stop = start;
8057 i = e - s;
8058 while (string[stop] && i--)
8059 ADVANCE_CHAR (string, slen, stop);
8060 tt = substring (string, start, stop);
8061 return tt;
8063 #endif
8065 /* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
8066 is `@', use the positional parameters; otherwise, use the value of
8067 VARNAME. If VARNAME is an array variable, use the array elements. */
8069 static char *
8070 parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags)
8071 char *varname, *value;
8072 int ind;
8073 char *substr;
8074 int quoted, pflags, flags;
8076 intmax_t e1, e2;
8077 int vtype, r, starsub;
8078 char *temp, *val, *tt, *oname;
8079 SHELL_VAR *v;
8081 if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1]))
8082 return ((char *)NULL);
8084 oname = this_command_name;
8085 this_command_name = varname;
8087 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
8088 if (vtype == -1)
8090 this_command_name = oname;
8091 return ((char *)NULL);
8094 starsub = vtype & VT_STARSUB;
8095 vtype &= ~VT_STARSUB;
8097 r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
8098 this_command_name = oname;
8099 if (r <= 0)
8101 if (vtype == VT_VARIABLE)
8102 FREE (val);
8103 return ((r == 0) ? &expand_param_error : (char *)NULL);
8106 switch (vtype)
8108 case VT_VARIABLE:
8109 case VT_ARRAYMEMBER:
8110 #if defined (HANDLE_MULTIBYTE)
8111 if (MB_CUR_MAX > 1)
8112 tt = mb_substring (val, e1, e2);
8113 else
8114 #endif
8115 tt = substring (val, e1, e2);
8117 if (vtype == VT_VARIABLE)
8118 FREE (val);
8119 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8120 temp = quote_string (tt);
8121 else
8122 temp = tt ? quote_escapes (tt) : (char *)NULL;
8123 FREE (tt);
8124 break;
8125 case VT_POSPARMS:
8126 case VT_ARRAYVAR:
8127 if (vtype == VT_POSPARMS)
8128 tt = pos_params (varname, e1, e2, quoted, pflags);
8129 #if defined (ARRAY_VARS)
8130 /* assoc_subrange and array_subrange both call string_list_pos_params,
8131 so we can treat this case just like VT_POSPARAMS. */
8132 else if (assoc_p (v))
8133 /* we convert to list and take first e2 elements starting at e1th
8134 element -- officially undefined for now */
8135 tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags);
8136 else
8137 /* We want E2 to be the number of elements desired (arrays can be
8138 sparse, so verify_substring_values just returns the numbers
8139 specified and we rely on array_subrange to understand how to
8140 deal with them). */
8141 tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags);
8142 #endif
8143 /* We want to leave this alone in every case where pos_params/
8144 string_list_pos_params quotes the list members */
8145 if (tt && quoted == 0 && ifs_is_null)
8147 temp = tt; /* Posix interp 888 */
8149 else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS))
8151 temp = tt; /* Posix interp 888 */
8153 else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
8155 temp = tt ? quote_escapes (tt) : (char *)NULL;
8156 FREE (tt);
8158 else
8159 temp = tt;
8160 break;
8162 default:
8163 temp = (char *)NULL;
8166 return temp;
8169 /****************************************************************/
8170 /* */
8171 /* Functions to perform pattern substitution on variable values */
8172 /* */
8173 /****************************************************************/
8175 #ifdef INCLUDE_UNUSED
8176 static int
8177 shouldexp_replacement (s)
8178 char *s;
8180 register char *p;
8182 for (p = s; p && *p; p++)
8184 if (*p == '\\')
8185 p++;
8186 else if (*p == '&')
8187 return 1;
8189 return 0;
8191 #endif
8193 char *
8194 pat_subst (string, pat, rep, mflags)
8195 char *string, *pat, *rep;
8196 int mflags;
8198 char *ret, *s, *e, *str, *rstr, *mstr, *send;
8199 int rptr, mtype, rxpand, mlen;
8200 size_t rsize, l, replen, rslen;
8201 DECLARE_MBSTATE;
8203 if (string == 0)
8204 return (savestring (""));
8206 mtype = mflags & MATCH_TYPEMASK;
8208 #if 0 /* TAG: bush-5.2? */
8209 rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0;
8210 #else
8211 rxpand = 0;
8212 #endif
8214 /* Special cases:
8215 * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
8216 * with REP and return the result.
8217 * 2. A null pattern with mtype == MATCH_END means to append REP to
8218 * STRING and return the result.
8219 * 3. A null STRING with a matching pattern means to append REP to
8220 * STRING and return the result.
8221 * These don't understand or process `&' in the replacement string.
8223 if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
8225 replen = STRLEN (rep);
8226 l = STRLEN (string);
8227 ret = (char *)xmalloc (replen + l + 2);
8228 if (replen == 0)
8229 strcpy (ret, string);
8230 else if (mtype == MATCH_BEG)
8232 strcpy (ret, rep);
8233 strcpy (ret + replen, string);
8235 else
8237 strcpy (ret, string);
8238 strcpy (ret + l, rep);
8240 return (ret);
8242 else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
8244 replen = STRLEN (rep);
8245 ret = (char *)xmalloc (replen + 1);
8246 if (replen == 0)
8247 ret[0] = '\0';
8248 else
8249 strcpy (ret, rep);
8250 return (ret);
8253 ret = (char *)xmalloc (rsize = 64);
8254 ret[0] = '\0';
8255 send = string + strlen (string);
8257 for (replen = STRLEN (rep), rptr = 0, str = string; *str;)
8259 if (match_pattern (str, pat, mtype, &s, &e) == 0)
8260 break;
8261 l = s - str;
8263 if (rep && rxpand)
8265 int x;
8266 mlen = e - s;
8267 mstr = xmalloc (mlen + 1);
8268 for (x = 0; x < mlen; x++)
8269 mstr[x] = s[x];
8270 mstr[mlen] = '\0';
8271 rstr = strcreplace (rep, '&', mstr, 0);
8272 free (mstr);
8273 rslen = strlen (rstr);
8275 else
8277 rstr = rep;
8278 rslen = replen;
8281 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
8283 /* OK, now copy the leading unmatched portion of the string (from
8284 str to s) to ret starting at rptr (the current offset). Then copy
8285 the replacement string at ret + rptr + (s - str). Increment
8286 rptr (if necessary) and str and go on. */
8287 if (l)
8289 strncpy (ret + rptr, str, l);
8290 rptr += l;
8292 if (replen)
8294 strncpy (ret + rptr, rstr, rslen);
8295 rptr += rslen;
8297 str = e; /* e == end of match */
8299 if (rstr != rep)
8300 free (rstr);
8302 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
8303 break;
8305 if (s == e)
8307 /* On a zero-length match, make sure we copy one character, since
8308 we increment one character to avoid infinite recursion. */
8309 char *p, *origp, *origs;
8310 size_t clen;
8312 RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64);
8313 #if defined (HANDLE_MULTIBYTE)
8314 p = origp = ret + rptr;
8315 origs = str;
8316 COPY_CHAR_P (p, str, send);
8317 rptr += p - origp;
8318 e += str - origs;
8319 #else
8320 ret[rptr++] = *str++;
8321 e++; /* avoid infinite recursion on zero-length match */
8322 #endif
8326 /* Now copy the unmatched portion of the input string */
8327 if (str && *str)
8329 RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
8330 strcpy (ret + rptr, str);
8332 else
8333 ret[rptr] = '\0';
8335 return ret;
8338 /* Do pattern match and replacement on the positional parameters. */
8339 static char *
8340 pos_params_pat_subst (string, pat, rep, mflags)
8341 char *string, *pat, *rep;
8342 int mflags;
8344 WORD_LIST *save, *params;
8345 WORD_DESC *w;
8346 char *ret;
8347 int pchar, qflags, pflags;
8349 save = params = list_rest_of_args ();
8350 if (save == 0)
8351 return ((char *)NULL);
8353 for ( ; params; params = params->next)
8355 ret = pat_subst (params->word->word, pat, rep, mflags);
8356 w = alloc_word_desc ();
8357 w->word = ret ? ret : savestring ("");
8358 dispose_word (params->word);
8359 params->word = w;
8362 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
8363 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
8364 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
8366 /* If we are expanding in a context where word splitting will not be
8367 performed, treat as quoted. This changes how $* will be expanded. */
8368 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null)
8369 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8371 ret = string_list_pos_params (pchar, save, qflags, pflags);
8372 dispose_words (save);
8374 return (ret);
8377 /* Perform pattern substitution on VALUE, which is the expansion of
8378 VARNAME. PATSUB is an expression supplying the pattern to match
8379 and the string to substitute. QUOTED is a flags word containing
8380 the type of quoting currently in effect. */
8381 static char *
8382 parameter_brace_patsub (varname, value, ind, patsub, quoted, pflags, flags)
8383 char *varname, *value;
8384 int ind;
8385 char *patsub;
8386 int quoted, pflags, flags;
8388 int vtype, mflags, starsub, delim;
8389 char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname;
8390 SHELL_VAR *v;
8392 if (value == 0)
8393 return ((char *)NULL);
8395 oname = this_command_name;
8396 this_command_name = varname; /* error messages */
8398 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
8399 if (vtype == -1)
8401 this_command_name = oname;
8402 return ((char *)NULL);
8405 starsub = vtype & VT_STARSUB;
8406 vtype &= ~VT_STARSUB;
8408 mflags = 0;
8409 /* PATSUB is never NULL when this is called. */
8410 if (*patsub == '/')
8412 mflags |= MATCH_GLOBREP;
8413 patsub++;
8416 /* Malloc this because expand_string_if_necessary or one of the expansion
8417 functions in its call chain may free it on a substitution error. */
8418 lpatsub = savestring (patsub);
8420 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8421 mflags |= MATCH_QUOTED;
8423 if (starsub)
8424 mflags |= MATCH_STARSUB;
8426 if (pflags & PF_ASSIGNRHS)
8427 mflags |= MATCH_ASSIGNRHS;
8429 /* If the pattern starts with a `/', make sure we skip over it when looking
8430 for the replacement delimiter. */
8431 delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
8432 if (lpatsub[delim] == '/')
8434 lpatsub[delim] = 0;
8435 rep = lpatsub + delim + 1;
8437 else
8438 rep = (char *)NULL;
8440 if (rep && *rep == '\0')
8441 rep = (char *)NULL;
8443 /* Perform the same expansions on the pattern as performed by the
8444 pattern removal expansions. */
8445 pat = getpattern (lpatsub, quoted, 1);
8447 if (rep)
8449 /* We want to perform quote removal on the expanded replacement even if
8450 the entire expansion is double-quoted because the parser and string
8451 extraction functions treated quotes in the replacement string as
8452 special. THIS IS NOT BACKWARDS COMPATIBLE WITH BUSH-4.2. */
8453 if (shell_compatibility_level > 42)
8454 rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
8455 /* This is the bush-4.2 code. */
8456 else if ((mflags & MATCH_QUOTED) == 0)
8457 rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
8458 else
8459 rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
8462 /* ksh93 doesn't allow the match specifier to be a part of the expanded
8463 pattern. This is an extension. Make sure we don't anchor the pattern
8464 at the beginning or end of the string if we're doing global replacement,
8465 though. */
8466 p = pat;
8467 if (mflags & MATCH_GLOBREP)
8468 mflags |= MATCH_ANY;
8469 else if (pat && pat[0] == '#')
8471 mflags |= MATCH_BEG;
8472 p++;
8474 else if (pat && pat[0] == '%')
8476 mflags |= MATCH_END;
8477 p++;
8479 else
8480 mflags |= MATCH_ANY;
8482 /* OK, we now want to substitute REP for PAT in VAL. If
8483 flags & MATCH_GLOBREP is non-zero, the substitution is done
8484 everywhere, otherwise only the first occurrence of PAT is
8485 replaced. The pattern matching code doesn't understand
8486 CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
8487 values passed in (VT_VARIABLE) so the pattern substitution
8488 code works right. We need to requote special chars after
8489 we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
8490 other cases if QUOTED == 0, since the posparams and arrays
8491 indexed by * or @ do special things when QUOTED != 0. */
8493 switch (vtype)
8495 case VT_VARIABLE:
8496 case VT_ARRAYMEMBER:
8497 temp = pat_subst (val, p, rep, mflags);
8498 if (vtype == VT_VARIABLE)
8499 FREE (val);
8500 if (temp)
8502 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
8503 free (temp);
8504 temp = tt;
8506 break;
8507 case VT_POSPARMS:
8508 /* This does the right thing for the case where we are not performing
8509 word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and
8510 pos_params_pat_subst/string_list_pos_params will do the right thing
8511 in turn for the case where ifs_is_null. Posix interp 888 */
8512 if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB))
8513 mflags |= MATCH_ASSIGNRHS;
8514 temp = pos_params_pat_subst (val, p, rep, mflags);
8515 if (temp && quoted == 0 && ifs_is_null)
8517 /* Posix interp 888 */
8519 else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS))
8521 /* Posix interp 888 */
8523 else if (temp && (mflags & MATCH_QUOTED) == 0)
8525 tt = quote_escapes (temp);
8526 free (temp);
8527 temp = tt;
8529 break;
8530 #if defined (ARRAY_VARS)
8531 case VT_ARRAYVAR:
8532 /* If we are expanding in a context where word splitting will not be
8533 performed, treat as quoted. This changes how ${A[*]} will be
8534 expanded to make it identical to $*. */
8535 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
8536 mflags |= MATCH_QUOTED; /* Posix interp 888 */
8538 /* these eventually call string_list_pos_params */
8539 if (assoc_p (v))
8540 temp = assoc_patsub (assoc_cell (v), p, rep, mflags);
8541 else
8542 temp = array_patsub (array_cell (v), p, rep, mflags);
8544 if (temp && quoted == 0 && ifs_is_null)
8546 /* Posix interp 888 */
8548 else if (temp && (mflags & MATCH_QUOTED) == 0)
8550 tt = quote_escapes (temp);
8551 free (temp);
8552 temp = tt;
8554 break;
8555 #endif
8558 FREE (pat);
8559 FREE (rep);
8560 free (lpatsub);
8562 this_command_name = oname;
8564 return temp;
8567 /****************************************************************/
8568 /* */
8569 /* Functions to perform case modification on variable values */
8570 /* */
8571 /****************************************************************/
8573 /* Do case modification on the positional parameters. */
8575 static char *
8576 pos_params_modcase (string, pat, modop, mflags)
8577 char *string, *pat;
8578 int modop;
8579 int mflags;
8581 WORD_LIST *save, *params;
8582 WORD_DESC *w;
8583 char *ret;
8584 int pchar, qflags, pflags;
8586 save = params = list_rest_of_args ();
8587 if (save == 0)
8588 return ((char *)NULL);
8590 for ( ; params; params = params->next)
8592 ret = sh_modcase (params->word->word, pat, modop);
8593 w = alloc_word_desc ();
8594 w->word = ret ? ret : savestring ("");
8595 dispose_word (params->word);
8596 params->word = w;
8599 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
8600 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
8601 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
8603 /* If we are expanding in a context where word splitting will not be
8604 performed, treat as quoted. This changes how $* will be expanded. */
8605 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
8606 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8608 ret = string_list_pos_params (pchar, save, qflags, pflags);
8609 dispose_words (save);
8611 return (ret);
8614 /* Perform case modification on VALUE, which is the expansion of
8615 VARNAME. MODSPEC is an expression supplying the type of modification
8616 to perform. QUOTED is a flags word containing the type of quoting
8617 currently in effect. */
8618 static char *
8619 parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, pflags, flags)
8620 char *varname, *value;
8621 int ind, modspec;
8622 char *patspec;
8623 int quoted, pflags, flags;
8625 int vtype, starsub, modop, mflags, x;
8626 char *val, *temp, *pat, *p, *lpat, *tt, *oname;
8627 SHELL_VAR *v;
8629 if (value == 0)
8630 return ((char *)NULL);
8632 oname = this_command_name;
8633 this_command_name = varname;
8635 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
8636 if (vtype == -1)
8638 this_command_name = oname;
8639 return ((char *)NULL);
8642 starsub = vtype & VT_STARSUB;
8643 vtype &= ~VT_STARSUB;
8645 modop = 0;
8646 mflags = 0;
8647 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8648 mflags |= MATCH_QUOTED;
8649 if (starsub)
8650 mflags |= MATCH_STARSUB;
8651 if (pflags & PF_ASSIGNRHS)
8652 mflags |= MATCH_ASSIGNRHS;
8654 p = patspec;
8655 if (modspec == '^')
8657 x = p && p[0] == modspec;
8658 modop = x ? CASE_UPPER : CASE_UPFIRST;
8659 p += x;
8661 else if (modspec == ',')
8663 x = p && p[0] == modspec;
8664 modop = x ? CASE_LOWER : CASE_LOWFIRST;
8665 p += x;
8667 else if (modspec == '~')
8669 x = p && p[0] == modspec;
8670 modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
8671 p += x;
8674 lpat = p ? savestring (p) : 0;
8675 /* Perform the same expansions on the pattern as performed by the
8676 pattern removal expansions. */
8677 pat = lpat ? getpattern (lpat, quoted, 1) : 0;
8679 /* OK, now we do the case modification. */
8680 switch (vtype)
8682 case VT_VARIABLE:
8683 case VT_ARRAYMEMBER:
8684 temp = sh_modcase (val, pat, modop);
8685 if (vtype == VT_VARIABLE)
8686 FREE (val);
8687 if (temp)
8689 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
8690 free (temp);
8691 temp = tt;
8693 break;
8695 case VT_POSPARMS:
8696 temp = pos_params_modcase (val, pat, modop, mflags);
8697 if (temp && quoted == 0 && ifs_is_null)
8699 /* Posix interp 888 */
8701 else if (temp && (mflags & MATCH_QUOTED) == 0)
8703 tt = quote_escapes (temp);
8704 free (temp);
8705 temp = tt;
8707 break;
8709 #if defined (ARRAY_VARS)
8710 case VT_ARRAYVAR:
8711 /* If we are expanding in a context where word splitting will not be
8712 performed, treat as quoted. This changes how ${A[*]} will be
8713 expanded to make it identical to $*. */
8714 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
8715 mflags |= MATCH_QUOTED; /* Posix interp 888 */
8717 temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
8718 : array_modcase (array_cell (v), pat, modop, mflags);
8720 if (temp && quoted == 0 && ifs_is_null)
8722 /* Posix interp 888 */
8724 else if (temp && (mflags & MATCH_QUOTED) == 0)
8726 tt = quote_escapes (temp);
8727 free (temp);
8728 temp = tt;
8731 break;
8732 #endif
8735 FREE (pat);
8736 free (lpat);
8738 this_command_name = oname;
8740 return temp;
8743 /* Check for unbalanced parens in S, which is the contents of $(( ... )). If
8744 any occur, this must be a nested command substitution, so return 0.
8745 Otherwise, return 1. A valid arithmetic expression must always have a
8746 ( before a matching ), so any cases where there are more right parens
8747 means that this must not be an arithmetic expression, though the parser
8748 will not accept it without a balanced total number of parens. */
8749 static int
8750 chk_arithsub (s, len)
8751 const char *s;
8752 int len;
8754 int i, count;
8755 DECLARE_MBSTATE;
8757 i = count = 0;
8758 while (i < len)
8760 if (s[i] == LPAREN)
8761 count++;
8762 else if (s[i] == RPAREN)
8764 count--;
8765 if (count < 0)
8766 return 0;
8769 switch (s[i])
8771 default:
8772 ADVANCE_CHAR (s, len, i);
8773 break;
8775 case '\\':
8776 i++;
8777 if (s[i])
8778 ADVANCE_CHAR (s, len, i);
8779 break;
8781 case '\'':
8782 i = skip_single_quoted (s, len, ++i, 0);
8783 break;
8785 case '"':
8786 i = skip_double_quoted ((char *)s, len, ++i, 0);
8787 break;
8791 return (count == 0);
8794 /****************************************************************/
8795 /* */
8796 /* Functions to perform parameter expansion on a string */
8797 /* */
8798 /****************************************************************/
8800 /* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
8801 static WORD_DESC *
8802 parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
8803 char *string;
8804 int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at;
8806 int check_nullness, var_is_set, var_is_null, var_is_special;
8807 int want_substring, want_indir, want_patsub, want_casemod, want_attributes;
8808 char *name, *value, *temp, *temp1;
8809 WORD_DESC *tdesc, *ret;
8810 int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref;
8811 intmax_t number;
8812 arrayind_t ind;
8814 temp = temp1 = value = (char *)NULL;
8815 var_is_set = var_is_null = var_is_special = check_nullness = 0;
8816 want_substring = want_indir = want_patsub = want_casemod = want_attributes = 0;
8818 local_pflags = 0;
8819 all_element_arrayref = 0;
8821 sindex = *indexp;
8822 t_index = ++sindex;
8823 /* ${#var} doesn't have any of the other parameter expansions on it. */
8824 if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
8825 name = string_extract (string, &t_index, "}", SX_VARNAME);
8826 else
8827 #if defined (CASEMOD_EXPANSIONS)
8828 /* To enable case-toggling expansions using the `~' operator character
8829 define CASEMOD_TOGGLECASE in config-top.h */
8830 # if defined (CASEMOD_TOGGLECASE)
8831 name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME);
8832 # else
8833 name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME);
8834 # endif /* CASEMOD_TOGGLECASE */
8835 #else
8836 name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME);
8837 #endif /* CASEMOD_EXPANSIONS */
8839 /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly
8840 the cleanest code ever. */
8841 if (*name == 0 && sindex == t_index && string[sindex] == '@')
8843 name = (char *)xrealloc (name, 2);
8844 name[0] = '@';
8845 name[1] = '\0';
8846 t_index++;
8848 else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE)
8850 name = (char *)xrealloc (name, t_index - sindex + 2);
8851 name[t_index - sindex] = '@';
8852 name[t_index - sindex + 1] = '\0';
8853 t_index++;
8856 ret = 0;
8857 tflag = 0;
8859 ind = INTMAX_MIN;
8861 /* If the name really consists of a special variable, then make sure
8862 that we have the entire name. We don't allow indirect references
8863 to special variables except `#', `?', `@' and `*'. This clause is
8864 designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more
8865 general. */
8866 if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
8867 (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) ||
8868 (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
8870 t_index++;
8871 temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0);
8872 name = (char *)xrealloc (name, 3 + (strlen (temp1)));
8873 *name = string[sindex];
8874 if (string[sindex] == '!')
8876 /* indirect reference of $#, $?, $@, or $* */
8877 name[1] = string[sindex + 1];
8878 strcpy (name + 2, temp1);
8880 else
8881 strcpy (name + 1, temp1);
8882 free (temp1);
8884 sindex = t_index;
8886 /* Find out what character ended the variable name. Then
8887 do the appropriate thing. */
8888 if (c = string[sindex])
8889 sindex++;
8891 /* If c is followed by one of the valid parameter expansion
8892 characters, move past it as normal. If not, assume that
8893 a substring specification is being given, and do not move
8894 past it. */
8895 if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
8897 check_nullness++;
8898 if (c = string[sindex])
8899 sindex++;
8901 else if (c == ':' && string[sindex] != RBRACE)
8902 want_substring = 1;
8903 else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */
8904 want_patsub = 1;
8905 #if defined (CASEMOD_EXPANSIONS)
8906 else if (c == '^' || c == ',' || c == '~')
8908 modspec = c;
8909 want_casemod = 1;
8911 #endif
8912 else if (c == '@' && (string[sindex] == 'a' || string[sindex] == 'A') && string[sindex+1] == RBRACE)
8914 /* special case because we do not want to shortcut foo as foo[0] here */
8915 want_attributes = 1;
8916 local_pflags |= PF_ALLINDS;
8919 /* Catch the valid and invalid brace expressions that made it through the
8920 tests above. */
8921 /* ${#-} is a valid expansion and means to take the length of $-.
8922 Similarly for ${#?} and ${##}... */
8923 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
8924 VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
8926 name = (char *)xrealloc (name, 3);
8927 name[1] = c;
8928 name[2] = '\0';
8929 c = string[sindex++];
8932 /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
8933 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
8934 member (c, "%:=+/") && string[sindex] == RBRACE)
8936 temp = (char *)NULL;
8937 goto bad_substitution; /* XXX - substitution error */
8940 /* Indirect expansion begins with a `!'. A valid indirect expansion is
8941 either a variable name, one of the positional parameters or a special
8942 variable that expands to one of the positional parameters. */
8943 want_indir = *name == '!' &&
8944 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
8945 || VALID_INDIR_PARAM (name[1]));
8947 /* Determine the value of this variable whose name is NAME. */
8949 /* Check for special variables, directly referenced. */
8950 if (SPECIAL_VAR (name, want_indir))
8951 var_is_special++;
8953 /* Check for special expansion things, like the length of a parameter */
8954 if (*name == '#' && name[1])
8956 /* If we are not pointing at the character just after the
8957 closing brace, then we haven't gotten all of the name.
8958 Since it begins with a special character, this is a bad
8959 substitution. Also check NAME for validity before trying
8960 to go on. */
8961 if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
8963 temp = (char *)NULL;
8964 goto bad_substitution; /* substitution error */
8967 number = parameter_brace_expand_length (name);
8968 if (number == INTMAX_MIN && unbound_vars_is_error)
8970 set_exit_status (EXECUTION_FAILURE);
8971 err_unboundvar (name+1);
8972 free (name);
8973 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
8975 free (name);
8977 *indexp = sindex;
8978 if (number < 0)
8979 return (&expand_wdesc_error);
8980 else
8982 ret = alloc_word_desc ();
8983 ret->word = itos (number);
8984 return ret;
8988 /* ${@} is identical to $@. */
8989 if (name[0] == '@' && name[1] == '\0')
8991 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
8992 *quoted_dollar_atp = 1;
8994 if (contains_dollar_at)
8995 *contains_dollar_at = 1;
8997 tflag |= W_DOLLARAT;
9000 /* Process ${!PREFIX*} expansion. */
9001 if (want_indir && string[sindex - 1] == RBRACE &&
9002 (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
9003 legal_variable_starter ((unsigned char) name[1]))
9005 char **x;
9006 WORD_LIST *xlist;
9008 temp1 = savestring (name + 1);
9009 number = strlen (temp1);
9010 temp1[number - 1] = '\0';
9011 x = all_variables_matching_prefix (temp1);
9012 xlist = strvec_to_word_list (x, 0, 0);
9013 if (string[sindex - 2] == '*')
9014 temp = string_list_dollar_star (xlist, quoted, 0);
9015 else
9017 temp = string_list_dollar_at (xlist, quoted, 0);
9018 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9019 *quoted_dollar_atp = 1;
9020 if (contains_dollar_at)
9021 *contains_dollar_at = 1;
9023 tflag |= W_DOLLARAT;
9025 free (x);
9026 dispose_words (xlist);
9027 free (temp1);
9028 *indexp = sindex;
9030 free (name);
9032 ret = alloc_word_desc ();
9033 ret->word = temp;
9034 ret->flags = tflag; /* XXX */
9035 return ret;
9038 #if defined (ARRAY_VARS)
9039 /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */
9040 if (want_indir && string[sindex - 1] == RBRACE &&
9041 string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0))
9043 char *x, *x1;
9045 temp1 = savestring (name + 1);
9046 x = array_variable_name (temp1, 0, &x1, (int *)0);
9047 FREE (x);
9048 if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK)
9050 temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */
9051 if (x1[0] == '@')
9053 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9054 *quoted_dollar_atp = 1;
9055 if (contains_dollar_at)
9056 *contains_dollar_at = 1;
9058 tflag |= W_DOLLARAT;
9061 free (name);
9062 free (temp1);
9063 *indexp = sindex;
9065 ret = alloc_word_desc ();
9066 ret->word = temp;
9067 ret->flags = tflag; /* XXX */
9068 return ret;
9071 free (temp1);
9073 #endif /* ARRAY_VARS */
9075 /* Make sure that NAME is valid before trying to go on. */
9076 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
9077 var_is_special) == 0)
9079 temp = (char *)NULL;
9080 goto bad_substitution; /* substitution error */
9083 if (want_indir)
9085 tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags|local_pflags, quoted_dollar_atp, contains_dollar_at);
9086 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9088 temp = (char *)NULL;
9089 goto bad_substitution;
9092 /* Turn off the W_ARRAYIND flag because there is no way for this function
9093 to return the index we're supposed to be using. */
9094 if (tdesc && tdesc->flags)
9095 tdesc->flags &= ~W_ARRAYIND;
9097 else
9099 local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS));
9100 tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &ind);
9103 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9105 tflag = 0;
9106 tdesc = 0;
9109 if (tdesc)
9111 temp = tdesc->word;
9112 tflag = tdesc->flags;
9113 dispose_word_desc (tdesc);
9115 else
9116 temp = (char *)0;
9118 if (temp == &expand_param_error || temp == &expand_param_fatal)
9120 FREE (name);
9121 FREE (value);
9122 return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9125 #if defined (ARRAY_VARS)
9126 if (valid_array_reference (name, 0))
9128 int qflags;
9129 char *t;
9131 qflags = quoted;
9132 /* If in a context where word splitting will not take place, treat as
9133 if double-quoted. Has effects with $* and ${array[*]} */
9135 if (pflags & PF_ASSIGNRHS)
9136 qflags |= Q_DOUBLE_QUOTES;
9137 /* We duplicate a little code here */
9138 t = mbschr (name, LBRACK);
9139 if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK)
9141 all_element_arrayref = 1;
9142 if (expand_no_split_dollar_star && t[1] == '*') /* XXX */
9143 qflags |= Q_DOUBLE_QUOTES;
9145 chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at);
9147 #endif
9149 var_is_set = temp != (char *)0;
9150 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
9151 /* XXX - this may not need to be restricted to special variables */
9152 if (check_nullness)
9153 var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp);
9154 #if defined (ARRAY_VARS)
9155 if (check_nullness)
9156 var_is_null |= var_is_set &&
9157 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) &&
9158 QUOTED_NULL (temp) &&
9159 valid_array_reference (name, 0) &&
9160 chk_atstar (name, 0, 0, (int *)0, (int *)0);
9161 #endif
9163 /* Get the rest of the stuff inside the braces. */
9164 if (c && c != RBRACE)
9166 /* Extract the contents of the ${ ... } expansion
9167 according to the Posix.2 rules. */
9168 value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
9169 if (string[sindex] == RBRACE)
9170 sindex++;
9171 else
9172 goto bad_substitution; /* substitution error */
9174 else
9175 value = (char *)NULL;
9177 *indexp = sindex;
9179 /* All the cases where an expansion can possibly generate an unbound
9180 variable error. */
9181 if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE)
9183 if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0)
9185 set_exit_status (EXECUTION_FAILURE);
9186 err_unboundvar (name);
9187 FREE (value);
9188 FREE (temp);
9189 free (name);
9190 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9194 /* If this is a substring spec, process it and add the result. */
9195 if (want_substring)
9197 temp1 = parameter_brace_substring (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9198 FREE (value);
9199 FREE (temp);
9201 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9203 FREE (name);
9204 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9207 ret = alloc_word_desc ();
9208 ret->word = temp1;
9209 /* We test quoted_dollar_atp because we want variants with double-quoted
9210 "$@" to take a different code path. In fact, we make sure at the end
9211 of expand_word_internal that we're only looking at these flags if
9212 quoted_dollar_at == 0. */
9213 if (temp1 &&
9214 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9215 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9216 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9217 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 &&
9218 (pflags & PF_ASSIGNRHS))
9219 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9220 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9221 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9222 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9224 FREE (name);
9225 return ret;
9227 else if (want_patsub)
9229 temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9230 FREE (value);
9231 FREE (temp);
9233 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9235 FREE (name);
9236 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9239 ret = alloc_word_desc ();
9240 ret->word = temp1;
9241 if (temp1 &&
9242 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9243 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9244 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9245 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9246 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9247 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9249 FREE (name);
9250 return ret;
9252 #if defined (CASEMOD_EXPANSIONS)
9253 else if (want_casemod)
9255 temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9256 FREE (value);
9257 FREE (temp);
9259 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9261 FREE (name);
9262 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9265 ret = alloc_word_desc ();
9266 ret->word = temp1;
9267 if (temp1 &&
9268 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9269 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9270 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9271 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9272 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9273 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9275 FREE (name);
9276 return ret;
9278 #endif
9280 /* Do the right thing based on which character ended the variable name. */
9281 switch (c)
9283 default:
9284 case '\0':
9285 bad_substitution:
9286 set_exit_status (EXECUTION_FAILURE);
9287 report_error (_("%s: bad substitution"), string ? string : "??");
9288 FREE (value);
9289 FREE (temp);
9290 free (name);
9291 if (shell_compatibility_level <= 43)
9292 return &expand_wdesc_error;
9293 else
9294 return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error);
9296 case RBRACE:
9297 break;
9299 case '@':
9300 temp1 = parameter_brace_transform (name, temp, ind, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9301 free (temp);
9302 free (value);
9304 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9306 free (name);
9307 set_exit_status (EXECUTION_FAILURE);
9308 report_error (_("%s: bad substitution"), string ? string : "??");
9309 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9312 ret = alloc_word_desc ();
9313 ret->word = temp1;
9314 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9315 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9316 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9317 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9318 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9320 free (name);
9321 return ret;
9323 case '#': /* ${param#[#]pattern} */
9324 case '%': /* ${param%[%]pattern} */
9325 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
9327 FREE (value);
9328 break;
9330 temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9331 free (temp);
9332 free (value);
9334 ret = alloc_word_desc ();
9335 ret->word = temp1;
9336 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9337 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9338 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9339 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9340 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9342 free (name);
9343 return ret;
9345 case '-':
9346 case '=':
9347 case '?':
9348 case '+':
9349 if (var_is_set && var_is_null == 0)
9351 /* If the operator is `+', we don't want the value of the named
9352 variable for anything, just the value of the right hand side. */
9353 if (c == '+')
9355 /* XXX -- if we're double-quoted and the named variable is "$@",
9356 we want to turn off any special handling of "$@" --
9357 we're not using it, so whatever is on the rhs applies. */
9358 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9359 *quoted_dollar_atp = 0;
9360 if (contains_dollar_at)
9361 *contains_dollar_at = 0;
9363 FREE (temp);
9364 if (value)
9366 /* From Posix discussion on austin-group list. Issue 221
9367 requires that backslashes escaping `}' inside
9368 double-quoted ${...} be removed. */
9369 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9370 quoted |= Q_DOLBRACE;
9371 ret = parameter_brace_expand_rhs (name, value, c,
9372 quoted,
9373 pflags,
9374 quoted_dollar_atp,
9375 contains_dollar_at);
9376 /* XXX - fix up later, esp. noting presence of
9377 W_HASQUOTEDNULL in ret->flags */
9378 free (value);
9380 else
9381 temp = (char *)NULL;
9383 else
9385 FREE (value);
9387 /* Otherwise do nothing; just use the value in TEMP. */
9389 else /* VAR not set or VAR is NULL. */
9391 FREE (temp);
9392 temp = (char *)NULL;
9393 if (c == '=' && var_is_special)
9395 set_exit_status (EXECUTION_FAILURE);
9396 report_error (_("$%s: cannot assign in this way"), name);
9397 free (name);
9398 free (value);
9399 return &expand_wdesc_error;
9401 else if (c == '?')
9403 parameter_brace_expand_error (name, value, check_nullness);
9404 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9406 else if (c != '+')
9408 /* XXX -- if we're double-quoted and the named variable is "$@",
9409 we want to turn off any special handling of "$@" --
9410 we're not using it, so whatever is on the rhs applies. */
9411 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9412 *quoted_dollar_atp = 0;
9413 if (contains_dollar_at)
9414 *contains_dollar_at = 0;
9416 /* From Posix discussion on austin-group list. Issue 221 requires
9417 that backslashes escaping `}' inside double-quoted ${...} be
9418 removed. */
9419 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9420 quoted |= Q_DOLBRACE;
9421 ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags,
9422 quoted_dollar_atp,
9423 contains_dollar_at);
9424 /* XXX - fix up later, esp. noting presence of
9425 W_HASQUOTEDNULL in tdesc->flags */
9427 free (value);
9430 break;
9432 free (name);
9434 if (ret == 0)
9436 ret = alloc_word_desc ();
9437 ret->flags = tflag;
9438 ret->word = temp;
9440 return (ret);
9443 /* Expand a single ${xxx} expansion. The braces are optional. When
9444 the braces are used, parameter_brace_expand() does the work,
9445 possibly calling param_expand recursively. */
9446 static WORD_DESC *
9447 param_expand (string, sindex, quoted, expanded_something,
9448 contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
9449 pflags)
9450 char *string;
9451 int *sindex, quoted, *expanded_something, *contains_dollar_at;
9452 int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
9454 char *temp, *temp1, uerror[3], *savecmd;
9455 int zindex, t_index, expok;
9456 unsigned char c;
9457 intmax_t number;
9458 SHELL_VAR *var;
9459 WORD_LIST *list, *l;
9460 WORD_DESC *tdesc, *ret;
9461 int tflag, nullarg;
9463 /*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/
9464 zindex = *sindex;
9465 c = string[++zindex];
9467 temp = (char *)NULL;
9468 ret = tdesc = (WORD_DESC *)NULL;
9469 tflag = 0;
9471 /* Do simple cases first. Switch on what follows '$'. */
9472 switch (c)
9474 /* $0 .. $9? */
9475 case '0':
9476 case '1':
9477 case '2':
9478 case '3':
9479 case '4':
9480 case '5':
9481 case '6':
9482 case '7':
9483 case '8':
9484 case '9':
9485 temp1 = dollar_vars[TODIGIT (c)];
9486 /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */
9487 if (unbound_vars_is_error && temp1 == (char *)NULL)
9489 uerror[0] = '$';
9490 uerror[1] = c;
9491 uerror[2] = '\0';
9492 set_exit_status (EXECUTION_FAILURE);
9493 err_unboundvar (uerror);
9494 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9496 if (temp1)
9497 temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9498 ? quote_string (temp1)
9499 : quote_escapes (temp1);
9500 else
9501 temp = (char *)NULL;
9503 break;
9505 /* $$ -- pid of the invoking shell. */
9506 case '$':
9507 temp = itos (dollar_dollar_pid);
9508 break;
9510 /* $# -- number of positional parameters. */
9511 case '#':
9512 temp = itos (number_of_args ());
9513 break;
9515 /* $? -- return value of the last synchronous command. */
9516 case '?':
9517 temp = itos (last_command_exit_value);
9518 break;
9520 /* $- -- flags supplied to the shell on invocation or by `set'. */
9521 case '-':
9522 temp = which_set_flags ();
9523 break;
9525 /* $! -- Pid of the last asynchronous command. */
9526 case '!':
9527 /* If no asynchronous pids have been created, expand to nothing.
9528 If `set -u' has been executed, and no async processes have
9529 been created, this is an expansion error. */
9530 if (last_asynchronous_pid == NO_PID)
9532 if (expanded_something)
9533 *expanded_something = 0;
9534 temp = (char *)NULL;
9535 if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
9537 uerror[0] = '$';
9538 uerror[1] = c;
9539 uerror[2] = '\0';
9540 set_exit_status (EXECUTION_FAILURE);
9541 err_unboundvar (uerror);
9542 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9545 else
9546 temp = itos (last_asynchronous_pid);
9547 break;
9549 /* The only difference between this and $@ is when the arg is quoted. */
9550 case '*': /* `$*' */
9551 list = list_rest_of_args ();
9553 #if 0
9554 /* According to austin-group posix proposal by Geoff Clare in
9555 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
9557 "The shell shall write a message to standard error and
9558 immediately exit when it tries to expand an unset parameter
9559 other than the '@' and '*' special parameters."
9562 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
9564 uerror[0] = '$';
9565 uerror[1] = '*';
9566 uerror[2] = '\0';
9567 set_exit_status (EXECUTION_FAILURE);
9568 err_unboundvar (uerror);
9569 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9571 #endif
9573 /* If there are no command-line arguments, this should just
9574 disappear if there are other characters in the expansion,
9575 even if it's quoted. */
9576 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
9577 temp = (char *)NULL;
9578 else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
9580 /* If we have "$*" we want to make a string of the positional
9581 parameters, separated by the first character of $IFS, and
9582 quote the whole string, including the separators. If IFS
9583 is unset, the parameters are separated by ' '; if $IFS is
9584 null, the parameters are concatenated. */
9585 temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list);
9586 if (temp)
9588 temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp;
9589 if (*temp == 0)
9590 tflag |= W_HASQUOTEDNULL;
9591 if (temp != temp1)
9592 free (temp);
9593 temp = temp1;
9596 else
9598 /* We check whether or not we're eventually going to split $* here,
9599 for example when IFS is empty and we are processing the rhs of
9600 an assignment statement. In that case, we don't separate the
9601 arguments at all. Otherwise, if the $* is not quoted it is
9602 identical to $@ */
9603 if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS))
9605 /* Posix interp 888: RHS of assignment, IFS unset: no splitting,
9606 separate with space */
9607 temp1 = string_list_dollar_star (list, quoted, pflags);
9608 temp = temp1 ? quote_string (temp1) : temp1;
9609 /* XXX - tentative - note that we saw a quoted null here */
9610 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
9611 tflag |= W_SAWQUOTEDNULL;
9612 FREE (temp1);
9614 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS))
9616 /* Posix interp 888: RHS of assignment, IFS set to '' */
9617 temp1 = string_list_dollar_star (list, quoted, pflags);
9618 temp = temp1 ? quote_escapes (temp1) : temp1;
9619 FREE (temp1);
9621 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS))
9623 /* Posix interp 888: RHS of assignment, IFS set to non-null value */
9624 temp1 = string_list_dollar_star (list, quoted, pflags);
9625 temp = temp1 ? quote_string (temp1) : temp1;
9627 /* XXX - tentative - note that we saw a quoted null here */
9628 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
9629 tflag |= W_SAWQUOTEDNULL;
9630 FREE (temp1);
9632 /* XXX - should we check ifs_is_set here as well? */
9633 # if defined (HANDLE_MULTIBYTE)
9634 else if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
9635 # else
9636 else if (expand_no_split_dollar_star && ifs_firstc == 0)
9637 # endif
9638 /* Posix interp 888: not RHS, no splitting, IFS set to '' */
9639 temp = string_list_dollar_star (list, quoted, 0);
9640 else
9642 temp = string_list_dollar_at (list, quoted, 0);
9643 /* Set W_SPLITSPACE to make sure the individual positional
9644 parameters are split into separate arguments */
9645 #if 0
9646 if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null))
9647 #else /* change with bush-5.0 */
9648 if (quoted == 0 && ifs_is_null)
9649 #endif
9650 tflag |= W_SPLITSPACE;
9651 /* If we're not quoted but we still don't want word splitting, make
9652 we quote the IFS characters to protect them from splitting (e.g.,
9653 when $@ is in the string as well). */
9654 else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS))
9656 temp1 = quote_string (temp);
9657 free (temp);
9658 temp = temp1;
9662 if (expand_no_split_dollar_star == 0 && contains_dollar_at)
9663 *contains_dollar_at = 1;
9666 dispose_words (list);
9667 break;
9669 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
9670 means that we have to turn quoting off after we split into
9671 the individually quoted arguments so that the final split
9672 on the first character of $IFS is still done. */
9673 case '@': /* `$@' */
9674 list = list_rest_of_args ();
9676 #if 0
9677 /* According to austin-group posix proposal by Geoff Clare in
9678 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
9680 "The shell shall write a message to standard error and
9681 immediately exit when it tries to expand an unset parameter
9682 other than the '@' and '*' special parameters."
9685 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
9687 uerror[0] = '$';
9688 uerror[1] = '@';
9689 uerror[2] = '\0';
9690 set_exit_status (EXECUTION_FAILURE);
9691 err_unboundvar (uerror);
9692 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9694 #endif
9696 for (nullarg = 0, l = list; l; l = l->next)
9698 if (l->word && (l->word->word == 0 || l->word->word[0] == 0))
9699 nullarg = 1;
9702 /* We want to flag the fact that we saw this. We can't turn
9703 off quoting entirely, because other characters in the
9704 string might need it (consider "\"$@\""), but we need some
9705 way to signal that the final split on the first character
9706 of $IFS should be done, even though QUOTED is 1. */
9707 /* XXX - should this test include Q_PATQUOTE? */
9708 if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9709 *quoted_dollar_at_p = 1;
9710 if (contains_dollar_at)
9711 *contains_dollar_at = 1;
9713 /* We want to separate the positional parameters with the first
9714 character of $IFS in case $IFS is something other than a space.
9715 We also want to make sure that splitting is done no matter what --
9716 according to POSIX.2, this expands to a list of the positional
9717 parameters no matter what IFS is set to. */
9718 /* XXX - what to do when in a context where word splitting is not
9719 performed? Even when IFS is not the default, posix seems to imply
9720 that we have to expand $@ to all the positional parameters and
9721 separate them with spaces, which are preserved because word splitting
9722 doesn't take place. See below for how we use PF_NOSPLIT2 here. */
9724 /* These are the cases where word splitting will not be performed. */
9725 if (pflags & PF_ASSIGNRHS)
9727 temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags);
9728 if (nullarg)
9729 tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */
9732 /* This needs to match what expand_word_internal does with non-quoted $@
9733 does with separating with spaces. Passing Q_DOUBLE_QUOTES means that
9734 the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that
9735 they will separated by spaces. After doing this, we need the special
9736 handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC
9737 quotes. */
9738 else if (pflags & PF_NOSPLIT2)
9740 #if defined (HANDLE_MULTIBYTE)
9741 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
9742 #else
9743 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
9744 #endif
9745 /* Posix interp 888 */
9746 temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags);
9747 else
9748 temp = string_list_dollar_at (list, quoted, pflags);
9750 else
9751 temp = string_list_dollar_at (list, quoted, pflags);
9753 tflag |= W_DOLLARAT;
9754 dispose_words (list);
9755 break;
9757 case LBRACE:
9758 tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
9759 quoted_dollar_at_p,
9760 contains_dollar_at);
9762 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9763 return (tdesc);
9764 temp = tdesc ? tdesc->word : (char *)0;
9766 /* XXX */
9767 /* Quoted nulls should be removed if there is anything else
9768 in the string. */
9769 /* Note that we saw the quoted null so we can add one back at
9770 the end of this function if there are no other characters
9771 in the string, discard TEMP, and go on. The exception to
9772 this is when we have "${@}" and $1 is '', since $@ needs
9773 special handling. */
9774 if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
9776 if (had_quoted_null_p)
9777 *had_quoted_null_p = 1;
9778 if (*quoted_dollar_at_p == 0)
9780 free (temp);
9781 tdesc->word = temp = (char *)NULL;
9786 ret = tdesc;
9787 goto return0;
9789 /* Do command or arithmetic substitution. */
9790 case LPAREN:
9791 /* We have to extract the contents of this paren substitution. */
9792 t_index = zindex + 1;
9793 /* XXX - might want to check for string[t_index+2] == LPAREN and parse
9794 as arithmetic substitution immediately. */
9795 temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0);
9796 zindex = t_index;
9798 /* For Posix.2-style `$(( ))' arithmetic substitution,
9799 extract the expression and pass it to the evaluator. */
9800 if (temp && *temp == LPAREN)
9802 char *temp2;
9803 temp1 = temp + 1;
9804 temp2 = savestring (temp1);
9805 t_index = strlen (temp2) - 1;
9807 if (temp2[t_index] != RPAREN)
9809 free (temp2);
9810 goto comsub;
9813 /* Cut off ending `)' */
9814 temp2[t_index] = '\0';
9816 if (chk_arithsub (temp2, t_index) == 0)
9818 free (temp2);
9819 #if 0
9820 internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
9821 #endif
9822 goto comsub;
9825 /* Expand variables found inside the expression. */
9826 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
9827 free (temp2);
9829 arithsub:
9830 /* No error messages. */
9831 savecmd = this_command_name;
9832 this_command_name = (char *)NULL;
9833 number = evalexp (temp1, EXP_EXPANDED, &expok);
9834 this_command_name = savecmd;
9835 free (temp);
9836 free (temp1);
9837 if (expok == 0)
9839 if (interactive_shell == 0 && posixly_correct)
9841 set_exit_status (EXECUTION_FAILURE);
9842 return (&expand_wdesc_fatal);
9844 else
9845 return (&expand_wdesc_error);
9847 temp = itos (number);
9848 break;
9851 comsub:
9852 if (pflags & PF_NOCOMSUB)
9853 /* we need zindex+1 because string[zindex] == RPAREN */
9854 temp1 = substring (string, *sindex, zindex+1);
9855 else
9857 tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS);
9858 temp1 = tdesc ? tdesc->word : (char *)NULL;
9859 if (tdesc)
9860 dispose_word_desc (tdesc);
9862 FREE (temp);
9863 temp = temp1;
9864 break;
9866 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
9867 away in a future bush release. */
9868 case '[': /*]*/
9869 /* Extract the contents of this arithmetic substitution. */
9870 t_index = zindex + 1;
9871 temp = extract_arithmetic_subst (string, &t_index);
9872 zindex = t_index;
9873 if (temp == 0)
9875 temp = savestring (string);
9876 if (expanded_something)
9877 *expanded_something = 0;
9878 goto return0;
9881 /* Do initial variable expansion. */
9882 temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH);
9884 goto arithsub;
9886 default:
9887 /* Find the variable in VARIABLE_LIST. */
9888 temp = (char *)NULL;
9890 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
9892 #if 1
9893 if (legal_variable_char3 (string, zindex) == 0)
9894 break;
9895 #else
9896 if (c == ':')
9898 if (string[zindex+1] == ':')
9899 zindex++;
9900 else
9901 break;
9903 #endif
9904 zindex++;
9906 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
9908 /* If this isn't a variable name, then just output the `$'. */
9909 if (temp1 == 0 || *temp1 == '\0')
9911 FREE (temp1);
9912 temp = (char *)xmalloc (2);
9913 temp[0] = '$';
9914 temp[1] = '\0';
9915 if (expanded_something)
9916 *expanded_something = 0;
9917 goto return0;
9920 /* If the variable exists, return its value cell. */
9921 var = find_variable (temp1);
9923 if (var && invisible_p (var) == 0 && var_isset (var))
9925 #if defined (ARRAY_VARS)
9926 if (assoc_p (var) || array_p (var))
9928 temp = array_p (var) ? array_reference (array_cell (var), 0)
9929 : assoc_reference (assoc_cell (var), "0");
9930 if (temp)
9931 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9932 ? quote_string (temp)
9933 : quote_escapes (temp);
9934 else if (unbound_vars_is_error)
9935 goto unbound_variable;
9937 else
9938 #endif
9940 temp = value_cell (var);
9942 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9943 ? quote_string (temp)
9944 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
9945 : quote_escapes (temp));
9948 free (temp1);
9950 goto return0;
9952 else if (var && (invisible_p (var) || var_isset (var) == 0))
9953 temp = (char *)NULL;
9954 else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0)
9956 temp = nameref_cell (var);
9957 #if defined (ARRAY_VARS)
9958 if (temp && *temp && valid_array_reference (temp, 0))
9960 tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (arrayind_t *)NULL);
9961 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9962 return (tdesc);
9963 ret = tdesc;
9964 goto return0;
9966 else
9967 #endif
9968 /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */
9969 if (temp && *temp && legal_identifier (temp) == 0)
9971 set_exit_status (EXECUTION_FAILURE);
9972 report_error (_("%s: invalid variable name for name reference"), temp);
9973 return (&expand_wdesc_error); /* XXX */
9975 else
9976 temp = (char *)NULL;
9979 temp = (char *)NULL;
9981 unbound_variable:
9982 if (unbound_vars_is_error)
9984 set_exit_status (EXECUTION_FAILURE);
9985 err_unboundvar (temp1);
9987 else
9989 free (temp1);
9990 goto return0;
9993 free (temp1);
9994 set_exit_status (EXECUTION_FAILURE);
9995 return ((unbound_vars_is_error && interactive_shell == 0)
9996 ? &expand_wdesc_fatal
9997 : &expand_wdesc_error);
10000 if (string[zindex])
10001 zindex++;
10003 return0:
10004 *sindex = zindex;
10006 if (ret == 0)
10008 ret = alloc_word_desc ();
10009 ret->flags = tflag; /* XXX */
10010 ret->word = temp;
10012 return ret;
10015 void
10016 invalidate_cached_quoted_dollar_at ()
10018 dispose_words (cached_quoted_dollar_at);
10019 cached_quoted_dollar_at = 0;
10022 /* Make a word list which is the result of parameter and variable
10023 expansion, command substitution, arithmetic substitution, and
10024 quote removal of WORD. Return a pointer to a WORD_LIST which is
10025 the result of the expansion. If WORD contains a null word, the
10026 word list returned is also null.
10028 QUOTED contains flag values defined in shell.h.
10030 ISEXP is used to tell expand_word_internal that the word should be
10031 treated as the result of an expansion. This has implications for
10032 how IFS characters in the word are treated.
10034 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
10035 they point to an integer value which receives information about expansion.
10036 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
10037 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
10038 else zero.
10040 This only does word splitting in the case of $@ expansion. In that
10041 case, we split on ' '. */
10043 /* Values for the local variable quoted_state. */
10044 #define UNQUOTED 0
10045 #define PARTIALLY_QUOTED 1
10046 #define WHOLLY_QUOTED 2
10048 static WORD_LIST *
10049 expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
10050 WORD_DESC *word;
10051 int quoted, isexp;
10052 int *contains_dollar_at;
10053 int *expanded_something;
10055 WORD_LIST *list;
10056 WORD_DESC *tword;
10058 /* The intermediate string that we build while expanding. */
10059 char *istring;
10061 /* The current size of the above object. */
10062 size_t istring_size;
10064 /* Index into ISTRING. */
10065 int istring_index;
10067 /* Temporary string storage. */
10068 char *temp, *temp1;
10070 /* The text of WORD. */
10071 register char *string;
10073 /* The size of STRING. */
10074 size_t string_size;
10076 /* The index into STRING. */
10077 int sindex;
10079 /* This gets 1 if we see a $@ while quoted. */
10080 int quoted_dollar_at;
10082 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
10083 whether WORD contains no quoting characters, a partially quoted
10084 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
10085 int quoted_state;
10087 /* State flags */
10088 int had_quoted_null;
10089 int has_quoted_ifs; /* did we add a quoted $IFS character here? */
10090 int has_dollar_at, temp_has_dollar_at;
10091 int split_on_spaces;
10092 int local_expanded;
10093 int tflag;
10094 int pflags; /* flags passed to param_expand */
10095 int mb_cur_max;
10097 int assignoff; /* If assignment, offset of `=' */
10099 register unsigned char c; /* Current character. */
10100 int t_index; /* For calls to string_extract_xxx. */
10102 char twochars[2];
10104 DECLARE_MBSTATE;
10106 /* OK, let's see if we can optimize a common idiom: "$@" */
10107 if (STREQ (word->word, "\"$@\"") &&
10108 (word->flags == (W_HASDOLLAR|W_QUOTED)) &&
10109 dollar_vars[1]) /* XXX - check IFS here as well? */
10111 if (contains_dollar_at)
10112 *contains_dollar_at = 1;
10113 if (expanded_something)
10114 *expanded_something = 1;
10115 if (cached_quoted_dollar_at)
10116 return (copy_word_list (cached_quoted_dollar_at));
10117 list = list_rest_of_args ();
10118 list = quote_list (list);
10119 cached_quoted_dollar_at = copy_word_list (list);
10120 return (list);
10123 istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
10124 istring[istring_index = 0] = '\0';
10125 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
10126 has_quoted_ifs = 0;
10127 split_on_spaces = 0;
10128 quoted_state = UNQUOTED;
10130 string = word->word;
10131 if (string == 0)
10132 goto finished_with_string;
10133 mb_cur_max = MB_CUR_MAX;
10135 /* Don't need the string length for the SADD... and COPY_ macros unless
10136 multibyte characters are possible, but do need it for bounds checking. */
10137 string_size = (mb_cur_max > 1) ? strlen (string) : 1;
10139 if (contains_dollar_at)
10140 *contains_dollar_at = 0;
10142 assignoff = -1;
10144 /* Begin the expansion. */
10146 for (sindex = 0; ;)
10148 c = string[sindex];
10150 /* Case on top-level character. */
10151 switch (c)
10153 case '\0':
10154 goto finished_with_string;
10156 case CTLESC:
10157 sindex++;
10158 #if HANDLE_MULTIBYTE
10159 if (mb_cur_max > 1 && string[sindex])
10161 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
10163 else
10164 #endif
10166 temp = (char *)xmalloc (3);
10167 temp[0] = CTLESC;
10168 temp[1] = c = string[sindex];
10169 temp[2] = '\0';
10172 dollar_add_string:
10173 if (string[sindex])
10174 sindex++;
10176 add_string:
10177 if (temp)
10179 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
10180 temp = (char *)0;
10183 break;
10185 #if defined (PROCESS_SUBSTITUTION)
10186 /* Process substitution. */
10187 case '<':
10188 case '>':
10190 /* XXX - technically this should only be expanded at the start
10191 of a word */
10192 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)))
10194 sindex--; /* add_character: label increments sindex */
10195 goto add_character;
10197 else
10198 t_index = sindex + 1; /* skip past both '<' and LPAREN */
10200 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/
10201 sindex = t_index;
10203 /* If the process substitution specification is `<()', we want to
10204 open the pipe for writing in the child and produce output; if
10205 it is `>()', we want to open the pipe for reading in the child
10206 and consume input. */
10207 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
10209 FREE (temp1);
10211 goto dollar_add_string;
10213 #endif /* PROCESS_SUBSTITUTION */
10215 case '=':
10216 /* Posix.2 section 3.6.1 says that tildes following `=' in words
10217 which are not assignment statements are not expanded. If the
10218 shell isn't in posix mode, though, we perform tilde expansion
10219 on `likely candidate' unquoted assignment statements (flags
10220 include W_ASSIGNMENT but not W_QUOTED). A likely candidate
10221 contains an unquoted :~ or =~. Something to think about: we
10222 now have a flag that says to perform tilde expansion on arguments
10223 to `assignment builtins' like declare and export that look like
10224 assignment statements. We now do tilde expansion on such words
10225 even in POSIX mode. */
10226 if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
10228 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
10229 goto add_ifs_character;
10230 else
10231 goto add_character;
10233 /* If we're not in posix mode or forcing assignment-statement tilde
10234 expansion, note where the first `=' appears in the word and prepare
10235 to do tilde expansion following the first `='. We have to keep
10236 track of the first `=' (using assignoff) to avoid being confused
10237 by an `=' in the rhs of the assignment statement. */
10238 if ((word->flags & W_ASSIGNMENT) &&
10239 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
10240 assignoff == -1 && sindex > 0)
10241 assignoff = sindex;
10242 if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
10243 word->flags |= W_ITILDE;
10245 if (word->flags & W_ASSIGNARG)
10246 word->flags |= W_ASSIGNRHS; /* affects $@ */
10248 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
10250 has_quoted_ifs++;
10251 goto add_ifs_character;
10253 else
10254 goto add_character;
10256 case ':':
10257 if (word->flags & (W_NOTILDE|W_NOASSNTILDE))
10259 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
10260 goto add_ifs_character;
10261 else
10262 goto add_character;
10265 if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) &&
10266 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
10267 string[sindex+1] == '~')
10268 word->flags |= W_ITILDE;
10270 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
10271 goto add_ifs_character;
10272 else
10273 goto add_character;
10275 case '~':
10276 /* If the word isn't supposed to be tilde expanded, or we're not
10277 at the start of a word or after an unquoted : or = in an
10278 assignment statement, we don't do tilde expansion. We don't
10279 do tilde expansion if quoted or in an arithmetic context. */
10281 if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
10282 (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
10283 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
10285 word->flags &= ~W_ITILDE;
10286 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
10287 goto add_ifs_character;
10288 else
10289 goto add_character;
10292 if (word->flags & W_ASSIGNRHS)
10293 tflag = 2;
10294 else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
10295 tflag = 1;
10296 else
10297 tflag = 0;
10299 temp = bush_tilde_find_word (string + sindex, tflag, &t_index);
10301 word->flags &= ~W_ITILDE;
10303 if (temp && *temp && t_index > 0)
10305 temp1 = bush_tilde_expand (temp, tflag);
10306 if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
10308 FREE (temp);
10309 FREE (temp1);
10310 goto add_character; /* tilde expansion failed */
10312 free (temp);
10313 temp = temp1;
10314 sindex += t_index;
10315 goto add_quoted_string; /* XXX was add_string */
10317 else
10319 FREE (temp);
10320 goto add_character;
10323 case '$':
10324 if (expanded_something)
10325 *expanded_something = 1;
10326 local_expanded = 1;
10328 temp_has_dollar_at = 0;
10329 pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
10330 if (word->flags & W_NOSPLIT2)
10331 pflags |= PF_NOSPLIT2;
10332 if (word->flags & W_ASSIGNRHS)
10333 pflags |= PF_ASSIGNRHS;
10334 if (word->flags & W_COMPLETE)
10335 pflags |= PF_COMPLETE;
10337 tword = param_expand (string, &sindex, quoted, expanded_something,
10338 &temp_has_dollar_at, &quoted_dollar_at,
10339 &had_quoted_null, pflags);
10340 has_dollar_at += temp_has_dollar_at;
10341 split_on_spaces += (tword->flags & W_SPLITSPACE);
10343 if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
10345 free (string);
10346 free (istring);
10347 return ((tword == &expand_wdesc_error) ? &expand_word_error
10348 : &expand_word_fatal);
10350 if (contains_dollar_at && has_dollar_at)
10351 *contains_dollar_at = 1;
10353 if (tword && (tword->flags & W_HASQUOTEDNULL))
10354 had_quoted_null = 1; /* note for later */
10355 if (tword && (tword->flags & W_SAWQUOTEDNULL))
10356 had_quoted_null = 1; /* XXX */
10358 temp = tword ? tword->word : (char *)NULL;
10359 dispose_word_desc (tword);
10361 /* Kill quoted nulls; we will add them back at the end of
10362 expand_word_internal if nothing else in the string */
10363 if (had_quoted_null && temp && QUOTED_NULL (temp))
10365 FREE (temp);
10366 temp = (char *)NULL;
10369 goto add_string;
10370 break;
10372 case '`': /* Backquoted command substitution. */
10374 t_index = sindex++;
10376 temp = string_extract (string, &sindex, "`", SX_REQMATCH);
10377 /* The test of sindex against t_index is to allow bare instances of
10378 ` to pass through, for backwards compatibility. */
10379 if (temp == &extract_string_error || temp == &extract_string_fatal)
10381 if (sindex - 1 == t_index)
10383 sindex = t_index;
10384 goto add_character;
10386 set_exit_status (EXECUTION_FAILURE);
10387 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
10388 free (string);
10389 free (istring);
10390 return ((temp == &extract_string_error) ? &expand_word_error
10391 : &expand_word_fatal);
10394 if (expanded_something)
10395 *expanded_something = 1;
10396 local_expanded = 1;
10398 if (word->flags & W_NOCOMSUB)
10399 /* sindex + 1 because string[sindex] == '`' */
10400 temp1 = substring (string, t_index, sindex + 1);
10401 else
10403 de_backslash (temp);
10404 tword = command_substitute (temp, quoted, 0);
10405 temp1 = tword ? tword->word : (char *)NULL;
10406 if (tword)
10407 dispose_word_desc (tword);
10409 FREE (temp);
10410 temp = temp1;
10411 goto dollar_add_string;
10414 case '\\':
10415 if (string[sindex + 1] == '\n')
10417 sindex += 2;
10418 continue;
10421 c = string[++sindex];
10423 /* "However, the double-quote character ( '"' ) shall not be treated
10424 specially within a here-document, except when the double-quote
10425 appears within "$()", "``", or "${}"." */
10426 if ((quoted & Q_HERE_DOCUMENT) && (quoted & Q_DOLBRACE) && c == '"')
10427 tflag = CBSDQUOTE; /* special case */
10428 else if (quoted & Q_HERE_DOCUMENT)
10429 tflag = CBSHDOC;
10430 else if (quoted & Q_DOUBLE_QUOTES)
10431 tflag = CBSDQUOTE;
10432 else
10433 tflag = 0;
10435 /* From Posix discussion on austin-group list: Backslash escaping
10436 a } in ${...} is removed. Issue 0000221 */
10437 if ((quoted & Q_DOLBRACE) && c == RBRACE)
10439 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
10441 /* This is the fix for " $@\ " */
10442 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c))
10444 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
10445 DEFAULT_ARRAY_SIZE);
10446 istring[istring_index++] = CTLESC;
10447 istring[istring_index++] = '\\';
10448 istring[istring_index] = '\0';
10450 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
10452 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0)
10454 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
10455 DEFAULT_ARRAY_SIZE);
10456 istring[istring_index++] = CTLESC;
10457 istring[istring_index++] = '\\';
10458 istring[istring_index] = '\0';
10459 break;
10461 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
10463 SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
10465 else if (c == 0)
10467 c = CTLNUL;
10468 sindex--; /* add_character: label increments sindex */
10469 goto add_character;
10471 else
10473 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
10476 sindex++;
10477 add_twochars:
10478 /* BEFORE jumping here, we need to increment sindex if appropriate */
10479 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
10480 DEFAULT_ARRAY_SIZE);
10481 istring[istring_index++] = twochars[0];
10482 istring[istring_index++] = twochars[1];
10483 istring[istring_index] = '\0';
10485 break;
10487 case '"':
10488 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0))
10489 goto add_character;
10491 t_index = ++sindex;
10492 temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0);
10494 /* If the quotes surrounded the entire string, then the
10495 whole word was quoted. */
10496 quoted_state = (t_index == 1 && string[sindex] == '\0')
10497 ? WHOLLY_QUOTED
10498 : PARTIALLY_QUOTED;
10500 if (temp && *temp)
10502 tword = alloc_word_desc ();
10503 tword->word = temp;
10505 if (word->flags & W_ASSIGNARG)
10506 tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */
10507 if (word->flags & W_COMPLETE)
10508 tword->flags |= W_COMPLETE; /* for command substitutions */
10509 if (word->flags & W_NOCOMSUB)
10510 tword->flags |= W_NOCOMSUB;
10511 if (word->flags & W_NOPROCSUB)
10512 tword->flags |= W_NOPROCSUB;
10514 if (word->flags & W_ASSIGNRHS)
10515 tword->flags |= W_ASSIGNRHS;
10517 temp = (char *)NULL;
10519 temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */
10520 /* Need to get W_HASQUOTEDNULL flag through this function. */
10521 list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL);
10522 has_dollar_at += temp_has_dollar_at;
10524 if (list == &expand_word_error || list == &expand_word_fatal)
10526 free (istring);
10527 free (string);
10528 /* expand_word_internal has already freed temp_word->word
10529 for us because of the way it prints error messages. */
10530 tword->word = (char *)NULL;
10531 dispose_word (tword);
10532 return list;
10535 dispose_word (tword);
10537 /* "$@" (a double-quoted dollar-at) expands into nothing,
10538 not even a NULL word, when there are no positional
10539 parameters. Posix interp 888 says that other parts of the
10540 word that expand to quoted nulls result in quoted nulls, so
10541 we can't just throw the entire word away if we have "$@"
10542 anywhere in it. We use had_quoted_null to keep track */
10543 if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */
10545 quoted_dollar_at++;
10546 break;
10549 /* If this list comes back with a quoted null from expansion,
10550 we have either "$x" or "$@" with $1 == ''. In either case,
10551 we need to make sure we add a quoted null argument and
10552 disable the special handling that "$@" gets. */
10553 if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL))
10555 if (had_quoted_null && temp_has_dollar_at)
10556 quoted_dollar_at++;
10557 had_quoted_null = 1; /* XXX */
10560 /* If we get "$@", we know we have expanded something, so we
10561 need to remember it for the final split on $IFS. This is
10562 a special case; it's the only case where a quoted string
10563 can expand into more than one word. It's going to come back
10564 from the above call to expand_word_internal as a list with
10565 multiple words. */
10566 if (list)
10567 dequote_list (list);
10569 if (temp_has_dollar_at) /* XXX - was has_dollar_at */
10571 quoted_dollar_at++;
10572 if (contains_dollar_at)
10573 *contains_dollar_at = 1;
10574 if (expanded_something)
10575 *expanded_something = 1;
10576 local_expanded = 1;
10579 else
10581 /* What we have is "". This is a minor optimization. */
10582 FREE (temp);
10583 list = (WORD_LIST *)NULL;
10584 had_quoted_null = 1; /* note for later */
10587 /* The code above *might* return a list (consider the case of "$@",
10588 where it returns "$1", "$2", etc.). We can't throw away the
10589 rest of the list, and we have to make sure each word gets added
10590 as quoted. We test on tresult->next: if it is non-NULL, we
10591 quote the whole list, save it to a string with string_list, and
10592 add that string. We don't need to quote the results of this
10593 (and it would be wrong, since that would quote the separators
10594 as well), so we go directly to add_string. */
10595 if (list)
10597 if (list->next)
10599 /* Testing quoted_dollar_at makes sure that "$@" is
10600 split correctly when $IFS does not contain a space. */
10601 temp = quoted_dollar_at
10602 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0)
10603 : string_list (quote_list (list));
10604 dispose_words (list);
10605 goto add_string;
10607 else
10609 temp = savestring (list->word->word);
10610 tflag = list->word->flags;
10611 dispose_words (list);
10613 /* If the string is not a quoted null string, we want
10614 to remove any embedded unquoted CTLNUL characters.
10615 We do not want to turn quoted null strings back into
10616 the empty string, though. We do this because we
10617 want to remove any quoted nulls from expansions that
10618 contain other characters. For example, if we have
10619 x"$*"y or "x$*y" and there are no positional parameters,
10620 the $* should expand into nothing. */
10621 /* We use the W_HASQUOTEDNULL flag to differentiate the
10622 cases: a quoted null character as above and when
10623 CTLNUL is contained in the (non-null) expansion
10624 of some variable. We use the had_quoted_null flag to
10625 pass the value through this function to its caller. */
10626 if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
10627 remove_quoted_nulls (temp); /* XXX */
10630 else
10631 temp = (char *)NULL;
10633 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
10634 had_quoted_null = 1; /* note for later */
10636 /* We do not want to add quoted nulls to strings that are only
10637 partially quoted; we can throw them away. The exception to
10638 this is when we are going to be performing word splitting,
10639 since we have to preserve a null argument if the next character
10640 will cause word splitting. */
10641 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
10643 c = CTLNUL;
10644 sindex--;
10645 had_quoted_null = 1;
10646 goto add_character;
10648 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
10649 continue;
10651 add_quoted_string:
10653 if (temp)
10655 temp1 = temp;
10656 temp = quote_string (temp);
10657 free (temp1);
10658 goto add_string;
10660 else
10662 /* Add NULL arg. */
10663 c = CTLNUL;
10664 sindex--; /* add_character: label increments sindex */
10665 had_quoted_null = 1; /* note for later */
10666 goto add_character;
10669 /* break; */
10671 case '\'':
10672 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
10673 goto add_character;
10675 t_index = ++sindex;
10676 temp = string_extract_single_quoted (string, &sindex);
10678 /* If the entire STRING was surrounded by single quotes,
10679 then the string is wholly quoted. */
10680 quoted_state = (t_index == 1 && string[sindex] == '\0')
10681 ? WHOLLY_QUOTED
10682 : PARTIALLY_QUOTED;
10684 /* If all we had was '', it is a null expansion. */
10685 if (*temp == '\0')
10687 free (temp);
10688 temp = (char *)NULL;
10690 else
10691 remove_quoted_escapes (temp); /* ??? */
10693 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
10694 had_quoted_null = 1; /* note for later */
10696 /* We do not want to add quoted nulls to strings that are only
10697 partially quoted; such nulls are discarded. See above for the
10698 exception, which is when the string is going to be split.
10699 Posix interp 888/1129 */
10700 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
10702 c = CTLNUL;
10703 sindex--;
10704 goto add_character;
10707 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
10708 continue;
10710 /* If we have a quoted null expansion, add a quoted NULL to istring. */
10711 if (temp == 0)
10713 c = CTLNUL;
10714 sindex--; /* add_character: label increments sindex */
10715 goto add_character;
10717 else
10718 goto add_quoted_string;
10720 /* break; */
10722 case ' ':
10723 /* If we are in a context where the word is not going to be split, but
10724 we need to account for $@ and $* producing one word for each
10725 positional parameter, add quoted spaces so the spaces in the
10726 expansion of "$@", if any, behave correctly. We still may need to
10727 split if we are expanding the rhs of a word expansion. */
10728 if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0))
10730 if (string[sindex])
10731 sindex++;
10732 twochars[0] = CTLESC;
10733 twochars[1] = c;
10734 goto add_twochars;
10736 /* FALLTHROUGH */
10738 default:
10739 /* This is the fix for " $@ " */
10740 add_ifs_character:
10741 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0))
10743 if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)
10744 has_quoted_ifs++;
10745 add_quoted_character:
10746 if (string[sindex]) /* from old goto dollar_add_string */
10747 sindex++;
10748 if (c == 0)
10750 c = CTLNUL;
10751 goto add_character;
10753 else
10755 #if HANDLE_MULTIBYTE
10756 /* XXX - should make sure that c is actually multibyte,
10757 otherwise we can use the twochars branch */
10758 if (mb_cur_max > 1)
10759 sindex--;
10761 if (mb_cur_max > 1)
10763 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
10765 else
10766 #endif
10768 twochars[0] = CTLESC;
10769 twochars[1] = c;
10770 goto add_twochars;
10775 SADD_MBCHAR (temp, string, sindex, string_size);
10777 add_character:
10778 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
10779 DEFAULT_ARRAY_SIZE);
10780 istring[istring_index++] = c;
10781 istring[istring_index] = '\0';
10783 /* Next character. */
10784 sindex++;
10788 finished_with_string:
10789 /* OK, we're ready to return. If we have a quoted string, and
10790 quoted_dollar_at is not set, we do no splitting at all; otherwise
10791 we split on ' '. The routines that call this will handle what to
10792 do if nothing has been expanded. */
10794 /* Partially and wholly quoted strings which expand to the empty
10795 string are retained as an empty arguments. Unquoted strings
10796 which expand to the empty string are discarded. The single
10797 exception is the case of expanding "$@" when there are no
10798 positional parameters. In that case, we discard the expansion. */
10800 /* Because of how the code that handles "" and '' in partially
10801 quoted strings works, we need to make ISTRING into a QUOTED_NULL
10802 if we saw quoting characters, but the expansion was empty.
10803 "" and '' are tossed away before we get to this point when
10804 processing partially quoted strings. This makes "" and $xxx""
10805 equivalent when xxx is unset. We also look to see whether we
10806 saw a quoted null from a ${} expansion and add one back if we
10807 need to. */
10809 /* If we expand to nothing and there were no single or double quotes
10810 in the word, we throw it away. Otherwise, we return a NULL word.
10811 The single exception is for $@ surrounded by double quotes when
10812 there are no positional parameters. In that case, we also throw
10813 the word away. */
10815 if (*istring == '\0')
10817 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
10819 istring[0] = CTLNUL;
10820 istring[1] = '\0';
10821 tword = alloc_word_desc ();
10822 tword->word = istring;
10823 istring = 0; /* avoid later free() */
10824 tword->flags |= W_HASQUOTEDNULL; /* XXX */
10825 list = make_word_list (tword, (WORD_LIST *)NULL);
10826 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10827 tword->flags |= W_QUOTED;
10829 /* According to sh, ksh, and Posix.2, if a word expands into nothing
10830 and a double-quoted "$@" appears anywhere in it, then the entire
10831 word is removed. */
10832 /* XXX - exception appears to be that quoted null strings result in
10833 null arguments */
10834 else if (quoted_state == UNQUOTED || quoted_dollar_at)
10835 list = (WORD_LIST *)NULL;
10836 else
10837 list = (WORD_LIST *)NULL;
10839 else if (word->flags & W_NOSPLIT)
10841 tword = alloc_word_desc ();
10842 tword->word = istring;
10843 if (had_quoted_null && QUOTED_NULL (istring))
10844 tword->flags |= W_HASQUOTEDNULL;
10845 istring = 0; /* avoid later free() */
10846 if (word->flags & W_ASSIGNMENT)
10847 tword->flags |= W_ASSIGNMENT; /* XXX */
10848 if (word->flags & W_COMPASSIGN)
10849 tword->flags |= W_COMPASSIGN; /* XXX */
10850 if (word->flags & W_NOGLOB)
10851 tword->flags |= W_NOGLOB; /* XXX */
10852 if (word->flags & W_NOBRACE)
10853 tword->flags |= W_NOBRACE; /* XXX */
10854 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10855 tword->flags |= W_QUOTED;
10856 list = make_word_list (tword, (WORD_LIST *)NULL);
10858 else if (word->flags & W_ASSIGNRHS)
10860 list = list_string (istring, "", quoted);
10861 tword = list->word;
10862 if (had_quoted_null && QUOTED_NULL (istring))
10863 tword->flags |= W_HASQUOTEDNULL;
10864 free (list);
10865 free (istring);
10866 istring = 0; /* avoid later free() */
10867 goto set_word_flags;
10869 else
10871 char *ifs_chars;
10873 ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
10875 /* If we have $@, we need to split the results no matter what. If
10876 IFS is unset or NULL, string_list_dollar_at has separated the
10877 positional parameters with a space, so we split on space (we have
10878 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
10879 string_list_dollar_at has separated the positional parameters
10880 with the first character of $IFS, so we split on $IFS. If
10881 SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
10882 unset or null, and we want to make sure that we split on spaces
10883 regardless of what else has happened to IFS since the expansion,
10884 or we expanded "$@" with IFS null and we need to split the positional
10885 parameters into separate words. */
10886 if (split_on_spaces)
10888 /* If IFS is not set, and the word is not quoted, we want to split
10889 the individual words on $' \t\n'. We rely on previous steps to
10890 quote the portions of the word that should not be split */
10891 if (ifs_is_set == 0)
10892 list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */
10893 else
10894 list = list_string (istring, " ", 1); /* XXX quoted == 1? */
10897 /* If we have $@ (has_dollar_at != 0) and we are in a context where we
10898 don't want to split the result (W_NOSPLIT2), and we are not quoted,
10899 we have already separated the arguments with the first character of
10900 $IFS. In this case, we want to return a list with a single word
10901 with the separator possibly replaced with a space (it's what other
10902 shells seem to do).
10903 quoted_dollar_at is internal to this function and is set if we are
10904 passed an argument that is unquoted (quoted == 0) but we encounter a
10905 double-quoted $@ while expanding it. */
10906 else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2))
10908 tword = alloc_word_desc ();
10909 /* Only split and rejoin if we have to */
10910 if (*ifs_chars && *ifs_chars != ' ')
10912 /* list_string dequotes CTLESCs in the string it's passed, so we
10913 need it to get the space separation right if space isn't the
10914 first character in IFS (but is present) and to remove the
10915 quoting we added back in param_expand(). */
10916 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
10917 /* This isn't exactly right in the case where we're expanding
10918 the RHS of an expansion like ${var-$@} where IFS=: (for
10919 example). The W_NOSPLIT2 means we do the separation with :;
10920 the list_string removes the quotes and breaks the string into
10921 a list, and the string_list rejoins it on spaces. When we
10922 return, we expect to be able to split the results, but the
10923 space separation means the right split doesn't happen. */
10924 tword->word = string_list (list);
10926 else
10927 tword->word = istring;
10928 if (had_quoted_null && QUOTED_NULL (istring))
10929 tword->flags |= W_HASQUOTEDNULL; /* XXX */
10930 if (tword->word != istring)
10931 free (istring);
10932 istring = 0; /* avoid later free() */
10933 goto set_word_flags;
10935 else if (has_dollar_at && ifs_chars)
10936 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
10937 else
10939 tword = alloc_word_desc ();
10940 if (expanded_something && *expanded_something == 0 && has_quoted_ifs)
10941 tword->word = remove_quoted_ifs (istring);
10942 else
10943 tword->word = istring;
10944 if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */
10945 tword->flags |= W_HASQUOTEDNULL; /* XXX */
10946 else if (had_quoted_null)
10947 tword->flags |= W_SAWQUOTEDNULL; /* XXX */
10948 if (tword->word != istring)
10949 free (istring);
10950 istring = 0; /* avoid later free() */
10951 set_word_flags:
10952 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
10953 tword->flags |= W_QUOTED;
10954 if (word->flags & W_ASSIGNMENT)
10955 tword->flags |= W_ASSIGNMENT;
10956 if (word->flags & W_COMPASSIGN)
10957 tword->flags |= W_COMPASSIGN;
10958 if (word->flags & W_NOGLOB)
10959 tword->flags |= W_NOGLOB;
10960 if (word->flags & W_NOBRACE)
10961 tword->flags |= W_NOBRACE;
10962 list = make_word_list (tword, (WORD_LIST *)NULL);
10966 free (istring);
10967 return (list);
10970 /* **************************************************************** */
10971 /* */
10972 /* Functions for Quote Removal */
10973 /* */
10974 /* **************************************************************** */
10976 /* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
10977 backslash quoting rules for within double quotes or a here document. */
10978 char *
10979 string_quote_removal (string, quoted)
10980 char *string;
10981 int quoted;
10983 size_t slen;
10984 char *r, *result_string, *temp, *send;
10985 int sindex, tindex, dquote;
10986 unsigned char c;
10987 DECLARE_MBSTATE;
10989 /* The result can be no longer than the original string. */
10990 slen = strlen (string);
10991 send = string + slen;
10993 r = result_string = (char *)xmalloc (slen + 1);
10995 for (dquote = sindex = 0; c = string[sindex];)
10997 switch (c)
10999 case '\\':
11000 c = string[++sindex];
11001 if (c == 0)
11003 *r++ = '\\';
11004 break;
11006 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
11007 *r++ = '\\';
11008 /* FALLTHROUGH */
11010 default:
11011 SCOPY_CHAR_M (r, string, send, sindex);
11012 break;
11014 case '\'':
11015 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
11017 *r++ = c;
11018 sindex++;
11019 break;
11021 tindex = sindex + 1;
11022 temp = string_extract_single_quoted (string, &tindex);
11023 if (temp)
11025 strcpy (r, temp);
11026 r += strlen (r);
11027 free (temp);
11029 sindex = tindex;
11030 break;
11032 case '"':
11033 dquote = 1 - dquote;
11034 sindex++;
11035 break;
11038 *r = '\0';
11039 return (result_string);
11042 #if 0
11043 /* UNUSED */
11044 /* Perform quote removal on word WORD. This allocates and returns a new
11045 WORD_DESC *. */
11046 WORD_DESC *
11047 word_quote_removal (word, quoted)
11048 WORD_DESC *word;
11049 int quoted;
11051 WORD_DESC *w;
11052 char *t;
11054 t = string_quote_removal (word->word, quoted);
11055 w = alloc_word_desc ();
11056 w->word = t ? t : savestring ("");
11057 return (w);
11060 /* Perform quote removal on all words in LIST. If QUOTED is non-zero,
11061 the members of the list are treated as if they are surrounded by
11062 double quotes. Return a new list, or NULL if LIST is NULL. */
11063 WORD_LIST *
11064 word_list_quote_removal (list, quoted)
11065 WORD_LIST *list;
11066 int quoted;
11068 WORD_LIST *result, *t, *tresult, *e;
11070 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
11072 tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
11073 #if 0
11074 result = (WORD_LIST *) list_append (result, tresult);
11075 #else
11076 if (result == 0)
11077 result = e = tresult;
11078 else
11080 e->next = tresult;
11081 while (e->next)
11082 e = e->next;
11084 #endif
11086 return (result);
11088 #endif
11090 /*******************************************
11092 * Functions to perform word splitting *
11094 *******************************************/
11096 void
11097 setifs (v)
11098 SHELL_VAR *v;
11100 char *t;
11101 unsigned char uc;
11103 ifs_var = v;
11104 ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
11106 ifs_is_set = ifs_var != 0;
11107 ifs_is_null = ifs_is_set && (*ifs_value == 0);
11109 /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
11110 handle multibyte chars in IFS */
11111 memset (ifs_cmap, '\0', sizeof (ifs_cmap));
11112 for (t = ifs_value ; t && *t; t++)
11114 uc = *t;
11115 ifs_cmap[uc] = 1;
11118 #if defined (HANDLE_MULTIBYTE)
11119 if (ifs_value == 0)
11121 ifs_firstc[0] = '\0'; /* XXX - ? */
11122 ifs_firstc_len = 1;
11124 else
11126 if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value))
11127 ifs_firstc_len = (*ifs_value != 0) ? 1 : 0;
11128 else
11130 size_t ifs_len;
11131 ifs_len = strnlen (ifs_value, MB_CUR_MAX);
11132 ifs_firstc_len = MBLEN (ifs_value, ifs_len);
11134 if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
11136 ifs_firstc[0] = ifs_value[0];
11137 ifs_firstc[1] = '\0';
11138 ifs_firstc_len = 1;
11140 else
11141 memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
11143 #else
11144 ifs_firstc = ifs_value ? *ifs_value : 0;
11145 #endif
11148 char *
11149 getifs ()
11151 return ifs_value;
11154 /* This splits a single word into a WORD LIST on $IFS, but only if the word
11155 is not quoted. list_string () performs quote removal for us, even if we
11156 don't do any splitting. */
11157 WORD_LIST *
11158 word_split (w, ifs_chars)
11159 WORD_DESC *w;
11160 char *ifs_chars;
11162 WORD_LIST *result;
11164 if (w)
11166 char *xifs;
11168 xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
11169 result = list_string (w->word, xifs, w->flags & W_QUOTED);
11171 else
11172 result = (WORD_LIST *)NULL;
11174 return (result);
11177 /* Perform word splitting on LIST and return the RESULT. It is possible
11178 to return (WORD_LIST *)NULL. */
11179 static WORD_LIST *
11180 word_list_split (list)
11181 WORD_LIST *list;
11183 WORD_LIST *result, *t, *tresult, *e;
11184 WORD_DESC *w;
11186 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
11188 tresult = word_split (t->word, ifs_value);
11189 /* POSIX 2.6: "If the complete expansion appropriate for a word results
11190 in an empty field, that empty field shall be deleted from the list
11191 of fields that form the completely expanded command, unless the
11192 original word contained single-quote or double-quote characters."
11193 This is where we handle these words that contain quoted null strings
11194 and other characters that expand to nothing after word splitting. */
11195 if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */
11197 w = alloc_word_desc ();
11198 w->word = (char *)xmalloc (1);
11199 w->word[0] = '\0';
11200 tresult = make_word_list (w, (WORD_LIST *)NULL);
11202 if (result == 0)
11203 result = e = tresult;
11204 else
11206 e->next = tresult;
11207 while (e->next)
11208 e = e->next;
11211 return (result);
11214 /**************************************************
11216 * Functions to expand an entire WORD_LIST *
11218 **************************************************/
11220 /* Do any word-expansion-specific cleanup and jump to top_level */
11221 static void
11222 exp_jump_to_top_level (v)
11223 int v;
11225 set_pipestatus_from_exit (last_command_exit_value);
11227 /* Cleanup code goes here. */
11228 expand_no_split_dollar_star = 0; /* XXX */
11229 if (expanding_redir)
11230 undo_partial_redirects ();
11231 expanding_redir = 0;
11232 assigning_in_environment = 0;
11234 if (parse_and_execute_level == 0)
11235 top_level_cleanup (); /* from sig.c */
11237 jump_to_top_level (v);
11240 /* Put NLIST (which is a WORD_LIST * of only one element) at the front of
11241 ELIST, and set ELIST to the new list. */
11242 #define PREPEND_LIST(nlist, elist) \
11243 do { nlist->next = elist; elist = nlist; } while (0)
11245 /* Separate out any initial variable assignments from TLIST. If set -k has
11246 been executed, remove all assignment statements from TLIST. Initial
11247 variable assignments and other environment assignments are placed
11248 on SUBST_ASSIGN_VARLIST. */
11249 static WORD_LIST *
11250 separate_out_assignments (tlist)
11251 WORD_LIST *tlist;
11253 register WORD_LIST *vp, *lp;
11255 if (tlist == 0)
11256 return ((WORD_LIST *)NULL);
11258 if (subst_assign_varlist)
11259 dispose_words (subst_assign_varlist); /* Clean up after previous error */
11261 subst_assign_varlist = (WORD_LIST *)NULL;
11262 vp = lp = tlist;
11264 /* Separate out variable assignments at the start of the command.
11265 Loop invariant: vp->next == lp
11266 Loop postcondition:
11267 lp = list of words left after assignment statements skipped
11268 tlist = original list of words
11270 while (lp && (lp->word->flags & W_ASSIGNMENT))
11272 vp = lp;
11273 lp = lp->next;
11276 /* If lp != tlist, we have some initial assignment statements.
11277 We make SUBST_ASSIGN_VARLIST point to the list of assignment
11278 words and TLIST point to the remaining words. */
11279 if (lp != tlist)
11281 subst_assign_varlist = tlist;
11282 /* ASSERT(vp->next == lp); */
11283 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
11284 tlist = lp; /* remainder of word list */
11287 /* vp == end of variable list */
11288 /* tlist == remainder of original word list without variable assignments */
11289 if (!tlist)
11290 /* All the words in tlist were assignment statements */
11291 return ((WORD_LIST *)NULL);
11293 /* ASSERT(tlist != NULL); */
11294 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
11296 /* If the -k option is in effect, we need to go through the remaining
11297 words, separate out the assignment words, and place them on
11298 SUBST_ASSIGN_VARLIST. */
11299 if (place_keywords_in_env)
11301 WORD_LIST *tp; /* tp == running pointer into tlist */
11303 tp = tlist;
11304 lp = tlist->next;
11306 /* Loop Invariant: tp->next == lp */
11307 /* Loop postcondition: tlist == word list without assignment statements */
11308 while (lp)
11310 if (lp->word->flags & W_ASSIGNMENT)
11312 /* Found an assignment statement, add this word to end of
11313 subst_assign_varlist (vp). */
11314 if (!subst_assign_varlist)
11315 subst_assign_varlist = vp = lp;
11316 else
11318 vp->next = lp;
11319 vp = lp;
11322 /* Remove the word pointed to by LP from TLIST. */
11323 tp->next = lp->next;
11324 /* ASSERT(vp == lp); */
11325 lp->next = (WORD_LIST *)NULL;
11326 lp = tp->next;
11328 else
11330 tp = lp;
11331 lp = lp->next;
11335 return (tlist);
11338 #define WEXP_VARASSIGN 0x001
11339 #define WEXP_BRACEEXP 0x002
11340 #define WEXP_TILDEEXP 0x004
11341 #define WEXP_PARAMEXP 0x008
11342 #define WEXP_PATHEXP 0x010
11344 /* All of the expansions, including variable assignments at the start of
11345 the list. */
11346 #define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
11348 /* All of the expansions except variable assignments at the start of
11349 the list. */
11350 #define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
11352 /* All of the `shell expansions': brace expansion, tilde expansion, parameter
11353 expansion, command substitution, arithmetic expansion, word splitting, and
11354 quote removal. */
11355 #define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
11357 /* Take the list of words in LIST and do the various substitutions. Return
11358 a new list of words which is the expanded list, and without things like
11359 variable assignments. */
11361 WORD_LIST *
11362 expand_words (list)
11363 WORD_LIST *list;
11365 return (expand_word_list_internal (list, WEXP_ALL));
11368 /* Same as expand_words (), but doesn't hack variable or environment
11369 variables. */
11370 WORD_LIST *
11371 expand_words_no_vars (list)
11372 WORD_LIST *list;
11374 return (expand_word_list_internal (list, WEXP_NOVARS));
11377 WORD_LIST *
11378 expand_words_shellexp (list)
11379 WORD_LIST *list;
11381 return (expand_word_list_internal (list, WEXP_SHELLEXP));
11384 static WORD_LIST *
11385 glob_expand_word_list (tlist, eflags)
11386 WORD_LIST *tlist;
11387 int eflags;
11389 char **glob_array, *temp_string;
11390 register int glob_index;
11391 WORD_LIST *glob_list, *output_list, *disposables, *next;
11392 WORD_DESC *tword;
11393 int x;
11395 output_list = disposables = (WORD_LIST *)NULL;
11396 glob_array = (char **)NULL;
11397 while (tlist)
11399 /* For each word, either globbing is attempted or the word is
11400 added to orig_list. If globbing succeeds, the results are
11401 added to orig_list and the word (tlist) is added to the list
11402 of disposable words. If globbing fails and failed glob
11403 expansions are left unchanged (the shell default), the
11404 original word is added to orig_list. If globbing fails and
11405 failed glob expansions are removed, the original word is
11406 added to the list of disposable words. orig_list ends up
11407 in reverse order and requires a call to REVERSE_LIST to
11408 be set right. After all words are examined, the disposable
11409 words are freed. */
11410 next = tlist->next;
11412 /* If the word isn't an assignment and contains an unquoted
11413 pattern matching character, then glob it. */
11414 if ((tlist->word->flags & W_NOGLOB) == 0 &&
11415 unquoted_glob_pattern_p (tlist->word->word))
11417 glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */
11419 /* Handle error cases.
11420 I don't think we should report errors like "No such file
11421 or directory". However, I would like to report errors
11422 like "Read failed". */
11424 if (glob_array == 0 || GLOB_FAILED (glob_array))
11426 glob_array = (char **)xmalloc (sizeof (char *));
11427 glob_array[0] = (char *)NULL;
11430 /* Dequote the current word in case we have to use it. */
11431 if (glob_array[0] == NULL)
11433 temp_string = dequote_string (tlist->word->word);
11434 free (tlist->word->word);
11435 tlist->word->word = temp_string;
11438 /* Make the array into a word list. */
11439 glob_list = (WORD_LIST *)NULL;
11440 for (glob_index = 0; glob_array[glob_index]; glob_index++)
11442 tword = make_bare_word (glob_array[glob_index]);
11443 glob_list = make_word_list (tword, glob_list);
11446 if (glob_list)
11448 output_list = (WORD_LIST *)list_append (glob_list, output_list);
11449 PREPEND_LIST (tlist, disposables);
11451 else if (fail_glob_expansion != 0)
11453 last_command_exit_value = EXECUTION_FAILURE;
11454 report_error (_("no match: %s"), tlist->word->word);
11455 exp_jump_to_top_level (DISCARD);
11457 else if (allow_null_glob_expansion == 0)
11459 /* Failed glob expressions are left unchanged. */
11460 PREPEND_LIST (tlist, output_list);
11462 else
11464 /* Failed glob expressions are removed. */
11465 PREPEND_LIST (tlist, disposables);
11468 else
11470 /* Dequote the string. */
11471 temp_string = dequote_string (tlist->word->word);
11472 free (tlist->word->word);
11473 tlist->word->word = temp_string;
11474 PREPEND_LIST (tlist, output_list);
11477 strvec_dispose (glob_array);
11478 glob_array = (char **)NULL;
11480 tlist = next;
11483 if (disposables)
11484 dispose_words (disposables);
11486 if (output_list)
11487 output_list = REVERSE_LIST (output_list, WORD_LIST *);
11489 return (output_list);
11492 #if defined (BRACE_EXPANSION)
11493 static WORD_LIST *
11494 brace_expand_word_list (tlist, eflags)
11495 WORD_LIST *tlist;
11496 int eflags;
11498 register char **expansions;
11499 char *temp_string;
11500 WORD_LIST *disposables, *output_list, *next;
11501 WORD_DESC *w;
11502 int eindex;
11504 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
11506 next = tlist->next;
11508 if (tlist->word->flags & W_NOBRACE)
11510 /*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/
11511 PREPEND_LIST (tlist, output_list);
11512 continue;
11515 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
11517 /*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
11518 PREPEND_LIST (tlist, output_list);
11519 continue;
11522 /* Only do brace expansion if the word has a brace character. If
11523 not, just add the word list element to BRACES and continue. In
11524 the common case, at least when running shell scripts, this will
11525 degenerate to a bunch of calls to `mbschr', and then what is
11526 basically a reversal of TLIST into BRACES, which is corrected
11527 by a call to REVERSE_LIST () on BRACES when the end of TLIST
11528 is reached. */
11529 if (mbschr (tlist->word->word, LBRACE))
11531 expansions = brace_expand (tlist->word->word);
11533 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
11535 w = alloc_word_desc ();
11536 w->word = temp_string;
11538 /* If brace expansion didn't change the word, preserve
11539 the flags. We may want to preserve the flags
11540 unconditionally someday -- XXX */
11541 if (STREQ (temp_string, tlist->word->word))
11542 w->flags = tlist->word->flags;
11543 else
11544 w = make_word_flags (w, temp_string);
11546 output_list = make_word_list (w, output_list);
11548 free (expansions);
11550 /* Add TLIST to the list of words to be freed after brace
11551 expansion has been performed. */
11552 PREPEND_LIST (tlist, disposables);
11554 else
11555 PREPEND_LIST (tlist, output_list);
11558 if (disposables)
11559 dispose_words (disposables);
11561 if (output_list)
11562 output_list = REVERSE_LIST (output_list, WORD_LIST *);
11564 return (output_list);
11566 #endif
11568 #if defined (ARRAY_VARS)
11569 /* Take WORD, a compound array assignment, and internally run (for example),
11570 'declare -A w', where W is the variable name portion of WORD. OPTION is
11571 the list of options to supply to `declare'. CMD is the declaration command
11572 we are expanding right now; it's unused currently. */
11573 static int
11574 make_internal_declare (word, option, cmd)
11575 char *word;
11576 char *option;
11577 char *cmd;
11579 int t, r;
11580 WORD_LIST *wl;
11581 WORD_DESC *w;
11583 w = make_word (word);
11585 t = assignment (w->word, 0);
11586 if (w->word[t] == '=')
11588 w->word[t] = '\0';
11589 if (w->word[t - 1] == '+') /* cut off any append op */
11590 w->word[t - 1] = '\0';
11593 wl = make_word_list (w, (WORD_LIST *)NULL);
11594 wl = make_word_list (make_word (option), wl);
11596 r = declare_builtin (wl);
11598 dispose_words (wl);
11599 return r;
11602 /* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME
11603 is an associative array.
11605 If we are processing an indexed array, expand_compound_array_assignment
11606 will expand all the individual words and quote_compound_array_list will
11607 single-quote them. If we are processing an associative array, we use
11608 parse_string_to_word_list to split VALUE into a list of words instead of
11609 faking up a shell variable and calling expand_compound_array_assignment.
11610 expand_and_quote_assoc_word expands and single-quotes each word in VALUE
11611 together so we don't have problems finding the end of the subscript when
11612 quoting it.
11614 Words in VALUE can be individual words, which are expanded and single-quoted,
11615 or words of the form [IND]=VALUE, which end up as explained below, as
11616 ['expanded-ind']='expanded-value'. */
11618 static WORD_LIST *
11619 expand_oneword (value, flags)
11620 char *value;
11621 int flags;
11623 WORD_LIST *l, *nl;
11624 char *t;
11626 if (flags == 0)
11628 /* Indexed array */
11629 l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags);
11630 /* Now we quote the results of the expansion above to prevent double
11631 expansion. */
11632 quote_compound_array_list (l, flags);
11633 return l;
11635 else
11637 /* Associative array */
11638 l = parse_string_to_word_list (value, 1, "array assign");
11639 /* For associative arrays, with their arbitrary subscripts, we have to
11640 expand and quote in one step so we don't have to search for the
11641 closing right bracket more than once. */
11642 for (nl = l; nl; nl = nl->next)
11644 if ((nl->word->flags & W_ASSIGNMENT) == 0)
11645 t = sh_single_quote (nl->word->word ? nl->word->word : "");
11646 else
11647 t = expand_and_quote_assoc_word (nl->word->word, flags);
11648 free (nl->word->word);
11649 nl->word->word = t;
11651 return l;
11655 /* Expand a single compound assignment argument to a declaration builtin.
11656 This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through
11657 unchanged. The VALUE is expanded and each word in the result is single-
11658 quoted. Words of the form [key]=value end up as
11659 ['expanded-key']='expanded-value'. Associative arrays have special
11660 handling, see expand_oneword() above. The return value is
11661 NAME[+]=( expanded-and-quoted-VALUE ). */
11662 static void
11663 expand_compound_assignment_word (tlist, flags)
11664 WORD_LIST *tlist;
11665 int flags;
11667 WORD_LIST *l;
11668 int wlen, oind, t;
11669 char *value, *temp;
11671 /*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/
11672 t = assignment (tlist->word->word, 0);
11674 /* value doesn't have the open and close parens */
11675 oind = 1;
11676 value = extract_array_assignment_list (tlist->word->word + t + 1, &oind);
11677 /* This performs one round of expansion on the index/key and value and
11678 single-quotes each word in the result. */
11679 l = expand_oneword (value, flags);
11680 free (value);
11682 value = string_list (l);
11683 wlen = STRLEN (value);
11685 /* Now, let's rebuild the string */
11686 temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */
11687 memcpy (temp, tlist->word->word, ++t);
11688 temp[t++] = '(';
11689 if (value)
11690 memcpy (temp + t, value, wlen);
11691 t += wlen;
11692 temp[t++] = ')';
11693 temp[t] = '\0';
11694 /*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/
11696 free (tlist->word->word);
11697 tlist->word->word = temp;
11699 free (value);
11702 /* Expand and process an argument to a declaration command. We have already
11703 set flags in TLIST->word->flags depending on the declaration command
11704 (declare, local, etc.) and the options supplied to it (-a, -A, etc.).
11705 TLIST->word->word is of the form NAME[+]=( VALUE ).
11707 This does several things, all using pieces of other functions to get the
11708 evaluation sequence right. It's called for compound array assignments with
11709 the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs).
11710 It parses out which flags need to be set for declare to create the variable
11711 correctly, then calls declare internally (make_internal_declare) to make
11712 sure the variable exists with the correct attributes. Before the variable
11713 is created, it calls expand_compound_assignment_word to expand VALUE to a
11714 list of words, appropriately quoted for further evaluation. This preserves
11715 the semantics of word-expansion-before-calling-builtins. Finally, it calls
11716 do_word_assignment to perform the expansion and assignment with the same
11717 expansion semantics as a standalone assignment statement (no word splitting,
11718 etc.) even though the word is single-quoted so all that needs to happen is
11719 quote removal. */
11720 static WORD_LIST *
11721 expand_declaration_argument (tlist, wcmd)
11722 WORD_LIST *tlist, *wcmd;
11724 char opts[16], omap[128];
11725 int t, opti, oind, skip, inheriting;
11726 WORD_LIST *l;
11728 inheriting = localvar_inherit;
11729 opti = 0;
11730 if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY))
11731 opts[opti++] = '-';
11733 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
11735 opts[opti++] = 'g';
11736 opts[opti++] = 'A';
11738 else if (tlist->word->flags & W_ASSIGNASSOC)
11740 opts[opti++] = 'A';
11742 else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
11744 opts[opti++] = 'g';
11745 opts[opti++] = 'a';
11747 else if (tlist->word->flags & W_ASSIGNARRAY)
11749 opts[opti++] = 'a';
11751 else if (tlist->word->flags & W_ASSNGLOBAL)
11752 opts[opti++] = 'g';
11754 if (tlist->word->flags & W_CHKLOCAL)
11755 opts[opti++] = 'G';
11757 /* If we have special handling note the integer attribute and others
11758 that transform the value upon assignment. What we do is take all
11759 of the option arguments and scan through them looking for options
11760 that cause such transformations, and add them to the `opts' array. */
11762 memset (omap, '\0', sizeof (omap));
11763 for (l = wcmd->next; l != tlist; l = l->next)
11765 if (l->word->word[0] != '-')
11766 break; /* non-option argument */
11767 if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0)
11768 break; /* -- signals end of options */
11769 for (oind = 1; l->word->word[oind]; oind++)
11770 switch (l->word->word[oind])
11772 case 'I':
11773 inheriting = 1;
11774 case 'i':
11775 case 'l':
11776 case 'u':
11777 case 'c':
11778 omap[l->word->word[oind]] = 1;
11779 if (opti == 0)
11780 opts[opti++] = '-';
11781 break;
11782 default:
11783 break;
11787 for (oind = 0; oind < sizeof (omap); oind++)
11788 if (omap[oind])
11789 opts[opti++] = oind;
11791 /* If there are no -a/-A options, but we have a compound assignment,
11792 we have a choice: we can set opts[0]='-', opts[1]='a', since the
11793 default is to create an indexed array, and call
11794 make_internal_declare with that, or we can just skip the -a and let
11795 declare_builtin deal with it. Once we're here, we're better set
11796 up for the latter, since we don't want to deal with looking up
11797 any existing variable here -- better to let declare_builtin do it.
11798 We need the variable created, though, especially if it's local, so
11799 we get the scoping right before we call do_word_assignment.
11800 To ensure that make_local_declare gets called, we add `--' if there
11801 aren't any options. */
11802 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0)
11804 if (opti == 0)
11806 opts[opti++] = '-';
11807 opts[opti++] = '-';
11810 opts[opti] = '\0';
11812 /* This isn't perfect, but it's a start. Improvements later. We expand
11813 tlist->word->word and single-quote the results to avoid multiple
11814 expansions by, say, do_assignment_internal(). We have to weigh the
11815 cost of reconstructing the compound assignment string with its single
11816 quoting and letting the declare builtin handle it. The single quotes
11817 will prevent any unwanted additional expansion or word splitting. */
11818 expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0);
11820 skip = 0;
11821 if (opti > 0)
11823 t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0);
11824 if (t != EXECUTION_SUCCESS)
11826 last_command_exit_value = t;
11827 if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */
11828 skip = 1;
11829 else
11830 exp_jump_to_top_level (DISCARD);
11834 if (skip == 0)
11836 t = do_word_assignment (tlist->word, 0);
11837 if (t == 0)
11839 last_command_exit_value = EXECUTION_FAILURE;
11840 exp_jump_to_top_level (DISCARD);
11844 /* Now transform the word as ksh93 appears to do and go on */
11845 t = assignment (tlist->word->word, 0);
11846 tlist->word->word[t] = '\0';
11847 if (tlist->word->word[t - 1] == '+')
11848 tlist->word->word[t - 1] = '\0'; /* cut off append op */
11849 tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
11851 return (tlist);
11853 #endif /* ARRAY_VARS */
11855 static WORD_LIST *
11856 shell_expand_word_list (tlist, eflags)
11857 WORD_LIST *tlist;
11858 int eflags;
11860 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd;
11861 int expanded_something, has_dollar_at;
11863 /* We do tilde expansion all the time. This is what 1003.2 says. */
11864 wcmd = new_list = (WORD_LIST *)NULL;
11866 for (orig_list = tlist; tlist; tlist = next)
11868 if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN))
11869 wcmd = tlist;
11871 next = tlist->next;
11873 #if defined (ARRAY_VARS)
11874 /* If this is a compound array assignment to a builtin that accepts
11875 such assignments (e.g., `declare'), take the assignment and perform
11876 it separately, handling the semantics of declarations inside shell
11877 functions. This avoids the double-evaluation of such arguments,
11878 because `declare' does some evaluation of compound assignments on
11879 its own. */
11880 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
11881 expand_declaration_argument (tlist, wcmd);
11882 #endif
11884 expanded_something = 0;
11885 expanded = expand_word_internal
11886 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
11888 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
11890 /* By convention, each time this error is returned,
11891 tlist->word->word has already been freed. */
11892 tlist->word->word = (char *)NULL;
11894 /* Dispose our copy of the original list. */
11895 dispose_words (orig_list);
11896 /* Dispose the new list we're building. */
11897 dispose_words (new_list);
11899 last_command_exit_value = EXECUTION_FAILURE;
11900 if (expanded == &expand_word_error)
11901 exp_jump_to_top_level (DISCARD);
11902 else
11903 exp_jump_to_top_level (FORCE_EOF);
11906 /* Don't split words marked W_NOSPLIT. */
11907 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
11909 temp_list = word_list_split (expanded);
11910 dispose_words (expanded);
11912 else
11914 /* If no parameter expansion, command substitution, process
11915 substitution, or arithmetic substitution took place, then
11916 do not do word splitting. We still have to remove quoted
11917 null characters from the result. */
11918 word_list_remove_quoted_nulls (expanded);
11919 temp_list = expanded;
11922 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
11923 new_list = (WORD_LIST *)list_append (expanded, new_list);
11926 if (orig_list)
11927 dispose_words (orig_list);
11929 if (new_list)
11930 new_list = REVERSE_LIST (new_list, WORD_LIST *);
11932 return (new_list);
11935 /* The workhorse for expand_words () and expand_words_no_vars ().
11936 First arg is LIST, a WORD_LIST of words.
11937 Second arg EFLAGS is a flags word controlling which expansions are
11938 performed.
11940 This does all of the substitutions: brace expansion, tilde expansion,
11941 parameter expansion, command substitution, arithmetic expansion,
11942 process substitution, word splitting, and pathname expansion, according
11943 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
11944 set, or for which no expansion is done, do not undergo word splitting.
11945 Words with the W_NOGLOB bit set do not undergo pathname expansion; words
11946 with W_NOBRACE set do not undergo brace expansion (see
11947 brace_expand_word_list above). */
11948 static WORD_LIST *
11949 expand_word_list_internal (list, eflags)
11950 WORD_LIST *list;
11951 int eflags;
11953 WORD_LIST *new_list, *temp_list;
11954 int tint;
11955 char *savecmd;
11957 tempenv_assign_error = 0;
11958 if (list == 0)
11959 return ((WORD_LIST *)NULL);
11961 garglist = new_list = copy_word_list (list);
11962 if (eflags & WEXP_VARASSIGN)
11964 garglist = new_list = separate_out_assignments (new_list);
11965 if (new_list == 0)
11967 if (subst_assign_varlist)
11969 /* All the words were variable assignments, so they are placed
11970 into the shell's environment. */
11971 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
11973 savecmd = this_command_name;
11974 this_command_name = (char *)NULL; /* no arithmetic errors */
11975 tint = do_word_assignment (temp_list->word, 0);
11976 this_command_name = savecmd;
11977 /* Variable assignment errors in non-interactive shells
11978 running in Posix.2 mode cause the shell to exit, unless
11979 they are being run by the `command' builtin. */
11980 if (tint == 0)
11982 last_command_exit_value = EXECUTION_FAILURE;
11983 if (interactive_shell == 0 && posixly_correct && executing_command_builtin == 0)
11984 exp_jump_to_top_level (FORCE_EOF);
11985 else
11986 exp_jump_to_top_level (DISCARD);
11989 dispose_words (subst_assign_varlist);
11990 subst_assign_varlist = (WORD_LIST *)NULL;
11992 return ((WORD_LIST *)NULL);
11996 /* Begin expanding the words that remain. The expansions take place on
11997 things that aren't really variable assignments. */
11999 #if defined (BRACE_EXPANSION)
12000 /* Do brace expansion on this word if there are any brace characters
12001 in the string. */
12002 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
12003 new_list = brace_expand_word_list (new_list, eflags);
12004 #endif /* BRACE_EXPANSION */
12006 /* Perform the `normal' shell expansions: tilde expansion, parameter and
12007 variable substitution, command substitution, arithmetic expansion,
12008 and word splitting. */
12009 new_list = shell_expand_word_list (new_list, eflags);
12011 /* Okay, we're almost done. Now let's just do some filename
12012 globbing. */
12013 if (new_list)
12015 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
12016 /* Glob expand the word list unless globbing has been disabled. */
12017 new_list = glob_expand_word_list (new_list, eflags);
12018 else
12019 /* Dequote the words, because we're not performing globbing. */
12020 new_list = dequote_list (new_list);
12023 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
12025 sh_wassign_func_t *assign_func;
12026 int is_special_builtin, is_builtin_or_func;
12028 /* If the remainder of the words expand to nothing, Posix.2 requires
12029 that the variable and environment assignments affect the shell's
12030 environment. */
12031 assign_func = new_list ? assign_in_env : do_word_assignment;
12032 tempenv_assign_error = 0;
12034 is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
12035 /* Posix says that special builtins exit if a variable assignment error
12036 occurs in an assignment preceding it. */
12037 is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
12039 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
12041 savecmd = this_command_name;
12042 this_command_name = (char *)NULL;
12043 assigning_in_environment = (assign_func == assign_in_env);
12044 tint = (*assign_func) (temp_list->word, is_builtin_or_func);
12045 assigning_in_environment = 0;
12046 this_command_name = savecmd;
12047 /* Variable assignment errors in non-interactive shells running
12048 in Posix.2 mode cause the shell to exit. */
12049 if (tint == 0)
12051 if (assign_func == do_word_assignment)
12053 last_command_exit_value = EXECUTION_FAILURE;
12054 if (interactive_shell == 0 && posixly_correct)
12055 exp_jump_to_top_level (FORCE_EOF);
12056 else
12057 exp_jump_to_top_level (DISCARD);
12059 else if (interactive_shell == 0 && is_special_builtin)
12061 last_command_exit_value = EXECUTION_FAILURE;
12062 exp_jump_to_top_level (FORCE_EOF);
12064 else
12065 tempenv_assign_error++;
12069 dispose_words (subst_assign_varlist);
12070 subst_assign_varlist = (WORD_LIST *)NULL;
12073 return (new_list);