]> git.ipfire.org Git - thirdparty/bash.git/blob - subst.c
Bash-5.2 patch 4: fix for nested brace expansions and brackets
[thirdparty/bash.git] / subst.c
1 /* subst.c -- The part of the shell that does parameter, command, arithmetic,
2 and globbing substitutions. */
3
4 /* ``Have a little faith, there's magic in the night. You ain't a
5 beauty, but, hey, you're alright.'' */
6
7 /* Copyright (C) 1987-2022 Free Software Foundation, Inc.
8
9 This file is part of GNU Bash, the Bourne Again SHell.
10
11 Bash is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 Bash is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with Bash. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "config.h"
26
27 #include "bashtypes.h"
28 #include <stdio.h>
29 #include "chartypes.h"
30 #if defined (HAVE_PWD_H)
31 # include <pwd.h>
32 #endif
33 #include <signal.h>
34 #include <errno.h>
35
36 #if defined (HAVE_UNISTD_H)
37 # include <unistd.h>
38 #endif
39
40 #define NEED_FPURGE_DECL
41
42 #include "bashansi.h"
43 #include "posixstat.h"
44 #include "bashintl.h"
45
46 #include "shell.h"
47 #include "parser.h"
48 #include "redir.h"
49 #include "flags.h"
50 #include "jobs.h"
51 #include "execute_cmd.h"
52 #include "filecntl.h"
53 #include "trap.h"
54 #include "pathexp.h"
55 #include "mailcheck.h"
56
57 #include "shmbutil.h"
58 #if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
59 # include <mbstr.h> /* mbschr */
60 #endif
61 #include "typemax.h"
62
63 #include "builtins/getopt.h"
64 #include "builtins/common.h"
65
66 #include "builtins/builtext.h"
67
68 #include <tilde/tilde.h>
69 #include <glob/strmatch.h>
70
71 #if !defined (errno)
72 extern int errno;
73 #endif /* !errno */
74
75 /* The size that strings change by. */
76 #define DEFAULT_INITIAL_ARRAY_SIZE 112
77 #define DEFAULT_ARRAY_SIZE 128
78
79 /* Variable types. */
80 #define VT_VARIABLE 0
81 #define VT_POSPARMS 1
82 #define VT_ARRAYVAR 2
83 #define VT_ARRAYMEMBER 3
84 #define VT_ASSOCVAR 4
85
86 #define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
87
88 /* Flags for quoted_strchr */
89 #define ST_BACKSL 0x01
90 #define ST_CTLESC 0x02
91 #define ST_SQUOTE 0x04 /* unused yet */
92 #define ST_DQUOTE 0x08 /* unused yet */
93
94 /* These defs make it easier to use the editor. */
95 #define LBRACE '{'
96 #define RBRACE '}'
97 #define LPAREN '('
98 #define RPAREN ')'
99 #define LBRACK '['
100 #define RBRACK ']'
101
102 #if defined (HANDLE_MULTIBYTE)
103 #define WLPAREN L'('
104 #define WRPAREN L')'
105 #endif
106
107 #define DOLLAR_AT_STAR(c) ((c) == '@' || (c) == '*')
108 #define STR_DOLLAR_AT_STAR(s) (DOLLAR_AT_STAR ((s)[0]) && (s)[1] == '\0')
109
110 /* Evaluates to 1 if C is one of the shell's special parameters whose length
111 can be taken, but is also one of the special expansion characters. */
112 #define VALID_SPECIAL_LENGTH_PARAM(c) \
113 ((c) == '-' || (c) == '?' || (c) == '#' || (c) == '@')
114
115 /* Evaluates to 1 if C is one of the shell's special parameters for which an
116 indirect variable reference may be made. */
117 #define VALID_INDIR_PARAM(c) \
118 ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
119
120 /* Evaluates to 1 if C is one of the OP characters that follows the parameter
121 in ${parameter[:]OPword}. */
122 #define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)
123
124 /* Evaluates to 1 if this is one of the shell's special variables. */
125 #define SPECIAL_VAR(name, wi) \
126 (*name && ((DIGIT (*name) && all_digits (name)) || \
127 (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \
128 (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))))
129
130 /* This can be used by all of the *_extract_* functions that have a similar
131 structure. It can't just be wrapped in a do...while(0) loop because of
132 the embedded `break'. The dangling else accommodates a trailing semicolon;
133 we could also put in a do ; while (0) */
134
135 #define CHECK_STRING_OVERRUN(oind, ind, len, ch) \
136 if (ind >= len) \
137 { \
138 oind = len; \
139 ch = 0; \
140 break; \
141 } \
142 else \
143
144 /* An expansion function that takes a string and a quoted flag and returns
145 a WORD_LIST *. Used as the type of the third argument to
146 expand_string_if_necessary(). */
147 typedef WORD_LIST *EXPFUNC PARAMS((char *, int));
148
149 /* Process ID of the last command executed within command substitution. */
150 pid_t last_command_subst_pid = NO_PID;
151 pid_t current_command_subst_pid = NO_PID;
152
153 /* Variables used to keep track of the characters in IFS. */
154 SHELL_VAR *ifs_var;
155 char *ifs_value;
156 unsigned char ifs_cmap[UCHAR_MAX + 1];
157 int ifs_is_set, ifs_is_null;
158
159 #if defined (HANDLE_MULTIBYTE)
160 unsigned char ifs_firstc[MB_LEN_MAX];
161 size_t ifs_firstc_len;
162 #else
163 unsigned char ifs_firstc;
164 #endif
165
166 /* If non-zero, command substitution inherits the value of errexit option */
167 int inherit_errexit = 0;
168
169 /* Sentinel to tell when we are performing variable assignments preceding a
170 command name and putting them into the environment. Used to make sure
171 we use the temporary environment when looking up variable values. */
172 int assigning_in_environment;
173
174 /* Used to hold a list of variable assignments preceding a command. Global
175 so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
176 SIGCHLD trap and so it can be saved and restored by the trap handlers. */
177 WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
178
179 /* Tell the expansion functions to not longjmp back to top_level on fatal
180 errors. Enabled when doing completion and prompt string expansion. */
181 int no_longjmp_on_fatal_error = 0;
182
183 /* Non-zero means to allow unmatched globbed filenames to expand to
184 a null file. */
185 int allow_null_glob_expansion;
186
187 /* Non-zero means to throw an error when globbing fails to match anything. */
188 int fail_glob_expansion;
189
190 /* If non-zero, perform `&' substitution on the replacement string in the
191 pattern substitution word expansion. */
192 int patsub_replacement = 1;
193
194 /* Extern functions and variables from different files. */
195 extern struct fd_bitmap *current_fds_to_close;
196 extern int wordexp_only;
197 extern int singlequote_translations;
198 extern int extended_quote;
199
200 #if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION)
201 extern PROCESS *last_procsub_child;
202 #endif
203
204 #if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)
205 extern wchar_t *wcsdup PARAMS((const wchar_t *));
206 #endif
207
208 #if 0
209 /* Variables to keep track of which words in an expanded word list (the
210 output of expand_word_list_internal) are the result of globbing
211 expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c.
212 (CURRENTLY UNUSED). */
213 char *glob_argv_flags;
214 static int glob_argv_flags_size;
215 #endif
216
217 static WORD_LIST *cached_quoted_dollar_at = 0;
218
219 /* Distinguished error values to return from expansion functions */
220 static WORD_LIST expand_word_error, expand_word_fatal;
221 static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
222 static char expand_param_error, expand_param_fatal, expand_param_unset;
223 static char extract_string_error, extract_string_fatal;
224
225 /* Set by expand_word_unsplit and several of the expand_string_XXX functions;
226 used to inhibit splitting and re-joining $* on $IFS, primarily when doing
227 assignment statements. The idea is that if we're in a context where this
228 is set, we're not going to be performing word splitting, so we use the same
229 rules to expand $* as we would if it appeared within double quotes. */
230 static int expand_no_split_dollar_star = 0;
231
232 /* A WORD_LIST of words to be expanded by expand_word_list_internal,
233 without any leading variable assignments. */
234 static WORD_LIST *garglist = (WORD_LIST *)NULL;
235
236 static char *quoted_substring PARAMS((char *, int, int));
237 static int quoted_strlen PARAMS((char *));
238 static char *quoted_strchr PARAMS((char *, int, int));
239
240 static char *expand_string_if_necessary PARAMS((char *, int, EXPFUNC *));
241 static inline char *expand_string_to_string_internal PARAMS((char *, int, EXPFUNC *));
242 static WORD_LIST *call_expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *));
243 static WORD_LIST *expand_string_internal PARAMS((char *, int));
244 static WORD_LIST *expand_string_leave_quoted PARAMS((char *, int));
245 static WORD_LIST *expand_string_for_rhs PARAMS((char *, int, int, int, int *, int *));
246 static WORD_LIST *expand_string_for_pat PARAMS((char *, int, int *, int *));
247
248 static char *quote_escapes_internal PARAMS((const char *, int));
249
250 static WORD_LIST *list_quote_escapes PARAMS((WORD_LIST *));
251 static WORD_LIST *list_dequote_escapes PARAMS((WORD_LIST *));
252
253 static char *make_quoted_char PARAMS((int));
254 static WORD_LIST *quote_list PARAMS((WORD_LIST *));
255
256 static int unquoted_substring PARAMS((char *, char *));
257 static int unquoted_member PARAMS((int, char *));
258
259 #if defined (ARRAY_VARS)
260 static SHELL_VAR *do_compound_assignment PARAMS((char *, char *, int));
261 #endif
262 static int do_assignment_internal PARAMS((const WORD_DESC *, int));
263
264 static char *string_extract_verbatim PARAMS((char *, size_t, int *, char *, int));
265 static char *string_extract PARAMS((char *, int *, char *, int));
266 static char *string_extract_double_quoted PARAMS((char *, int *, int));
267 static inline char *string_extract_single_quoted PARAMS((char *, int *, int));
268 static inline int skip_single_quoted PARAMS((const char *, size_t, int, int));
269 static int skip_double_quoted PARAMS((char *, size_t, int, int));
270 static char *extract_delimited_string PARAMS((char *, int *, char *, char *, char *, int));
271 static char *extract_heredoc_dolbrace_string PARAMS((char *, int *, int, int));
272 static char *extract_dollar_brace_string PARAMS((char *, int *, int, int));
273 static int skip_matched_pair PARAMS((const char *, int, int, int, int));
274
275 static char *pos_params PARAMS((char *, int, int, int, int));
276
277 static unsigned char *mb_getcharlens PARAMS((char *, int));
278
279 static char *remove_upattern PARAMS((char *, char *, int));
280 #if defined (HANDLE_MULTIBYTE)
281 static wchar_t *remove_wpattern PARAMS((wchar_t *, size_t, wchar_t *, int));
282 #endif
283 static char *remove_pattern PARAMS((char *, char *, int));
284
285 static int match_upattern PARAMS((char *, char *, int, char **, char **));
286 #if defined (HANDLE_MULTIBYTE)
287 static int match_wpattern PARAMS((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
288 #endif
289 static int match_pattern PARAMS((char *, char *, int, char **, char **));
290 static int getpatspec PARAMS((int, char *));
291 static char *getpattern PARAMS((char *, int, int));
292 static char *variable_remove_pattern PARAMS((char *, char *, int, int));
293 static char *list_remove_pattern PARAMS((WORD_LIST *, char *, int, int, int));
294 static char *parameter_list_remove_pattern PARAMS((int, char *, int, int));
295 #ifdef ARRAY_VARS
296 static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int));
297 #endif
298 static char *parameter_brace_remove_pattern PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
299
300 static char *string_var_assignment PARAMS((SHELL_VAR *, char *));
301 #if defined (ARRAY_VARS)
302 static char *array_var_assignment PARAMS((SHELL_VAR *, int, int, int));
303 #endif
304 static char *pos_params_assignment PARAMS((WORD_LIST *, int, int));
305 static char *string_transform PARAMS((int, SHELL_VAR *, char *));
306 static char *list_transform PARAMS((int, SHELL_VAR *, WORD_LIST *, int, int));
307 static char *parameter_list_transform PARAMS((int, int, int));
308 #if defined ARRAY_VARS
309 static char *array_transform PARAMS((int, SHELL_VAR *, int, int));
310 #endif
311 static char *parameter_brace_transform PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int, int));
312 static int valid_parameter_transform PARAMS((char *));
313
314 static char *process_substitute PARAMS((char *, int));
315
316 static char *optimize_cat_file PARAMS((REDIRECT *, int, int, int *));
317 static char *read_comsub PARAMS((int, int, int, int *));
318
319 #ifdef ARRAY_VARS
320 static arrayind_t array_length_reference PARAMS((char *));
321 #endif
322
323 static int valid_brace_expansion_word PARAMS((char *, int));
324 static int chk_atstar PARAMS((char *, int, int, int *, int *));
325 static int chk_arithsub PARAMS((const char *, int));
326
327 static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, array_eltstate_t *));
328 static char *parameter_brace_find_indir PARAMS((char *, int, int, int));
329 static WORD_DESC *parameter_brace_expand_indir PARAMS((char *, int, int, int, int *, int *));
330 static WORD_DESC *parameter_brace_expand_rhs PARAMS((char *, char *, int, int, int, int *, int *));
331 static void parameter_brace_expand_error PARAMS((char *, char *, int));
332
333 static int valid_length_expression PARAMS((char *));
334 static intmax_t parameter_brace_expand_length PARAMS((char *));
335
336 static char *skiparith PARAMS((char *, int));
337 static int verify_substring_values PARAMS((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
338 static int get_var_and_type PARAMS((char *, char *, array_eltstate_t *, int, int, SHELL_VAR **, char **));
339 static char *mb_substring PARAMS((char *, int, int));
340 static char *parameter_brace_substring PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
341
342 static int shouldexp_replacement PARAMS((char *));
343
344 static char *pos_params_pat_subst PARAMS((char *, char *, char *, int));
345
346 static char *expand_string_for_patsub PARAMS((char *, int));
347 static char *parameter_brace_patsub PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
348
349 static char *pos_params_casemod PARAMS((char *, char *, int, int));
350 static char *parameter_brace_casemod PARAMS((char *, char *, array_eltstate_t *, int, char *, int, int, int));
351
352 static WORD_DESC *parameter_brace_expand PARAMS((char *, int *, int, int, int *, int *));
353 static WORD_DESC *param_expand PARAMS((char *, int *, int, int *, int *, int *, int *, int));
354
355 static WORD_LIST *expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *));
356
357 static WORD_LIST *word_list_split PARAMS((WORD_LIST *));
358
359 static void exp_jump_to_top_level PARAMS((int));
360
361 static WORD_LIST *separate_out_assignments PARAMS((WORD_LIST *));
362 static WORD_LIST *glob_expand_word_list PARAMS((WORD_LIST *, int));
363 #ifdef BRACE_EXPANSION
364 static WORD_LIST *brace_expand_word_list PARAMS((WORD_LIST *, int));
365 #endif
366 #if defined (ARRAY_VARS)
367 static int make_internal_declare PARAMS((char *, char *, char *));
368 static void expand_compound_assignment_word PARAMS((WORD_LIST *, int));
369 static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *));
370 #endif
371 static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int));
372 static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int));
373
374 static int do_assignment_statements PARAMS((WORD_LIST *, char *, int));
375
376 /* **************************************************************** */
377 /* */
378 /* Utility Functions */
379 /* */
380 /* **************************************************************** */
381
382 #if defined (DEBUG)
383 void
384 dump_word_flags (flags)
385 int flags;
386 {
387 int f;
388
389 f = flags;
390 fprintf (stderr, "%d -> ", f);
391 if (f & W_ARRAYIND)
392 {
393 f &= ~W_ARRAYIND;
394 fprintf (stderr, "W_ARRAYIND%s", f ? "|" : "");
395 }
396 if (f & W_ASSIGNASSOC)
397 {
398 f &= ~W_ASSIGNASSOC;
399 fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
400 }
401 if (f & W_ASSIGNARRAY)
402 {
403 f &= ~W_ASSIGNARRAY;
404 fprintf (stderr, "W_ASSIGNARRAY%s", f ? "|" : "");
405 }
406 if (f & W_SAWQUOTEDNULL)
407 {
408 f &= ~W_SAWQUOTEDNULL;
409 fprintf (stderr, "W_SAWQUOTEDNULL%s", f ? "|" : "");
410 }
411 if (f & W_NOPROCSUB)
412 {
413 f &= ~W_NOPROCSUB;
414 fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
415 }
416 if (f & W_DQUOTE)
417 {
418 f &= ~W_DQUOTE;
419 fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
420 }
421 if (f & W_HASQUOTEDNULL)
422 {
423 f &= ~W_HASQUOTEDNULL;
424 fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
425 }
426 if (f & W_ASSIGNARG)
427 {
428 f &= ~W_ASSIGNARG;
429 fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
430 }
431 if (f & W_ASSNBLTIN)
432 {
433 f &= ~W_ASSNBLTIN;
434 fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
435 }
436 if (f & W_ASSNGLOBAL)
437 {
438 f &= ~W_ASSNGLOBAL;
439 fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : "");
440 }
441 if (f & W_COMPASSIGN)
442 {
443 f &= ~W_COMPASSIGN;
444 fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
445 }
446 if (f & W_EXPANDRHS)
447 {
448 f &= ~W_EXPANDRHS;
449 fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : "");
450 }
451 if (f & W_NOTILDE)
452 {
453 f &= ~W_NOTILDE;
454 fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
455 }
456 if (f & W_ASSIGNRHS)
457 {
458 f &= ~W_ASSIGNRHS;
459 fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
460 }
461 if (f & W_NOASSNTILDE)
462 {
463 f &= ~W_NOASSNTILDE;
464 fprintf (stderr, "W_NOASSNTILDE%s", f ? "|" : "");
465 }
466 if (f & W_NOCOMSUB)
467 {
468 f &= ~W_NOCOMSUB;
469 fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
470 }
471 if (f & W_ARRAYREF)
472 {
473 f &= ~W_ARRAYREF;
474 fprintf (stderr, "W_ARRAYREF%s", f ? "|" : "");
475 }
476 if (f & W_DOLLARAT)
477 {
478 f &= ~W_DOLLARAT;
479 fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
480 }
481 if (f & W_TILDEEXP)
482 {
483 f &= ~W_TILDEEXP;
484 fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
485 }
486 if (f & W_NOSPLIT2)
487 {
488 f &= ~W_NOSPLIT2;
489 fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
490 }
491 if (f & W_NOSPLIT)
492 {
493 f &= ~W_NOSPLIT;
494 fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
495 }
496 if (f & W_NOBRACE)
497 {
498 f &= ~W_NOBRACE;
499 fprintf (stderr, "W_NOBRACE%s", f ? "|" : "");
500 }
501 if (f & W_NOGLOB)
502 {
503 f &= ~W_NOGLOB;
504 fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
505 }
506 if (f & W_SPLITSPACE)
507 {
508 f &= ~W_SPLITSPACE;
509 fprintf (stderr, "W_SPLITSPACE%s", f ? "|" : "");
510 }
511 if (f & W_ASSIGNMENT)
512 {
513 f &= ~W_ASSIGNMENT;
514 fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
515 }
516 if (f & W_QUOTED)
517 {
518 f &= ~W_QUOTED;
519 fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
520 }
521 if (f & W_HASDOLLAR)
522 {
523 f &= ~W_HASDOLLAR;
524 fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
525 }
526 if (f & W_COMPLETE)
527 {
528 f &= ~W_COMPLETE;
529 fprintf (stderr, "W_COMPLETE%s", f ? "|" : "");
530 }
531 if (f & W_CHKLOCAL)
532 {
533 f &= ~W_CHKLOCAL;
534 fprintf (stderr, "W_CHKLOCAL%s", f ? "|" : "");
535 }
536 if (f & W_FORCELOCAL)
537 {
538 f &= ~W_FORCELOCAL;
539 fprintf (stderr, "W_FORCELOCAL%s", f ? "|" : "");
540 }
541
542 fprintf (stderr, "\n");
543 fflush (stderr);
544 }
545 #endif
546
547 #ifdef INCLUDE_UNUSED
548 static char *
549 quoted_substring (string, start, end)
550 char *string;
551 int start, end;
552 {
553 register int len, l;
554 register char *result, *s, *r;
555
556 len = end - start;
557
558 /* Move to string[start], skipping quoted characters. */
559 for (s = string, l = 0; *s && l < start; )
560 {
561 if (*s == CTLESC)
562 {
563 s++;
564 continue;
565 }
566 l++;
567 if (*s == 0)
568 break;
569 }
570
571 r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */
572
573 /* Copy LEN characters, including quote characters. */
574 s = string + l;
575 for (l = 0; l < len; s++)
576 {
577 if (*s == CTLESC)
578 *r++ = *s++;
579 *r++ = *s;
580 l++;
581 if (*s == 0)
582 break;
583 }
584 *r = '\0';
585 return result;
586 }
587 #endif
588
589 #ifdef INCLUDE_UNUSED
590 /* Return the length of S, skipping over quoted characters */
591 static int
592 quoted_strlen (s)
593 char *s;
594 {
595 register char *p;
596 int i;
597
598 i = 0;
599 for (p = s; *p; p++)
600 {
601 if (*p == CTLESC)
602 {
603 p++;
604 if (*p == 0)
605 return (i + 1);
606 }
607 i++;
608 }
609
610 return i;
611 }
612 #endif
613
614 #ifdef INCLUDE_UNUSED
615 /* Find the first occurrence of character C in string S, obeying shell
616 quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
617 characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters
618 escaped with CTLESC are skipped. */
619 static char *
620 quoted_strchr (s, c, flags)
621 char *s;
622 int c, flags;
623 {
624 register char *p;
625
626 for (p = s; *p; p++)
627 {
628 if (((flags & ST_BACKSL) && *p == '\\')
629 || ((flags & ST_CTLESC) && *p == CTLESC))
630 {
631 p++;
632 if (*p == '\0')
633 return ((char *)NULL);
634 continue;
635 }
636 else if (*p == c)
637 return p;
638 }
639 return ((char *)NULL);
640 }
641
642 /* Return 1 if CHARACTER appears in an unquoted portion of
643 STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */
644 static int
645 unquoted_member (character, string)
646 int character;
647 char *string;
648 {
649 size_t slen;
650 int sindex, c;
651 DECLARE_MBSTATE;
652
653 slen = strlen (string);
654 sindex = 0;
655 while (c = string[sindex])
656 {
657 if (c == character)
658 return (1);
659
660 switch (c)
661 {
662 default:
663 ADVANCE_CHAR (string, slen, sindex);
664 break;
665
666 case '\\':
667 sindex++;
668 if (string[sindex])
669 ADVANCE_CHAR (string, slen, sindex);
670 break;
671
672 case '\'':
673 sindex = skip_single_quoted (string, slen, ++sindex, 0);
674 break;
675
676 case '"':
677 sindex = skip_double_quoted (string, slen, ++sindex, 0);
678 break;
679 }
680 }
681 return (0);
682 }
683
684 /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
685 static int
686 unquoted_substring (substr, string)
687 char *substr, *string;
688 {
689 size_t slen;
690 int sindex, c, sublen;
691 DECLARE_MBSTATE;
692
693 if (substr == 0 || *substr == '\0')
694 return (0);
695
696 slen = strlen (string);
697 sublen = strlen (substr);
698 for (sindex = 0; c = string[sindex]; )
699 {
700 if (STREQN (string + sindex, substr, sublen))
701 return (1);
702
703 switch (c)
704 {
705 case '\\':
706 sindex++;
707 if (string[sindex])
708 ADVANCE_CHAR (string, slen, sindex);
709 break;
710
711 case '\'':
712 sindex = skip_single_quoted (string, slen, ++sindex, 0);
713 break;
714
715 case '"':
716 sindex = skip_double_quoted (string, slen, ++sindex, 0);
717 break;
718
719 default:
720 ADVANCE_CHAR (string, slen, sindex);
721 break;
722 }
723 }
724 return (0);
725 }
726 #endif
727
728 /* Most of the substitutions must be done in parallel. In order
729 to avoid using tons of unclear goto's, I have some functions
730 for manipulating malloc'ed strings. They all take INDX, a
731 pointer to an integer which is the offset into the string
732 where manipulation is taking place. They also take SIZE, a
733 pointer to an integer which is the current length of the
734 character array for this string. */
735
736 /* Append SOURCE to TARGET at INDEX. SIZE is the current amount
737 of space allocated to TARGET. SOURCE can be NULL, in which
738 case nothing happens. Gets rid of SOURCE by freeing it.
739 Returns TARGET in case the location has changed. */
740 INLINE char *
741 sub_append_string (source, target, indx, size)
742 char *source, *target;
743 size_t *indx;
744 size_t *size;
745 {
746 if (source)
747 {
748 size_t n, srclen;
749
750 srclen = STRLEN (source);
751 if (srclen >= (*size - *indx))
752 {
753 n = srclen + *indx;
754 n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
755 target = (char *)xrealloc (target, (*size = n));
756 }
757
758 FASTCOPY (source, target + *indx, srclen);
759 *indx += srclen;
760 target[*indx] = '\0';
761
762 free (source);
763 }
764 return (target);
765 }
766
767 #if 0
768 /* UNUSED */
769 /* Append the textual representation of NUMBER to TARGET.
770 INDX and SIZE are as in SUB_APPEND_STRING. */
771 char *
772 sub_append_number (number, target, indx, size)
773 intmax_t number;
774 char *target;
775 size_t *indx;
776 size_t *size;
777 {
778 char *temp;
779
780 temp = itos (number);
781 return (sub_append_string (temp, target, indx, size));
782 }
783 #endif
784
785 /* Extract a substring from STRING, starting at SINDEX and ending with
786 one of the characters in CHARLIST. Don't make the ending character
787 part of the string. Leave SINDEX pointing at the ending character.
788 Understand about backslashes in the string. If (flags & SX_VARNAME)
789 is non-zero, and array variables have been compiled into the shell,
790 everything between a `[' and a corresponding `]' is skipped over.
791 If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
792 update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must
793 contain a closing character from CHARLIST. */
794 static char *
795 string_extract (string, sindex, charlist, flags)
796 char *string;
797 int *sindex;
798 char *charlist;
799 int flags;
800 {
801 register int c, i;
802 int found;
803 size_t slen;
804 char *temp;
805 DECLARE_MBSTATE;
806
807 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
808 i = *sindex;
809 found = 0;
810 while (c = string[i])
811 {
812 if (c == '\\')
813 {
814 if (string[i + 1])
815 i++;
816 else
817 break;
818 }
819 #if defined (ARRAY_VARS)
820 else if ((flags & SX_VARNAME) && c == LBRACK)
821 {
822 int ni;
823 /* If this is an array subscript, skip over it and continue. */
824 ni = skipsubscript (string, i, 0);
825 if (string[ni] == RBRACK)
826 i = ni;
827 }
828 #endif
829 else if (MEMBER (c, charlist))
830 {
831 found = 1;
832 break;
833 }
834
835 ADVANCE_CHAR (string, slen, i);
836 }
837
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)
841 {
842 *sindex = i;
843 return (&extract_string_error);
844 }
845
846 temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
847 *sindex = i;
848
849 return (temp);
850 }
851
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;
863 {
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;
873
874 slen = strlen (string + *sindex) + *sindex;
875 send = string + slen;
876
877 stripdq = (flags & SX_STRIPDQ);
878
879 pass_next = backquote = dquote = 0;
880 temp = (char *)xmalloc (1 + slen - *sindex);
881
882 j = 0;
883 i = *sindex;
884 while (c = string[i])
885 {
886 /* Process a character that was quoted by a backslash. */
887 if (pass_next)
888 {
889 /* XXX - take another look at this in light of Interp 221 */
890 /* Posix.2 sez:
891
892 ``The backslash shall retain its special meaning as an escape
893 character only when followed by one of the characters:
894 $ ` " \ <newline>''.
895
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. */
901
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;
916
917 add_one_character:
918 COPY_CHAR_I (temp, j, string, send, i);
919 continue;
920 }
921
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 == '\\')
926 {
927 pass_next++;
928 i++;
929 continue;
930 }
931
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)
937 {
938 if (c == '`')
939 backquote = 0;
940 temp[j++] = c; /* COPY_CHAR_I? */
941 i++;
942 continue;
943 }
944
945 if (c == '`')
946 {
947 temp[j++] = c;
948 backquote++;
949 i++;
950 continue;
951 }
952
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)))
956 {
957 int free_ret = 1;
958
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);
964
965 temp[j++] = '$';
966 temp[j++] = string[i + 1];
967
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)
971 {
972 free_ret = 0;
973 ret = string + i + 2;
974 }
975
976 /* XXX - CHECK_STRING_OVERRUN here? */
977 for (t = 0; ret[t]; t++, j++)
978 temp[j] = ret[t];
979 temp[j] = string[si];
980
981 if (si < i + 2) /* we went back? */
982 i += 2;
983 else if (string[si])
984 {
985 j++;
986 i = si + 1;
987 }
988 else
989 i = si;
990
991 if (free_ret)
992 free (ret);
993 continue;
994 }
995
996 /* Add any character but a double quote to the quoted string we're
997 accumulating. */
998 if (c != '"')
999 goto add_one_character;
1000
1001 /* c == '"' */
1002 if (stripdq)
1003 {
1004 dquote ^= 1;
1005 i++;
1006 continue;
1007 }
1008
1009 break;
1010 }
1011 temp[j] = '\0';
1012
1013 /* Point to after the closing quote. */
1014 if (c)
1015 i++;
1016 *sindex = i;
1017
1018 return (temp);
1019 }
1020
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;
1028 {
1029 int c, i;
1030 char *ret;
1031 int pass_next, backquote, si;
1032 DECLARE_MBSTATE;
1033
1034 pass_next = backquote = 0;
1035 i = sind;
1036 while (c = string[i])
1037 {
1038 if (pass_next)
1039 {
1040 pass_next = 0;
1041 ADVANCE_CHAR (string, slen, i);
1042 continue;
1043 }
1044 else if (c == '\\')
1045 {
1046 pass_next++;
1047 i++;
1048 continue;
1049 }
1050 else if (backquote)
1051 {
1052 if (c == '`')
1053 backquote = 0;
1054 ADVANCE_CHAR (string, slen, i);
1055 continue;
1056 }
1057 else if (c == '`')
1058 {
1059 backquote++;
1060 i++;
1061 continue;
1062 }
1063 else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
1064 {
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);
1070
1071 /* These can consume the entire string if they are unterminated */
1072 CHECK_STRING_OVERRUN (i, si, slen, c);
1073
1074 i = si + 1;
1075 continue;
1076 }
1077 else if (c != '"')
1078 {
1079 ADVANCE_CHAR (string, slen, i);
1080 continue;
1081 }
1082 else
1083 break;
1084 }
1085
1086 if (c)
1087 i++;
1088
1089 return (i);
1090 }
1091
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. ALLOWESC allows the single quote to be quoted by
1096 a backslash; it's not used yet. */
1097 static inline char *
1098 string_extract_single_quoted (string, sindex, allowesc)
1099 char *string;
1100 int *sindex;
1101 int allowesc;
1102 {
1103 register int i;
1104 size_t slen;
1105 char *t;
1106 int pass_next;
1107 DECLARE_MBSTATE;
1108
1109 /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */
1110 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
1111 i = *sindex;
1112 pass_next = 0;
1113 while (string[i])
1114 {
1115 if (pass_next)
1116 {
1117 pass_next = 0;
1118 ADVANCE_CHAR (string, slen, i);
1119 continue;
1120 }
1121 if (allowesc && string[i] == '\\')
1122 pass_next++;
1123 else if (string[i] == '\'')
1124 break;
1125 ADVANCE_CHAR (string, slen, i);
1126 }
1127
1128 t = substring (string, *sindex, i);
1129
1130 if (string[i])
1131 i++;
1132 *sindex = i;
1133
1134 return (t);
1135 }
1136
1137 /* Skip over a single-quoted string. We overload the SX_COMPLETE flag to mean
1138 that we are splitting out words for completion and have encountered a $'...'
1139 string, which allows backslash-escaped single quotes. */
1140 static inline int
1141 skip_single_quoted (string, slen, sind, flags)
1142 const char *string;
1143 size_t slen;
1144 int sind;
1145 int flags;
1146 {
1147 register int c;
1148 DECLARE_MBSTATE;
1149
1150 c = sind;
1151 while (string[c] && string[c] != '\'')
1152 {
1153 if ((flags & SX_COMPLETE) && string[c] == '\\' && string[c+1] == '\'' && string[c+2])
1154 ADVANCE_CHAR (string, slen, c);
1155 ADVANCE_CHAR (string, slen, c);
1156 }
1157
1158 if (string[c])
1159 c++;
1160 return c;
1161 }
1162
1163 /* Just like string_extract, but doesn't hack backslashes or any of
1164 that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */
1165 static char *
1166 string_extract_verbatim (string, slen, sindex, charlist, flags)
1167 char *string;
1168 size_t slen;
1169 int *sindex;
1170 char *charlist;
1171 int flags;
1172 {
1173 register int i;
1174 #if defined (HANDLE_MULTIBYTE)
1175 wchar_t *wcharlist;
1176 #endif
1177 int c;
1178 char *temp;
1179 DECLARE_MBSTATE;
1180
1181 if ((flags & SX_NOCTLESC) && charlist[0] == '\'' && charlist[1] == '\0')
1182 {
1183 temp = string_extract_single_quoted (string, sindex, 0);
1184 --*sindex; /* leave *sindex at separator character */
1185 return temp;
1186 }
1187
1188 /* This can never be called with charlist == NULL. If *charlist == NULL,
1189 we can skip the loop and just return a copy of the string, updating
1190 *sindex */
1191 if (*charlist == 0)
1192 {
1193 temp = string + *sindex;
1194 c = (*sindex == 0) ? slen : STRLEN (temp);
1195 temp = savestring (temp);
1196 *sindex += c;
1197 return temp;
1198 }
1199
1200 i = *sindex;
1201 #if defined (HANDLE_MULTIBYTE)
1202 wcharlist = 0;
1203 #endif
1204 while (c = string[i])
1205 {
1206 #if defined (HANDLE_MULTIBYTE)
1207 size_t mblength;
1208 #endif
1209 if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
1210 {
1211 i += 2;
1212 CHECK_STRING_OVERRUN (i, i, slen, c);
1213 continue;
1214 }
1215 /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
1216 through, to protect the CTLNULs from later calls to
1217 remove_quoted_nulls. */
1218 else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
1219 {
1220 i += 2;
1221 CHECK_STRING_OVERRUN (i, i, slen, c);
1222 continue;
1223 }
1224
1225 #if defined (HANDLE_MULTIBYTE)
1226 if (locale_utf8locale && slen > i && UTF8_SINGLEBYTE (string[i]))
1227 mblength = (string[i] != 0) ? 1 : 0;
1228 else
1229 mblength = MBLEN (string + i, slen - i);
1230 if (mblength > 1)
1231 {
1232 wchar_t wc;
1233 mblength = mbtowc (&wc, string + i, slen - i);
1234 if (MB_INVALIDCH (mblength))
1235 {
1236 if (MEMBER (c, charlist))
1237 break;
1238 }
1239 else
1240 {
1241 if (wcharlist == 0)
1242 {
1243 size_t len;
1244 len = mbstowcs (wcharlist, charlist, 0);
1245 if (len == -1)
1246 len = 0;
1247 wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
1248 mbstowcs (wcharlist, charlist, len + 1);
1249 }
1250
1251 if (wcschr (wcharlist, wc))
1252 break;
1253 }
1254 }
1255 else
1256 #endif
1257 if (MEMBER (c, charlist))
1258 break;
1259
1260 ADVANCE_CHAR (string, slen, i);
1261 }
1262
1263 #if defined (HANDLE_MULTIBYTE)
1264 FREE (wcharlist);
1265 #endif
1266
1267 temp = substring (string, *sindex, i);
1268 *sindex = i;
1269
1270 return (temp);
1271 }
1272
1273 /* Extract the $( construct in STRING, and return a new string.
1274 Start extracting at (SINDEX) as if we had just seen "$(".
1275 Make (SINDEX) get the position of the matching ")". )
1276 XFLAGS is additional flags to pass to other extraction functions. */
1277 char *
1278 extract_command_subst (string, sindex, xflags)
1279 char *string;
1280 int *sindex;
1281 int xflags;
1282 {
1283 char *ret;
1284
1285 if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE))
1286 return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
1287 else
1288 {
1289 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1290 ret = xparse_dolparen (string, string+*sindex, sindex, xflags);
1291 return ret;
1292 }
1293 }
1294
1295 /* Extract the $[ construct in STRING, and return a new string. (])
1296 Start extracting at (SINDEX) as if we had just seen "$[".
1297 Make (SINDEX) get the position of the matching "]". */
1298 char *
1299 extract_arithmetic_subst (string, sindex)
1300 char *string;
1301 int *sindex;
1302 {
1303 return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/
1304 }
1305
1306 #if defined (PROCESS_SUBSTITUTION)
1307 /* Extract the <( or >( construct in STRING, and return a new string.
1308 Start extracting at (SINDEX) as if we had just seen "<(".
1309 Make (SINDEX) get the position of the matching ")". */ /*))*/
1310 char *
1311 extract_process_subst (string, starter, sindex, xflags)
1312 char *string;
1313 char *starter;
1314 int *sindex;
1315 int xflags;
1316 {
1317 #if 0
1318 /* XXX - check xflags&SX_COMPLETE here? */
1319 return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND));
1320 #else
1321 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1322 return (xparse_dolparen (string, string+*sindex, sindex, xflags));
1323 #endif
1324 }
1325 #endif /* PROCESS_SUBSTITUTION */
1326
1327 #if defined (ARRAY_VARS)
1328 /* This can be fooled by unquoted right parens in the passed string. If
1329 each caller verifies that the last character in STRING is a right paren,
1330 we don't even need to call extract_delimited_string. */
1331 char *
1332 extract_array_assignment_list (string, sindex)
1333 char *string;
1334 int *sindex;
1335 {
1336 int slen;
1337 char *ret;
1338
1339 slen = strlen (string);
1340 if (string[slen - 1] == RPAREN)
1341 {
1342 ret = substring (string, *sindex, slen - 1);
1343 *sindex = slen - 1;
1344 return ret;
1345 }
1346 return 0;
1347 }
1348 #endif
1349
1350 /* Extract and create a new string from the contents of STRING, a
1351 character string delimited with OPENER and CLOSER. SINDEX is
1352 the address of an int describing the current offset in STRING;
1353 it should point to just after the first OPENER found. On exit,
1354 SINDEX gets the position of the last character of the matching CLOSER.
1355 If OPENER is more than a single character, ALT_OPENER, if non-null,
1356 contains a character string that can also match CLOSER and thus
1357 needs to be skipped. */
1358 static char *
1359 extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
1360 char *string;
1361 int *sindex;
1362 char *opener, *alt_opener, *closer;
1363 int flags;
1364 {
1365 int i, c, si;
1366 size_t slen;
1367 char *t, *result;
1368 int pass_character, nesting_level, in_comment;
1369 int len_closer, len_opener, len_alt_opener;
1370 DECLARE_MBSTATE;
1371
1372 slen = strlen (string + *sindex) + *sindex;
1373 len_opener = STRLEN (opener);
1374 len_alt_opener = STRLEN (alt_opener);
1375 len_closer = STRLEN (closer);
1376
1377 pass_character = in_comment = 0;
1378
1379 nesting_level = 1;
1380 i = *sindex;
1381
1382 while (nesting_level)
1383 {
1384 c = string[i];
1385
1386 /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond
1387 the end of the string, catch it and cut the loop. */
1388 if (i > slen)
1389 {
1390 i = slen;
1391 c = string[i = slen];
1392 break;
1393 }
1394
1395 if (c == 0)
1396 break;
1397
1398 if (in_comment)
1399 {
1400 if (c == '\n')
1401 in_comment = 0;
1402 ADVANCE_CHAR (string, slen, i);
1403 continue;
1404 }
1405
1406 if (pass_character) /* previous char was backslash */
1407 {
1408 pass_character = 0;
1409 ADVANCE_CHAR (string, slen, i);
1410 continue;
1411 }
1412
1413 /* Not exactly right yet; should handle shell metacharacters and
1414 multibyte characters, too. See COMMENT_BEGIN define in parse.y */
1415 if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
1416 {
1417 in_comment = 1;
1418 ADVANCE_CHAR (string, slen, i);
1419 continue;
1420 }
1421
1422 if (c == CTLESC || c == '\\')
1423 {
1424 pass_character++;
1425 i++;
1426 continue;
1427 }
1428
1429 /* Process a nested command substitution, but only if we're parsing an
1430 arithmetic substitution. */
1431 if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
1432 {
1433 si = i + 2;
1434 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1435 CHECK_STRING_OVERRUN (i, si, slen, c);
1436 i = si + 1;
1437 continue;
1438 }
1439
1440 /* Process a nested OPENER. */
1441 if (STREQN (string + i, opener, len_opener))
1442 {
1443 si = i + len_opener;
1444 t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
1445 CHECK_STRING_OVERRUN (i, si, slen, c);
1446 i = si + 1;
1447 continue;
1448 }
1449
1450 /* Process a nested ALT_OPENER */
1451 if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
1452 {
1453 si = i + len_alt_opener;
1454 t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
1455 CHECK_STRING_OVERRUN (i, si, slen, c);
1456 i = si + 1;
1457 continue;
1458 }
1459
1460 /* If the current substring terminates the delimited string, decrement
1461 the nesting level. */
1462 if (STREQN (string + i, closer, len_closer))
1463 {
1464 i += len_closer - 1; /* move to last byte of the closer */
1465 nesting_level--;
1466 if (nesting_level == 0)
1467 break;
1468 }
1469
1470 /* Pass old-style command substitution through verbatim. */
1471 if (c == '`')
1472 {
1473 si = i + 1;
1474 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1475 CHECK_STRING_OVERRUN (i, si, slen, c);
1476 i = si + 1;
1477 continue;
1478 }
1479
1480 /* Pass single-quoted and double-quoted strings through verbatim. */
1481 if (c == '\'' || c == '"')
1482 {
1483 si = i + 1;
1484 i = (c == '\'') ? skip_single_quoted (string, slen, si, 0)
1485 : skip_double_quoted (string, slen, si, 0);
1486 continue;
1487 }
1488
1489 /* move past this character, which was not special. */
1490 ADVANCE_CHAR (string, slen, i);
1491 }
1492
1493 if (c == 0 && nesting_level)
1494 {
1495 if (no_longjmp_on_fatal_error == 0)
1496 {
1497 last_command_exit_value = EXECUTION_FAILURE;
1498 report_error (_("bad substitution: no closing `%s' in %s"), closer, string);
1499 exp_jump_to_top_level (DISCARD);
1500 }
1501 else
1502 {
1503 *sindex = i;
1504 return (char *)NULL;
1505 }
1506 }
1507
1508 si = i - *sindex - len_closer + 1;
1509 if (flags & SX_NOALLOC)
1510 result = (char *)NULL;
1511 else
1512 {
1513 result = (char *)xmalloc (1 + si);
1514 strncpy (result, string + *sindex, si);
1515 result[si] = '\0';
1516 }
1517 *sindex = i;
1518
1519 return (result);
1520 }
1521
1522 /* A simplified version of extract_dollar_brace_string that exists to handle
1523 $'...' and $"..." quoting in here-documents, since the here-document read
1524 path doesn't. It's separate because we don't want to mess with the fast
1525 common path. We already know we're going to allocate and return a new
1526 string and quoted == Q_HERE_DOCUMENT. We might be able to cut it down
1527 some more, but extracting strings and adding them as we go adds complexity.
1528 This needs to match the logic in parse.y:parse_matched_pair so we get
1529 consistent behavior between here-documents and double-quoted strings. */
1530 static char *
1531 extract_heredoc_dolbrace_string (string, sindex, quoted, flags)
1532 char *string;
1533 int *sindex, quoted, flags;
1534 {
1535 register int i, c;
1536 size_t slen, tlen, result_index, result_size;
1537 int pass_character, nesting_level, si, dolbrace_state;
1538 char *result, *t, *send;
1539 DECLARE_MBSTATE;
1540
1541 pass_character = 0;
1542 nesting_level = 1;
1543 slen = strlen (string + *sindex) + *sindex;
1544 send = string + slen;
1545
1546 result_size = slen;
1547 result_index = 0;
1548 result = xmalloc (result_size + 1);
1549
1550 /* This function isn't called if this condition is not true initially. */
1551 dolbrace_state = DOLBRACE_QUOTE;
1552
1553 i = *sindex;
1554 while (c = string[i])
1555 {
1556 if (pass_character)
1557 {
1558 pass_character = 0;
1559 RESIZE_MALLOCED_BUFFER (result, result_index, locale_mb_cur_max + 1, result_size, 64);
1560 COPY_CHAR_I (result, result_index, string, send, i);
1561 continue;
1562 }
1563
1564 /* CTLESCs and backslashes quote the next character. */
1565 if (c == CTLESC || c == '\\')
1566 {
1567 pass_character++;
1568 RESIZE_MALLOCED_BUFFER (result, result_index, 2, result_size, 64);
1569 result[result_index++] = c;
1570 i++;
1571 continue;
1572 }
1573
1574 /* The entire reason we have this separate function right here. */
1575 if (c == '$' && string[i+1] == '\'')
1576 {
1577 char *ttrans;
1578 int ttranslen;
1579
1580 if ((posixly_correct || extended_quote == 0) && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2)
1581 {
1582 RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, 64);
1583 result[result_index++] = '$';
1584 result[result_index++] = '\'';
1585 i += 2;
1586 continue;
1587 }
1588
1589 si = i + 2;
1590 t = string_extract_single_quoted (string, &si, 1); /* XXX */
1591 CHECK_STRING_OVERRUN (i, si, slen, c);
1592
1593 tlen = si - i - 2; /* -2 since si is one after the close quote */
1594 ttrans = ansiexpand (t, 0, tlen, &ttranslen);
1595 free (t);
1596
1597 /* needed to correctly quote any embedded single quotes. */
1598 if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2)
1599 {
1600 t = sh_single_quote (ttrans);
1601 tlen = strlen (t);
1602 free (ttrans);
1603 }
1604 else if (extended_quote) /* dolbrace_state == DOLBRACE_PARAM */
1605 {
1606 /* This matches what parse.y:parse_matched_pair() does */
1607 t = ttrans;
1608 tlen = strlen (t);
1609 }
1610
1611 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 1, result_size, 64);
1612 strncpy (result + result_index, t, tlen);
1613 result_index += tlen;
1614 free (t);
1615 i = si;
1616 continue;
1617 }
1618
1619 #if defined (TRANSLATABLE_STRINGS)
1620 if (c == '$' && string[i+1] == '"')
1621 {
1622 char *ttrans;
1623 int ttranslen;
1624
1625 si = i + 2;
1626 t = string_extract_double_quoted (string, &si, flags); /* XXX */
1627 CHECK_STRING_OVERRUN (i, si, slen, c);
1628
1629 tlen = si - i - 2; /* -2 since si is one after the close quote */
1630 ttrans = locale_expand (t, 0, tlen, line_number, &ttranslen);
1631 free (t);
1632
1633 t = singlequote_translations ? sh_single_quote (ttrans) : sh_mkdoublequoted (ttrans, ttranslen, 0);
1634 tlen = strlen (t);
1635 free (ttrans);
1636
1637 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 1, result_size, 64);
1638 strncpy (result + result_index, t, tlen);
1639 result_index += tlen;
1640 free (t);
1641 i = si;
1642 continue;
1643 }
1644 #endif /* TRANSLATABLE_STRINGS */
1645
1646 if (c == '$' && string[i+1] == LBRACE)
1647 {
1648 nesting_level++;
1649 RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, 64);
1650 result[result_index++] = c;
1651 result[result_index++] = string[i+1];
1652 i += 2;
1653 if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2 || dolbrace_state == DOLBRACE_WORD)
1654 dolbrace_state = DOLBRACE_PARAM;
1655 continue;
1656 }
1657
1658 if (c == RBRACE)
1659 {
1660 nesting_level--;
1661 if (nesting_level == 0)
1662 break;
1663 RESIZE_MALLOCED_BUFFER (result, result_index, 2, result_size, 64);
1664 result[result_index++] = c;
1665 i++;
1666 continue;
1667 }
1668
1669 /* Pass the contents of old-style command substitutions through
1670 verbatim. */
1671 if (c == '`')
1672 {
1673 si = i + 1;
1674 t = string_extract (string, &si, "`", flags); /* already know (flags & SX_NOALLOC) == 0) */
1675 CHECK_STRING_OVERRUN (i, si, slen, c);
1676
1677 tlen = si - i - 1;
1678 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 3, result_size, 64);
1679 result[result_index++] = c;
1680 strncpy (result + result_index, t, tlen);
1681 result_index += tlen;
1682 result[result_index++] = string[si];
1683 free (t);
1684 i = si + 1;
1685 continue;
1686 }
1687
1688 /* Pass the contents of new-style command substitutions and
1689 arithmetic substitutions through verbatim. */
1690 if (string[i] == '$' && string[i+1] == LPAREN)
1691 {
1692 si = i + 2;
1693 t = extract_command_subst (string, &si, flags);
1694 CHECK_STRING_OVERRUN (i, si, slen, c);
1695
1696 tlen = si - i - 1;
1697 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 4, result_size, 64);
1698 result[result_index++] = c;
1699 result[result_index++] = LPAREN;
1700 strncpy (result + result_index, t, tlen);
1701 result_index += tlen;
1702 result[result_index++] = string[si];
1703 free (t);
1704 i = si + 1;
1705 continue;
1706 }
1707
1708 #if defined (PROCESS_SUBSTITUTION)
1709 /* Technically this should only work at the start of a word */
1710 if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN)
1711 {
1712 si = i + 2;
1713 t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags);
1714 CHECK_STRING_OVERRUN (i, si, slen, c);
1715
1716 tlen = si - i - 1;
1717 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 4, result_size, 64);
1718 result[result_index++] = c;
1719 result[result_index++] = LPAREN;
1720 strncpy (result + result_index, t, tlen);
1721 result_index += tlen;
1722 result[result_index++] = string[si];
1723 free (t);
1724 i = si + 1;
1725 continue;
1726 }
1727 #endif
1728
1729 if (c == '\'' && posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE)
1730 {
1731 COPY_CHAR_I (result, result_index, string, send, i);
1732 continue;
1733 }
1734
1735 /* Pass the contents of single and double-quoted strings through verbatim. */
1736 if (c == '"' || c == '\'')
1737 {
1738 si = i + 1;
1739 if (c == '"')
1740 t = string_extract_double_quoted (string, &si, flags);
1741 else
1742 t = string_extract_single_quoted (string, &si, 0);
1743 CHECK_STRING_OVERRUN (i, si, slen, c);
1744
1745 tlen = si - i - 2; /* -2 since si is one after the close quote */
1746 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 3, result_size, 64);
1747 result[result_index++] = c;
1748 strncpy (result + result_index, t, tlen);
1749 result_index += tlen;
1750 result[result_index++] = string[si - 1];
1751 free (t);
1752 i = si;
1753 continue;
1754 }
1755
1756 /* copy this character, which was not special. */
1757 COPY_CHAR_I (result, result_index, string, send, i);
1758
1759 /* This logic must agree with parse.y:parse_matched_pair, since they
1760 share the same defines. */
1761 if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
1762 dolbrace_state = DOLBRACE_QUOTE;
1763 else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
1764 dolbrace_state = DOLBRACE_QUOTE;
1765 else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
1766 dolbrace_state = DOLBRACE_QUOTE2; /* XXX */
1767 else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
1768 dolbrace_state = DOLBRACE_QUOTE;
1769 else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
1770 dolbrace_state = DOLBRACE_QUOTE;
1771 /* This is intended to handle all of the [:]op expansions and the substring/
1772 length/pattern removal/pattern substitution expansions. */
1773 else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
1774 dolbrace_state = DOLBRACE_OP;
1775 else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
1776 dolbrace_state = DOLBRACE_WORD;
1777 }
1778
1779 if (c == 0 && nesting_level)
1780 {
1781 free (result);
1782 if (no_longjmp_on_fatal_error == 0)
1783 { /* { */
1784 last_command_exit_value = EXECUTION_FAILURE;
1785 report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
1786 exp_jump_to_top_level (DISCARD);
1787 }
1788 else
1789 {
1790 *sindex = i;
1791 return ((char *)NULL);
1792 }
1793 }
1794
1795 *sindex = i;
1796 result[result_index] = '\0';
1797
1798 return (result);
1799 }
1800
1801 #define PARAMEXPNEST_MAX 32 // for now
1802 static int dbstate[PARAMEXPNEST_MAX];
1803
1804 /* Extract a parameter expansion expression within ${ and } from STRING.
1805 Obey the Posix.2 rules for finding the ending `}': count braces while
1806 skipping over enclosed quoted strings and command substitutions.
1807 SINDEX is the address of an int describing the current offset in STRING;
1808 it should point to just after the first `{' found. On exit, SINDEX
1809 gets the position of the matching `}'. QUOTED is non-zero if this
1810 occurs inside double quotes. */
1811 /* XXX -- this is very similar to extract_delimited_string -- XXX */
1812 static char *
1813 extract_dollar_brace_string (string, sindex, quoted, flags)
1814 char *string;
1815 int *sindex, quoted, flags;
1816 {
1817 register int i, c;
1818 size_t slen;
1819 int pass_character, nesting_level, si, dolbrace_state;
1820 char *result, *t;
1821 DECLARE_MBSTATE;
1822
1823 /* The handling of dolbrace_state needs to agree with the code in parse.y:
1824 parse_matched_pair(). The different initial value is to handle the
1825 case where this function is called to parse the word in
1826 ${param op word} (SX_WORD). */
1827 dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM;
1828 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP))
1829 dolbrace_state = DOLBRACE_QUOTE;
1830
1831 if (quoted == Q_HERE_DOCUMENT && dolbrace_state == DOLBRACE_QUOTE && (flags & SX_NOALLOC) == 0)
1832 return (extract_heredoc_dolbrace_string (string, sindex, quoted, flags));
1833
1834 dbstate[0] = dolbrace_state;
1835
1836 pass_character = 0;
1837 nesting_level = 1;
1838 slen = strlen (string + *sindex) + *sindex;
1839
1840 i = *sindex;
1841 while (c = string[i])
1842 {
1843 if (pass_character)
1844 {
1845 pass_character = 0;
1846 ADVANCE_CHAR (string, slen, i);
1847 continue;
1848 }
1849
1850 /* CTLESCs and backslashes quote the next character. */
1851 if (c == CTLESC || c == '\\')
1852 {
1853 pass_character++;
1854 i++;
1855 continue;
1856 }
1857
1858 if (string[i] == '$' && string[i+1] == LBRACE)
1859 {
1860 if (nesting_level < PARAMEXPNEST_MAX)
1861 dbstate[nesting_level] = dolbrace_state;
1862 nesting_level++;
1863 i += 2;
1864 if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_WORD)
1865 dolbrace_state = DOLBRACE_PARAM;
1866 continue;
1867 }
1868
1869 if (c == RBRACE)
1870 {
1871 nesting_level--;
1872 if (nesting_level == 0)
1873 break;
1874 dolbrace_state = (nesting_level < PARAMEXPNEST_MAX) ? dbstate[nesting_level] : dbstate[0]; /* Guess using initial state */
1875 i++;
1876 continue;
1877 }
1878
1879 /* Pass the contents of old-style command substitutions through
1880 verbatim. */
1881 if (c == '`')
1882 {
1883 si = i + 1;
1884 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1885
1886 CHECK_STRING_OVERRUN (i, si, slen, c);
1887
1888 i = si + 1;
1889 continue;
1890 }
1891
1892 /* Pass the contents of new-style command substitutions and
1893 arithmetic substitutions through verbatim. */
1894 if (string[i] == '$' && string[i+1] == LPAREN)
1895 {
1896 si = i + 2;
1897 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1898
1899 CHECK_STRING_OVERRUN (i, si, slen, c);
1900
1901 i = si + 1;
1902 continue;
1903 }
1904
1905 #if defined (PROCESS_SUBSTITUTION)
1906 /* Technically this should only work at the start of a word */
1907 if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN)
1908 {
1909 si = i + 2;
1910 t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags|SX_NOALLOC);
1911
1912 CHECK_STRING_OVERRUN (i, si, slen, c);
1913
1914 i = si + 1;
1915 continue;
1916 }
1917 #endif
1918
1919 /* Pass the contents of double-quoted strings through verbatim. */
1920 if (c == '"')
1921 {
1922 si = i + 1;
1923 i = skip_double_quoted (string, slen, si, 0);
1924 /* skip_XXX_quoted leaves index one past close quote */
1925 continue;
1926 }
1927
1928 if (c == '\'')
1929 {
1930 /*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
1931 if (posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1932 ADVANCE_CHAR (string, slen, i);
1933 else
1934 {
1935 si = i + 1;
1936 i = skip_single_quoted (string, slen, si, 0);
1937 }
1938
1939 continue;
1940 }
1941
1942 #if defined (ARRAY_VARS)
1943 if (c == LBRACK && dolbrace_state == DOLBRACE_PARAM)
1944 {
1945 si = skipsubscript (string, i, 0);
1946 CHECK_STRING_OVERRUN (i, si, slen, c);
1947 if (string[si] == RBRACK)
1948 c = string[i = si];
1949 }
1950 #endif
1951
1952 /* move past this character, which was not special. */
1953 ADVANCE_CHAR (string, slen, i);
1954
1955 /* This logic must agree with parse.y:parse_matched_pair, since they
1956 share the same defines. */
1957 if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
1958 dolbrace_state = DOLBRACE_QUOTE;
1959 else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
1960 dolbrace_state = DOLBRACE_QUOTE;
1961 else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
1962 dolbrace_state = DOLBRACE_QUOTE2; /* XXX */
1963 else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
1964 dolbrace_state = DOLBRACE_QUOTE;
1965 else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
1966 dolbrace_state = DOLBRACE_QUOTE;
1967 /* This is intended to handle all of the [:]op expansions and the substring/
1968 length/pattern removal/pattern substitution expansions. */
1969 else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
1970 dolbrace_state = DOLBRACE_OP;
1971 else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
1972 dolbrace_state = DOLBRACE_WORD;
1973 }
1974
1975 if (c == 0 && nesting_level)
1976 {
1977 if (no_longjmp_on_fatal_error == 0)
1978 { /* { */
1979 last_command_exit_value = EXECUTION_FAILURE;
1980 report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
1981 exp_jump_to_top_level (DISCARD);
1982 }
1983 else
1984 {
1985 *sindex = i;
1986 return ((char *)NULL);
1987 }
1988 }
1989
1990 result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
1991 *sindex = i;
1992
1993 return (result);
1994 }
1995
1996 /* Remove backslashes which are quoting backquotes from STRING. Modifies
1997 STRING, and returns a pointer to it. */
1998 char *
1999 de_backslash (string)
2000 char *string;
2001 {
2002 register size_t slen;
2003 register int i, j, prev_i;
2004 DECLARE_MBSTATE;
2005
2006 slen = strlen (string);
2007 i = j = 0;
2008
2009 /* Loop copying string[i] to string[j], i >= j. */
2010 while (i < slen)
2011 {
2012 if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
2013 string[i + 1] == '$'))
2014 i++;
2015 prev_i = i;
2016 ADVANCE_CHAR (string, slen, i);
2017 if (j < prev_i)
2018 do string[j++] = string[prev_i++]; while (prev_i < i);
2019 else
2020 j = i;
2021 }
2022 string[j] = '\0';
2023
2024 return (string);
2025 }
2026
2027 #if 0
2028 /*UNUSED*/
2029 /* Replace instances of \! in a string with !. */
2030 void
2031 unquote_bang (string)
2032 char *string;
2033 {
2034 register int i, j;
2035 register char *temp;
2036
2037 temp = (char *)xmalloc (1 + strlen (string));
2038
2039 for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
2040 {
2041 if (string[i] == '\\' && string[i + 1] == '!')
2042 {
2043 temp[j] = '!';
2044 i++;
2045 }
2046 }
2047 strcpy (string, temp);
2048 free (temp);
2049 }
2050 #endif
2051
2052 #define CQ_RETURN(x) do { no_longjmp_on_fatal_error = oldjmp; return (x); } while (0)
2053
2054 /* When FLAGS & 2 == 0, this function assumes STRING[I] == OPEN; when
2055 FLAGS & 2 != 0, it assumes STRING[I] points to one character past OPEN;
2056 returns with STRING[RET] == close; used to parse array subscripts.
2057 FLAGS & 1 means not to attempt to skip over matched pairs of quotes or
2058 backquotes, or skip word expansions; it is intended to be used after
2059 expansion has been performed and during final assignment parsing (see
2060 arrayfunc.c:assign_compound_array_list()) or during execution by a builtin
2061 which has already undergone word expansion. */
2062 static int
2063 skip_matched_pair (string, start, open, close, flags)
2064 const char *string;
2065 int start, open, close, flags;
2066 {
2067 int i, pass_next, backq, si, c, count, oldjmp;
2068 size_t slen;
2069 char *temp, *ss;
2070 DECLARE_MBSTATE;
2071
2072 slen = strlen (string + start) + start;
2073 oldjmp = no_longjmp_on_fatal_error;
2074 no_longjmp_on_fatal_error = 1;
2075
2076 /* Move to the first character after a leading OPEN. If FLAGS&2, we assume
2077 that START already points to that character. If not, we need to skip over
2078 it here. */
2079 i = (flags & 2) ? start : start + 1;
2080 count = 1;
2081 pass_next = backq = 0;
2082 ss = (char *)string;
2083 while (c = string[i])
2084 {
2085 if (pass_next)
2086 {
2087 pass_next = 0;
2088 if (c == 0)
2089 CQ_RETURN(i);
2090 ADVANCE_CHAR (string, slen, i);
2091 continue;
2092 }
2093 else if ((flags & 1) == 0 && c == '\\')
2094 {
2095 pass_next = 1;
2096 i++;
2097 continue;
2098 }
2099 else if (backq)
2100 {
2101 if (c == '`')
2102 backq = 0;
2103 ADVANCE_CHAR (string, slen, i);
2104 continue;
2105 }
2106 else if ((flags & 1) == 0 && c == '`')
2107 {
2108 backq = 1;
2109 i++;
2110 continue;
2111 }
2112 else if ((flags & 1) == 0 && c == open)
2113 {
2114 count++;
2115 i++;
2116 continue;
2117 }
2118 else if (c == close)
2119 {
2120 count--;
2121 if (count == 0)
2122 break;
2123 i++;
2124 continue;
2125 }
2126 else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
2127 {
2128 i = (c == '\'') ? skip_single_quoted (ss, slen, ++i, 0)
2129 : skip_double_quoted (ss, slen, ++i, 0);
2130 /* no increment, the skip functions increment past the closing quote. */
2131 }
2132 else if ((flags & 1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
2133 {
2134 si = i + 2;
2135 if (string[si] == '\0')
2136 CQ_RETURN(si);
2137
2138 /* XXX - extract_command_subst here? */
2139 if (string[i+1] == LPAREN)
2140 temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
2141 else
2142 temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
2143
2144 CHECK_STRING_OVERRUN (i, si, slen, c);
2145
2146 i = si;
2147 if (string[i] == '\0') /* don't increment i past EOS in loop */
2148 break;
2149 i++;
2150 continue;
2151 }
2152 else
2153 ADVANCE_CHAR (string, slen, i);
2154 }
2155
2156 CQ_RETURN(i);
2157 }
2158
2159 #if defined (ARRAY_VARS)
2160 /* FLAGS has 1 as a reserved value, since skip_matched_pair uses it for
2161 skipping over quoted strings and taking the first instance of the
2162 closing character. FLAGS & 2 means that STRING[START] points one
2163 character past the open bracket; FLAGS & 2 == 0 means that STRING[START]
2164 points to the open bracket. skip_matched_pair knows how to deal with this. */
2165 int
2166 skipsubscript (string, start, flags)
2167 const char *string;
2168 int start, flags;
2169 {
2170 return (skip_matched_pair (string, start, '[', ']', flags));
2171 }
2172 #endif
2173
2174 /* Skip characters in STRING until we find a character in DELIMS, and return
2175 the index of that character. START is the index into string at which we
2176 begin. This is similar in spirit to strpbrk, but it returns an index into
2177 STRING and takes a starting index. This little piece of code knows quite
2178 a lot of shell syntax. It's very similar to skip_double_quoted and other
2179 functions of that ilk. */
2180 int
2181 skip_to_delim (string, start, delims, flags)
2182 char *string;
2183 int start;
2184 char *delims;
2185 int flags;
2186 {
2187 int i, pass_next, backq, dquote, si, c, oldjmp;
2188 int invert, skipquote, skipcmd, noprocsub, completeflag;
2189 int arithexp, skipcol;
2190 size_t slen;
2191 char *temp, open[3];
2192 DECLARE_MBSTATE;
2193
2194 slen = strlen (string + start) + start;
2195 oldjmp = no_longjmp_on_fatal_error;
2196 if (flags & SD_NOJMP)
2197 no_longjmp_on_fatal_error = 1;
2198 invert = (flags & SD_INVERT);
2199 skipcmd = (flags & SD_NOSKIPCMD) == 0;
2200 noprocsub = (flags & SD_NOPROCSUB);
2201 completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0;
2202
2203 arithexp = (flags & SD_ARITHEXP);
2204 skipcol = 0;
2205
2206 i = start;
2207 pass_next = backq = dquote = 0;
2208 while (c = string[i])
2209 {
2210 /* If this is non-zero, we should not let quote characters be delimiters
2211 and the current character is a single or double quote. We should not
2212 test whether or not it's a delimiter until after we skip single- or
2213 double-quoted strings. */
2214 skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
2215 if (pass_next)
2216 {
2217 pass_next = 0;
2218 if (c == 0)
2219 CQ_RETURN(i);
2220 ADVANCE_CHAR (string, slen, i);
2221 continue;
2222 }
2223 else if (c == '\\')
2224 {
2225 pass_next = 1;
2226 i++;
2227 continue;
2228 }
2229 else if (backq)
2230 {
2231 if (c == '`')
2232 backq = 0;
2233 ADVANCE_CHAR (string, slen, i);
2234 continue;
2235 }
2236 else if (c == '`')
2237 {
2238 backq = 1;
2239 i++;
2240 continue;
2241 }
2242 else if (arithexp && skipcol && c == ':')
2243 {
2244 skipcol--;
2245 i++;
2246 continue;
2247 }
2248 else if (arithexp && c == '?')
2249 {
2250 skipcol++;
2251 i++;
2252 continue;
2253 }
2254 else if (skipquote == 0 && invert == 0 && member (c, delims))
2255 break;
2256 /* the usual case is to use skip_xxx_quoted, but we don't skip over double
2257 quoted strings when looking for the history expansion character as a
2258 delimiter. */
2259 /* special case for programmable completion which takes place before
2260 parser converts backslash-escaped single quotes between $'...' to
2261 `regular' single-quoted strings. */
2262 else if (completeflag && i > 0 && string[i-1] == '$' && c == '\'')
2263 i = skip_single_quoted (string, slen, ++i, SX_COMPLETE);
2264 else if (c == '\'')
2265 i = skip_single_quoted (string, slen, ++i, 0);
2266 else if (c == '"')
2267 i = skip_double_quoted (string, slen, ++i, completeflag);
2268 else if (c == LPAREN && arithexp)
2269 {
2270 si = i + 1;
2271 if (string[si] == '\0')
2272 CQ_RETURN(si);
2273
2274 temp = extract_delimited_string (string, &si, "(", "(", ")", SX_NOALLOC); /* ) */
2275 i = si;
2276 if (string[i] == '\0') /* don't increment i past EOS in loop */
2277 break;
2278 i++;
2279 continue;
2280 }
2281 else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
2282 {
2283 si = i + 2;
2284 if (string[si] == '\0')
2285 CQ_RETURN(si);
2286
2287 if (string[i+1] == LPAREN)
2288 temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND|completeflag); /* ) */
2289 else
2290 temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
2291 CHECK_STRING_OVERRUN (i, si, slen, c);
2292 i = si;
2293 if (string[i] == '\0') /* don't increment i past EOS in loop */
2294 break;
2295 i++;
2296 continue;
2297 }
2298 #if defined (PROCESS_SUBSTITUTION)
2299 else if (skipcmd && noprocsub == 0 && (c == '<' || c == '>') && string[i+1] == LPAREN)
2300 {
2301 si = i + 2;
2302 if (string[si] == '\0')
2303 CQ_RETURN(si);
2304
2305 temp = extract_delimited_string (string, &si, (c == '<') ? "<(" : ">(", "(", ")", SX_COMMAND|SX_NOALLOC); /* )) */
2306 CHECK_STRING_OVERRUN (i, si, slen, c);
2307 i = si;
2308 if (string[i] == '\0')
2309 break;
2310 i++;
2311 continue;
2312 }
2313 #endif /* PROCESS_SUBSTITUTION */
2314 #if defined (EXTENDED_GLOB)
2315 else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@"))
2316 {
2317 si = i + 2;
2318 if (string[si] == '\0')
2319 CQ_RETURN(si);
2320
2321 open[0] = c;
2322 open[1] = LPAREN;
2323 open[2] = '\0';
2324 temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */
2325
2326 CHECK_STRING_OVERRUN (i, si, slen, c);
2327 i = si;
2328 if (string[i] == '\0') /* don't increment i past EOS in loop */
2329 break;
2330 i++;
2331 continue;
2332 }
2333 #endif
2334 else if ((flags & SD_GLOB) && c == LBRACK)
2335 {
2336 si = i + 1;
2337 if (string[si] == '\0')
2338 CQ_RETURN(si);
2339
2340 temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */
2341
2342 i = si;
2343 if (string[i] == '\0') /* don't increment i past EOS in loop */
2344 break;
2345 i++;
2346 continue;
2347 }
2348 else if ((skipquote || invert) && (member (c, delims) == 0))
2349 break;
2350 else
2351 ADVANCE_CHAR (string, slen, i);
2352 }
2353
2354 CQ_RETURN(i);
2355 }
2356
2357 #if defined (BANG_HISTORY)
2358 /* Skip to the history expansion character (delims[0]), paying attention to
2359 quoted strings and command and process substitution. This is a stripped-
2360 down version of skip_to_delims. The essential difference is that this
2361 resets the quoting state when starting a command substitution */
2362 int
2363 skip_to_histexp (string, start, delims, flags)
2364 char *string;
2365 int start;
2366 char *delims;
2367 int flags;
2368 {
2369 int i, pass_next, backq, dquote, c, oldjmp;
2370 int histexp_comsub, histexp_backq, old_dquote;
2371 size_t slen;
2372 DECLARE_MBSTATE;
2373
2374 slen = strlen (string + start) + start;
2375 oldjmp = no_longjmp_on_fatal_error;
2376 if (flags & SD_NOJMP)
2377 no_longjmp_on_fatal_error = 1;
2378
2379 histexp_comsub = histexp_backq = old_dquote = 0;
2380
2381 i = start;
2382 pass_next = backq = dquote = 0;
2383 while (c = string[i])
2384 {
2385 if (pass_next)
2386 {
2387 pass_next = 0;
2388 if (c == 0)
2389 CQ_RETURN(i);
2390 ADVANCE_CHAR (string, slen, i);
2391 continue;
2392 }
2393 else if (c == '\\')
2394 {
2395 pass_next = 1;
2396 i++;
2397 continue;
2398 }
2399 else if (backq && c == '`')
2400 {
2401 backq = 0;
2402 histexp_backq--;
2403 dquote = old_dquote;
2404 i++;
2405 continue;
2406 }
2407 else if (c == '`')
2408 {
2409 backq = 1;
2410 histexp_backq++;
2411 old_dquote = dquote; /* simple - one level for now */
2412 dquote = 0;
2413 i++;
2414 continue;
2415 }
2416 /* When in double quotes, act as if the double quote is a member of
2417 history_no_expand_chars, like the history library does */
2418 else if (dquote && c == delims[0] && string[i+1] == '"')
2419 {
2420 i++;
2421 continue;
2422 }
2423 else if (c == delims[0])
2424 break;
2425 /* the usual case is to use skip_xxx_quoted, but we don't skip over double
2426 quoted strings when looking for the history expansion character as a
2427 delimiter. */
2428 else if (dquote && c == '\'')
2429 {
2430 i++;
2431 continue;
2432 }
2433 else if (c == '\'')
2434 i = skip_single_quoted (string, slen, ++i, 0);
2435 /* The posixly_correct test makes posix-mode shells allow double quotes
2436 to quote the history expansion character */
2437 else if (posixly_correct == 0 && c == '"')
2438 {
2439 dquote = 1 - dquote;
2440 i++;
2441 continue;
2442 }
2443 else if (c == '"')
2444 i = skip_double_quoted (string, slen, ++i, 0);
2445 #if defined (PROCESS_SUBSTITUTION)
2446 else if ((c == '$' || c == '<' || c == '>') && string[i+1] == LPAREN && string[i+2] != LPAREN)
2447 #else
2448 else if (c == '$' && string[i+1] == LPAREN && string[i+2] != LPAREN)
2449 #endif
2450 {
2451 if (string[i+2] == '\0')
2452 CQ_RETURN(i+2);
2453 i += 2;
2454 histexp_comsub++;
2455 old_dquote = dquote;
2456 dquote = 0;
2457 }
2458 else if (histexp_comsub && c == RPAREN)
2459 {
2460 histexp_comsub--;
2461 dquote = old_dquote;
2462 i++;
2463 continue;
2464 }
2465 else if (backq) /* placeholder */
2466 {
2467 ADVANCE_CHAR (string, slen, i);
2468 continue;
2469 }
2470 else
2471 ADVANCE_CHAR (string, slen, i);
2472 }
2473
2474 CQ_RETURN(i);
2475 }
2476 #endif /* BANG_HISTORY */
2477
2478 #if defined (READLINE)
2479 /* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
2480 an unclosed quoted string), or if the character at EINDEX is quoted
2481 by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various
2482 single and double-quoted string parsing functions should not return an
2483 error if there are unclosed quotes or braces. The characters that this
2484 recognizes need to be the same as the contents of
2485 rl_completer_quote_characters. */
2486
2487 int
2488 char_is_quoted (string, eindex)
2489 char *string;
2490 int eindex;
2491 {
2492 int i, pass_next, c, oldjmp;
2493 size_t slen;
2494 DECLARE_MBSTATE;
2495
2496 slen = strlen (string);
2497 oldjmp = no_longjmp_on_fatal_error;
2498 no_longjmp_on_fatal_error = 1;
2499 i = pass_next = 0;
2500
2501 /* If we have an open quoted string from a previous line, see if it's
2502 closed before string[eindex], so we don't interpret that close quote
2503 as starting a new quoted string. */
2504 if (current_command_line_count > 0 && dstack.delimiter_depth > 0)
2505 {
2506 c = dstack.delimiters[dstack.delimiter_depth - 1];
2507 if (c == '\'')
2508 i = skip_single_quoted (string, slen, 0, 0);
2509 else if (c == '"')
2510 i = skip_double_quoted (string, slen, 0, SX_COMPLETE);
2511 if (i > eindex)
2512 CQ_RETURN (1);
2513 }
2514
2515 while (i <= eindex)
2516 {
2517 c = string[i];
2518
2519 if (pass_next)
2520 {
2521 pass_next = 0;
2522 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
2523 CQ_RETURN(1);
2524 ADVANCE_CHAR (string, slen, i);
2525 continue;
2526 }
2527 else if (c == '\\')
2528 {
2529 pass_next = 1;
2530 i++;
2531 continue;
2532 }
2533 else if (c == '$' && string[i+1] == '\'' && string[i+2])
2534 {
2535 i += 2;
2536 i = skip_single_quoted (string, slen, i, SX_COMPLETE);
2537 if (i > eindex)
2538 CQ_RETURN (i);
2539 }
2540 else if (c == '\'' || c == '"')
2541 {
2542 i = (c == '\'') ? skip_single_quoted (string, slen, ++i, 0)
2543 : skip_double_quoted (string, slen, ++i, SX_COMPLETE);
2544 if (i > eindex)
2545 CQ_RETURN(1);
2546 /* no increment, the skip_xxx functions go one past end */
2547 }
2548 else
2549 ADVANCE_CHAR (string, slen, i);
2550 }
2551
2552 CQ_RETURN(0);
2553 }
2554
2555 int
2556 unclosed_pair (string, eindex, openstr)
2557 char *string;
2558 int eindex;
2559 char *openstr;
2560 {
2561 int i, pass_next, openc, olen;
2562 size_t slen;
2563 DECLARE_MBSTATE;
2564
2565 slen = strlen (string);
2566 olen = strlen (openstr);
2567 i = pass_next = openc = 0;
2568 while (i <= eindex)
2569 {
2570 if (pass_next)
2571 {
2572 pass_next = 0;
2573 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
2574 return 0;
2575 ADVANCE_CHAR (string, slen, i);
2576 continue;
2577 }
2578 else if (string[i] == '\\')
2579 {
2580 pass_next = 1;
2581 i++;
2582 continue;
2583 }
2584 else if (STREQN (string + i, openstr, olen))
2585 {
2586 openc = 1 - openc;
2587 i += olen;
2588 }
2589 /* XXX - may want to handle $'...' specially here */
2590 else if (string[i] == '\'' || string[i] == '"')
2591 {
2592 i = (string[i] == '\'') ? skip_single_quoted (string, slen, i, 0)
2593 : skip_double_quoted (string, slen, i, SX_COMPLETE);
2594 if (i > eindex)
2595 return 0;
2596 }
2597 else
2598 ADVANCE_CHAR (string, slen, i);
2599 }
2600 return (openc);
2601 }
2602
2603 /* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
2604 individual words. If DELIMS is NULL, the current value of $IFS is used
2605 to split the string, and the function follows the shell field splitting
2606 rules. SENTINEL is an index to look for. NWP, if non-NULL,
2607 gets the number of words in the returned list. CWP, if non-NULL, gets
2608 the index of the word containing SENTINEL. Non-whitespace chars in
2609 DELIMS delimit separate fields. This is used by programmable completion. */
2610 WORD_LIST *
2611 split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
2612 char *string;
2613 int slen;
2614 const char *delims;
2615 int sentinel, flags;
2616 int *nwp, *cwp;
2617 {
2618 int ts, te, i, nw, cw, ifs_split, dflags;
2619 char *token, *d, *d2;
2620 WORD_LIST *ret, *tl;
2621
2622 if (string == 0 || *string == '\0')
2623 {
2624 if (nwp)
2625 *nwp = 0;
2626 if (cwp)
2627 *cwp = 0;
2628 return ((WORD_LIST *)NULL);
2629 }
2630
2631 d = (delims == 0) ? ifs_value : (char *)delims;
2632 ifs_split = delims == 0;
2633
2634 /* Make d2 the non-whitespace characters in delims */
2635 d2 = 0;
2636 if (delims)
2637 {
2638 size_t slength;
2639 #if defined (HANDLE_MULTIBYTE)
2640 size_t mblength = 1;
2641 #endif
2642 DECLARE_MBSTATE;
2643
2644 slength = strlen (delims);
2645 d2 = (char *)xmalloc (slength + 1);
2646 i = ts = 0;
2647 while (delims[i])
2648 {
2649 #if defined (HANDLE_MULTIBYTE)
2650 mbstate_t state_bak;
2651 state_bak = state;
2652 mblength = MBRLEN (delims + i, slength, &state);
2653 if (MB_INVALIDCH (mblength))
2654 state = state_bak;
2655 else if (mblength > 1)
2656 {
2657 memcpy (d2 + ts, delims + i, mblength);
2658 ts += mblength;
2659 i += mblength;
2660 slength -= mblength;
2661 continue;
2662 }
2663 #endif
2664 if (whitespace (delims[i]) == 0)
2665 d2[ts++] = delims[i];
2666
2667 i++;
2668 slength--;
2669 }
2670 d2[ts] = '\0';
2671 }
2672
2673 ret = (WORD_LIST *)NULL;
2674
2675 /* Remove sequences of whitespace characters at the start of the string, as
2676 long as those characters are delimiters. */
2677 for (i = 0; member (string[i], d) && spctabnl (string[i]); i++)
2678 ;
2679 if (string[i] == '\0')
2680 {
2681 FREE (d2);
2682 return (ret);
2683 }
2684
2685 ts = i;
2686 nw = 0;
2687 cw = -1;
2688 dflags = flags|SD_NOJMP;
2689 while (1)
2690 {
2691 te = skip_to_delim (string, ts, d, dflags);
2692
2693 /* If we have a non-whitespace delimiter character, use it to make a
2694 separate field. This is just about what $IFS splitting does and
2695 is closer to the behavior of the shell parser. */
2696 if (ts == te && d2 && member (string[ts], d2))
2697 {
2698 te = ts + 1;
2699 /* If we're using IFS splitting, the non-whitespace delimiter char
2700 and any additional IFS whitespace delimits a field. */
2701 if (ifs_split)
2702 while (member (string[te], d) && spctabnl (string[te]) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2703 te++;
2704 else
2705 while (member (string[te], d2) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2706 te++;
2707 }
2708
2709 token = substring (string, ts, te);
2710
2711 ret = add_string_to_list (token, ret); /* XXX */
2712 free (token);
2713 nw++;
2714
2715 if (sentinel >= ts && sentinel <= te)
2716 cw = nw;
2717
2718 /* If the cursor is at whitespace just before word start, set the
2719 sentinel word to the current word. */
2720 if (cwp && cw == -1 && sentinel == ts-1)
2721 cw = nw;
2722
2723 /* If the cursor is at whitespace between two words, make a new, empty
2724 word, add it before (well, after, since the list is in reverse order)
2725 the word we just added, and set the current word to that one. */
2726 if (cwp && cw == -1 && sentinel < ts)
2727 {
2728 tl = make_word_list (make_word (""), ret->next);
2729 ret->next = tl;
2730 cw = nw;
2731 nw++;
2732 }
2733
2734 if (string[te] == 0)
2735 break;
2736
2737 i = te;
2738 /* XXX - honor SD_NOQUOTEDELIM here */
2739 while (member (string[i], d) && (ifs_split || spctabnl(string[i])) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2740 i++;
2741
2742 if (string[i])
2743 ts = i;
2744 else
2745 break;
2746 }
2747
2748 /* Special case for SENTINEL at the end of STRING. If we haven't found
2749 the word containing SENTINEL yet, and the index we're looking for is at
2750 the end of STRING (or past the end of the previously-found token,
2751 possible if the end of the line is composed solely of IFS whitespace)
2752 add an additional null argument and set the current word pointer to that. */
2753 if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
2754 {
2755 if (whitespace (string[sentinel - 1]))
2756 {
2757 token = "";
2758 ret = add_string_to_list (token, ret);
2759 nw++;
2760 }
2761 cw = nw;
2762 }
2763
2764 if (nwp)
2765 *nwp = nw;
2766 if (cwp)
2767 *cwp = cw;
2768
2769 FREE (d2);
2770
2771 return (REVERSE_LIST (ret, WORD_LIST *));
2772 }
2773 #endif /* READLINE */
2774
2775 #if 0
2776 /* UNUSED */
2777 /* Extract the name of the variable to bind to from the assignment string. */
2778 char *
2779 assignment_name (string)
2780 char *string;
2781 {
2782 int offset;
2783 char *temp;
2784
2785 offset = assignment (string, 0);
2786 if (offset == 0)
2787 return (char *)NULL;
2788 temp = substring (string, 0, offset);
2789 return (temp);
2790 }
2791 #endif
2792
2793 /* **************************************************************** */
2794 /* */
2795 /* Functions to convert strings to WORD_LISTs and vice versa */
2796 /* */
2797 /* **************************************************************** */
2798
2799 /* Return a single string of all the words in LIST. SEP is the separator
2800 to put between individual elements of LIST in the output string. */
2801 char *
2802 string_list_internal (list, sep)
2803 WORD_LIST *list;
2804 char *sep;
2805 {
2806 register WORD_LIST *t;
2807 char *result, *r;
2808 size_t word_len, sep_len, result_size;
2809
2810 if (list == 0)
2811 return ((char *)NULL);
2812
2813 /* Short-circuit quickly if we don't need to separate anything. */
2814 if (list->next == 0)
2815 return (savestring (list->word->word));
2816
2817 /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
2818 sep_len = STRLEN (sep);
2819 result_size = 0;
2820
2821 for (t = list; t; t = t->next)
2822 {
2823 if (t != list)
2824 result_size += sep_len;
2825 result_size += strlen (t->word->word);
2826 }
2827
2828 r = result = (char *)xmalloc (result_size + 1);
2829
2830 for (t = list; t; t = t->next)
2831 {
2832 if (t != list && sep_len)
2833 {
2834 if (sep_len > 1)
2835 {
2836 FASTCOPY (sep, r, sep_len);
2837 r += sep_len;
2838 }
2839 else
2840 *r++ = sep[0];
2841 }
2842
2843 word_len = strlen (t->word->word);
2844 FASTCOPY (t->word->word, r, word_len);
2845 r += word_len;
2846 }
2847
2848 *r = '\0';
2849 return (result);
2850 }
2851
2852 /* Return a single string of all the words present in LIST, separating
2853 each word with a space. */
2854 char *
2855 string_list (list)
2856 WORD_LIST *list;
2857 {
2858 return (string_list_internal (list, " "));
2859 }
2860
2861 /* An external interface that can be used by the rest of the shell to
2862 obtain a string containing the first character in $IFS. Handles all
2863 the multibyte complications. If LENP is non-null, it is set to the
2864 length of the returned string. */
2865 char *
2866 ifs_firstchar (lenp)
2867 int *lenp;
2868 {
2869 char *ret;
2870 int len;
2871
2872 ret = xmalloc (MB_LEN_MAX + 1);
2873 #if defined (HANDLE_MULTIBYTE)
2874 if (ifs_firstc_len == 1)
2875 {
2876 ret[0] = ifs_firstc[0];
2877 ret[1] = '\0';
2878 len = ret[0] ? 1 : 0;
2879 }
2880 else
2881 {
2882 memcpy (ret, ifs_firstc, ifs_firstc_len);
2883 ret[len = ifs_firstc_len] = '\0';
2884 }
2885 #else
2886 ret[0] = ifs_firstc;
2887 ret[1] = '\0';
2888 len = ret[0] ? 0 : 1;
2889 #endif
2890
2891 if (lenp)
2892 *lenp = len;
2893
2894 return ret;
2895 }
2896
2897 /* Return a single string of all the words present in LIST, obeying the
2898 quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
2899 expansion [of $*] appears within a double quoted string, it expands
2900 to a single field with the value of each parameter separated by the
2901 first character of the IFS variable, or by a <space> if IFS is unset." */
2902 /* Posix interpretation 888 changes this when IFS is null by specifying
2903 that when unquoted, this expands to separate arguments */
2904 char *
2905 string_list_dollar_star (list, quoted, flags)
2906 WORD_LIST *list;
2907 int quoted, flags;
2908 {
2909 char *ret;
2910 #if defined (HANDLE_MULTIBYTE)
2911 # if defined (__GNUC__)
2912 char sep[MB_CUR_MAX + 1];
2913 # else
2914 char *sep = 0;
2915 # endif
2916 #else
2917 char sep[2];
2918 #endif
2919
2920 #if defined (HANDLE_MULTIBYTE)
2921 # if !defined (__GNUC__)
2922 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2923 # endif /* !__GNUC__ */
2924 if (ifs_firstc_len == 1)
2925 {
2926 sep[0] = ifs_firstc[0];
2927 sep[1] = '\0';
2928 }
2929 else
2930 {
2931 memcpy (sep, ifs_firstc, ifs_firstc_len);
2932 sep[ifs_firstc_len] = '\0';
2933 }
2934 #else
2935 sep[0] = ifs_firstc;
2936 sep[1] = '\0';
2937 #endif
2938
2939 ret = string_list_internal (list, sep);
2940 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2941 free (sep);
2942 #endif
2943 return ret;
2944 }
2945
2946 /* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
2947 is non-zero, the $@ appears within double quotes, and we should quote
2948 the list before converting it into a string. If IFS is unset, and the
2949 word is not quoted, we just need to quote CTLESC and CTLNUL characters
2950 in the words in the list, because the default value of $IFS is
2951 <space><tab><newline>, IFS characters in the words in the list should
2952 also be split. If IFS is null, and the word is not quoted, we need
2953 to quote the words in the list to preserve the positional parameters
2954 exactly.
2955 Valid values for the FLAGS argument are the PF_ flags in command.h,
2956 the only one we care about is PF_ASSIGNRHS. $@ is supposed to expand
2957 to the positional parameters separated by spaces no matter what IFS is
2958 set to if in a context where word splitting is not performed. The only
2959 one that we didn't handle before is assignment statement arguments to
2960 declaration builtins like `declare'. */
2961 char *
2962 string_list_dollar_at (list, quoted, flags)
2963 WORD_LIST *list;
2964 int quoted;
2965 int flags;
2966 {
2967 char *ifs, *ret;
2968 #if defined (HANDLE_MULTIBYTE)
2969 # if defined (__GNUC__)
2970 char sep[MB_CUR_MAX + 1];
2971 # else
2972 char *sep = 0;
2973 # endif /* !__GNUC__ */
2974 #else
2975 char sep[2];
2976 #endif
2977 WORD_LIST *tlist;
2978
2979 /* XXX this could just be ifs = ifs_value; */
2980 ifs = ifs_var ? value_cell (ifs_var) : (char *)0;
2981
2982 #if defined (HANDLE_MULTIBYTE)
2983 # if !defined (__GNUC__)
2984 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2985 # endif /* !__GNUC__ */
2986 /* XXX - testing PF_ASSIGNRHS to make sure positional parameters are
2987 separated with a space even when word splitting will not occur. */
2988 if (flags & PF_ASSIGNRHS)
2989 {
2990 sep[0] = ' ';
2991 sep[1] = '\0';
2992 }
2993 else if (ifs && *ifs)
2994 {
2995 if (ifs_firstc_len == 1)
2996 {
2997 sep[0] = ifs_firstc[0];
2998 sep[1] = '\0';
2999 }
3000 else
3001 {
3002 memcpy (sep, ifs_firstc, ifs_firstc_len);
3003 sep[ifs_firstc_len] = '\0';
3004 }
3005 }
3006 else
3007 {
3008 sep[0] = ' ';
3009 sep[1] = '\0';
3010 }
3011 #else /* !HANDLE_MULTIBYTE */
3012 /* XXX - PF_ASSIGNRHS means no word splitting, so we want positional
3013 parameters separated by a space. */
3014 sep[0] = ((flags & PF_ASSIGNRHS) || ifs == 0 || *ifs == 0) ? ' ' : *ifs;
3015 sep[1] = '\0';
3016 #endif /* !HANDLE_MULTIBYTE */
3017
3018 /* XXX -- why call quote_list if ifs == 0? we can get away without doing
3019 it now that quote_escapes quotes spaces */
3020 tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
3021 ? quote_list (list)
3022 : list_quote_escapes (list);
3023
3024 ret = string_list_internal (tlist, sep);
3025 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
3026 free (sep);
3027 #endif
3028 return ret;
3029 }
3030
3031 /* Turn the positional parameters into a string, understanding quoting and
3032 the various subtleties of using the first character of $IFS as the
3033 separator. Calls string_list_dollar_at, string_list_dollar_star, and
3034 string_list as appropriate. */
3035 /* This needs to fully understand the additional contexts where word
3036 splitting does not occur (W_ASSIGNRHS, etc.) */
3037 char *
3038 string_list_pos_params (pchar, list, quoted, pflags)
3039 int pchar;
3040 WORD_LIST *list;
3041 int quoted, pflags;
3042 {
3043 char *ret;
3044 WORD_LIST *tlist;
3045
3046 if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
3047 {
3048 tlist = quote_list (list);
3049 word_list_remove_quoted_nulls (tlist);
3050 ret = string_list_dollar_star (tlist, 0, 0);
3051 }
3052 else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
3053 {
3054 tlist = quote_list (list);
3055 word_list_remove_quoted_nulls (tlist);
3056 ret = string_list (tlist);
3057 }
3058 else if (pchar == '*' && quoted == 0 && ifs_is_null) /* XXX */
3059 ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
3060 else if (pchar == '*' && quoted == 0 && (pflags & PF_ASSIGNRHS)) /* XXX */
3061 ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
3062 else if (pchar == '*')
3063 {
3064 /* Even when unquoted, string_list_dollar_star does the right thing
3065 making sure that the first character of $IFS is used as the
3066 separator. */
3067 ret = string_list_dollar_star (list, quoted, 0);
3068 }
3069 else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
3070 /* We use string_list_dollar_at, but only if the string is quoted, since
3071 that quotes the escapes if it's not, which we don't want. We could
3072 use string_list (the old code did), but that doesn't do the right
3073 thing if the first character of $IFS is not a space. We use
3074 string_list_dollar_star if the string is unquoted so we make sure that
3075 the elements of $@ are separated by the first character of $IFS for
3076 later splitting. */
3077 ret = string_list_dollar_at (list, quoted, 0);
3078 else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */
3079 ret = string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
3080 else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS))
3081 ret = string_list_dollar_at (list, quoted, pflags); /* Posix interp 888 */
3082 else if (pchar == '@')
3083 ret = string_list_dollar_star (list, quoted, 0);
3084 else
3085 ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
3086
3087 return ret;
3088 }
3089
3090 /* Return the list of words present in STRING. Separate the string into
3091 words at any of the characters found in SEPARATORS. If QUOTED is
3092 non-zero then word in the list will have its quoted flag set, otherwise
3093 the quoted flag is left as make_word () deemed fit.
3094
3095 This obeys the P1003.2 word splitting semantics. If `separators' is
3096 exactly <space><tab><newline>, then the splitting algorithm is that of
3097 the Bourne shell, which treats any sequence of characters from `separators'
3098 as a delimiter. If IFS is unset, which results in `separators' being set
3099 to "", no splitting occurs. If separators has some other value, the
3100 following rules are applied (`IFS white space' means zero or more
3101 occurrences of <space>, <tab>, or <newline>, as long as those characters
3102 are in `separators'):
3103
3104 1) IFS white space is ignored at the start and the end of the
3105 string.
3106 2) Each occurrence of a character in `separators' that is not
3107 IFS white space, along with any adjacent occurrences of
3108 IFS white space delimits a field.
3109 3) Any nonzero-length sequence of IFS white space delimits a field.
3110 */
3111
3112 /* BEWARE! list_string strips null arguments. Don't call it twice and
3113 expect to have "" preserved! */
3114
3115 /* This performs word splitting and quoted null character removal on
3116 STRING. */
3117 #define issep(c) \
3118 (((separators)[0]) ? ((separators)[1] ? isifs(c) \
3119 : (c) == (separators)[0]) \
3120 : 0)
3121
3122 /* member of the space character class in the current locale */
3123 #define ifs_whitespace(c) ISSPACE(c)
3124
3125 /* "adjacent IFS white space" */
3126 #define ifs_whitesep(c) ((sh_style_split || separators == 0) ? spctabnl (c) \
3127 : ifs_whitespace (c))
3128
3129 WORD_LIST *
3130 list_string (string, separators, quoted)
3131 register char *string, *separators;
3132 int quoted;
3133 {
3134 WORD_LIST *result;
3135 WORD_DESC *t;
3136 char *current_word, *s;
3137 int sindex, sh_style_split, whitesep, xflags, free_word;
3138 size_t slen;
3139
3140 if (!string || !*string)
3141 return ((WORD_LIST *)NULL);
3142
3143 sh_style_split = separators && separators[0] == ' ' &&
3144 separators[1] == '\t' &&
3145 separators[2] == '\n' &&
3146 separators[3] == '\0';
3147 for (xflags = 0, s = ifs_value; s && *s; s++)
3148 {
3149 if (*s == CTLESC) xflags |= SX_NOCTLESC;
3150 else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
3151 }
3152
3153 slen = 0;
3154 /* Remove sequences of whitespace at the beginning of STRING, as
3155 long as those characters appear in IFS. Do not do this if
3156 STRING is quoted or if there are no separator characters. We use the
3157 Posix definition of whitespace as a member of the space character
3158 class in the current locale. */
3159 #if 0
3160 if (!quoted || !separators || !*separators)
3161 #else
3162 /* issep() requires that separators be non-null, and always returns 0 if
3163 separator is the empty string, so don't bother if we get an empty string
3164 for separators. We already returned NULL above if STRING is empty. */
3165 if (!quoted && separators && *separators)
3166 #endif
3167 {
3168 for (s = string; *s && issep (*s) && ifs_whitespace (*s); s++);
3169
3170 if (!*s)
3171 return ((WORD_LIST *)NULL);
3172
3173 string = s;
3174 }
3175
3176 /* OK, now STRING points to a word that does not begin with white space.
3177 The splitting algorithm is:
3178 extract a word, stopping at a separator
3179 skip sequences of whitespace characters as long as they are separators
3180 This obeys the field splitting rules in Posix.2. */
3181 slen = STRLEN (string);
3182 for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
3183 {
3184 /* Don't need string length in ADVANCE_CHAR unless multibyte chars are
3185 possible, but need it in string_extract_verbatim for bounds checking */
3186 current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
3187 if (current_word == 0)
3188 break;
3189
3190 free_word = 1; /* If non-zero, we free current_word */
3191
3192 /* If we have a quoted empty string, add a quoted null argument. We
3193 want to preserve the quoted null character iff this is a quoted
3194 empty string; otherwise the quoted null characters are removed
3195 below. */
3196 if (QUOTED_NULL (current_word))
3197 {
3198 t = alloc_word_desc ();
3199 t->word = make_quoted_char ('\0');
3200 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
3201 result = make_word_list (t, result);
3202 }
3203 else if (current_word[0] != '\0')
3204 {
3205 /* If we have something, then add it regardless. However,
3206 perform quoted null character removal on the current word. */
3207 remove_quoted_nulls (current_word);
3208
3209 /* We don't want to set the word flags based on the string contents
3210 here -- that's mostly for the parser -- so we just allocate a
3211 WORD_DESC *, assign current_word (noting that we don't want to
3212 free it), and skip all of make_word. */
3213 t = alloc_word_desc ();
3214 t->word = current_word;
3215 result = make_word_list (t, result);
3216 free_word = 0;
3217 result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */
3218 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
3219 result->word->flags |= W_QUOTED;
3220 /* If removing quoted null characters leaves an empty word, note
3221 that we saw this for the caller to act on. */
3222 if (current_word == 0 || current_word[0] == '\0')
3223 result->word->flags |= W_SAWQUOTEDNULL;
3224 }
3225
3226 /* If we're not doing sequences of separators in the traditional
3227 Bourne shell style, then add a quoted null argument. */
3228 else if (!sh_style_split && !ifs_whitespace (string[sindex]))
3229 {
3230 t = alloc_word_desc ();
3231 t->word = make_quoted_char ('\0');
3232 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
3233 result = make_word_list (t, result);
3234 }
3235
3236 if (free_word)
3237 free (current_word);
3238
3239 /* Note whether or not the separator is IFS whitespace, used later. */
3240 whitesep = string[sindex] && ifs_whitesep (string[sindex]);
3241
3242 /* Move past the current separator character. */
3243 if (string[sindex])
3244 {
3245 DECLARE_MBSTATE;
3246 ADVANCE_CHAR (string, slen, sindex);
3247 }
3248
3249 /* Now skip sequences of whitespace characters if they are
3250 in the list of separators. */
3251 while (string[sindex] && ifs_whitesep (string[sindex]) && issep (string[sindex]))
3252 sindex++;
3253
3254 /* If the first separator was IFS whitespace and the current character
3255 is a non-whitespace IFS character, it should be part of the current
3256 field delimiter, not a separate delimiter that would result in an
3257 empty field. Look at POSIX.2, 3.6.5, (3)(b). */
3258 if (string[sindex] && whitesep && issep (string[sindex]) && !ifs_whitesep (string[sindex]))
3259 {
3260 sindex++;
3261 /* An IFS character that is not IFS white space, along with any
3262 adjacent IFS white space, shall delimit a field. (SUSv3) */
3263 while (string[sindex] && ifs_whitesep (string[sindex]) && isifs (string[sindex]))
3264 sindex++;
3265 }
3266 }
3267 return (REVERSE_LIST (result, WORD_LIST *));
3268 }
3269
3270 /* Parse a single word from STRING, using SEPARATORS to separate fields.
3271 ENDPTR is set to the first character after the word. This is used by
3272 the `read' builtin.
3273
3274 This is never called with SEPARATORS != $IFS, and takes advantage of that.
3275
3276 XXX - this function is very similar to list_string; they should be
3277 combined - XXX */
3278
3279 /* character is in $IFS */
3280 #define islocalsep(c) (local_cmap[(unsigned char)(c)] != 0)
3281
3282 char *
3283 get_word_from_string (stringp, separators, endptr)
3284 char **stringp, *separators, **endptr;
3285 {
3286 register char *s;
3287 char *current_word;
3288 int sindex, sh_style_split, whitesep, xflags;
3289 unsigned char local_cmap[UCHAR_MAX+1]; /* really only need single-byte chars here */
3290 size_t slen;
3291
3292 if (!stringp || !*stringp || !**stringp)
3293 return ((char *)NULL);
3294
3295 sh_style_split = separators && separators[0] == ' ' &&
3296 separators[1] == '\t' &&
3297 separators[2] == '\n' &&
3298 separators[3] == '\0';
3299 memset (local_cmap, '\0', sizeof (local_cmap));
3300 for (xflags = 0, s = separators; s && *s; s++)
3301 {
3302 if (*s == CTLESC) xflags |= SX_NOCTLESC;
3303 if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
3304 local_cmap[(unsigned char)*s] = 1; /* local charmap of separators */
3305 }
3306
3307 s = *stringp;
3308 slen = 0;
3309
3310 /* Remove sequences of whitespace at the beginning of STRING, as
3311 long as those characters appear in SEPARATORS. This happens if
3312 SEPARATORS == $' \t\n' or if IFS is unset. */
3313 if (sh_style_split || separators == 0)
3314 for (; *s && spctabnl (*s) && islocalsep (*s); s++);
3315 else
3316 for (; *s && ifs_whitespace (*s) && islocalsep (*s); s++);
3317
3318 /* If the string is nothing but whitespace, update it and return. */
3319 if (!*s)
3320 {
3321 *stringp = s;
3322 if (endptr)
3323 *endptr = s;
3324 return ((char *)NULL);
3325 }
3326
3327 /* OK, S points to a word that does not begin with white space.
3328 Now extract a word, stopping at a separator, save a pointer to
3329 the first character after the word, then skip sequences of spc,
3330 tab, or nl as long as they are separators.
3331
3332 This obeys the field splitting rules in Posix.2. */
3333 sindex = 0;
3334 /* Don't need string length in ADVANCE_CHAR unless multibyte chars are
3335 possible, but need it in string_extract_verbatim for bounds checking */
3336 slen = STRLEN (s);
3337 current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
3338
3339 /* Set ENDPTR to the first character after the end of the word. */
3340 if (endptr)
3341 *endptr = s + sindex;
3342
3343 /* Note whether or not the separator is IFS whitespace, used later. */
3344 whitesep = s[sindex] && ifs_whitesep (s[sindex]);
3345
3346 /* Move past the current separator character. */
3347 if (s[sindex])
3348 {
3349 DECLARE_MBSTATE;
3350 ADVANCE_CHAR (s, slen, sindex);
3351 }
3352
3353 /* Now skip sequences of space, tab, or newline characters if they are
3354 in the list of separators. */
3355 while (s[sindex] && spctabnl (s[sindex]) && islocalsep (s[sindex]))
3356 sindex++;
3357
3358 /* If the first separator was IFS whitespace and the current character is
3359 a non-whitespace IFS character, it should be part of the current field
3360 delimiter, not a separate delimiter that would result in an empty field.
3361 Look at POSIX.2, 3.6.5, (3)(b). */
3362 if (s[sindex] && whitesep && islocalsep (s[sindex]) && !ifs_whitesep (s[sindex]))
3363 {
3364 sindex++;
3365 /* An IFS character that is not IFS white space, along with any adjacent
3366 IFS white space, shall delimit a field. */
3367 while (s[sindex] && ifs_whitesep (s[sindex]) && islocalsep(s[sindex]))
3368 sindex++;
3369 }
3370
3371 /* Update STRING to point to the next field. */
3372 *stringp = s + sindex;
3373 return (current_word);
3374 }
3375
3376 /* Remove IFS white space at the end of STRING. Start at the end
3377 of the string and walk backwards until the beginning of the string
3378 or we find a character that's not IFS white space and not CTLESC.
3379 Only let CTLESC escape a white space character if SAW_ESCAPE is
3380 non-zero. */
3381 char *
3382 strip_trailing_ifs_whitespace (string, separators, saw_escape)
3383 char *string, *separators;
3384 int saw_escape;
3385 {
3386 char *s;
3387
3388 s = string + STRLEN (string) - 1;
3389 while (s > string && ((spctabnl (*s) && isifs (*s)) ||
3390 (saw_escape && *s == CTLESC && spctabnl (s[1]))))
3391 s--;
3392 *++s = '\0';
3393 return string;
3394 }
3395
3396 #if 0
3397 /* UNUSED */
3398 /* Split STRING into words at whitespace. Obeys shell-style quoting with
3399 backslashes, single and double quotes. */
3400 WORD_LIST *
3401 list_string_with_quotes (string)
3402 char *string;
3403 {
3404 WORD_LIST *list;
3405 char *token, *s;
3406 size_t s_len;
3407 int c, i, tokstart, len;
3408
3409 for (s = string; s && *s && spctabnl (*s); s++)
3410 ;
3411 if (s == 0 || *s == 0)
3412 return ((WORD_LIST *)NULL);
3413
3414 s_len = strlen (s);
3415 tokstart = i = 0;
3416 list = (WORD_LIST *)NULL;
3417 while (1)
3418 {
3419 c = s[i];
3420 if (c == '\\')
3421 {
3422 i++;
3423 if (s[i])
3424 i++;
3425 }
3426 else if (c == '\'')
3427 i = skip_single_quoted (s, s_len, ++i, 0);
3428 else if (c == '"')
3429 i = skip_double_quoted (s, s_len, ++i, 0);
3430 else if (c == 0 || spctabnl (c))
3431 {
3432 /* We have found the end of a token. Make a word out of it and
3433 add it to the word list. */
3434 token = substring (s, tokstart, i);
3435 list = add_string_to_list (token, list);
3436 free (token);
3437 while (spctabnl (s[i]))
3438 i++;
3439 if (s[i])
3440 tokstart = i;
3441 else
3442 break;
3443 }
3444 else
3445 i++; /* normal character */
3446 }
3447 return (REVERSE_LIST (list, WORD_LIST *));
3448 }
3449 #endif
3450
3451 /********************************************************/
3452 /* */
3453 /* Functions to perform assignment statements */
3454 /* */
3455 /********************************************************/
3456
3457 #if defined (ARRAY_VARS)
3458 static SHELL_VAR *
3459 do_compound_assignment (name, value, flags)
3460 char *name, *value;
3461 int flags;
3462 {
3463 SHELL_VAR *v;
3464 int mklocal, mkassoc, mkglobal, chklocal;
3465 WORD_LIST *list;
3466 char *newname; /* used for local nameref references */
3467
3468 mklocal = flags & ASS_MKLOCAL;
3469 mkassoc = flags & ASS_MKASSOC;
3470 mkglobal = flags & ASS_MKGLOBAL;
3471 chklocal = flags & ASS_CHKLOCAL;
3472
3473 if (mklocal && variable_context)
3474 {
3475 v = find_variable (name); /* follows namerefs */
3476 newname = (v == 0) ? nameref_transform_name (name, flags) : v->name;
3477 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3478 {
3479 if (readonly_p (v))
3480 err_readonly (name);
3481 return (v); /* XXX */
3482 }
3483 list = expand_compound_array_assignment (v, value, flags);
3484 if (mkassoc)
3485 v = make_local_assoc_variable (newname, 0);
3486 else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context)
3487 v = make_local_array_variable (newname, 0);
3488 if (v)
3489 assign_compound_array_list (v, list, flags);
3490 if (list)
3491 dispose_words (list);
3492 }
3493 /* In a function but forcing assignment in global context. CHKLOCAL means to
3494 check for an existing local variable first. */
3495 else if (mkglobal && variable_context)
3496 {
3497 v = chklocal ? find_variable (name) : 0;
3498 if (v && (local_p (v) == 0 || v->context != variable_context))
3499 v = 0;
3500 if (v == 0)
3501 v = find_global_variable (name);
3502 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3503 {
3504 if (readonly_p (v))
3505 err_readonly (name);
3506 return (v); /* XXX */
3507 }
3508 /* sanity check */
3509 newname = (v == 0) ? nameref_transform_name (name, flags) : name;
3510 list = expand_compound_array_assignment (v, value, flags);
3511 if (v == 0 && mkassoc)
3512 v = make_new_assoc_variable (newname);
3513 else if (v && mkassoc && assoc_p (v) == 0)
3514 v = convert_var_to_assoc (v);
3515 else if (v == 0)
3516 v = make_new_array_variable (newname);
3517 else if (v && mkassoc == 0 && array_p (v) == 0)
3518 v = convert_var_to_array (v);
3519 if (v)
3520 assign_compound_array_list (v, list, flags);
3521 if (list)
3522 dispose_words (list);
3523 }
3524 else
3525 {
3526 v = assign_array_from_string (name, value, flags);
3527 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3528 {
3529 if (readonly_p (v))
3530 err_readonly (name);
3531 return (v); /* XXX */
3532 }
3533 }
3534
3535 return (v);
3536 }
3537 #endif
3538
3539 /* Given STRING, an assignment string, get the value of the right side
3540 of the `=', and bind it to the left side. If EXPAND is true, then
3541 perform parameter expansion, command substitution, and arithmetic
3542 expansion on the right-hand side. Perform tilde expansion in any
3543 case. Do not perform word splitting on the result of expansion. */
3544 static int
3545 do_assignment_internal (word, expand)
3546 const WORD_DESC *word;
3547 int expand;
3548 {
3549 int offset, appendop, assign_list, aflags, retval;
3550 char *name, *value, *temp;
3551 SHELL_VAR *entry;
3552 #if defined (ARRAY_VARS)
3553 char *t;
3554 int ni;
3555 #endif
3556 const char *string;
3557
3558 if (word == 0 || word->word == 0)
3559 return 0;
3560
3561 appendop = assign_list = aflags = 0;
3562 string = word->word;
3563 offset = assignment (string, 0);
3564 name = savestring (string);
3565 value = (char *)NULL;
3566
3567 if (name[offset] == '=')
3568 {
3569 if (name[offset - 1] == '+')
3570 {
3571 appendop = 1;
3572 name[offset - 1] = '\0';
3573 }
3574
3575 name[offset] = 0; /* might need this set later */
3576 temp = name + offset + 1;
3577
3578 #if defined (ARRAY_VARS)
3579 if (expand && (word->flags & W_COMPASSIGN))
3580 {
3581 assign_list = ni = 1;
3582 value = extract_array_assignment_list (temp, &ni);
3583 }
3584 else
3585 #endif
3586 if (expand && temp[0])
3587 value = expand_string_if_necessary (temp, 0, expand_string_assignment);
3588 else
3589 value = savestring (temp);
3590 }
3591
3592 if (value == 0)
3593 {
3594 value = (char *)xmalloc (1);
3595 value[0] = '\0';
3596 }
3597
3598 if (echo_command_at_execute)
3599 {
3600 if (appendop)
3601 name[offset - 1] = '+';
3602 xtrace_print_assignment (name, value, assign_list, 1);
3603 if (appendop)
3604 name[offset - 1] = '\0';
3605 }
3606
3607 #define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
3608
3609 if (appendop)
3610 aflags |= ASS_APPEND;
3611
3612 #if defined (ARRAY_VARS)
3613 if (t = mbschr (name, LBRACK))
3614 {
3615 if (assign_list)
3616 {
3617 report_error (_("%s: cannot assign list to array member"), name);
3618 ASSIGN_RETURN (0);
3619 }
3620 aflags |= ASS_ALLOWALLSUB; /* allow a[@]=value for existing associative arrays */
3621 entry = assign_array_element (name, value, aflags, (array_eltstate_t *)0);
3622 if (entry == 0)
3623 ASSIGN_RETURN (0);
3624 }
3625 else if (assign_list)
3626 {
3627 if ((word->flags & W_ASSIGNARG) && (word->flags & W_CHKLOCAL))
3628 aflags |= ASS_CHKLOCAL;
3629 if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0)
3630 aflags |= ASS_MKLOCAL;
3631 if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL))
3632 aflags |= ASS_MKGLOBAL;
3633 if (word->flags & W_ASSIGNASSOC)
3634 aflags |= ASS_MKASSOC;
3635 entry = do_compound_assignment (name, value, aflags);
3636 }
3637 else
3638 #endif /* ARRAY_VARS */
3639 entry = bind_variable (name, value, aflags);
3640
3641 if (entry)
3642 stupidly_hack_special_variables (entry->name); /* might be a nameref */
3643 else
3644 stupidly_hack_special_variables (name);
3645
3646 /* Return 1 if the assignment seems to have been performed correctly. */
3647 if (entry == 0 || readonly_p (entry))
3648 retval = 0; /* assignment failure */
3649 else if (noassign_p (entry))
3650 {
3651 set_exit_status (EXECUTION_FAILURE);
3652 retval = 1; /* error status, but not assignment failure */
3653 }
3654 else
3655 retval = 1;
3656
3657 if (entry && retval != 0 && noassign_p (entry) == 0)
3658 VUNSETATTR (entry, att_invisible);
3659
3660 ASSIGN_RETURN (retval);
3661 }
3662
3663 /* Perform the assignment statement in STRING, and expand the
3664 right side by doing tilde, command and parameter expansion. */
3665 int
3666 do_assignment (string)
3667 char *string;
3668 {
3669 WORD_DESC td;
3670
3671 td.flags = W_ASSIGNMENT;
3672 td.word = string;
3673
3674 return do_assignment_internal (&td, 1);
3675 }
3676
3677 int
3678 do_word_assignment (word, flags)
3679 WORD_DESC *word;
3680 int flags;
3681 {
3682 return do_assignment_internal (word, 1);
3683 }
3684
3685 /* Given STRING, an assignment string, get the value of the right side
3686 of the `=', and bind it to the left side. Do not perform any word
3687 expansions on the right hand side. */
3688 int
3689 do_assignment_no_expand (string)
3690 char *string;
3691 {
3692 WORD_DESC td;
3693
3694 td.flags = W_ASSIGNMENT;
3695 td.word = string;
3696
3697 return (do_assignment_internal (&td, 0));
3698 }
3699
3700 /***************************************************
3701 * *
3702 * Functions to manage the positional parameters *
3703 * *
3704 ***************************************************/
3705
3706 /* Return the word list that corresponds to `$*'. */
3707 WORD_LIST *
3708 list_rest_of_args ()
3709 {
3710 register WORD_LIST *list, *args;
3711 int i;
3712
3713 /* Break out of the loop as soon as one of the dollar variables is null. */
3714 for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
3715 list = make_word_list (make_bare_word (dollar_vars[i]), list);
3716
3717 for (args = rest_of_args; args; args = args->next)
3718 list = make_word_list (make_bare_word (args->word->word), list);
3719
3720 return (REVERSE_LIST (list, WORD_LIST *));
3721 }
3722
3723 /* Return the value of a positional parameter. This handles values > 10. */
3724 char *
3725 get_dollar_var_value (ind)
3726 intmax_t ind;
3727 {
3728 char *temp;
3729 WORD_LIST *p;
3730
3731 if (ind < 10)
3732 temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
3733 else /* We want something like ${11} */
3734 {
3735 ind -= 10;
3736 for (p = rest_of_args; p && ind--; p = p->next)
3737 ;
3738 temp = p ? savestring (p->word->word) : (char *)NULL;
3739 }
3740 return (temp);
3741 }
3742
3743 /* Make a single large string out of the dollar digit variables,
3744 and the rest_of_args. If DOLLAR_STAR is 1, then obey the special
3745 case of "$*" with respect to IFS. */
3746 char *
3747 string_rest_of_args (dollar_star)
3748 int dollar_star;
3749 {
3750 register WORD_LIST *list;
3751 char *string;
3752
3753 list = list_rest_of_args ();
3754 string = dollar_star ? string_list_dollar_star (list, 0, 0) : string_list (list);
3755 dispose_words (list);
3756 return (string);
3757 }
3758
3759 /* Return a string containing the positional parameters from START to
3760 END, inclusive. If STRING[0] == '*', we obey the rules for $*,
3761 which only makes a difference if QUOTED is non-zero. If QUOTED includes
3762 Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise
3763 no quoting chars are added. */
3764 static char *
3765 pos_params (string, start, end, quoted, pflags)
3766 char *string;
3767 int start, end, quoted, pflags;
3768 {
3769 WORD_LIST *save, *params, *h, *t;
3770 char *ret;
3771 int i;
3772
3773 /* see if we can short-circuit. if start == end, we want 0 parameters. */
3774 if (start == end)
3775 return ((char *)NULL);
3776
3777 save = params = list_rest_of_args ();
3778 if (save == 0 && start > 0)
3779 return ((char *)NULL);
3780
3781 if (start == 0) /* handle ${@:0[:x]} specially */
3782 {
3783 t = make_word_list (make_word (dollar_vars[0]), params);
3784 save = params = t;
3785 }
3786
3787 for (i = start ? 1 : 0; params && i < start; i++)
3788 params = params->next;
3789 if (params == 0)
3790 {
3791 dispose_words (save);
3792 return ((char *)NULL);
3793 }
3794 for (h = t = params; params && i < end; i++)
3795 {
3796 t = params;
3797 params = params->next;
3798 }
3799 t->next = (WORD_LIST *)NULL;
3800
3801 ret = string_list_pos_params (string[0], h, quoted, pflags);
3802
3803 if (t != params)
3804 t->next = params;
3805
3806 dispose_words (save);
3807 return (ret);
3808 }
3809
3810 /******************************************************************/
3811 /* */
3812 /* Functions to expand strings to strings or WORD_LISTs */
3813 /* */
3814 /******************************************************************/
3815
3816 #if defined (PROCESS_SUBSTITUTION)
3817 #define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~')
3818 #else
3819 #define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
3820 #endif
3821
3822 /* If there are any characters in STRING that require full expansion,
3823 then call FUNC to expand STRING; otherwise just perform quote
3824 removal if necessary. This returns a new string. */
3825 static char *
3826 expand_string_if_necessary (string, quoted, func)
3827 char *string;
3828 int quoted;
3829 EXPFUNC *func;
3830 {
3831 WORD_LIST *list;
3832 size_t slen;
3833 int i, saw_quote;
3834 char *ret;
3835 DECLARE_MBSTATE;
3836
3837 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3838 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
3839 i = saw_quote = 0;
3840 while (string[i])
3841 {
3842 if (EXP_CHAR (string[i]))
3843 break;
3844 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3845 saw_quote = 1;
3846 ADVANCE_CHAR (string, slen, i);
3847 }
3848
3849 if (string[i])
3850 {
3851 list = (*func) (string, quoted);
3852 if (list)
3853 {
3854 ret = string_list (list);
3855 dispose_words (list);
3856 }
3857 else
3858 ret = (char *)NULL;
3859 }
3860 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3861 ret = string_quote_removal (string, quoted);
3862 else
3863 ret = savestring (string);
3864
3865 return ret;
3866 }
3867
3868 static inline char *
3869 expand_string_to_string_internal (string, quoted, func)
3870 char *string;
3871 int quoted;
3872 EXPFUNC *func;
3873 {
3874 WORD_LIST *list;
3875 char *ret;
3876
3877 if (string == 0 || *string == '\0')
3878 return ((char *)NULL);
3879
3880 list = (*func) (string, quoted);
3881 if (list)
3882 {
3883 ret = string_list (list);
3884 dispose_words (list);
3885 }
3886 else
3887 ret = (char *)NULL;
3888
3889 return (ret);
3890 }
3891
3892 char *
3893 expand_string_to_string (string, quoted)
3894 char *string;
3895 int quoted;
3896 {
3897 return (expand_string_to_string_internal (string, quoted, expand_string));
3898 }
3899
3900 char *
3901 expand_string_unsplit_to_string (string, quoted)
3902 char *string;
3903 int quoted;
3904 {
3905 return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
3906 }
3907
3908 char *
3909 expand_assignment_string_to_string (string, quoted)
3910 char *string;
3911 int quoted;
3912 {
3913 return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
3914 }
3915
3916 /* Kind of like a combination of dequote_string and quote_string_for_globbing;
3917 try to remove CTLESC quoting characters and convert CTLESC escaping a `&'
3918 or a backslash into a backslash. The output of this function must eventually
3919 be processed by strcreplace(). */
3920 static char *
3921 quote_string_for_repl (string, flags)
3922 char *string;
3923 int flags;
3924 {
3925 size_t slen;
3926 char *result, *t;
3927 const char *s, *send;
3928 DECLARE_MBSTATE;
3929
3930 slen = strlen (string);
3931 send = string + slen;
3932
3933 result = (char *)xmalloc (slen * 2 + 1);
3934
3935 if (string[0] == CTLESC && string[1] == 0)
3936 {
3937 result[0] = CTLESC;
3938 result[1] = '\0';
3939 return (result);
3940 }
3941
3942 /* This is awkward. We want to translate CTLESC-\ to \\ if we will
3943 eventually send this string through strcreplace(), which we will do
3944 only if shouldexp_replacement() determines that there is something
3945 to replace. We can either make sure to escape backslashes here and
3946 have shouldexp_replacement() signal that we should send the string to
3947 strcreplace() if it sees an escaped backslash, or we can scan the
3948 string before copying it and turn CTLESC-\ into \\ only if we encounter
3949 a CTLESC-& or a &. This does the former and changes shouldexp_replacement().
3950 If we double the backslashes here, we'll get doubled backslashes in any
3951 result that doesn't get passed to strcreplace(). */
3952
3953 for (s = string, t = result; *s; )
3954 {
3955 /* This function's result has to be processed by strcreplace() */
3956 if (*s == CTLESC && (s[1] == '&' || s[1] == '\\'))
3957 {
3958 *t++ = '\\';
3959 s++;
3960 *t++ = *s++;
3961 continue;
3962 }
3963 /* Dequote it */
3964 if (*s == CTLESC)
3965 {
3966 s++;
3967 if (*s == '\0')
3968 break;
3969 }
3970 COPY_CHAR_P (t, s, send);
3971 }
3972
3973 *t = '\0';
3974 return (result);
3975 }
3976
3977 /* This does not perform word splitting on the WORD_LIST it returns and
3978 it treats $* as if it were quoted. It dequotes the WORD_LIST, adds
3979 backslash escapes before CTLESC-quoted backslash and `& if
3980 patsub_replacement is enabled. */
3981 static char *
3982 expand_string_for_patsub (string, quoted)
3983 char *string;
3984 int quoted;
3985 {
3986 WORD_LIST *value;
3987 char *ret, *t;
3988
3989 if (string == 0 || *string == '\0')
3990 return (char *)NULL;
3991
3992 value = expand_string_for_pat (string, quoted, (int *)0, (int *)0);
3993
3994 if (value && value->word)
3995 {
3996 remove_quoted_nulls (value->word->word); /* XXX */
3997 value->word->flags &= ~W_HASQUOTEDNULL;
3998 }
3999
4000 if (value)
4001 {
4002 t = (value->next) ? string_list (value) : value->word->word;
4003 ret = quote_string_for_repl (t, quoted);
4004 if (t != value->word->word)
4005 free (t);
4006 dispose_words (value);
4007 }
4008 else
4009 ret = (char *)NULL;
4010
4011 return (ret);
4012 }
4013
4014 char *
4015 expand_arith_string (string, quoted)
4016 char *string;
4017 int quoted;
4018 {
4019 WORD_DESC td;
4020 WORD_LIST *list, *tlist;
4021 size_t slen;
4022 int i, saw_quote;
4023 char *ret;
4024 DECLARE_MBSTATE;
4025
4026 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
4027 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
4028 i = saw_quote = 0;
4029 while (string[i])
4030 {
4031 if (EXP_CHAR (string[i]))
4032 break;
4033 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
4034 saw_quote = string[i];
4035 ADVANCE_CHAR (string, slen, i);
4036 }
4037
4038 if (string[i])
4039 {
4040 /* This is expanded version of expand_string_internal as it's called by
4041 expand_string_leave_quoted */
4042 td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */
4043 #if 0 /* TAG: bash-5.2 */
4044 if (quoted & Q_ARRAYSUB)
4045 td.flags |= W_NOCOMSUB;
4046 #endif
4047 td.word = savestring (string);
4048 list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4049 /* This takes care of the calls from expand_string_leave_quoted and
4050 expand_string */
4051 if (list)
4052 {
4053 tlist = word_list_split (list);
4054 dispose_words (list);
4055 list = tlist;
4056 if (list)
4057 dequote_list (list);
4058 }
4059 /* This comes from expand_string_if_necessary */
4060 if (list)
4061 {
4062 ret = string_list (list);
4063 dispose_words (list);
4064 }
4065 else
4066 ret = (char *)NULL;
4067 FREE (td.word);
4068 }
4069 else if (saw_quote && (quoted & Q_ARITH))
4070 ret = string_quote_removal (string, quoted);
4071 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4072 ret = string_quote_removal (string, quoted);
4073 else
4074 ret = savestring (string);
4075
4076 return ret;
4077 }
4078
4079 #if defined (COND_COMMAND)
4080 /* Just remove backslashes in STRING. Returns a new string. */
4081 char *
4082 remove_backslashes (string)
4083 char *string;
4084 {
4085 char *r, *ret, *s;
4086
4087 r = ret = (char *)xmalloc (strlen (string) + 1);
4088 for (s = string; s && *s; )
4089 {
4090 if (*s == '\\')
4091 s++;
4092 if (*s == 0)
4093 break;
4094 *r++ = *s++;
4095 }
4096 *r = '\0';
4097 return ret;
4098 }
4099
4100 /* This needs better error handling. */
4101 /* Expand W for use as an argument to a unary or binary operator in a
4102 [[...]] expression. If SPECIAL is 1, this is the rhs argument
4103 to the != or == operator, and should be treated as a pattern. In
4104 this case, we quote the string specially for the globbing code. If
4105 SPECIAL is 2, this is an rhs argument for the =~ operator, and should
4106 be quoted appropriately for regcomp/regexec. If SPECIAL is 3, this is
4107 an array subscript and should be quoted after expansion so it's only
4108 expanded once (Q_ARITH). The caller is responsible
4109 for removing the backslashes if the unquoted word is needed later. In
4110 any case, since we don't perform word splitting, we need to do quoted
4111 null character removal. */
4112 char *
4113 cond_expand_word (w, special)
4114 WORD_DESC *w;
4115 int special;
4116 {
4117 char *r, *p;
4118 WORD_LIST *l;
4119 int qflags;
4120
4121 if (w->word == 0 || w->word[0] == '\0')
4122 return ((char *)NULL);
4123
4124 expand_no_split_dollar_star = 1;
4125 w->flags |= W_NOSPLIT2;
4126 qflags = (special == 3) ? Q_ARITH : 0;
4127 l = call_expand_word_internal (w, qflags, 0, (int *)0, (int *)0);
4128 expand_no_split_dollar_star = 0;
4129 if (l)
4130 {
4131 if (special == 0) /* LHS */
4132 {
4133 if (l->word)
4134 word_list_remove_quoted_nulls (l);
4135 dequote_list (l);
4136 r = string_list (l);
4137 }
4138 else if (special == 3) /* arithmetic expression, Q_ARITH */
4139 {
4140 if (l->word)
4141 word_list_remove_quoted_nulls (l); /* for now */
4142 dequote_list (l);
4143 r = string_list (l);
4144 }
4145 else
4146 {
4147 /* Need to figure out whether or not we should call dequote_escapes
4148 or a new dequote_ctlnul function here, and under what
4149 circumstances. */
4150 qflags = QGLOB_CVTNULL|QGLOB_CTLESC;
4151 if (special == 2)
4152 qflags |= QGLOB_REGEXP;
4153 word_list_remove_quoted_nulls (l);
4154 p = string_list (l);
4155 r = quote_string_for_globbing (p, qflags);
4156 free (p);
4157 }
4158 dispose_words (l);
4159 }
4160 else
4161 r = (char *)NULL;
4162
4163 return r;
4164 }
4165 #endif
4166
4167 /* Expand $'...' and $"..." in a string for code paths that don't do it. The
4168 FLAGS argument is 1 if this function should treat CTLESC as a quote
4169 character (e.g., for here-documents) or not (e.g., for shell_expand_line). */
4170 char *
4171 expand_string_dollar_quote (string, flags)
4172 char *string;
4173 int flags;
4174 {
4175 size_t slen, retind, retsize;
4176 int sindex, c, translen, peekc, news;
4177 char *ret, *trans, *send, *t;
4178 DECLARE_MBSTATE;
4179
4180 slen = strlen (string);
4181 send = string + slen;
4182 sindex = 0;
4183
4184 retsize = slen + 1;
4185 ret = xmalloc (retsize);
4186 retind = 0;
4187
4188 while (c = string[sindex])
4189 {
4190 switch (c)
4191 {
4192 default:
4193 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 1, retsize, 64);
4194 COPY_CHAR_I (ret, retind, string, send, sindex);
4195 break;
4196
4197 case '\\':
4198 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 2, retsize, 64);
4199 ret[retind++] = string[sindex++];
4200
4201 if (string[sindex])
4202 COPY_CHAR_I (ret, retind, string, send, sindex);
4203 break;
4204
4205 case '\'':
4206 case '"':
4207 if (c == '\'')
4208 news = skip_single_quoted (string, slen, ++sindex, SX_COMPLETE);
4209 else
4210 news = skip_double_quoted (string, slen, ++sindex, SX_COMPLETE);
4211 translen = news - sindex - 1;
4212 RESIZE_MALLOCED_BUFFER (ret, retind, translen + 3, retsize, 64);
4213 ret[retind++] = c;
4214 if (translen > 0)
4215 {
4216 strncpy (ret + retind, string + sindex, translen);
4217 retind += translen;
4218 }
4219 if (news > sindex && string[news - 1] == c)
4220 ret[retind++] = c;
4221 sindex = news;
4222 break;
4223
4224 case CTLESC:
4225 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 2, retsize, 64);
4226 if (flags)
4227 ret[retind++] = string[sindex++];
4228 if (string[sindex])
4229 COPY_CHAR_I (ret, retind, string, send, sindex);
4230 break;
4231
4232 case '$':
4233 peekc = string[++sindex];
4234 #if defined (TRANSLATABLE_STRINGS)
4235 if (peekc != '\'' && peekc != '"')
4236 #else
4237 if (peekc != '\'')
4238 #endif
4239 {
4240 RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 16);
4241 ret[retind++] = c;
4242 break;
4243 }
4244 if (string[sindex + 1] == '\0') /* don't bother */
4245 {
4246 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4247 ret[retind++] = c;
4248 ret[retind++] = peekc;
4249 sindex++;
4250 break;
4251 }
4252 if (peekc == '\'')
4253 {
4254 /* SX_COMPLETE is the equivalent of ALLOWESC here */
4255 /* We overload SX_COMPLETE below */
4256 news = skip_single_quoted (string, slen, ++sindex, SX_COMPLETE);
4257 /* Check for unclosed string and don't bother if so */
4258 if (news > sindex && string[news] == '\0' && string[news-1] != peekc)
4259 {
4260 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4261 ret[retind++] = c;
4262 ret[retind++] = peekc;
4263 continue;
4264 }
4265 t = substring (string, sindex, news - 1);
4266 trans = ansiexpand (t, 0, news-sindex-1, &translen);
4267 free (t);
4268 t = sh_single_quote (trans);
4269 sindex = news;
4270 }
4271 #if defined (TRANSLATABLE_STRINGS)
4272 else
4273 {
4274 news = ++sindex;
4275 t = string_extract_double_quoted (string, &news, SX_COMPLETE);
4276 /* Check for unclosed string and don't bother if so */
4277 if (news > sindex && string[news] == '\0' && string[news-1] != peekc)
4278 {
4279 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4280 ret[retind++] = c;
4281 ret[retind++] = peekc;
4282 free (t);
4283 continue;
4284 }
4285 trans = locale_expand (t, 0, news-sindex, 0, &translen);
4286 free (t);
4287 if (singlequote_translations &&
4288 ((news-sindex-1) != translen || STREQN (t, trans, translen) == 0))
4289 t = sh_single_quote (trans);
4290 else
4291 t = sh_mkdoublequoted (trans, translen, 0);
4292 sindex = news;
4293 }
4294 #endif /* TRANSLATABLE_STRINGS */
4295 free (trans);
4296 trans = t;
4297 translen = strlen (trans);
4298
4299 RESIZE_MALLOCED_BUFFER (ret, retind, translen + 1, retsize, 128);
4300 strcpy (ret + retind, trans);
4301 retind += translen;
4302 FREE (trans);
4303 break;
4304 }
4305 }
4306
4307 ret[retind] = 0;
4308 return ret;
4309 }
4310
4311 /* Call expand_word_internal to expand W and handle error returns.
4312 A convenience function for functions that don't want to handle
4313 any errors or free any memory before aborting. */
4314 static WORD_LIST *
4315 call_expand_word_internal (w, q, i, c, e)
4316 WORD_DESC *w;
4317 int q, i, *c, *e;
4318 {
4319 WORD_LIST *result;
4320
4321 result = expand_word_internal (w, q, i, c, e);
4322 if (result == &expand_word_error || result == &expand_word_fatal)
4323 {
4324 /* By convention, each time this error is returned, w->word has
4325 already been freed (it sometimes may not be in the fatal case,
4326 but that doesn't result in a memory leak because we're going
4327 to exit in most cases). */
4328 w->word = (char *)NULL;
4329 last_command_exit_value = EXECUTION_FAILURE;
4330 exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
4331 /* NOTREACHED */
4332 return (NULL);
4333 }
4334 else
4335 return (result);
4336 }
4337
4338 /* Perform parameter expansion, command substitution, and arithmetic
4339 expansion on STRING, as if it were a word. Leave the result quoted.
4340 Since this does not perform word splitting, it leaves quoted nulls
4341 in the result. */
4342 static WORD_LIST *
4343 expand_string_internal (string, quoted)
4344 char *string;
4345 int quoted;
4346 {
4347 WORD_DESC td;
4348 WORD_LIST *tresult;
4349
4350 if (string == 0 || *string == 0)
4351 return ((WORD_LIST *)NULL);
4352
4353 td.flags = 0;
4354 td.word = savestring (string);
4355
4356 tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4357
4358 FREE (td.word);
4359 return (tresult);
4360 }
4361
4362 /* Expand STRING by performing parameter expansion, command substitution,
4363 and arithmetic expansion. Dequote the resulting WORD_LIST before
4364 returning it, but do not perform word splitting. The call to
4365 remove_quoted_nulls () is in here because word splitting normally
4366 takes care of quote removal. */
4367 WORD_LIST *
4368 expand_string_unsplit (string, quoted)
4369 char *string;
4370 int quoted;
4371 {
4372 WORD_LIST *value;
4373
4374 if (string == 0 || *string == '\0')
4375 return ((WORD_LIST *)NULL);
4376
4377 expand_no_split_dollar_star = 1;
4378 value = expand_string_internal (string, quoted);
4379 expand_no_split_dollar_star = 0;
4380
4381 if (value)
4382 {
4383 if (value->word)
4384 {
4385 remove_quoted_nulls (value->word->word); /* XXX */
4386 value->word->flags &= ~W_HASQUOTEDNULL;
4387 }
4388 dequote_list (value);
4389 }
4390 return (value);
4391 }
4392
4393 /* Expand the rhs of an assignment statement */
4394 WORD_LIST *
4395 expand_string_assignment (string, quoted)
4396 char *string;
4397 int quoted;
4398 {
4399 WORD_DESC td;
4400 WORD_LIST *value;
4401
4402 if (string == 0 || *string == '\0')
4403 return ((WORD_LIST *)NULL);
4404
4405 expand_no_split_dollar_star = 1;
4406
4407 #if 0
4408 /* Other shells (ksh93) do it this way, which affects how $@ is expanded
4409 in constructs like bar=${@#0} (preserves the spaces resulting from the
4410 expansion of $@ in a context where you don't do word splitting); Posix
4411 interp 888 makes the expansion of $@ in contexts where word splitting
4412 is not performed unspecified. */
4413 td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */
4414 #else
4415 td.flags = W_ASSIGNRHS;
4416 #endif
4417 td.flags |= (W_NOGLOB|W_TILDEEXP);
4418 td.word = savestring (string);
4419 value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4420 FREE (td.word);
4421
4422 expand_no_split_dollar_star = 0;
4423
4424 if (value)
4425 {
4426 if (value->word)
4427 {
4428 remove_quoted_nulls (value->word->word); /* XXX */
4429 value->word->flags &= ~W_HASQUOTEDNULL;
4430 }
4431 dequote_list (value);
4432 }
4433 return (value);
4434 }
4435
4436 /* Expand one of the PS? prompt strings. This is a sort of combination of
4437 expand_string_unsplit and expand_string_internal, but returns the
4438 passed string when an error occurs. Might want to trap other calls
4439 to jump_to_top_level here so we don't endlessly loop. */
4440 WORD_LIST *
4441 expand_prompt_string (string, quoted, wflags)
4442 char *string;
4443 int quoted;
4444 int wflags;
4445 {
4446 WORD_LIST *value;
4447 WORD_DESC td;
4448
4449 if (string == 0 || *string == 0)
4450 return ((WORD_LIST *)NULL);
4451
4452 td.flags = wflags;
4453 td.word = savestring (string);
4454
4455 no_longjmp_on_fatal_error = 1;
4456 value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4457 no_longjmp_on_fatal_error = 0;
4458
4459 if (value == &expand_word_error || value == &expand_word_fatal)
4460 {
4461 value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
4462 return value;
4463 }
4464 FREE (td.word);
4465 if (value)
4466 {
4467 if (value->word)
4468 {
4469 remove_quoted_nulls (value->word->word); /* XXX */
4470 value->word->flags &= ~W_HASQUOTEDNULL;
4471 }
4472 dequote_list (value);
4473 }
4474 return (value);
4475 }
4476
4477 /* Expand STRING just as if you were expanding a word, but do not dequote
4478 the resultant WORD_LIST. This is called only from within this file,
4479 and is used to correctly preserve quoted characters when expanding
4480 things like ${1+"$@"}. This does parameter expansion, command
4481 substitution, arithmetic expansion, and word splitting. */
4482 static WORD_LIST *
4483 expand_string_leave_quoted (string, quoted)
4484 char *string;
4485 int quoted;
4486 {
4487 WORD_LIST *tlist;
4488 WORD_LIST *tresult;
4489
4490 if (string == 0 || *string == '\0')
4491 return ((WORD_LIST *)NULL);
4492
4493 tlist = expand_string_internal (string, quoted);
4494
4495 if (tlist)
4496 {
4497 tresult = word_list_split (tlist);
4498 dispose_words (tlist);
4499 return (tresult);
4500 }
4501 return ((WORD_LIST *)NULL);
4502 }
4503
4504 /* This does not perform word splitting or dequote the WORD_LIST
4505 it returns. */
4506 static WORD_LIST *
4507 expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p)
4508 char *string;
4509 int quoted, op, pflags;
4510 int *dollar_at_p, *expanded_p;
4511 {
4512 WORD_DESC td;
4513 WORD_LIST *tresult;
4514 int old_nosplit;
4515
4516 if (string == 0 || *string == '\0')
4517 return (WORD_LIST *)NULL;
4518
4519 /* We want field splitting to be determined by what is going to be done with
4520 the entire ${parameterOPword} expansion, so we don't want to split the RHS
4521 we expand here. However, the expansion of $* is determined by whether we
4522 are going to eventually perform word splitting, so we want to set this
4523 depending on whether or not are are going to be splitting: if the expansion
4524 is quoted, if the OP is `=', or if IFS is set to the empty string, we
4525 are not going to be splitting, so we set expand_no_split_dollar_star to
4526 note this to callees.
4527 We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an
4528 assignment statement. */
4529 /* The updated treatment of $* is the result of Posix interp 888 */
4530 /* This was further clarified on the austin-group list in March, 2017 and
4531 in Posix bug 1129 */
4532 old_nosplit = expand_no_split_dollar_star;
4533 expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */
4534 td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */
4535 td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */
4536 if (pflags & PF_ASSIGNRHS) /* pass through */
4537 td.flags |= W_ASSIGNRHS;
4538 if (op == '=')
4539 #if 0
4540 td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */
4541 #else
4542 td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */
4543 #endif
4544 td.word = savestring (string);
4545 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
4546 expand_no_split_dollar_star = old_nosplit;
4547 free (td.word);
4548
4549 return (tresult);
4550 }
4551
4552 /* This does not perform word splitting or dequote the WORD_LIST
4553 it returns and it treats $* as if it were quoted. */
4554 static WORD_LIST *
4555 expand_string_for_pat (string, quoted, dollar_at_p, expanded_p)
4556 char *string;
4557 int quoted, *dollar_at_p, *expanded_p;
4558 {
4559 WORD_DESC td;
4560 WORD_LIST *tresult;
4561 int oexp;
4562
4563 if (string == 0 || *string == '\0')
4564 return (WORD_LIST *)NULL;
4565
4566 oexp = expand_no_split_dollar_star;
4567 expand_no_split_dollar_star = 1;
4568 td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */
4569 td.word = savestring (string);
4570 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
4571 expand_no_split_dollar_star = oexp;
4572 free (td.word);
4573
4574 return (tresult);
4575 }
4576
4577 /* Expand STRING just as if you were expanding a word. This also returns
4578 a list of words. Note that filename globbing is *NOT* done for word
4579 or string expansion, just when the shell is expanding a command. This
4580 does parameter expansion, command substitution, arithmetic expansion,
4581 and word splitting. Dequote the resultant WORD_LIST before returning. */
4582 WORD_LIST *
4583 expand_string (string, quoted)
4584 char *string;
4585 int quoted;
4586 {
4587 WORD_LIST *result;
4588
4589 if (string == 0 || *string == '\0')
4590 return ((WORD_LIST *)NULL);
4591
4592 result = expand_string_leave_quoted (string, quoted);
4593 return (result ? dequote_list (result) : result);
4594 }
4595
4596 /*******************************************
4597 * *
4598 * Functions to expand WORD_DESCs *
4599 * *
4600 *******************************************/
4601
4602 /* Expand WORD, performing word splitting on the result. This does
4603 parameter expansion, command substitution, arithmetic expansion,
4604 word splitting, and quote removal. */
4605
4606 WORD_LIST *
4607 expand_word (word, quoted)
4608 WORD_DESC *word;
4609 int quoted;
4610 {
4611 WORD_LIST *result, *tresult;
4612
4613 tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4614 result = word_list_split (tresult);
4615 dispose_words (tresult);
4616 return (result ? dequote_list (result) : result);
4617 }
4618
4619 /* Expand WORD, but do not perform word splitting on the result. This
4620 does parameter expansion, command substitution, arithmetic expansion,
4621 and quote removal. */
4622 WORD_LIST *
4623 expand_word_unsplit (word, quoted)
4624 WORD_DESC *word;
4625 int quoted;
4626 {
4627 WORD_LIST *result;
4628
4629 result = expand_word_leave_quoted (word, quoted);
4630 return (result ? dequote_list (result) : result);
4631 }
4632
4633 /* Perform shell expansions on WORD, but do not perform word splitting or
4634 quote removal on the result. Virtually identical to expand_word_unsplit;
4635 could be combined if implementations don't diverge. */
4636 WORD_LIST *
4637 expand_word_leave_quoted (word, quoted)
4638 WORD_DESC *word;
4639 int quoted;
4640 {
4641 WORD_LIST *result;
4642
4643 expand_no_split_dollar_star = 1;
4644 if (ifs_is_null)
4645 word->flags |= W_NOSPLIT;
4646 word->flags |= W_NOSPLIT2;
4647 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4648 expand_no_split_dollar_star = 0;
4649
4650 return result;
4651 }
4652
4653 /***************************************************
4654 * *
4655 * Functions to handle quoting chars *
4656 * *
4657 ***************************************************/
4658
4659 /* Conventions:
4660
4661 A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
4662 The parser passes CTLNUL as CTLESC CTLNUL. */
4663
4664 /* Quote escape characters in string s, but no other characters. This is
4665 used to protect CTLESC and CTLNUL in variable values from the rest of
4666 the word expansion process after the variable is expanded (word splitting
4667 and filename generation). If IFS is null, we quote spaces as well, just
4668 in case we split on spaces later (in the case of unquoted $@, we will
4669 eventually attempt to split the entire word on spaces). Corresponding
4670 code exists in dequote_escapes. Even if we don't end up splitting on
4671 spaces, quoting spaces is not a problem. This should never be called on
4672 a string that is quoted with single or double quotes or part of a here
4673 document (effectively double-quoted).
4674 FLAGS says whether or not we are going to split the result. If we are not,
4675 and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL,
4676 respectively, to prevent them from being removed as part of dequoting. */
4677 static char *
4678 quote_escapes_internal (string, flags)
4679 const char *string;
4680 int flags;
4681 {
4682 const char *s, *send;
4683 char *t, *result;
4684 size_t slen;
4685 int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit;
4686 DECLARE_MBSTATE;
4687
4688 slen = strlen (string);
4689 send = string + slen;
4690
4691 quote_spaces = (ifs_value && *ifs_value == 0);
4692 nosplit = (flags & PF_NOSPLIT2);
4693
4694 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
4695 {
4696 skip_ctlesc |= (nosplit == 0 && *s == CTLESC);
4697 skip_ctlnul |= (nosplit == 0 && *s == CTLNUL);
4698 }
4699
4700 t = result = (char *)xmalloc ((slen * 2) + 1);
4701 s = string;
4702
4703 while (*s)
4704 {
4705 if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
4706 *t++ = CTLESC;
4707 COPY_CHAR_P (t, s, send);
4708 }
4709 *t = '\0';
4710
4711 return (result);
4712 }
4713
4714 char *
4715 quote_escapes (string)
4716 const char *string;
4717 {
4718 return (quote_escapes_internal (string, 0));
4719 }
4720
4721 char *
4722 quote_rhs (string)
4723 const char *string;
4724 {
4725 return (quote_escapes_internal (string, PF_NOSPLIT2));
4726 }
4727
4728 static WORD_LIST *
4729 list_quote_escapes (list)
4730 WORD_LIST *list;
4731 {
4732 register WORD_LIST *w;
4733 char *t;
4734
4735 for (w = list; w; w = w->next)
4736 {
4737 t = w->word->word;
4738 w->word->word = quote_escapes (t);
4739 free (t);
4740 }
4741 return list;
4742 }
4743
4744 /* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
4745
4746 The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
4747 This is necessary to make unquoted CTLESC and CTLNUL characters in the
4748 data stream pass through properly.
4749
4750 We need to remove doubled CTLESC characters inside quoted strings before
4751 quoting the entire string, so we do not double the number of CTLESC
4752 characters.
4753
4754 Also used by parts of the pattern substitution code. */
4755 char *
4756 dequote_escapes (string)
4757 const char *string;
4758 {
4759 const char *s, *send;
4760 char *t, *result;
4761 size_t slen;
4762 int quote_spaces;
4763 DECLARE_MBSTATE;
4764
4765 if (string == 0)
4766 return (char *)0;
4767
4768 slen = strlen (string);
4769 send = string + slen;
4770
4771 t = result = (char *)xmalloc (slen + 1);
4772
4773 if (strchr (string, CTLESC) == 0)
4774 return (strcpy (result, string));
4775
4776 quote_spaces = (ifs_value && *ifs_value == 0);
4777
4778 s = string;
4779 while (*s)
4780 {
4781 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
4782 {
4783 s++;
4784 if (*s == '\0')
4785 break;
4786 }
4787 COPY_CHAR_P (t, s, send);
4788 }
4789 *t = '\0';
4790
4791 return result;
4792 }
4793
4794 #if defined (INCLUDE_UNUSED)
4795 static WORD_LIST *
4796 list_dequote_escapes (list)
4797 WORD_LIST *list;
4798 {
4799 register WORD_LIST *w;
4800 char *t;
4801
4802 for (w = list; w; w = w->next)
4803 {
4804 t = w->word->word;
4805 w->word->word = dequote_escapes (t);
4806 free (t);
4807 }
4808 return list;
4809 }
4810 #endif
4811
4812 /* Return a new string with the quoted representation of character C.
4813 This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
4814 set in any resultant WORD_DESC where this value is the word. */
4815 static char *
4816 make_quoted_char (c)
4817 int c;
4818 {
4819 char *temp;
4820
4821 temp = (char *)xmalloc (3);
4822 if (c == 0)
4823 {
4824 temp[0] = CTLNUL;
4825 temp[1] = '\0';
4826 }
4827 else
4828 {
4829 temp[0] = CTLESC;
4830 temp[1] = c;
4831 temp[2] = '\0';
4832 }
4833 return (temp);
4834 }
4835
4836 /* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so
4837 the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
4838 this value is the word. */
4839 char *
4840 quote_string (string)
4841 char *string;
4842 {
4843 register char *t;
4844 size_t slen;
4845 char *result, *send;
4846
4847 if (*string == 0)
4848 {
4849 result = (char *)xmalloc (2);
4850 result[0] = CTLNUL;
4851 result[1] = '\0';
4852 }
4853 else
4854 {
4855 DECLARE_MBSTATE;
4856
4857 slen = strlen (string);
4858 send = string + slen;
4859
4860 result = (char *)xmalloc ((slen * 2) + 1);
4861
4862 for (t = result; string < send; )
4863 {
4864 *t++ = CTLESC;
4865 COPY_CHAR_P (t, string, send);
4866 }
4867 *t = '\0';
4868 }
4869 return (result);
4870 }
4871
4872 /* De-quote quoted characters in STRING. */
4873 char *
4874 dequote_string (string)
4875 char *string;
4876 {
4877 register char *s, *t;
4878 size_t slen;
4879 char *result, *send;
4880 DECLARE_MBSTATE;
4881
4882 if (string[0] == CTLESC && string[1] == 0)
4883 internal_debug ("dequote_string: string with bare CTLESC");
4884
4885 slen = STRLEN (string);
4886
4887 t = result = (char *)xmalloc (slen + 1);
4888
4889 if (QUOTED_NULL (string))
4890 {
4891 result[0] = '\0';
4892 return (result);
4893 }
4894
4895 /* A string consisting of only a single CTLESC should pass through unchanged */
4896 if (string[0] == CTLESC && string[1] == 0)
4897 {
4898 result[0] = CTLESC;
4899 result[1] = '\0';
4900 return (result);
4901 }
4902
4903 /* If no character in the string can be quoted, don't bother examining
4904 each character. Just return a copy of the string passed to us. */
4905 if (strchr (string, CTLESC) == NULL)
4906 return (strcpy (result, string));
4907
4908 send = string + slen;
4909 s = string;
4910 while (*s)
4911 {
4912 if (*s == CTLESC)
4913 {
4914 s++;
4915 if (*s == '\0')
4916 break;
4917 }
4918 COPY_CHAR_P (t, s, send);
4919 }
4920
4921 *t = '\0';
4922 return (result);
4923 }
4924
4925 /* Quote the entire WORD_LIST list. */
4926 static WORD_LIST *
4927 quote_list (list)
4928 WORD_LIST *list;
4929 {
4930 register WORD_LIST *w;
4931 char *t;
4932
4933 for (w = list; w; w = w->next)
4934 {
4935 t = w->word->word;
4936 w->word->word = quote_string (t);
4937 if (*t == 0)
4938 w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
4939 w->word->flags |= W_QUOTED;
4940 free (t);
4941 }
4942 return list;
4943 }
4944
4945 WORD_DESC *
4946 dequote_word (word)
4947 WORD_DESC *word;
4948 {
4949 register char *s;
4950
4951 s = dequote_string (word->word);
4952 if (QUOTED_NULL (word->word))
4953 word->flags &= ~W_HASQUOTEDNULL;
4954 free (word->word);
4955 word->word = s;
4956
4957 return word;
4958 }
4959
4960 /* De-quote quoted characters in each word in LIST. */
4961 WORD_LIST *
4962 dequote_list (list)
4963 WORD_LIST *list;
4964 {
4965 register char *s;
4966 register WORD_LIST *tlist;
4967
4968 for (tlist = list; tlist; tlist = tlist->next)
4969 {
4970 s = dequote_string (tlist->word->word);
4971 if (QUOTED_NULL (tlist->word->word))
4972 tlist->word->flags &= ~W_HASQUOTEDNULL;
4973 free (tlist->word->word);
4974 tlist->word->word = s;
4975 }
4976 return list;
4977 }
4978
4979 /* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
4980 string. */
4981 char *
4982 remove_quoted_escapes (string)
4983 char *string;
4984 {
4985 char *t;
4986
4987 if (string)
4988 {
4989 t = dequote_escapes (string);
4990 strcpy (string, t);
4991 free (t);
4992 }
4993
4994 return (string);
4995 }
4996
4997 /* Remove quoted $IFS characters from STRING. Quoted IFS characters are
4998 added to protect them from word splitting, but we need to remove them
4999 if no word splitting takes place. This returns newly-allocated memory,
5000 so callers can use it to replace savestring(). */
5001 char *
5002 remove_quoted_ifs (string)
5003 char *string;
5004 {
5005 register size_t slen;
5006 register int i, j;
5007 char *ret, *send;
5008 DECLARE_MBSTATE;
5009
5010 slen = strlen (string);
5011 send = string + slen;
5012
5013 i = j = 0;
5014 ret = (char *)xmalloc (slen + 1);
5015
5016 while (i < slen)
5017 {
5018 if (string[i] == CTLESC)
5019 {
5020 i++;
5021 if (string[i] == 0 || isifs (string[i]) == 0)
5022 ret[j++] = CTLESC;
5023 if (i == slen)
5024 break;
5025 }
5026
5027 COPY_CHAR_I (ret, j, string, send, i);
5028 }
5029 ret[j] = '\0';
5030
5031 return (ret);
5032 }
5033
5034 char *
5035 remove_quoted_nulls (string)
5036 char *string;
5037 {
5038 register size_t slen;
5039 register int i, j, prev_i;
5040 DECLARE_MBSTATE;
5041
5042 if (strchr (string, CTLNUL) == 0) /* XXX */
5043 return string; /* XXX */
5044
5045 slen = strlen (string);
5046 i = j = 0;
5047
5048 while (i < slen)
5049 {
5050 if (string[i] == CTLESC)
5051 {
5052 /* Old code had j++, but we cannot assume that i == j at this
5053 point -- what if a CTLNUL has already been removed from the
5054 string? We don't want to drop the CTLESC or recopy characters
5055 that we've already copied down. */
5056 i++;
5057 string[j++] = CTLESC;
5058 if (i == slen)
5059 break;
5060 }
5061 else if (string[i] == CTLNUL)
5062 {
5063 i++;
5064 continue;
5065 }
5066
5067 prev_i = i;
5068 ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */
5069 if (j < prev_i)
5070 {
5071 do string[j++] = string[prev_i++]; while (prev_i < i);
5072 }
5073 else
5074 j = i;
5075 }
5076 string[j] = '\0';
5077
5078 return (string);
5079 }
5080
5081 /* Perform quoted null character removal on each element of LIST.
5082 This modifies LIST. */
5083 void
5084 word_list_remove_quoted_nulls (list)
5085 WORD_LIST *list;
5086 {
5087 register WORD_LIST *t;
5088
5089 for (t = list; t; t = t->next)
5090 {
5091 remove_quoted_nulls (t->word->word);
5092 t->word->flags &= ~W_HASQUOTEDNULL;
5093 }
5094 }
5095
5096 /* **************************************************************** */
5097 /* */
5098 /* Functions for Matching and Removing Patterns */
5099 /* */
5100 /* **************************************************************** */
5101
5102 #if defined (HANDLE_MULTIBYTE)
5103 # ifdef INCLUDE_UNUSED
5104 static unsigned char *
5105 mb_getcharlens (string, len)
5106 char *string;
5107 int len;
5108 {
5109 int i, offset, last;
5110 unsigned char *ret;
5111 char *p;
5112 DECLARE_MBSTATE;
5113
5114 i = offset = 0;
5115 last = 0;
5116 ret = (unsigned char *)xmalloc (len);
5117 memset (ret, 0, len);
5118 while (string[last])
5119 {
5120 ADVANCE_CHAR (string, len, offset);
5121 ret[last] = offset - last;
5122 last = offset;
5123 }
5124 return ret;
5125 }
5126 # endif
5127 #endif
5128
5129 /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
5130 can have one of 4 values:
5131 RP_LONG_LEFT remove longest matching portion at start of PARAM
5132 RP_SHORT_LEFT remove shortest matching portion at start of PARAM
5133 RP_LONG_RIGHT remove longest matching portion at end of PARAM
5134 RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
5135 */
5136
5137 #define RP_LONG_LEFT 1
5138 #define RP_SHORT_LEFT 2
5139 #define RP_LONG_RIGHT 3
5140 #define RP_SHORT_RIGHT 4
5141
5142 /* Returns its first argument if nothing matched; new memory otherwise */
5143 static char *
5144 remove_upattern (param, pattern, op)
5145 char *param, *pattern;
5146 int op;
5147 {
5148 register size_t len;
5149 register char *end;
5150 register char *p, *ret, c;
5151
5152 len = STRLEN (param);
5153 end = param + len;
5154
5155 switch (op)
5156 {
5157 case RP_LONG_LEFT: /* remove longest match at start */
5158 for (p = end; p >= param; p--)
5159 {
5160 c = *p; *p = '\0';
5161 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5162 {
5163 *p = c;
5164 return (savestring (p));
5165 }
5166 *p = c;
5167
5168 }
5169 break;
5170
5171 case RP_SHORT_LEFT: /* remove shortest match at start */
5172 for (p = param; p <= end; p++)
5173 {
5174 c = *p; *p = '\0';
5175 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5176 {
5177 *p = c;
5178 return (savestring (p));
5179 }
5180 *p = c;
5181 }
5182 break;
5183
5184 case RP_LONG_RIGHT: /* remove longest match at end */
5185 for (p = param; p <= end; p++)
5186 {
5187 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5188 {
5189 c = *p; *p = '\0';
5190 ret = savestring (param);
5191 *p = c;
5192 return (ret);
5193 }
5194 }
5195 break;
5196
5197 case RP_SHORT_RIGHT: /* remove shortest match at end */
5198 for (p = end; p >= param; p--)
5199 {
5200 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5201 {
5202 c = *p; *p = '\0';
5203 ret = savestring (param);
5204 *p = c;
5205 return (ret);
5206 }
5207 }
5208 break;
5209 }
5210
5211 return (param); /* no match, return original string */
5212 }
5213
5214 #if defined (HANDLE_MULTIBYTE)
5215 /* Returns its first argument if nothing matched; new memory otherwise */
5216 static wchar_t *
5217 remove_wpattern (wparam, wstrlen, wpattern, op)
5218 wchar_t *wparam;
5219 size_t wstrlen;
5220 wchar_t *wpattern;
5221 int op;
5222 {
5223 wchar_t wc, *ret;
5224 int n;
5225
5226 switch (op)
5227 {
5228 case RP_LONG_LEFT: /* remove longest match at start */
5229 for (n = wstrlen; n >= 0; n--)
5230 {
5231 wc = wparam[n]; wparam[n] = L'\0';
5232 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5233 {
5234 wparam[n] = wc;
5235 return (wcsdup (wparam + n));
5236 }
5237 wparam[n] = wc;
5238 }
5239 break;
5240
5241 case RP_SHORT_LEFT: /* remove shortest match at start */
5242 for (n = 0; n <= wstrlen; n++)
5243 {
5244 wc = wparam[n]; wparam[n] = L'\0';
5245 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5246 {
5247 wparam[n] = wc;
5248 return (wcsdup (wparam + n));
5249 }
5250 wparam[n] = wc;
5251 }
5252 break;
5253
5254 case RP_LONG_RIGHT: /* remove longest match at end */
5255 for (n = 0; n <= wstrlen; n++)
5256 {
5257 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5258 {
5259 wc = wparam[n]; wparam[n] = L'\0';
5260 ret = wcsdup (wparam);
5261 wparam[n] = wc;
5262 return (ret);
5263 }
5264 }
5265 break;
5266
5267 case RP_SHORT_RIGHT: /* remove shortest match at end */
5268 for (n = wstrlen; n >= 0; n--)
5269 {
5270 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5271 {
5272 wc = wparam[n]; wparam[n] = L'\0';
5273 ret = wcsdup (wparam);
5274 wparam[n] = wc;
5275 return (ret);
5276 }
5277 }
5278 break;
5279 }
5280
5281 return (wparam); /* no match, return original string */
5282 }
5283 #endif /* HANDLE_MULTIBYTE */
5284
5285 static char *
5286 remove_pattern (param, pattern, op)
5287 char *param, *pattern;
5288 int op;
5289 {
5290 char *xret;
5291
5292 if (param == NULL)
5293 return (param);
5294 if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
5295 return (savestring (param));
5296
5297 #if defined (HANDLE_MULTIBYTE)
5298 if (MB_CUR_MAX > 1)
5299 {
5300 wchar_t *ret, *oret;
5301 size_t n;
5302 wchar_t *wparam, *wpattern;
5303 mbstate_t ps;
5304
5305 /* XXX - could optimize here by checking param and pattern for multibyte
5306 chars with mbsmbchar and calling remove_upattern. */
5307
5308 n = xdupmbstowcs (&wpattern, NULL, pattern);
5309 if (n == (size_t)-1)
5310 {
5311 xret = remove_upattern (param, pattern, op);
5312 return ((xret == param) ? savestring (param) : xret);
5313 }
5314 n = xdupmbstowcs (&wparam, NULL, param);
5315
5316 if (n == (size_t)-1)
5317 {
5318 free (wpattern);
5319 xret = remove_upattern (param, pattern, op);
5320 return ((xret == param) ? savestring (param) : xret);
5321 }
5322 oret = ret = remove_wpattern (wparam, n, wpattern, op);
5323 /* Don't bother to convert wparam back to multibyte string if nothing
5324 matched; just return copy of original string */
5325 if (ret == wparam)
5326 {
5327 free (wparam);
5328 free (wpattern);
5329 return (savestring (param));
5330 }
5331
5332 free (wparam);
5333 free (wpattern);
5334
5335 n = strlen (param);
5336 xret = (char *)xmalloc (n + 1);
5337 memset (&ps, '\0', sizeof (mbstate_t));
5338 n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
5339 xret[n] = '\0'; /* just to make sure */
5340 free (oret);
5341 return xret;
5342 }
5343 else
5344 #endif
5345 {
5346 xret = remove_upattern (param, pattern, op);
5347 return ((xret == param) ? savestring (param) : xret);
5348 }
5349 }
5350
5351 /* Match PAT anywhere in STRING and return the match boundaries.
5352 This returns 1 in case of a successful match, 0 otherwise. SP
5353 and EP are pointers into the string where the match begins and
5354 ends, respectively. MTYPE controls what kind of match is attempted.
5355 MATCH_BEG and MATCH_END anchor the match at the beginning and end
5356 of the string, respectively. The longest match is returned. */
5357 static int
5358 match_upattern (string, pat, mtype, sp, ep)
5359 char *string, *pat;
5360 int mtype;
5361 char **sp, **ep;
5362 {
5363 int c, mlen;
5364 size_t len;
5365 register char *p, *p1, *npat;
5366 char *end;
5367
5368 /* If the pattern doesn't match anywhere in the string, go ahead and
5369 short-circuit right away. A minor optimization, saves a bunch of
5370 unnecessary calls to strmatch (up to N calls for a string of N
5371 characters) if the match is unsuccessful. To preserve the semantics
5372 of the substring matches below, we make sure that the pattern has
5373 `*' as first and last character, making a new pattern if necessary. */
5374 /* XXX - check this later if I ever implement `**' with special meaning,
5375 since this will potentially result in `**' at the beginning or end */
5376 len = STRLEN (pat);
5377 if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
5378 {
5379 int unescaped_backslash;
5380 char *pp;
5381
5382 p = npat = (char *)xmalloc (len + 3);
5383 p1 = pat;
5384 if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob)))
5385 *p++ = '*';
5386 while (*p1)
5387 *p++ = *p1++;
5388 #if 1
5389 /* Need to also handle a pattern that ends with an unescaped backslash.
5390 For right now, we ignore it because the pattern matching code will
5391 fail the match anyway */
5392 /* If the pattern ends with a `*' we leave it alone if it's preceded by
5393 an even number of backslashes, but if it's escaped by a backslash
5394 we need to add another `*'. */
5395 if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\')))
5396 {
5397 pp = p1 - 3;
5398 while (pp >= pat && *pp-- == '\\')
5399 unescaped_backslash = 1 - unescaped_backslash;
5400 if (unescaped_backslash)
5401 *p++ = '*';
5402 }
5403 else if (mtype != MATCH_END && p1[-1] != '*')
5404 *p++ = '*';
5405 #else
5406 if (p1[-1] != '*' || p1[-2] == '\\')
5407 *p++ = '*';
5408 #endif
5409 *p = '\0';
5410 }
5411 else
5412 npat = pat;
5413 c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
5414 if (npat != pat)
5415 free (npat);
5416 if (c == FNM_NOMATCH)
5417 return (0);
5418
5419 len = STRLEN (string);
5420 end = string + len;
5421
5422 mlen = umatchlen (pat, len);
5423 if (mlen > (int)len)
5424 return (0);
5425
5426 switch (mtype)
5427 {
5428 case MATCH_ANY:
5429 for (p = string; p <= end; p++)
5430 {
5431 if (match_pattern_char (pat, p, FNMATCH_IGNCASE))
5432 {
5433 p1 = (mlen == -1) ? end : p + mlen;
5434 /* p1 - p = length of portion of string to be considered
5435 p = current position in string
5436 mlen = number of characters consumed by match (-1 for entire string)
5437 end = end of string
5438 we want to break immediately if the potential match len
5439 is greater than the number of characters remaining in the
5440 string
5441 */
5442 if (p1 > end)
5443 break;
5444 for ( ; p1 >= p; p1--)
5445 {
5446 c = *p1; *p1 = '\0';
5447 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5448 {
5449 *p1 = c;
5450 *sp = p;
5451 *ep = p1;
5452 return 1;
5453 }
5454 *p1 = c;
5455 #if 1
5456 /* If MLEN != -1, we have a fixed length pattern. */
5457 if (mlen != -1)
5458 break;
5459 #endif
5460 }
5461 }
5462 }
5463
5464 return (0);
5465
5466 case MATCH_BEG:
5467 if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0)
5468 return (0);
5469
5470 for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
5471 {
5472 c = *p; *p = '\0';
5473 if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5474 {
5475 *p = c;
5476 *sp = string;
5477 *ep = p;
5478 return 1;
5479 }
5480 *p = c;
5481 /* If MLEN != -1, we have a fixed length pattern. */
5482 if (mlen != -1)
5483 break;
5484 }
5485
5486 return (0);
5487
5488 case MATCH_END:
5489 for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
5490 {
5491 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5492 {
5493 *sp = p;
5494 *ep = end;
5495 return 1;
5496 }
5497 /* If MLEN != -1, we have a fixed length pattern. */
5498 if (mlen != -1)
5499 break;
5500 }
5501
5502 return (0);
5503 }
5504
5505 return (0);
5506 }
5507
5508 #if defined (HANDLE_MULTIBYTE)
5509
5510 #define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c))
5511
5512 /* Match WPAT anywhere in WSTRING and return the match boundaries.
5513 This returns 1 in case of a successful match, 0 otherwise. Wide
5514 character version. */
5515 static int
5516 match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
5517 wchar_t *wstring;
5518 char **indices;
5519 size_t wstrlen;
5520 wchar_t *wpat;
5521 int mtype;
5522 char **sp, **ep;
5523 {
5524 wchar_t wc, *wp, *nwpat, *wp1;
5525 size_t len;
5526 int mlen;
5527 int n, n1, n2, simple;
5528
5529 simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
5530 #if defined (EXTENDED_GLOB)
5531 if (extended_glob)
5532 simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
5533 #endif
5534
5535 /* If the pattern doesn't match anywhere in the string, go ahead and
5536 short-circuit right away. A minor optimization, saves a bunch of
5537 unnecessary calls to strmatch (up to N calls for a string of N
5538 characters) if the match is unsuccessful. To preserve the semantics
5539 of the substring matches below, we make sure that the pattern has
5540 `*' as first and last character, making a new pattern if necessary. */
5541 len = wcslen (wpat);
5542 if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
5543 {
5544 int unescaped_backslash;
5545 wchar_t *wpp;
5546
5547 wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
5548 wp1 = wpat;
5549 if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
5550 *wp++ = L'*';
5551 while (*wp1 != L'\0')
5552 *wp++ = *wp1++;
5553 #if 1
5554 /* See comments above in match_upattern. */
5555 if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\'))
5556 {
5557 wpp = wp1 - 3;
5558 while (wpp >= wpat && *wpp-- == L'\\')
5559 unescaped_backslash = 1 - unescaped_backslash;
5560 if (unescaped_backslash)
5561 *wp++ = L'*';
5562 }
5563 else if (wp1[-1] != L'*')
5564 *wp++ = L'*';
5565 #else
5566 if (wp1[-1] != L'*' || wp1[-2] == L'\\')
5567 *wp++ = L'*';
5568 #endif
5569 *wp = '\0';
5570 }
5571 else
5572 nwpat = wpat;
5573 len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
5574 if (nwpat != wpat)
5575 free (nwpat);
5576 if (len == FNM_NOMATCH)
5577 return (0);
5578
5579 mlen = wmatchlen (wpat, wstrlen);
5580 if (mlen > (int)wstrlen)
5581 return (0);
5582
5583 /* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
5584 switch (mtype)
5585 {
5586 case MATCH_ANY:
5587 for (n = 0; n <= wstrlen; n++)
5588 {
5589 n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE);
5590 if (n2)
5591 {
5592 n1 = (mlen == -1) ? wstrlen : n + mlen;
5593 if (n1 > wstrlen)
5594 break;
5595
5596 for ( ; n1 >= n; n1--)
5597 {
5598 wc = wstring[n1]; wstring[n1] = L'\0';
5599 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5600 {
5601 wstring[n1] = wc;
5602 *sp = indices[n];
5603 *ep = indices[n1];
5604 return 1;
5605 }
5606 wstring[n1] = wc;
5607 /* If MLEN != -1, we have a fixed length pattern. */
5608 if (mlen != -1)
5609 break;
5610 }
5611 }
5612 }
5613
5614 return (0);
5615
5616 case MATCH_BEG:
5617 if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0)
5618 return (0);
5619
5620 for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
5621 {
5622 wc = wstring[n]; wstring[n] = L'\0';
5623 if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5624 {
5625 wstring[n] = wc;
5626 *sp = indices[0];
5627 *ep = indices[n];
5628 return 1;
5629 }
5630 wstring[n] = wc;
5631 /* If MLEN != -1, we have a fixed length pattern. */
5632 if (mlen != -1)
5633 break;
5634 }
5635
5636 return (0);
5637
5638 case MATCH_END:
5639 for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
5640 {
5641 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5642 {
5643 *sp = indices[n];
5644 *ep = indices[wstrlen];
5645 return 1;
5646 }
5647 /* If MLEN != -1, we have a fixed length pattern. */
5648 if (mlen != -1)
5649 break;
5650 }
5651
5652 return (0);
5653 }
5654
5655 return (0);
5656 }
5657 #undef WFOLD
5658 #endif /* HANDLE_MULTIBYTE */
5659
5660 static int
5661 match_pattern (string, pat, mtype, sp, ep)
5662 char *string, *pat;
5663 int mtype;
5664 char **sp, **ep;
5665 {
5666 #if defined (HANDLE_MULTIBYTE)
5667 int ret;
5668 size_t n;
5669 wchar_t *wstring, *wpat;
5670 char **indices;
5671 #endif
5672
5673 if (string == 0 || pat == 0 || *pat == 0)
5674 return (0);
5675
5676 #if defined (HANDLE_MULTIBYTE)
5677 if (MB_CUR_MAX > 1)
5678 {
5679 if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
5680 return (match_upattern (string, pat, mtype, sp, ep));
5681
5682 n = xdupmbstowcs (&wpat, NULL, pat);
5683 if (n == (size_t)-1)
5684 return (match_upattern (string, pat, mtype, sp, ep));
5685 n = xdupmbstowcs (&wstring, &indices, string);
5686 if (n == (size_t)-1)
5687 {
5688 free (wpat);
5689 return (match_upattern (string, pat, mtype, sp, ep));
5690 }
5691 ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
5692
5693 free (wpat);
5694 free (wstring);
5695 free (indices);
5696
5697 return (ret);
5698 }
5699 else
5700 #endif
5701 return (match_upattern (string, pat, mtype, sp, ep));
5702 }
5703
5704 static int
5705 getpatspec (c, value)
5706 int c;
5707 char *value;
5708 {
5709 if (c == '#')
5710 return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
5711 else /* c == '%' */
5712 return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
5713 }
5714
5715 /* Posix.2 says that the WORD should be run through tilde expansion,
5716 parameter expansion, command substitution and arithmetic expansion.
5717 This leaves the result quoted, so quote_string_for_globbing () has
5718 to be called to fix it up for strmatch (). If QUOTED is non-zero,
5719 it means that the entire expression was enclosed in double quotes.
5720 This means that quoting characters in the pattern do not make any
5721 special pattern characters quoted. For example, the `*' in the
5722 following retains its special meaning: "${foo#'*'}". */
5723 static char *
5724 getpattern (value, quoted, expandpat)
5725 char *value;
5726 int quoted, expandpat;
5727 {
5728 char *pat, *tword;
5729 WORD_LIST *l;
5730 #if 0
5731 int i;
5732 #endif
5733 /* There is a problem here: how to handle single or double quotes in the
5734 pattern string when the whole expression is between double quotes?
5735 POSIX.2 says that enclosing double quotes do not cause the pattern to
5736 be quoted, but does that leave us a problem with @ and array[@] and their
5737 expansions inside a pattern? */
5738 #if 0
5739 if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
5740 {
5741 i = 0;
5742 pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ);
5743 free (tword);
5744 tword = pat;
5745 }
5746 #endif
5747
5748 /* expand_string_for_pat () leaves WORD quoted and does not perform
5749 word splitting. */
5750 l = *value ? expand_string_for_pat (value,
5751 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
5752 (int *)NULL, (int *)NULL)
5753 : (WORD_LIST *)0;
5754 if (l)
5755 word_list_remove_quoted_nulls (l);
5756 pat = string_list (l);
5757 dispose_words (l);
5758 if (pat)
5759 {
5760 tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
5761 free (pat);
5762 pat = tword;
5763 }
5764 return (pat);
5765 }
5766
5767 #if 0
5768 /* Handle removing a pattern from a string as a result of ${name%[%]value}
5769 or ${name#[#]value}. */
5770 static char *
5771 variable_remove_pattern (value, pattern, patspec, quoted)
5772 char *value, *pattern;
5773 int patspec, quoted;
5774 {
5775 char *tword;
5776
5777 tword = remove_pattern (value, pattern, patspec);
5778
5779 return (tword);
5780 }
5781 #endif
5782
5783 static char *
5784 list_remove_pattern (list, pattern, patspec, itype, quoted)
5785 WORD_LIST *list;
5786 char *pattern;
5787 int patspec, itype, quoted;
5788 {
5789 WORD_LIST *new, *l;
5790 WORD_DESC *w;
5791 char *tword;
5792
5793 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
5794 {
5795 tword = remove_pattern (l->word->word, pattern, patspec);
5796 w = alloc_word_desc ();
5797 w->word = tword ? tword : savestring ("");
5798 new = make_word_list (w, new);
5799 }
5800
5801 l = REVERSE_LIST (new, WORD_LIST *);
5802 tword = string_list_pos_params (itype, l, quoted, 0);
5803 dispose_words (l);
5804
5805 return (tword);
5806 }
5807
5808 static char *
5809 parameter_list_remove_pattern (itype, pattern, patspec, quoted)
5810 int itype;
5811 char *pattern;
5812 int patspec, quoted;
5813 {
5814 char *ret;
5815 WORD_LIST *list;
5816
5817 list = list_rest_of_args ();
5818 if (list == 0)
5819 return ((char *)NULL);
5820 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5821 dispose_words (list);
5822 return (ret);
5823 }
5824
5825 #if defined (ARRAY_VARS)
5826 static char *
5827 array_remove_pattern (var, pattern, patspec, starsub, quoted)
5828 SHELL_VAR *var;
5829 char *pattern;
5830 int patspec;
5831 int starsub; /* so we can figure out how it's indexed */
5832 int quoted;
5833 {
5834 ARRAY *a;
5835 HASH_TABLE *h;
5836 int itype;
5837 char *ret;
5838 WORD_LIST *list;
5839 SHELL_VAR *v;
5840
5841 v = var; /* XXX - for now */
5842
5843 itype = starsub ? '*' : '@';
5844
5845 a = (v && array_p (v)) ? array_cell (v) : 0;
5846 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
5847
5848 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
5849 if (list == 0)
5850 return ((char *)NULL);
5851 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5852 dispose_words (list);
5853
5854 return ret;
5855 }
5856 #endif /* ARRAY_VARS */
5857
5858 static char *
5859 parameter_brace_remove_pattern (varname, value, estatep, patstr, rtype, quoted, flags)
5860 char *varname, *value;
5861 array_eltstate_t *estatep;
5862 char *patstr;
5863 int rtype, quoted, flags;
5864 {
5865 int vtype, patspec, starsub;
5866 char *temp1, *val, *pattern, *oname;
5867 SHELL_VAR *v;
5868
5869 if (value == 0)
5870 return ((char *)NULL);
5871
5872 oname = this_command_name;
5873 this_command_name = varname;
5874
5875 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
5876 if (vtype == -1)
5877 {
5878 this_command_name = oname;
5879 return ((char *)NULL);
5880 }
5881
5882 starsub = vtype & VT_STARSUB;
5883 vtype &= ~VT_STARSUB;
5884
5885 patspec = getpatspec (rtype, patstr);
5886 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
5887 patstr++;
5888
5889 /* Need to pass getpattern newly-allocated memory in case of expansion --
5890 the expansion code will free the passed string on an error. */
5891 temp1 = savestring (patstr);
5892 pattern = getpattern (temp1, quoted, 1);
5893 free (temp1);
5894
5895 temp1 = (char *)NULL; /* shut up gcc */
5896 switch (vtype)
5897 {
5898 case VT_VARIABLE:
5899 case VT_ARRAYMEMBER:
5900 temp1 = remove_pattern (val, pattern, patspec);
5901 if (vtype == VT_VARIABLE)
5902 FREE (val);
5903 if (temp1)
5904 {
5905 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5906 ? quote_string (temp1)
5907 : quote_escapes (temp1);
5908 free (temp1);
5909 temp1 = val;
5910 }
5911 break;
5912 #if defined (ARRAY_VARS)
5913 case VT_ARRAYVAR:
5914 temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted);
5915 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5916 {
5917 val = quote_escapes (temp1);
5918 free (temp1);
5919 temp1 = val;
5920 }
5921 break;
5922 #endif
5923 case VT_POSPARMS:
5924 temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
5925 if (temp1 && quoted == 0 && ifs_is_null)
5926 {
5927 /* Posix interp 888 */
5928 }
5929 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5930 {
5931 val = quote_escapes (temp1);
5932 free (temp1);
5933 temp1 = val;
5934 }
5935 break;
5936 }
5937
5938 this_command_name = oname;
5939
5940 FREE (pattern);
5941 return temp1;
5942 }
5943
5944 #if defined (PROCESS_SUBSTITUTION)
5945
5946 static void reap_some_procsubs PARAMS((int));
5947
5948 /*****************************************************************/
5949 /* */
5950 /* Hacking Process Substitution */
5951 /* */
5952 /*****************************************************************/
5953
5954 #if !defined (HAVE_DEV_FD)
5955 /* Named pipes must be removed explicitly with `unlink'. This keeps a list
5956 of FIFOs the shell has open. unlink_fifo_list will walk the list and
5957 unlink the ones that don't have a living process on the other end.
5958 unlink_all_fifos will walk the list and unconditionally unlink them, trying
5959 to open and close the FIFO first to release any child processes sleeping on
5960 the FIFO. add_fifo_list adds the name of an open FIFO to the list.
5961 NFIFO is a count of the number of FIFOs in the list. */
5962 #define FIFO_INCR 20
5963
5964 /* PROC value of -1 means the process has been reaped and the FIFO needs to
5965 be removed. PROC value of 0 means the slot is unused. */
5966 struct temp_fifo {
5967 char *file;
5968 pid_t proc;
5969 };
5970
5971 static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
5972 static int nfifo;
5973 static int fifo_list_size;
5974
5975 void
5976 clear_fifo_list ()
5977 {
5978 int i;
5979
5980 for (i = 0; i < fifo_list_size; i++)
5981 {
5982 if (fifo_list[i].file)
5983 free (fifo_list[i].file);
5984 fifo_list[i].file = NULL;
5985 fifo_list[i].proc = 0;
5986 }
5987 nfifo = 0;
5988 }
5989
5990 void *
5991 copy_fifo_list (sizep)
5992 int *sizep;
5993 {
5994 if (sizep)
5995 *sizep = 0;
5996 return (void *)NULL;
5997 }
5998
5999 static void
6000 add_fifo_list (pathname)
6001 char *pathname;
6002 {
6003 int osize, i;
6004
6005 if (nfifo >= fifo_list_size - 1)
6006 {
6007 osize = fifo_list_size;
6008 fifo_list_size += FIFO_INCR;
6009 fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
6010 fifo_list_size * sizeof (struct temp_fifo));
6011 for (i = osize; i < fifo_list_size; i++)
6012 {
6013 fifo_list[i].file = (char *)NULL;
6014 fifo_list[i].proc = 0; /* unused */
6015 }
6016 }
6017
6018 fifo_list[nfifo].file = savestring (pathname);
6019 nfifo++;
6020 }
6021
6022 void
6023 unlink_fifo (i)
6024 int i;
6025 {
6026 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
6027 {
6028 unlink (fifo_list[i].file);
6029 free (fifo_list[i].file);
6030 fifo_list[i].file = (char *)NULL;
6031 fifo_list[i].proc = 0;
6032 }
6033 }
6034
6035 void
6036 unlink_fifo_list ()
6037 {
6038 int saved, i, j;
6039
6040 if (nfifo == 0)
6041 return;
6042
6043 for (i = saved = 0; i < nfifo; i++)
6044 {
6045 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
6046 {
6047 unlink (fifo_list[i].file);
6048 free (fifo_list[i].file);
6049 fifo_list[i].file = (char *)NULL;
6050 fifo_list[i].proc = 0;
6051 }
6052 else
6053 saved++;
6054 }
6055
6056 /* If we didn't remove some of the FIFOs, compact the list. */
6057 if (saved)
6058 {
6059 for (i = j = 0; i < nfifo; i++)
6060 if (fifo_list[i].file)
6061 {
6062 if (i != j)
6063 {
6064 fifo_list[j].file = fifo_list[i].file;
6065 fifo_list[j].proc = fifo_list[i].proc;
6066 fifo_list[i].file = (char *)NULL;
6067 fifo_list[i].proc = 0;
6068 }
6069 j++;
6070 }
6071 nfifo = j;
6072 }
6073 else
6074 nfifo = 0;
6075 }
6076
6077 void
6078 unlink_all_fifos ()
6079 {
6080 int i, fd;
6081
6082 if (nfifo == 0)
6083 return;
6084
6085 for (i = 0; i < nfifo; i++)
6086 {
6087 fifo_list[i].proc = (pid_t)-1;
6088 #if defined (O_NONBLOCK)
6089 fd = open (fifo_list[i].file, O_RDWR|O_NONBLOCK);
6090 #else
6091 fd = -1;
6092 #endif
6093 unlink_fifo (i);
6094 if (fd >= 0)
6095 close (fd);
6096 }
6097
6098 nfifo = 0;
6099 }
6100
6101 /* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
6102 from some point in the past, and close all open FIFOs in fifo_list
6103 that are not marked as active in LIST. If LIST is NULL, close
6104 everything in fifo_list. LSIZE is the number of elements in LIST, in
6105 case it's larger than fifo_list_size (size of fifo_list). */
6106 void
6107 close_new_fifos (list, lsize)
6108 void *list;
6109 int lsize;
6110 {
6111 int i;
6112 char *plist;
6113
6114 if (list == 0)
6115 {
6116 unlink_fifo_list ();
6117 return;
6118 }
6119
6120 for (plist = (char *)list, i = 0; i < lsize; i++)
6121 if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
6122 unlink_fifo (i);
6123
6124 for (i = lsize; i < fifo_list_size; i++)
6125 unlink_fifo (i);
6126 }
6127
6128 int
6129 find_procsub_child (pid)
6130 pid_t pid;
6131 {
6132 int i;
6133
6134 for (i = 0; i < nfifo; i++)
6135 if (fifo_list[i].proc == pid)
6136 return i;
6137 return -1;
6138 }
6139
6140 void
6141 set_procsub_status (ind, pid, status)
6142 int ind;
6143 pid_t pid;
6144 int status;
6145 {
6146 if (ind >= 0 && ind < nfifo)
6147 fifo_list[ind].proc = (pid_t)-1; /* sentinel */
6148 }
6149
6150 /* If we've marked the process for this procsub as dead, close the
6151 associated file descriptor and delete the FIFO. */
6152 static void
6153 reap_some_procsubs (max)
6154 int max;
6155 {
6156 int i;
6157
6158 for (i = 0; i < max; i++)
6159 if (fifo_list[i].proc == (pid_t)-1) /* reaped */
6160 unlink_fifo (i);
6161 }
6162
6163 void
6164 reap_procsubs ()
6165 {
6166 reap_some_procsubs (nfifo);
6167 }
6168
6169 #if 0
6170 /* UNUSED */
6171 void
6172 wait_procsubs ()
6173 {
6174 int i, r;
6175
6176 for (i = 0; i < nfifo; i++)
6177 {
6178 if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0)
6179 {
6180 r = wait_for (fifo_list[i].proc, 0);
6181 save_proc_status (fifo_list[i].proc, r);
6182 fifo_list[i].proc = (pid_t)-1;
6183 }
6184 }
6185 }
6186 #endif
6187
6188 int
6189 fifos_pending ()
6190 {
6191 return nfifo;
6192 }
6193
6194 int
6195 num_fifos ()
6196 {
6197 return nfifo;
6198 }
6199
6200 static char *
6201 make_named_pipe ()
6202 {
6203 char *tname;
6204
6205 tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
6206 if (mkfifo (tname, 0600) < 0)
6207 {
6208 free (tname);
6209 return ((char *)NULL);
6210 }
6211
6212 add_fifo_list (tname);
6213 return (tname);
6214 }
6215
6216 #else /* HAVE_DEV_FD */
6217
6218 /* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
6219 has open to children. NFDS is a count of the number of bits currently
6220 set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
6221 of open files. */
6222 /* dev_fd_list[I] value of -1 means the process has been reaped and file
6223 descriptor I needs to be closed. Value of 0 means the slot is unused. */
6224
6225 static pid_t *dev_fd_list = (pid_t *)NULL;
6226 static int nfds;
6227 static int totfds; /* The highest possible number of open files. */
6228
6229 void
6230 clear_fifo (i)
6231 int i;
6232 {
6233 if (dev_fd_list[i])
6234 {
6235 dev_fd_list[i] = 0;
6236 nfds--;
6237 }
6238 }
6239
6240 void
6241 clear_fifo_list ()
6242 {
6243 register int i;
6244
6245 if (nfds == 0)
6246 return;
6247
6248 for (i = 0; nfds && i < totfds; i++)
6249 clear_fifo (i);
6250
6251 nfds = 0;
6252 }
6253
6254 void *
6255 copy_fifo_list (sizep)
6256 int *sizep;
6257 {
6258 void *ret;
6259
6260 if (nfds == 0 || totfds == 0)
6261 {
6262 if (sizep)
6263 *sizep = 0;
6264 return (void *)NULL;
6265 }
6266
6267 if (sizep)
6268 *sizep = totfds;
6269 ret = xmalloc (totfds * sizeof (pid_t));
6270 return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t)));
6271 }
6272
6273 static void
6274 add_fifo_list (fd)
6275 int fd;
6276 {
6277 if (dev_fd_list == 0 || fd >= totfds)
6278 {
6279 int ofds;
6280
6281 ofds = totfds;
6282 totfds = getdtablesize ();
6283 if (totfds < 0 || totfds > 256)
6284 totfds = 256;
6285 if (fd >= totfds)
6286 totfds = fd + 2;
6287
6288 dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0]));
6289 /* XXX - might need a loop for this */
6290 memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t));
6291 }
6292
6293 dev_fd_list[fd] = 1; /* marker; updated later */
6294 nfds++;
6295 }
6296
6297 int
6298 fifos_pending ()
6299 {
6300 return 0; /* used for cleanup; not needed with /dev/fd */
6301 }
6302
6303 int
6304 num_fifos ()
6305 {
6306 return nfds;
6307 }
6308
6309 void
6310 unlink_fifo (fd)
6311 int fd;
6312 {
6313 if (dev_fd_list[fd])
6314 {
6315 close (fd);
6316 dev_fd_list[fd] = 0;
6317 nfds--;
6318 }
6319 }
6320
6321 void
6322 unlink_fifo_list ()
6323 {
6324 register int i;
6325
6326 if (nfds == 0)
6327 return;
6328
6329 for (i = totfds-1; nfds && i >= 0; i--)
6330 unlink_fifo (i);
6331
6332 nfds = 0;
6333 }
6334
6335 void
6336 unlink_all_fifos ()
6337 {
6338 unlink_fifo_list ();
6339 }
6340
6341 /* Take LIST, which is a snapshot copy of dev_fd_list from some point in
6342 the past, and close all open fds in dev_fd_list that are not marked
6343 as open in LIST. If LIST is NULL, close everything in dev_fd_list.
6344 LSIZE is the number of elements in LIST, in case it's larger than
6345 totfds (size of dev_fd_list). */
6346 void
6347 close_new_fifos (list, lsize)
6348 void *list;
6349 int lsize;
6350 {
6351 int i;
6352 pid_t *plist;
6353
6354 if (list == 0)
6355 {
6356 unlink_fifo_list ();
6357 return;
6358 }
6359
6360 for (plist = (pid_t *)list, i = 0; i < lsize; i++)
6361 if (plist[i] == 0 && i < totfds && dev_fd_list[i])
6362 unlink_fifo (i);
6363
6364 for (i = lsize; i < totfds; i++)
6365 unlink_fifo (i);
6366 }
6367
6368 int
6369 find_procsub_child (pid)
6370 pid_t pid;
6371 {
6372 int i;
6373
6374 if (nfds == 0)
6375 return -1;
6376
6377 for (i = 0; i < totfds; i++)
6378 if (dev_fd_list[i] == pid)
6379 return i;
6380
6381 return -1;
6382 }
6383
6384 void
6385 set_procsub_status (ind, pid, status)
6386 int ind;
6387 pid_t pid;
6388 int status;
6389 {
6390 if (ind >= 0 && ind < totfds)
6391 dev_fd_list[ind] = (pid_t)-1; /* sentinel */
6392 }
6393
6394 /* If we've marked the process for this procsub as dead, close the
6395 associated file descriptor. */
6396 static void
6397 reap_some_procsubs (max)
6398 int max;
6399 {
6400 int i;
6401
6402 for (i = 0; nfds > 0 && i < max; i++)
6403 if (dev_fd_list[i] == (pid_t)-1)
6404 unlink_fifo (i);
6405 }
6406
6407 void
6408 reap_procsubs ()
6409 {
6410 reap_some_procsubs (totfds);
6411 }
6412
6413 #if 0
6414 /* UNUSED */
6415 void
6416 wait_procsubs ()
6417 {
6418 int i, r;
6419
6420 for (i = 0; nfds > 0 && i < totfds; i++)
6421 {
6422 if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0)
6423 {
6424 r = wait_for (dev_fd_list[i], 0);
6425 save_proc_status (dev_fd_list[i], r);
6426 dev_fd_list[i] = (pid_t)-1;
6427 }
6428 }
6429 }
6430 #endif
6431
6432 #if defined (NOTDEF)
6433 print_dev_fd_list ()
6434 {
6435 register int i;
6436
6437 fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
6438 fflush (stderr);
6439
6440 for (i = 0; i < totfds; i++)
6441 {
6442 if (dev_fd_list[i])
6443 fprintf (stderr, " %d", i);
6444 }
6445 fprintf (stderr, "\n");
6446 }
6447 #endif /* NOTDEF */
6448
6449 static char *
6450 make_dev_fd_filename (fd)
6451 int fd;
6452 {
6453 char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
6454
6455 ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
6456
6457 strcpy (ret, DEV_FD_PREFIX);
6458 p = inttostr (fd, intbuf, sizeof (intbuf));
6459 strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
6460
6461 add_fifo_list (fd);
6462 return (ret);
6463 }
6464
6465 #endif /* HAVE_DEV_FD */
6466
6467 /* Return a filename that will open a connection to the process defined by
6468 executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
6469 a filename in /dev/fd corresponding to a descriptor that is one of the
6470 ends of the pipe. If not defined, we use named pipes on systems that have
6471 them. Systems without /dev/fd and named pipes are out of luck.
6472
6473 OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
6474 use the read end of the pipe and dup that file descriptor to fd 0 in
6475 the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
6476 writing or use the write end of the pipe in the child, and dup that
6477 file descriptor to fd 1 in the child. The parent does the opposite. */
6478
6479 static char *
6480 process_substitute (string, open_for_read_in_child)
6481 char *string;
6482 int open_for_read_in_child;
6483 {
6484 char *pathname;
6485 int fd, result, rc, function_value;
6486 pid_t old_pid, pid;
6487 #if defined (HAVE_DEV_FD)
6488 int parent_pipe_fd, child_pipe_fd;
6489 int fildes[2];
6490 #endif /* HAVE_DEV_FD */
6491 #if defined (JOB_CONTROL)
6492 pid_t old_pipeline_pgrp;
6493 #endif
6494
6495 if (!string || !*string || wordexp_only)
6496 return ((char *)NULL);
6497
6498 #if !defined (HAVE_DEV_FD)
6499 pathname = make_named_pipe ();
6500 #else /* HAVE_DEV_FD */
6501 if (pipe (fildes) < 0)
6502 {
6503 sys_error ("%s", _("cannot make pipe for process substitution"));
6504 return ((char *)NULL);
6505 }
6506 /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
6507 the pipe in the parent, otherwise the read end. */
6508 parent_pipe_fd = fildes[open_for_read_in_child];
6509 child_pipe_fd = fildes[1 - open_for_read_in_child];
6510 /* Move the parent end of the pipe to some high file descriptor, to
6511 avoid clashes with FDs used by the script. */
6512 parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
6513
6514 pathname = make_dev_fd_filename (parent_pipe_fd);
6515 #endif /* HAVE_DEV_FD */
6516
6517 if (pathname == 0)
6518 {
6519 sys_error ("%s", _("cannot make pipe for process substitution"));
6520 return ((char *)NULL);
6521 }
6522
6523 old_pid = last_made_pid;
6524
6525 #if defined (JOB_CONTROL)
6526 old_pipeline_pgrp = pipeline_pgrp;
6527 if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0)
6528 pipeline_pgrp = shell_pgrp;
6529 save_pipeline (1);
6530 #endif /* JOB_CONTROL */
6531
6532 pid = make_child ((char *)NULL, FORK_ASYNC);
6533 if (pid == 0)
6534 {
6535 #if 0
6536 int old_interactive;
6537
6538 old_interactive = interactive;
6539 #endif
6540 /* The currently-executing shell is not interactive */
6541 interactive = 0;
6542
6543 reset_terminating_signals (); /* XXX */
6544 free_pushed_string_input ();
6545 /* Cancel traps, in trap.c. */
6546 restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */
6547 subshell_environment &= ~SUBSHELL_IGNTRAP;
6548 QUIT; /* catch any interrupts we got post-fork */
6549 setup_async_signals ();
6550 #if 0
6551 if (open_for_read_in_child == 0 && old_interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))
6552 async_redirect_stdin ();
6553 #endif
6554
6555 subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB|SUBSHELL_ASYNC;
6556
6557 /* We don't inherit the verbose option for command substitutions now, so
6558 let's try it for process substitutions. */
6559 change_flag ('v', FLAG_OFF);
6560
6561 /* if we're expanding a redirection, we shouldn't have access to the
6562 temporary environment, but commands in the subshell should have
6563 access to their own temporary environment. */
6564 if (expanding_redir)
6565 flush_temporary_env ();
6566 }
6567
6568 #if defined (JOB_CONTROL)
6569 set_sigchld_handler ();
6570 stop_making_children ();
6571 /* XXX - should we only do this in the parent? (as in command subst) */
6572 pipeline_pgrp = old_pipeline_pgrp;
6573 #else
6574 stop_making_children ();
6575 #endif /* JOB_CONTROL */
6576
6577 if (pid < 0)
6578 {
6579 sys_error ("%s", _("cannot make child for process substitution"));
6580 free (pathname);
6581 #if defined (HAVE_DEV_FD)
6582 close (parent_pipe_fd);
6583 close (child_pipe_fd);
6584 #endif /* HAVE_DEV_FD */
6585 #if defined (JOB_CONTROL)
6586 restore_pipeline (1);
6587 #endif
6588 return ((char *)NULL);
6589 }
6590
6591 if (pid > 0)
6592 {
6593 #if defined (JOB_CONTROL)
6594 last_procsub_child = restore_pipeline (0);
6595 /* We assume that last_procsub_child->next == last_procsub_child because
6596 of how jobs.c:add_process() works. */
6597 last_procsub_child->next = 0;
6598 procsub_add (last_procsub_child);
6599 #endif
6600
6601 #if defined (HAVE_DEV_FD)
6602 dev_fd_list[parent_pipe_fd] = pid;
6603 #else
6604 fifo_list[nfifo-1].proc = pid;
6605 #endif
6606
6607 last_made_pid = old_pid;
6608
6609 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
6610 close_pgrp_pipe ();
6611 #endif /* JOB_CONTROL && PGRP_PIPE */
6612
6613 #if defined (HAVE_DEV_FD)
6614 close (child_pipe_fd);
6615 #endif /* HAVE_DEV_FD */
6616
6617 return (pathname);
6618 }
6619
6620 set_sigint_handler ();
6621
6622 #if defined (JOB_CONTROL)
6623 /* make sure we don't have any job control */
6624 set_job_control (0);
6625
6626 /* Clear out any existing list of process substitutions */
6627 procsub_clear ();
6628
6629 /* The idea is that we want all the jobs we start from an async process
6630 substitution to be in the same process group, but not the same pgrp
6631 as our parent shell, since we don't want to affect our parent shell's
6632 jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example.
6633 If pipeline_pgrp != shell_pgrp, we assume that there is a job control
6634 shell somewhere in our parent process chain (since make_child initializes
6635 pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this
6636 case is to set pipeline_pgrp to our PID, so all jobs started by this
6637 process have that same pgrp and we are basically the process group leader.
6638 This should not have negative effects on child processes surviving
6639 after we exit, since we wait for the children we create, but that is
6640 something to watch for. */
6641
6642 if (pipeline_pgrp != shell_pgrp)
6643 pipeline_pgrp = getpid ();
6644 #endif /* JOB_CONTROL */
6645
6646 #if !defined (HAVE_DEV_FD)
6647 /* Open the named pipe in the child. */
6648 fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY);
6649 if (fd < 0)
6650 {
6651 /* Two separate strings for ease of translation. */
6652 if (open_for_read_in_child)
6653 sys_error (_("cannot open named pipe %s for reading"), pathname);
6654 else
6655 sys_error (_("cannot open named pipe %s for writing"), pathname);
6656
6657 exit (127);
6658 }
6659 if (open_for_read_in_child)
6660 {
6661 if (sh_unset_nodelay_mode (fd) < 0)
6662 {
6663 sys_error (_("cannot reset nodelay mode for fd %d"), fd);
6664 exit (127);
6665 }
6666 }
6667 #else /* HAVE_DEV_FD */
6668 fd = child_pipe_fd;
6669 #endif /* HAVE_DEV_FD */
6670
6671 /* Discard buffered stdio output before replacing the underlying file
6672 descriptor. */
6673 if (open_for_read_in_child == 0)
6674 fpurge (stdout);
6675
6676 if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
6677 {
6678 sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
6679 open_for_read_in_child ? 0 : 1);
6680 exit (127);
6681 }
6682
6683 if (fd != (open_for_read_in_child ? 0 : 1))
6684 close (fd);
6685
6686 /* Need to close any files that this process has open to pipes inherited
6687 from its parent. */
6688 if (current_fds_to_close)
6689 {
6690 close_fd_bitmap (current_fds_to_close);
6691 current_fds_to_close = (struct fd_bitmap *)NULL;
6692 }
6693
6694 #if defined (HAVE_DEV_FD)
6695 /* Make sure we close the parent's end of the pipe and clear the slot
6696 in the fd list so it is not closed later, if reallocated by, for
6697 instance, pipe(2). */
6698 close (parent_pipe_fd);
6699 dev_fd_list[parent_pipe_fd] = 0;
6700 #endif /* HAVE_DEV_FD */
6701
6702 /* subshells shouldn't have this flag, which controls using the temporary
6703 environment for variable lookups. We have already flushed the temporary
6704 environment above in the case we're expanding a redirection, so processes
6705 executed by this command need to be able to set it independently of their
6706 parent. */
6707 expanding_redir = 0;
6708
6709 remove_quoted_escapes (string);
6710
6711 startup_state = 2; /* see if we can avoid a fork */
6712 parse_and_execute_level = 0;
6713
6714 /* Give process substitution a place to jump back to on failure,
6715 so we don't go back up to main (). */
6716 result = setjmp_nosigs (top_level);
6717
6718 /* If we're running a process substitution inside a shell function,
6719 trap `return' so we don't return from the function in the subshell
6720 and go off to never-never land. */
6721 if (result == 0 && return_catch_flag)
6722 function_value = setjmp_nosigs (return_catch);
6723 else
6724 function_value = 0;
6725
6726 if (result == ERREXIT)
6727 rc = last_command_exit_value;
6728 else if (result == EXITPROG || result == EXITBLTIN)
6729 rc = last_command_exit_value;
6730 else if (result)
6731 rc = EXECUTION_FAILURE;
6732 else if (function_value)
6733 rc = return_catch_value;
6734 else
6735 {
6736 subshell_level++;
6737 rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
6738 /* leave subshell level intact for any exit trap */
6739 }
6740
6741 #if !defined (HAVE_DEV_FD)
6742 /* Make sure we close the named pipe in the child before we exit. */
6743 close (open_for_read_in_child ? 0 : 1);
6744 #endif /* !HAVE_DEV_FD */
6745
6746 last_command_exit_value = rc;
6747 rc = run_exit_trap ();
6748 exit (rc);
6749 /*NOTREACHED*/
6750 }
6751 #endif /* PROCESS_SUBSTITUTION */
6752
6753 /***********************************/
6754 /* */
6755 /* Command Substitution */
6756 /* */
6757 /***********************************/
6758
6759 #define COMSUB_PIPEBUF 4096
6760
6761 static char *
6762 optimize_cat_file (r, quoted, flags, flagp)
6763 REDIRECT *r;
6764 int quoted, flags, *flagp;
6765 {
6766 char *ret;
6767 int fd;
6768
6769 fd = open_redir_file (r, (char **)0);
6770 if (fd < 0)
6771 return &expand_param_error;
6772
6773 ret = read_comsub (fd, quoted, flags, flagp);
6774 close (fd);
6775
6776 return ret;
6777 }
6778
6779 static char *
6780 read_comsub (fd, quoted, flags, rflag)
6781 int fd, quoted, flags;
6782 int *rflag;
6783 {
6784 char *istring, buf[COMSUB_PIPEBUF], *bufp;
6785 int c, tflag, skip_ctlesc, skip_ctlnul;
6786 int mb_cur_max;
6787 size_t istring_index;
6788 size_t istring_size;
6789 ssize_t bufn;
6790 int nullbyte;
6791 #if defined (HANDLE_MULTIBYTE)
6792 mbstate_t ps;
6793 wchar_t wc;
6794 size_t mblen;
6795 int i;
6796 #endif
6797
6798 istring = (char *)NULL;
6799 istring_index = istring_size = bufn = tflag = 0;
6800
6801 skip_ctlesc = ifs_cmap[CTLESC];
6802 skip_ctlnul = ifs_cmap[CTLNUL];
6803
6804 mb_cur_max = MB_CUR_MAX;
6805 nullbyte = 0;
6806
6807 /* Read the output of the command through the pipe. */
6808 while (1)
6809 {
6810 if (fd < 0)
6811 break;
6812 if (--bufn <= 0)
6813 {
6814 bufn = zread (fd, buf, sizeof (buf));
6815 if (bufn <= 0)
6816 break;
6817 bufp = buf;
6818 }
6819 c = *bufp++;
6820
6821 if (c == 0)
6822 {
6823 #if 1
6824 if (nullbyte == 0)
6825 {
6826 internal_warning ("%s", _("command substitution: ignored null byte in input"));
6827 nullbyte = 1;
6828 }
6829 #endif
6830 continue;
6831 }
6832
6833 /* Add the character to ISTRING, possibly after resizing it. */
6834 RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512);
6835
6836 /* This is essentially quote_string inline */
6837 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
6838 istring[istring_index++] = CTLESC;
6839 else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC)
6840 istring[istring_index++] = CTLESC;
6841 /* Escape CTLESC and CTLNUL in the output to protect those characters
6842 from the rest of the word expansions (word splitting and globbing.)
6843 This is essentially quote_escapes inline. */
6844 else if (skip_ctlesc == 0 && c == CTLESC)
6845 istring[istring_index++] = CTLESC;
6846 else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
6847 istring[istring_index++] = CTLESC;
6848
6849 #if defined (HANDLE_MULTIBYTE)
6850 if ((locale_utf8locale && (c & 0x80)) ||
6851 (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127))
6852 {
6853 /* read a multibyte character from buf */
6854 /* punt on the hard case for now */
6855 memset (&ps, '\0', sizeof (mbstate_t));
6856 mblen = mbrtowc (&wc, bufp-1, bufn, &ps);
6857 if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1)
6858 istring[istring_index++] = c;
6859 else
6860 {
6861 istring[istring_index++] = c;
6862 for (i = 0; i < mblen-1; i++)
6863 istring[istring_index++] = *bufp++;
6864 bufn -= mblen - 1;
6865 }
6866 continue;
6867 }
6868 #endif
6869
6870 istring[istring_index++] = c;
6871 }
6872
6873 if (istring)
6874 istring[istring_index] = '\0';
6875
6876 /* If we read no output, just return now and save ourselves some
6877 trouble. */
6878 if (istring_index == 0)
6879 {
6880 FREE (istring);
6881 if (rflag)
6882 *rflag = tflag;
6883 return (char *)NULL;
6884 }
6885
6886 /* Strip trailing newlines from the output of the command. */
6887 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6888 {
6889 while (istring_index > 0)
6890 {
6891 if (istring[istring_index - 1] == '\n')
6892 {
6893 --istring_index;
6894
6895 /* If the newline was quoted, remove the quoting char. */
6896 if (istring[istring_index - 1] == CTLESC)
6897 --istring_index;
6898 }
6899 else
6900 break;
6901 }
6902 istring[istring_index] = '\0';
6903 }
6904 else
6905 strip_trailing (istring, istring_index - 1, 1);
6906
6907 if (rflag)
6908 *rflag = tflag;
6909 return istring;
6910 }
6911
6912 /* Perform command substitution on STRING. This returns a WORD_DESC * with the
6913 contained string possibly quoted. */
6914 WORD_DESC *
6915 command_substitute (string, quoted, flags)
6916 char *string;
6917 int quoted;
6918 int flags;
6919 {
6920 pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
6921 char *istring, *s;
6922 int result, fildes[2], function_value, pflags, rc, tflag, fork_flags;
6923 WORD_DESC *ret;
6924 sigset_t set, oset;
6925
6926 istring = (char *)NULL;
6927
6928 /* Don't fork () if there is no need to. In the case of no command to
6929 run, just return NULL. */
6930 for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++)
6931 ;
6932 if (s == 0 || *s == 0)
6933 return ((WORD_DESC *)NULL);
6934
6935 if (*s == '<' && (s[1] != '<' && s[1] != '>' && s[1] != '&'))
6936 {
6937 COMMAND *cmd;
6938
6939 cmd = parse_string_to_command (string, 0); /* XXX - flags */
6940 if (cmd && can_optimize_cat_file (cmd))
6941 {
6942 tflag = 0;
6943 istring = optimize_cat_file (cmd->value.Simple->redirects, quoted, flags, &tflag);
6944 if (istring == &expand_param_error)
6945 {
6946 last_command_exit_value = EXECUTION_FAILURE;
6947 istring = 0;
6948 }
6949 else
6950 last_command_exit_value = EXECUTION_SUCCESS; /* compat */
6951 last_command_subst_pid = dollar_dollar_pid;
6952
6953 dispose_command (cmd);
6954 ret = alloc_word_desc ();
6955 ret->word = istring;
6956 ret->flags = tflag;
6957
6958 return ret;
6959 }
6960 dispose_command (cmd);
6961 }
6962
6963 if (wordexp_only && read_but_dont_execute)
6964 {
6965 last_command_exit_value = EX_WEXPCOMSUB;
6966 jump_to_top_level (EXITPROG);
6967 }
6968
6969 /* We're making the assumption here that the command substitution will
6970 eventually run a command from the file system. Since we'll run
6971 maybe_make_export_env in this subshell before executing that command,
6972 the parent shell and any other shells it starts will have to remake
6973 the environment. If we make it before we fork, other shells won't
6974 have to. Don't bother if we have any temporary variable assignments,
6975 though, because the export environment will be remade after this
6976 command completes anyway, but do it if all the words to be expanded
6977 are variable assignments. */
6978 if (subst_assign_varlist == 0 || garglist == 0)
6979 maybe_make_export_env (); /* XXX */
6980
6981 /* Flags to pass to parse_and_execute() */
6982 pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
6983
6984 old_pid = last_made_pid;
6985
6986 /* Pipe the output of executing STRING into the current shell. */
6987 if (pipe (fildes) < 0)
6988 {
6989 sys_error ("%s", _("cannot make pipe for command substitution"));
6990 goto error_exit;
6991 }
6992
6993 #if defined (JOB_CONTROL)
6994 old_pipeline_pgrp = pipeline_pgrp;
6995 /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline or
6996 we've already forked to run a disk command (and are expanding redirections,
6997 for example). */
6998 if ((subshell_environment & (SUBSHELL_FORK|SUBSHELL_PIPE)) == 0)
6999 pipeline_pgrp = shell_pgrp;
7000 cleanup_the_pipeline ();
7001 #endif /* JOB_CONTROL */
7002
7003 old_async_pid = last_asynchronous_pid;
7004 fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0;
7005 pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM);
7006 last_asynchronous_pid = old_async_pid;
7007
7008 if (pid == 0)
7009 {
7010 /* Reset the signal handlers in the child, but don't free the
7011 trap strings. Set a flag noting that we have to free the
7012 trap strings if we run trap to change a signal disposition. */
7013 reset_signal_handlers ();
7014 if (ISINTERRUPT)
7015 {
7016 kill (getpid (), SIGINT);
7017 CLRINTERRUPT; /* if we're ignoring SIGINT somehow */
7018 }
7019 QUIT; /* catch any interrupts we got post-fork */
7020 subshell_environment |= SUBSHELL_RESETTRAP;
7021 subshell_environment &= ~SUBSHELL_IGNTRAP;
7022 }
7023
7024 #if defined (JOB_CONTROL)
7025 /* XXX DO THIS ONLY IN PARENT ? XXX */
7026 set_sigchld_handler ();
7027 stop_making_children ();
7028 if (pid != 0)
7029 pipeline_pgrp = old_pipeline_pgrp;
7030 #else
7031 stop_making_children ();
7032 #endif /* JOB_CONTROL */
7033
7034 if (pid < 0)
7035 {
7036 sys_error (_("cannot make child for command substitution"));
7037 error_exit:
7038
7039 last_made_pid = old_pid;
7040
7041 FREE (istring);
7042 close (fildes[0]);
7043 close (fildes[1]);
7044 return ((WORD_DESC *)NULL);
7045 }
7046
7047 if (pid == 0)
7048 {
7049 /* The currently executing shell is not interactive. */
7050 interactive = 0;
7051
7052 #if defined (JOB_CONTROL)
7053 /* Invariant: in child processes started to run command substitutions,
7054 pipeline_pgrp == shell_pgrp. Other parts of the shell assume this. */
7055 if (pipeline_pgrp > 0 && pipeline_pgrp != shell_pgrp)
7056 shell_pgrp = pipeline_pgrp;
7057 #endif
7058
7059 set_sigint_handler (); /* XXX */
7060
7061 free_pushed_string_input ();
7062
7063 /* Discard buffered stdio output before replacing the underlying file
7064 descriptor. */
7065 fpurge (stdout);
7066
7067 if (dup2 (fildes[1], 1) < 0)
7068 {
7069 sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1"));
7070 exit (EXECUTION_FAILURE);
7071 }
7072
7073 /* If standard output is closed in the parent shell
7074 (such as after `exec >&-'), file descriptor 1 will be
7075 the lowest available file descriptor, and end up in
7076 fildes[0]. This can happen for stdin and stderr as well,
7077 but stdout is more important -- it will cause no output
7078 to be generated from this command. */
7079 if ((fildes[1] != fileno (stdin)) &&
7080 (fildes[1] != fileno (stdout)) &&
7081 (fildes[1] != fileno (stderr)))
7082 close (fildes[1]);
7083
7084 if ((fildes[0] != fileno (stdin)) &&
7085 (fildes[0] != fileno (stdout)) &&
7086 (fildes[0] != fileno (stderr)))
7087 close (fildes[0]);
7088
7089 #ifdef __CYGWIN__
7090 /* Let stdio know the fd may have changed from text to binary mode, and
7091 make sure to preserve stdout line buffering. */
7092 freopen (NULL, "w", stdout);
7093 sh_setlinebuf (stdout);
7094 #endif /* __CYGWIN__ */
7095
7096 /* This is a subshell environment. */
7097 subshell_environment |= SUBSHELL_COMSUB;
7098
7099 /* Many shells do not appear to inherit the -v option for command
7100 substitutions. */
7101 change_flag ('v', FLAG_OFF);
7102
7103 /* When inherit_errexit option is not enabled, command substitution does
7104 not inherit the -e flag. It is enabled when Posix mode is enabled */
7105 if (inherit_errexit == 0)
7106 {
7107 builtin_ignoring_errexit = 0;
7108 change_flag ('e', FLAG_OFF);
7109 }
7110 set_shellopts ();
7111
7112 /* If we are expanding a redirection, we can dispose of any temporary
7113 environment we received, since redirections are not supposed to have
7114 access to the temporary environment. We will have to see whether this
7115 affects temporary environments supplied to `eval', but the temporary
7116 environment gets copied to builtin_env at some point. */
7117 if (expanding_redir)
7118 {
7119 flush_temporary_env ();
7120 expanding_redir = 0;
7121 }
7122
7123 remove_quoted_escapes (string);
7124
7125 /* We want to expand aliases on this pass if we are not in posix mode
7126 for backwards compatibility. */
7127 if (expand_aliases)
7128 expand_aliases = posixly_correct == 0;
7129
7130 startup_state = 2; /* see if we can avoid a fork */
7131 parse_and_execute_level = 0;
7132
7133 /* Give command substitution a place to jump back to on failure,
7134 so we don't go back up to main (). */
7135 result = setjmp_nosigs (top_level);
7136
7137 /* If we're running a command substitution inside a shell function,
7138 trap `return' so we don't return from the function in the subshell
7139 and go off to never-never land. */
7140 if (result == 0 && return_catch_flag)
7141 function_value = setjmp_nosigs (return_catch);
7142 else
7143 function_value = 0;
7144
7145 if (result == ERREXIT)
7146 rc = last_command_exit_value;
7147 else if (result == EXITPROG || result == EXITBLTIN)
7148 rc = last_command_exit_value;
7149 else if (result)
7150 rc = EXECUTION_FAILURE;
7151 else if (function_value)
7152 rc = return_catch_value;
7153 else
7154 {
7155 subshell_level++;
7156 rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
7157 /* leave subshell level intact for any exit trap */
7158 }
7159
7160 last_command_exit_value = rc;
7161 rc = run_exit_trap ();
7162 #if defined (PROCESS_SUBSTITUTION)
7163 unlink_fifo_list ();
7164 #endif
7165 exit (rc);
7166 }
7167 else
7168 {
7169 int dummyfd;
7170
7171 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
7172 close_pgrp_pipe ();
7173 #endif /* JOB_CONTROL && PGRP_PIPE */
7174
7175 close (fildes[1]);
7176
7177 begin_unwind_frame ("read-comsub");
7178 dummyfd = fildes[0];
7179 add_unwind_protect (close, dummyfd);
7180
7181 /* Block SIGINT while we're reading from the pipe. If the child
7182 process gets a SIGINT, it will either handle it or die, and the
7183 read will return. */
7184 BLOCK_SIGNAL (SIGINT, set, oset);
7185 tflag = 0;
7186 istring = read_comsub (fildes[0], quoted, flags, &tflag);
7187
7188 close (fildes[0]);
7189 discard_unwind_frame ("read-comsub");
7190 UNBLOCK_SIGNAL (oset);
7191
7192 current_command_subst_pid = pid;
7193 last_command_exit_value = wait_for (pid, JWAIT_NOTERM);
7194 last_command_subst_pid = pid;
7195 last_made_pid = old_pid;
7196
7197 #if defined (JOB_CONTROL)
7198 /* If last_command_exit_value > 128, then the substituted command
7199 was terminated by a signal. If that signal was SIGINT, then send
7200 SIGINT to ourselves. This will break out of loops, for instance. */
7201 if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
7202 kill (getpid (), SIGINT);
7203 #endif /* JOB_CONTROL */
7204
7205 ret = alloc_word_desc ();
7206 ret->word = istring;
7207 ret->flags = tflag;
7208
7209 return ret;
7210 }
7211 }
7212
7213 /********************************************************
7214 * *
7215 * Utility functions for parameter expansion *
7216 * *
7217 ********************************************************/
7218
7219 #if defined (ARRAY_VARS)
7220
7221 static arrayind_t
7222 array_length_reference (s)
7223 char *s;
7224 {
7225 int len;
7226 arrayind_t ind;
7227 char *akey;
7228 char *t, c;
7229 ARRAY *array;
7230 HASH_TABLE *h;
7231 SHELL_VAR *var;
7232
7233 var = array_variable_part (s, 0, &t, &len);
7234
7235 /* If unbound variables should generate an error, report one and return
7236 failure. */
7237 if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
7238 {
7239 c = *--t;
7240 *t = '\0';
7241 set_exit_status (EXECUTION_FAILURE);
7242 err_unboundvar (s);
7243 *t = c;
7244 return (-1);
7245 }
7246 else if (var == 0 || invisible_p (var))
7247 return 0;
7248
7249 /* We support a couple of expansions for variables that are not arrays.
7250 We'll return the length of the value for v[0], and 1 for v[@] or
7251 v[*]. Return 0 for everything else. */
7252
7253 array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
7254 h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
7255
7256 if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK)
7257 {
7258 if (assoc_p (var))
7259 return (h ? assoc_num_elements (h) : 0);
7260 else if (array_p (var))
7261 return (array ? array_num_elements (array) : 0);
7262 else
7263 return (var_isset (var) ? 1 : 0);
7264 }
7265
7266 if (assoc_p (var))
7267 {
7268 t[len - 1] = '\0';
7269 akey = expand_subscript_string (t, 0); /* [ */
7270 t[len - 1] = RBRACK;
7271 if (akey == 0 || *akey == 0)
7272 {
7273 err_badarraysub (t);
7274 FREE (akey);
7275 return (-1);
7276 }
7277 t = assoc_reference (assoc_cell (var), akey);
7278 free (akey);
7279 }
7280 else
7281 {
7282 ind = array_expand_index (var, t, len, 0);
7283 /* negative subscripts to indexed arrays count back from end */
7284 if (var && array_p (var) && ind < 0)
7285 ind = array_max_index (array_cell (var)) + 1 + ind;
7286 if (ind < 0)
7287 {
7288 err_badarraysub (t);
7289 return (-1);
7290 }
7291 if (array_p (var))
7292 t = array_reference (array, ind);
7293 else
7294 t = (ind == 0) ? value_cell (var) : (char *)NULL;
7295 }
7296
7297 len = MB_STRLEN (t);
7298 return (len);
7299 }
7300 #endif /* ARRAY_VARS */
7301
7302 static int
7303 valid_brace_expansion_word (name, var_is_special)
7304 char *name;
7305 int var_is_special;
7306 {
7307 if (DIGIT (*name) && all_digits (name))
7308 return 1;
7309 else if (var_is_special)
7310 return 1;
7311 #if defined (ARRAY_VARS)
7312 else if (valid_array_reference (name, 0))
7313 return 1;
7314 #endif /* ARRAY_VARS */
7315 else if (legal_identifier (name))
7316 return 1;
7317 else
7318 return 0;
7319 }
7320
7321 static int
7322 chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
7323 char *name;
7324 int quoted, pflags;
7325 int *quoted_dollar_atp, *contains_dollar_at;
7326 {
7327 char *temp1;
7328
7329 if (name == 0)
7330 {
7331 if (quoted_dollar_atp)
7332 *quoted_dollar_atp = 0;
7333 if (contains_dollar_at)
7334 *contains_dollar_at = 0;
7335 return 0;
7336 }
7337
7338 /* check for $@ and $* */
7339 if (name[0] == '@' && name[1] == 0)
7340 {
7341 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7342 *quoted_dollar_atp = 1;
7343 if (contains_dollar_at)
7344 *contains_dollar_at = 1;
7345 return 1;
7346 }
7347 else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
7348 {
7349 /* Need more checks here that parallel what string_list_pos_params and
7350 param_expand do. Check expand_no_split_dollar_star and ??? */
7351 if (contains_dollar_at && expand_no_split_dollar_star == 0)
7352 *contains_dollar_at = 1;
7353 return 1;
7354 }
7355
7356 /* Now check for ${array[@]} and ${array[*]} */
7357 #if defined (ARRAY_VARS)
7358 else if (valid_array_reference (name, 0))
7359 {
7360 temp1 = mbschr (name, LBRACK);
7361 if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK)
7362 {
7363 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7364 *quoted_dollar_atp = 1;
7365 if (contains_dollar_at)
7366 *contains_dollar_at = 1;
7367 return 1;
7368 }
7369 /* ${array[*]}, when unquoted, should be treated like ${array[@]},
7370 which should result in separate words even when IFS is unset. */
7371 if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0)
7372 {
7373 if (contains_dollar_at)
7374 *contains_dollar_at = 1;
7375 return 1;
7376 }
7377 }
7378 #endif
7379 return 0;
7380 }
7381
7382 /* Parameter expand NAME, and return a new string which is the expansion,
7383 or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}.
7384 VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
7385 the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
7386 NAME was found inside of a double-quoted expression. */
7387 static WORD_DESC *
7388 parameter_brace_expand_word (name, var_is_special, quoted, pflags, estatep)
7389 char *name;
7390 int var_is_special, quoted, pflags;
7391 array_eltstate_t *estatep;
7392 {
7393 WORD_DESC *ret;
7394 char *temp, *tt;
7395 intmax_t arg_index;
7396 SHELL_VAR *var;
7397 int rflags;
7398 array_eltstate_t es;
7399
7400 ret = 0;
7401 temp = 0;
7402 rflags = 0;
7403
7404 #if defined (ARRAY_VARS)
7405 if (estatep)
7406 es = *estatep; /* structure copy */
7407 else
7408 {
7409 init_eltstate (&es);
7410 es.ind = INTMAX_MIN;
7411 }
7412 #endif
7413
7414 /* Handle multiple digit arguments, as in ${11}. */
7415 if (legal_number (name, &arg_index))
7416 {
7417 tt = get_dollar_var_value (arg_index);
7418 if (tt)
7419 temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7420 ? quote_string (tt)
7421 : quote_escapes (tt);
7422 else
7423 temp = (char *)NULL;
7424 FREE (tt);
7425 }
7426 else if (var_is_special) /* ${@} */
7427 {
7428 int sindex;
7429 tt = (char *)xmalloc (2 + strlen (name));
7430 tt[sindex = 0] = '$';
7431 strcpy (tt + 1, name);
7432
7433 ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
7434 (int *)NULL, (int *)NULL, pflags);
7435
7436 /* Make sure we note that we saw a quoted null string and pass the flag back
7437 to the caller in addition to the value. */
7438 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && STR_DOLLAR_AT_STAR (name) &&
7439 ret && ret->word && QUOTED_NULL (ret->word))
7440 ret->flags |= W_HASQUOTEDNULL;
7441
7442 free (tt);
7443 }
7444 #if defined (ARRAY_VARS)
7445 else if (valid_array_reference (name, 0))
7446 {
7447 expand_arrayref:
7448 var = array_variable_part (name, 0, &tt, (int *)0);
7449 /* These are the cases where word splitting will not be performed */
7450 if (pflags & PF_ASSIGNRHS)
7451 {
7452 if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK)
7453 {
7454 /* Only treat as double quoted if array variable */
7455 if (var && (array_p (var) || assoc_p (var)))
7456 temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &es);
7457 else
7458 temp = array_value (name, quoted, 0, &es);
7459 }
7460 else
7461 temp = array_value (name, quoted, 0, &es);
7462 }
7463 /* Posix interp 888 */
7464 else if (pflags & PF_NOSPLIT2)
7465 {
7466 /* Special cases, then general case, for each of A[@], A[*], A[n] */
7467 #if defined (HANDLE_MULTIBYTE)
7468 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
7469 #else
7470 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
7471 #endif
7472 temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &es);
7473 else if (tt[0] == '@' && tt[1] == RBRACK)
7474 temp = array_value (name, quoted, 0, &es);
7475 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
7476 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &es);
7477 else if (tt[0] == '*' && tt[1] == RBRACK)
7478 temp = array_value (name, quoted, 0, &es);
7479 else
7480 temp = array_value (name, quoted, 0, &es);
7481 }
7482 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
7483 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &es);
7484 else
7485 temp = array_value (name, quoted, 0, &es);
7486 if (es.subtype == 0 && temp)
7487 {
7488 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7489 ? quote_string (temp)
7490 : quote_escapes (temp);
7491 rflags |= W_ARRAYIND;
7492 if (estatep)
7493 *estatep = es; /* structure copy */
7494 }
7495 /* Note that array[*] and array[@] expanded to a quoted null string by
7496 returning the W_HASQUOTEDNULL flag to the caller in addition to TEMP. */
7497 else if (es.subtype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7498 rflags |= W_HASQUOTEDNULL;
7499 else if (es.subtype == 2 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7500 rflags |= W_HASQUOTEDNULL;
7501
7502 if (estatep == 0)
7503 flush_eltstate (&es);
7504 }
7505 #endif
7506 else if (var = find_variable (name))
7507 {
7508 if (var_isset (var) && invisible_p (var) == 0)
7509 {
7510 #if defined (ARRAY_VARS)
7511 /* We avoid a memory leak by saving TT as the memory allocated by
7512 assoc_to_string or array_to_string and leaving it 0 otherwise,
7513 then freeing TT after quoting temp. */
7514 tt = (char *)NULL;
7515 if ((pflags & PF_ALLINDS) && assoc_p (var))
7516 tt = temp = assoc_empty (assoc_cell (var)) ? (char *)NULL : assoc_to_string (assoc_cell (var), " ", quoted);
7517 else if ((pflags & PF_ALLINDS) && array_p (var))
7518 tt = temp = array_empty (array_cell (var)) ? (char *)NULL : array_to_string (array_cell (var), " ", quoted);
7519 else if (assoc_p (var))
7520 temp = assoc_reference (assoc_cell (var), "0");
7521 else if (array_p (var))
7522 temp = array_reference (array_cell (var), 0);
7523 else
7524 temp = value_cell (var);
7525 #else
7526 temp = value_cell (var);
7527 #endif
7528
7529 if (temp)
7530 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7531 ? quote_string (temp)
7532 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
7533 : quote_escapes (temp));
7534 FREE (tt);
7535 }
7536 else
7537 temp = (char *)NULL;
7538 }
7539 else if (var = find_variable_last_nameref (name, 0))
7540 {
7541 temp = nameref_cell (var);
7542 #if defined (ARRAY_VARS)
7543 /* Handle expanding nameref whose value is x[n] */
7544 if (temp && *temp && valid_array_reference (temp, 0))
7545 {
7546 name = temp;
7547 goto expand_arrayref;
7548 }
7549 else
7550 #endif
7551 /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */
7552 if (temp && *temp && legal_identifier (temp) == 0)
7553 {
7554 set_exit_status (EXECUTION_FAILURE);
7555 report_error (_("%s: invalid variable name for name reference"), temp);
7556 temp = &expand_param_error;
7557 }
7558 else
7559 temp = (char *)NULL;
7560 }
7561 else
7562 temp = (char *)NULL;
7563
7564 if (ret == 0)
7565 {
7566 ret = alloc_word_desc ();
7567 ret->word = temp;
7568 ret->flags |= rflags;
7569 }
7570 return ret;
7571 }
7572
7573 static char *
7574 parameter_brace_find_indir (name, var_is_special, quoted, find_nameref)
7575 char *name;
7576 int var_is_special, quoted, find_nameref;
7577 {
7578 char *temp, *t;
7579 WORD_DESC *w;
7580 SHELL_VAR *v;
7581 int pflags, oldex;
7582
7583 if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) &&
7584 nameref_p (v) && (t = nameref_cell (v)) && *t)
7585 return (savestring (t));
7586
7587 /* If var_is_special == 0, and name is not an array reference, this does
7588 more expansion than necessary. It should really look up the variable's
7589 value and not try to expand it. */
7590 pflags = PF_IGNUNBOUND;
7591 /* Note that we're not going to be doing word splitting here */
7592 if (var_is_special)
7593 {
7594 pflags |= PF_ASSIGNRHS; /* suppresses word splitting */
7595 oldex = expand_no_split_dollar_star;
7596 expand_no_split_dollar_star = 1;
7597 }
7598 w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0);
7599 if (var_is_special)
7600 expand_no_split_dollar_star = oldex;
7601
7602 t = w->word;
7603 /* Have to dequote here if necessary */
7604 if (t)
7605 {
7606 temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special)
7607 ? dequote_string (t)
7608 : dequote_escapes (t);
7609 free (t);
7610 t = temp;
7611 }
7612 dispose_word_desc (w);
7613
7614 return t;
7615 }
7616
7617 /* Expand an indirect reference to a variable: ${!NAME} expands to the
7618 value of the variable whose name is the value of NAME. */
7619 static WORD_DESC *
7620 parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
7621 char *name;
7622 int var_is_special, quoted, pflags;
7623 int *quoted_dollar_atp, *contains_dollar_at;
7624 {
7625 char *t;
7626 WORD_DESC *w;
7627 SHELL_VAR *v;
7628
7629 /* See if it's a nameref first, behave in ksh93-compatible fashion.
7630 There is at least one incompatibility: given ${!foo[0]} where foo=bar,
7631 bash performs an indirect lookup on foo[0] and expands the result;
7632 ksh93 expands bar[0]. We could do that here -- there are enough usable
7633 primitives to do that -- but do not at this point. */
7634 if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0)))
7635 {
7636 if (nameref_p (v) && (t = nameref_cell (v)) && *t)
7637 {
7638 w = alloc_word_desc ();
7639 w->word = savestring (t);
7640 w->flags = 0;
7641 return w;
7642 }
7643 }
7644
7645 /* An indirect reference to a positional parameter or a special parameter
7646 is ok. Indirect references to array references, as explained above, are
7647 ok (currently). Only references to unset variables are errors at this
7648 point. */
7649 if (legal_identifier (name) && v == 0)
7650 {
7651 report_error (_("%s: invalid indirect expansion"), name);
7652 w = alloc_word_desc ();
7653 w->word = &expand_param_error;
7654 w->flags = 0;
7655 return (w);
7656 }
7657
7658 t = parameter_brace_find_indir (name, var_is_special, quoted, 0);
7659
7660 chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at);
7661
7662 #if defined (ARRAY_VARS)
7663 /* Array references to unset variables are also an error */
7664 if (t == 0 && valid_array_reference (name, 0))
7665 {
7666 v = array_variable_part (name, 0, (char **)0, (int *)0);
7667 if (v == 0)
7668 {
7669 report_error (_("%s: invalid indirect expansion"), name);
7670 w = alloc_word_desc ();
7671 w->word = &expand_param_error;
7672 w->flags = 0;
7673 return (w);
7674 }
7675 else
7676 return (WORD_DESC *)NULL;
7677 }
7678 #endif
7679
7680 if (t == 0)
7681 return (WORD_DESC *)NULL;
7682
7683 if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0)
7684 {
7685 report_error (_("%s: invalid variable name"), t);
7686 free (t);
7687 w = alloc_word_desc ();
7688 w->word = &expand_param_error;
7689 w->flags = 0;
7690 return (w);
7691 }
7692
7693 w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0);
7694 free (t);
7695
7696 return w;
7697 }
7698
7699 /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
7700 depending on the value of C, the separating character. C can be one of
7701 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
7702 between double quotes. */
7703 static WORD_DESC *
7704 parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat)
7705 char *name, *value;
7706 int op, quoted, pflags, *qdollaratp, *hasdollarat;
7707 {
7708 WORD_DESC *w;
7709 WORD_LIST *l, *tl;
7710 char *t, *t1, *temp, *vname, *newval;
7711 int l_hasdollat, sindex, arrayref;
7712 SHELL_VAR *v;
7713 array_eltstate_t es;
7714
7715 /*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/
7716 /* If the entire expression is between double quotes, we want to treat
7717 the value as a double-quoted string, with the exception that we strip
7718 embedded unescaped double quotes (for sh backwards compatibility). */
7719 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
7720 {
7721 sindex = 0;
7722 temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ);
7723 }
7724 else
7725 temp = value;
7726
7727 w = alloc_word_desc ();
7728 l_hasdollat = 0;
7729 l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL)
7730 : (WORD_LIST *)0;
7731 if (hasdollarat)
7732 *hasdollarat = l_hasdollat || (l && l->next);
7733 if (temp != value)
7734 free (temp);
7735
7736 /* list_string takes multiple CTLNULs and turns them into an empty word
7737 with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the
7738 rest of this function and the caller. */
7739 for (tl = l; tl; tl = tl->next)
7740 {
7741 if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) &&
7742 (tl->word->flags | W_SAWQUOTEDNULL))
7743 {
7744 t = make_quoted_char ('\0');
7745 FREE (tl->word->word);
7746 tl->word->word = t;
7747 tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL;
7748 tl->word->flags &= ~W_SAWQUOTEDNULL;
7749 }
7750 }
7751
7752 if (l)
7753 {
7754 /* If l->next is not null, we know that TEMP contained "$@", since that
7755 is the only expansion that creates more than one word. */
7756 if (qdollaratp && ((l_hasdollat && quoted) || l->next))
7757 {
7758 /*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/
7759 *qdollaratp = 1;
7760 }
7761
7762 /* The expansion of TEMP returned something. We need to treat things
7763 slightly differently if L_HASDOLLAT is non-zero. If we have "$@",
7764 the individual words have already been quoted. We need to turn them
7765 into a string with the words separated by the first character of
7766 $IFS without any additional quoting, so string_list_dollar_at won't
7767 do the right thing. If IFS is null, we want "$@" to split into
7768 separate arguments, not be concatenated, so we use string_list_internal
7769 and mark the word to be split on spaces later. We use
7770 string_list_dollar_star for "$@" otherwise. */
7771 if (l->next && ifs_is_null)
7772 {
7773 temp = string_list_internal (l, " ");
7774 w->flags |= W_SPLITSPACE;
7775 }
7776 else if (l_hasdollat || l->next)
7777 temp = string_list_dollar_star (l, quoted, 0);
7778 else
7779 {
7780 temp = string_list (l);
7781 if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL))
7782 w->flags |= W_SAWQUOTEDNULL; /* XXX */
7783 }
7784
7785 /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
7786 a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
7787 flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
7788 expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7789 (which is more paranoia than anything else), we need to return the
7790 quoted null string and set the flags to indicate it. */
7791 if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL))
7792 {
7793 w->flags |= W_HASQUOTEDNULL;
7794 /*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/
7795 /* If we return a quoted null with L_HASDOLLARAT, we either have a
7796 construct like "${@-$@}" or "${@-${@-$@}}" with no positional
7797 parameters or a quoted expansion of "$@" with $1 == ''. In either
7798 case, we don't want to enable special handling of $@. */
7799 if (qdollaratp && l_hasdollat)
7800 *qdollaratp = 0;
7801 }
7802 dispose_words (l);
7803 }
7804 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat)
7805 {
7806 /* Posix interp 221 changed the rules on this. The idea is that
7807 something like "$xxx$@" should expand the same as "${foo-$xxx$@}"
7808 when foo and xxx are unset. The problem is that it's not in any
7809 way backwards compatible and few other shells do it. We're eventually
7810 going to try and split the difference (heh) a little bit here. */
7811 /* l_hasdollat == 1 means we saw a quoted dollar at. */
7812
7813 /* The brace expansion occurred between double quotes and there was
7814 a $@ in TEMP. It does not matter if the $@ is quoted, as long as
7815 it does not expand to anything. In this case, we want to return
7816 a quoted empty string. Posix interp 888 */
7817 temp = make_quoted_char ('\0');
7818 w->flags |= W_HASQUOTEDNULL;
7819 /*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/
7820 }
7821 else
7822 temp = (char *)NULL;
7823
7824 if (op == '-' || op == '+')
7825 {
7826 w->word = temp;
7827 return w;
7828 }
7829
7830 /* op == '=' */
7831 t1 = temp ? dequote_string (temp) : savestring ("");
7832 free (temp);
7833
7834 /* bash-4.4/5.0 */
7835 vname = name;
7836 if (*name == '!' &&
7837 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1])))
7838 {
7839 vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1);
7840 if (vname == 0 || *vname == 0)
7841 {
7842 report_error (_("%s: invalid indirect expansion"), name);
7843 free (vname);
7844 free (t1);
7845 dispose_word (w);
7846 return &expand_wdesc_error;
7847 }
7848 if (legal_identifier (vname) == 0)
7849 {
7850 report_error (_("%s: invalid variable name"), vname);
7851 free (vname);
7852 free (t1);
7853 dispose_word (w);
7854 return &expand_wdesc_error;
7855 }
7856 }
7857
7858 arrayref = 0;
7859 #if defined (ARRAY_VARS)
7860 if (valid_array_reference (vname, 0))
7861 {
7862 init_eltstate (&es);
7863 v = assign_array_element (vname, t1, ASS_ALLOWALLSUB, &es);
7864 arrayref = 1;
7865 newval = es.value;
7866 }
7867 else
7868 #endif /* ARRAY_VARS */
7869 v = bind_variable (vname, t1, 0);
7870
7871 if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */
7872 {
7873 if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct)
7874 {
7875 last_command_exit_value = EXECUTION_FAILURE;
7876 exp_jump_to_top_level (FORCE_EOF);
7877 }
7878 else
7879 {
7880 if (vname != name)
7881 free (vname);
7882 last_command_exit_value = EX_BADUSAGE;
7883 exp_jump_to_top_level (DISCARD);
7884 }
7885 }
7886
7887 stupidly_hack_special_variables (vname);
7888
7889 /* "In all cases, the final value of parameter shall be substituted." */
7890 if (shell_compatibility_level > 51)
7891 {
7892 FREE (t1);
7893 #if defined (ARRAY_VARS)
7894 if (arrayref)
7895 {
7896 t1 = newval;
7897 flush_eltstate (&es);
7898 }
7899 else
7900 t1 = get_variable_value (v);
7901 #else
7902 t1 = value_cell (v);
7903 #endif
7904 }
7905
7906 if (vname != name)
7907 free (vname);
7908
7909 /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
7910
7911 /* If we are double-quoted or if we are not going to be performing word
7912 splitting, we want to quote the value we return appropriately, like
7913 the other expansions this function handles. */
7914 w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1);
7915 /* If we have something that's non-null, but not a quoted null string,
7916 and we're not going to be performing word splitting (we know we're not
7917 because the operator is `='), we can forget we saw a quoted null. */
7918 if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0)
7919 w->flags &= ~W_SAWQUOTEDNULL;
7920
7921 /* If we convert a null string into a quoted null, make sure the caller
7922 knows it. */
7923 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word))
7924 w->flags |= W_HASQUOTEDNULL;
7925
7926 return w;
7927 }
7928
7929 /* Deal with the right hand side of a ${name:?value} expansion in the case
7930 that NAME is null or not set. If VALUE is non-null it is expanded and
7931 used as the error message to print, otherwise a standard message is
7932 printed. */
7933 static void
7934 parameter_brace_expand_error (name, value, check_null)
7935 char *name, *value;
7936 int check_null;
7937 {
7938 WORD_LIST *l;
7939 char *temp;
7940
7941 set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */
7942 if (value && *value)
7943 {
7944 l = expand_string (value, 0);
7945 temp = string_list (l);
7946 report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
7947 FREE (temp);
7948 dispose_words (l);
7949 }
7950 else if (check_null == 0)
7951 report_error (_("%s: parameter not set"), name);
7952 else
7953 report_error (_("%s: parameter null or not set"), name);
7954
7955 /* Free the data we have allocated during this expansion, since we
7956 are about to longjmp out. */
7957 free (name);
7958 FREE (value);
7959 }
7960
7961 /* Return 1 if NAME is something for which parameter_brace_expand_length is
7962 OK to do. */
7963 static int
7964 valid_length_expression (name)
7965 char *name;
7966 {
7967 return (name[1] == '\0' || /* ${#} */
7968 ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */
7969 (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
7970 #if defined (ARRAY_VARS)
7971 valid_array_reference (name + 1, 0) || /* ${#a[7]} */
7972 #endif
7973 legal_identifier (name + 1)); /* ${#PS1} */
7974 }
7975
7976 /* Handle the parameter brace expansion that requires us to return the
7977 length of a parameter. */
7978 static intmax_t
7979 parameter_brace_expand_length (name)
7980 char *name;
7981 {
7982 char *t, *newname;
7983 intmax_t number, arg_index;
7984 WORD_LIST *list;
7985 SHELL_VAR *var;
7986
7987 var = (SHELL_VAR *)NULL;
7988
7989 if (name[1] == '\0') /* ${#} */
7990 number = number_of_args ();
7991 else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */
7992 number = number_of_args ();
7993 else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
7994 {
7995 /* Take the lengths of some of the shell's special parameters. */
7996 switch (name[1])
7997 {
7998 case '-':
7999 t = which_set_flags ();
8000 break;
8001 case '?':
8002 t = itos (last_command_exit_value);
8003 break;
8004 case '$':
8005 t = itos (dollar_dollar_pid);
8006 break;
8007 case '!':
8008 if (last_asynchronous_pid == NO_PID)
8009 t = (char *)NULL; /* XXX - error if set -u set? */
8010 else
8011 t = itos (last_asynchronous_pid);
8012 break;
8013 case '#':
8014 t = itos (number_of_args ());
8015 break;
8016 }
8017 number = STRLEN (t);
8018 FREE (t);
8019 }
8020 #if defined (ARRAY_VARS)
8021 else if (valid_array_reference (name + 1, 0))
8022 number = array_length_reference (name + 1);
8023 #endif /* ARRAY_VARS */
8024 else
8025 {
8026 number = 0;
8027
8028 if (legal_number (name + 1, &arg_index)) /* ${#1} */
8029 {
8030 t = get_dollar_var_value (arg_index);
8031 if (t == 0 && unbound_vars_is_error)
8032 return INTMAX_MIN;
8033 number = MB_STRLEN (t);
8034 FREE (t);
8035 }
8036 #if defined (ARRAY_VARS)
8037 else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
8038 {
8039 if (assoc_p (var))
8040 t = assoc_reference (assoc_cell (var), "0");
8041 else
8042 t = array_reference (array_cell (var), 0);
8043 if (t == 0 && unbound_vars_is_error)
8044 return INTMAX_MIN;
8045 number = MB_STRLEN (t);
8046 }
8047 #endif
8048 /* Fast path for the common case of taking the length of a non-dynamic
8049 scalar variable value. */
8050 else if ((var || (var = find_variable (name + 1))) &&
8051 invisible_p (var) == 0 &&
8052 array_p (var) == 0 && assoc_p (var) == 0 &&
8053 var->dynamic_value == 0)
8054 number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0;
8055 else if (var == 0 && unbound_vars_is_error == 0)
8056 number = 0;
8057 else /* ${#PS1} */
8058 {
8059 newname = savestring (name);
8060 newname[0] = '$';
8061 list = expand_string (newname, Q_DOUBLE_QUOTES);
8062 t = list ? string_list (list) : (char *)NULL;
8063 free (newname);
8064 if (list)
8065 dispose_words (list);
8066
8067 number = t ? MB_STRLEN (t) : 0;
8068 FREE (t);
8069 }
8070 }
8071
8072 return (number);
8073 }
8074
8075 /* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression,
8076 so we do some ad-hoc parsing of an arithmetic expression to find
8077 the first DELIM, instead of using strchr(3). Two rules:
8078 1. If the substring contains a `(', read until closing `)'.
8079 2. If the substring contains a `?', read past one `:' for each `?'.
8080 The SD_ARITHEXP flag to skip_to_delim takes care of doing this.
8081 */
8082
8083 static char *
8084 skiparith (substr, delim)
8085 char *substr;
8086 int delim;
8087 {
8088 int i;
8089 char delims[2];
8090
8091 delims[0] = delim;
8092 delims[1] = '\0';
8093
8094 i = skip_to_delim (substr, 0, delims, SD_ARITHEXP);
8095 return (substr + i);
8096 }
8097
8098 /* Verify and limit the start and end of the desired substring. If
8099 VTYPE == 0, a regular shell variable is being used; if it is 1,
8100 then the positional parameters are being used; if it is 2, then
8101 VALUE is really a pointer to an array variable that should be used.
8102 Return value is 1 if both values were OK, 0 if there was a problem
8103 with an invalid expression, or -1 if the values were out of range. */
8104 static int
8105 verify_substring_values (v, value, substr, vtype, e1p, e2p)
8106 SHELL_VAR *v;
8107 char *value, *substr;
8108 int vtype;
8109 intmax_t *e1p, *e2p;
8110 {
8111 char *t, *temp1, *temp2;
8112 arrayind_t len;
8113 int expok, eflag;
8114 #if defined (ARRAY_VARS)
8115 ARRAY *a;
8116 HASH_TABLE *h;
8117 #endif
8118
8119 /* duplicate behavior of strchr(3) */
8120 t = skiparith (substr, ':');
8121 if (*t && *t == ':')
8122 *t = '\0';
8123 else
8124 t = (char *)0;
8125
8126 temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES|Q_ARITH);
8127 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
8128
8129 *e1p = evalexp (temp1, eflag, &expok);
8130 free (temp1);
8131 if (expok == 0)
8132 return (0);
8133
8134 len = -1; /* paranoia */
8135 switch (vtype)
8136 {
8137 case VT_VARIABLE:
8138 case VT_ARRAYMEMBER:
8139 len = MB_STRLEN (value);
8140 break;
8141 case VT_POSPARMS:
8142 len = number_of_args () + 1;
8143 if (*e1p == 0)
8144 len++; /* add one arg if counting from $0 */
8145 break;
8146 #if defined (ARRAY_VARS)
8147 case VT_ARRAYVAR:
8148 /* For arrays, the first value deals with array indices. Negative
8149 offsets count from one past the array's maximum index. Associative
8150 arrays treat the number of elements as the maximum index. */
8151 if (assoc_p (v))
8152 {
8153 h = assoc_cell (v);
8154 len = assoc_num_elements (h) + (*e1p < 0);
8155 }
8156 else
8157 {
8158 a = (ARRAY *)value;
8159 len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
8160 }
8161 break;
8162 #endif
8163 }
8164
8165 if (len == -1) /* paranoia */
8166 return -1;
8167
8168 if (*e1p < 0) /* negative offsets count from end */
8169 *e1p += len;
8170
8171 if (*e1p > len || *e1p < 0)
8172 return (-1);
8173
8174 #if defined (ARRAY_VARS)
8175 /* For arrays, the second offset deals with the number of elements. */
8176 if (vtype == VT_ARRAYVAR)
8177 len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
8178 #endif
8179
8180 if (t)
8181 {
8182 t++;
8183 temp2 = savestring (t);
8184 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
8185 free (temp2);
8186 t[-1] = ':';
8187 *e2p = evalexp (temp1, eflag, &expok);
8188 free (temp1);
8189 if (expok == 0)
8190 return (0);
8191
8192 /* Should we allow positional parameter length < 0 to count backwards
8193 from end of positional parameters? */
8194 #if 1
8195 if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
8196 #else /* XXX - postponed; this isn't really a valuable feature */
8197 if (vtype == VT_ARRAYVAR && *e2p < 0)
8198 #endif
8199 {
8200 internal_error (_("%s: substring expression < 0"), t);
8201 return (0);
8202 }
8203 #if defined (ARRAY_VARS)
8204 /* In order to deal with sparse arrays, push the intelligence about how
8205 to deal with the number of elements desired down to the array-
8206 specific functions. */
8207 if (vtype != VT_ARRAYVAR)
8208 #endif
8209 {
8210 if (*e2p < 0)
8211 {
8212 *e2p += len;
8213 if (*e2p < 0 || *e2p < *e1p)
8214 {
8215 internal_error (_("%s: substring expression < 0"), t);
8216 return (0);
8217 }
8218 }
8219 else
8220 *e2p += *e1p; /* want E2 chars starting at E1 */
8221 if (*e2p > len)
8222 *e2p = len;
8223 }
8224 }
8225 else
8226 *e2p = len;
8227
8228 return (1);
8229 }
8230
8231 /* Return the type of variable specified by VARNAME (simple variable,
8232 positional param, or array variable). Also return the value specified
8233 by VARNAME (value of a variable or a reference to an array element).
8234 QUOTED is the standard description of quoting state, using Q_* defines.
8235 FLAGS is currently a set of flags to pass to array_value. If IND is
8236 not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
8237 passed to array_value so the array index is not computed again.
8238 If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
8239 characters in the value are quoted with CTLESC and takes appropriate
8240 steps. For convenience, *VALP is set to the dequoted VALUE. */
8241 static int
8242 get_var_and_type (varname, value, estatep, quoted, flags, varp, valp)
8243 char *varname, *value;
8244 array_eltstate_t *estatep;
8245 int quoted, flags;
8246 SHELL_VAR **varp;
8247 char **valp;
8248 {
8249 int vtype, want_indir;
8250 char *temp, *vname;
8251 SHELL_VAR *v;
8252
8253 want_indir = *varname == '!' &&
8254 (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1])
8255 || VALID_INDIR_PARAM (varname[1]));
8256 if (want_indir)
8257 vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1);
8258 /* XXX - what if vname == 0 || *vname == 0 ? */
8259 else
8260 vname = varname;
8261
8262 if (vname == 0)
8263 {
8264 vtype = VT_VARIABLE;
8265 *varp = (SHELL_VAR *)NULL;
8266 *valp = (char *)NULL;
8267 return (vtype);
8268 }
8269
8270 /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
8271 vtype = STR_DOLLAR_AT_STAR (vname);
8272 if (vtype == VT_POSPARMS && vname[0] == '*')
8273 vtype |= VT_STARSUB;
8274 *varp = (SHELL_VAR *)NULL;
8275
8276 #if defined (ARRAY_VARS)
8277 if (valid_array_reference (vname, 0))
8278 {
8279 v = array_variable_part (vname, 0, &temp, (int *)0);
8280 /* If we want to signal array_value to use an already-computed index,
8281 the caller will set ESTATEP->IND to that index and pass AV_USEIND in
8282 FLAGS. */
8283 if (estatep && (flags & AV_USEIND) == 0)
8284 estatep->ind = INTMAX_MIN;
8285
8286 if (v && invisible_p (v))
8287 {
8288 vtype = VT_ARRAYMEMBER;
8289 *varp = (SHELL_VAR *)NULL;
8290 *valp = (char *)NULL;
8291 }
8292 if (v && (array_p (v) || assoc_p (v)))
8293 {
8294 if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)
8295 {
8296 /* Callers have to differentiate between indexed and associative */
8297 vtype = VT_ARRAYVAR;
8298 if (temp[0] == '*')
8299 vtype |= VT_STARSUB;
8300 *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
8301 }
8302 else
8303 {
8304 vtype = VT_ARRAYMEMBER;
8305 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
8306 }
8307 *varp = v;
8308 }
8309 else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK))
8310 {
8311 vtype = VT_VARIABLE;
8312 *varp = v;
8313 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8314 *valp = value ? dequote_string (value) : (char *)NULL;
8315 else
8316 *valp = value ? dequote_escapes (value) : (char *)NULL;
8317 }
8318 else
8319 {
8320 vtype = VT_ARRAYMEMBER;
8321 *varp = v;
8322 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
8323 }
8324 }
8325 else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
8326 {
8327 vtype = VT_ARRAYMEMBER;
8328 *varp = v;
8329 *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
8330 }
8331 else
8332 #endif
8333 {
8334 if (value && vtype == VT_VARIABLE)
8335 {
8336 *varp = find_variable (vname);
8337 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8338 *valp = dequote_string (value);
8339 else
8340 *valp = dequote_escapes (value);
8341 }
8342 else
8343 *valp = value;
8344 }
8345
8346 if (want_indir)
8347 free (vname);
8348
8349 return vtype;
8350 }
8351
8352 /***********************************************************/
8353 /* */
8354 /* Functions to perform transformations on variable values */
8355 /* */
8356 /***********************************************************/
8357
8358 static char *
8359 string_var_assignment (v, s)
8360 SHELL_VAR *v;
8361 char *s;
8362 {
8363 char flags[MAX_ATTRIBUTES], *ret, *val;
8364 int i;
8365
8366 val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0);
8367 i = var_attribute_string (v, 0, flags);
8368 if (i == 0 && val == 0)
8369 return (char *)NULL;
8370
8371 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES);
8372 if (i > 0 && val == 0)
8373 sprintf (ret, "declare -%s %s", flags, v->name);
8374 else if (i > 0)
8375 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
8376 else
8377 sprintf (ret, "%s=%s", v->name, val);
8378 free (val);
8379 return ret;
8380 }
8381
8382 #if defined (ARRAY_VARS)
8383 static char *
8384 array_var_assignment (v, itype, quoted, atype)
8385 SHELL_VAR *v;
8386 int itype, quoted, atype;
8387 {
8388 char *ret, *val, flags[MAX_ATTRIBUTES];
8389 int i;
8390
8391 if (v == 0)
8392 return (char *)NULL;
8393 if (atype == 2)
8394 val = array_p (v) ? array_to_kvpair (array_cell (v), 0)
8395 : assoc_to_kvpair (assoc_cell (v), 0);
8396 else
8397 val = array_p (v) ? array_to_assign (array_cell (v), 0)
8398 : assoc_to_assign (assoc_cell (v), 0);
8399
8400 if (val == 0 && (invisible_p (v) || var_isset (v) == 0))
8401 ; /* placeholder */
8402 else if (val == 0)
8403 {
8404 val = (char *)xmalloc (3);
8405 val[0] = LPAREN;
8406 val[1] = RPAREN;
8407 val[2] = 0;
8408 }
8409 else
8410 {
8411 ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val);
8412 free (val);
8413 val = ret;
8414 }
8415
8416 if (atype == 2)
8417 return val;
8418
8419 i = var_attribute_string (v, 0, flags);
8420 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16);
8421 if (val)
8422 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
8423 else
8424 sprintf (ret, "declare -%s %s", flags, v->name);
8425 free (val);
8426 return ret;
8427 }
8428 #endif
8429
8430 static char *
8431 pos_params_assignment (list, itype, quoted)
8432 WORD_LIST *list;
8433 int itype;
8434 int quoted;
8435 {
8436 char *temp, *ret;
8437
8438 /* first, we transform the list to quote each word. */
8439 temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted);
8440 ret = (char *)xmalloc (strlen (temp) + 8);
8441 strcpy (ret, "set -- ");
8442 strcpy (ret + 7, temp);
8443 free (temp);
8444 return ret;
8445 }
8446
8447 static char *
8448 string_transform (xc, v, s)
8449 int xc;
8450 SHELL_VAR *v;
8451 char *s;
8452 {
8453 char *ret, flags[MAX_ATTRIBUTES], *t;
8454 int i;
8455
8456 if (((xc == 'A' || xc == 'a') && v == 0))
8457 return (char *)NULL;
8458 else if (xc != 'a' && xc != 'A' && s == 0)
8459 return (char *)NULL;
8460
8461 switch (xc)
8462 {
8463 /* Transformations that interrogate the variable */
8464 case 'a':
8465 i = var_attribute_string (v, 0, flags);
8466 ret = (i > 0) ? savestring (flags) : (char *)NULL;
8467 break;
8468 case 'A':
8469 ret = string_var_assignment (v, s);
8470 break;
8471 case 'K':
8472 case 'k':
8473 ret = sh_quote_reusable (s, 0);
8474 break;
8475 /* Transformations that modify the variable's value */
8476 case 'E':
8477 t = ansiexpand (s, 0, strlen (s), (int *)0);
8478 ret = dequote_escapes (t);
8479 free (t);
8480 break;
8481 case 'P':
8482 ret = decode_prompt_string (s);
8483 break;
8484 case 'Q':
8485 ret = sh_quote_reusable (s, 0);
8486 break;
8487 case 'U':
8488 ret = sh_modcase (s, 0, CASE_UPPER);
8489 break;
8490 case 'u':
8491 ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */
8492 break;
8493 case 'L':
8494 ret = sh_modcase (s, 0, CASE_LOWER);
8495 break;
8496 default:
8497 ret = (char *)NULL;
8498 break;
8499 }
8500 return ret;
8501 }
8502
8503 static char *
8504 list_transform (xc, v, list, itype, quoted)
8505 int xc;
8506 SHELL_VAR *v;
8507 WORD_LIST *list;
8508 int itype, quoted;
8509 {
8510 WORD_LIST *new, *l;
8511 WORD_DESC *w;
8512 char *tword;
8513 int qflags;
8514
8515 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
8516 {
8517 tword = string_transform (xc, v, l->word->word);
8518 w = alloc_word_desc ();
8519 w->word = tword ? tword : savestring (""); /* XXX */
8520 new = make_word_list (w, new);
8521 }
8522 l = REVERSE_LIST (new, WORD_LIST *);
8523
8524 qflags = quoted;
8525 /* If we are expanding in a context where word splitting will not be
8526 performed, treat as quoted. This changes how $* will be expanded. */
8527 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
8528 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8529
8530 tword = string_list_pos_params (itype, l, qflags, 0);
8531 dispose_words (l);
8532
8533 return (tword);
8534 }
8535
8536 static char *
8537 parameter_list_transform (xc, itype, quoted)
8538 int xc;
8539 int itype;
8540 int quoted;
8541 {
8542 char *ret;
8543 WORD_LIST *list;
8544
8545 list = list_rest_of_args ();
8546 if (list == 0)
8547 return ((char *)NULL);
8548 if (xc == 'A')
8549 ret = pos_params_assignment (list, itype, quoted);
8550 else
8551 ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted);
8552 dispose_words (list);
8553 return (ret);
8554 }
8555
8556 #if defined (ARRAY_VARS)
8557 static char *
8558 array_transform (xc, var, starsub, quoted)
8559 int xc;
8560 SHELL_VAR *var;
8561 int starsub; /* so we can figure out how it's indexed */
8562 int quoted;
8563 {
8564 ARRAY *a;
8565 HASH_TABLE *h;
8566 int itype, qflags;
8567 char *ret;
8568 WORD_LIST *list;
8569 SHELL_VAR *v;
8570
8571 v = var; /* XXX - for now */
8572
8573 itype = starsub ? '*' : '@';
8574
8575 if (xc == 'A')
8576 return (array_var_assignment (v, itype, quoted, 1));
8577 else if (xc == 'K')
8578 return (array_var_assignment (v, itype, quoted, 2));
8579
8580 /* special case for unset arrays and attributes */
8581 if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0))
8582 {
8583 char flags[MAX_ATTRIBUTES];
8584 int i;
8585
8586 i = var_attribute_string (v, 0, flags);
8587 return ((i > 0) ? savestring (flags) : (char *)NULL);
8588 }
8589
8590 a = (v && array_p (v)) ? array_cell (v) : 0;
8591 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
8592
8593 /* XXX - for now */
8594 if (xc == 'k')
8595 {
8596 if (v == 0)
8597 return ((char *)NULL);
8598 list = array_p (v) ? array_to_kvpair_list (a) : assoc_to_kvpair_list (h);
8599 qflags = quoted;
8600 /* If we are expanding in a context where word splitting will not be
8601 performed, treat as quoted. This changes how $* will be expanded. */
8602 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
8603 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8604
8605 ret = string_list_pos_params (itype, list, qflags, 0);
8606 dispose_words (list);
8607 return ret;
8608 }
8609
8610 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
8611 if (list == 0)
8612 return ((char *)NULL);
8613 ret = list_transform (xc, v, list, itype, quoted);
8614 dispose_words (list);
8615
8616 return ret;
8617 }
8618 #endif /* ARRAY_VARS */
8619
8620 static int
8621 valid_parameter_transform (xform)
8622 char *xform;
8623 {
8624 if (xform[1])
8625 return 0;
8626
8627 /* check for valid values of xform[0] */
8628 switch (xform[0])
8629 {
8630 case 'a': /* expand to a string with just attributes */
8631 case 'A': /* expand as an assignment statement with attributes */
8632 case 'K': /* expand assoc array to list of key/value pairs */
8633 case 'k': /* XXX - for now */
8634 case 'E': /* expand like $'...' */
8635 case 'P': /* expand like prompt string */
8636 case 'Q': /* quote reusably */
8637 case 'U': /* transform to uppercase */
8638 case 'u': /* transform by capitalizing */
8639 case 'L': /* transform to lowercase */
8640 return 1;
8641 default:
8642 return 0;
8643 }
8644 }
8645
8646 static char *
8647 parameter_brace_transform (varname, value, estatep, xform, rtype, quoted, pflags, flags)
8648 char *varname, *value;
8649 array_eltstate_t *estatep;
8650 char *xform;
8651 int rtype, quoted, pflags, flags;
8652 {
8653 int vtype, xc, starsub;
8654 char *temp1, *val, *oname;
8655 SHELL_VAR *v;
8656
8657 xc = xform[0];
8658 if (value == 0 && xc != 'A' && xc != 'a')
8659 return ((char *)NULL);
8660
8661 oname = this_command_name;
8662 this_command_name = varname;
8663
8664 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
8665 if (vtype == -1)
8666 {
8667 this_command_name = oname;
8668 return ((char *)NULL);
8669 }
8670
8671 if (xform[0] == 0 || valid_parameter_transform (xform) == 0)
8672 {
8673 this_command_name = oname;
8674 if (vtype == VT_VARIABLE)
8675 FREE (val);
8676 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
8677 }
8678
8679 starsub = vtype & VT_STARSUB;
8680 vtype &= ~VT_STARSUB;
8681
8682 /* If we are asked to display the attributes of an unset variable, V will
8683 be NULL after the call to get_var_and_type. Double-check here. */
8684 if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0)
8685 v = find_variable (varname);
8686
8687 temp1 = (char *)NULL; /* shut up gcc */
8688 switch (vtype)
8689 {
8690 case VT_VARIABLE:
8691 case VT_ARRAYMEMBER:
8692 temp1 = string_transform (xc, v, val);
8693 if (vtype == VT_VARIABLE)
8694 FREE (val);
8695 if (temp1)
8696 {
8697 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8698 ? quote_string (temp1)
8699 : quote_escapes (temp1);
8700 free (temp1);
8701 temp1 = val;
8702 }
8703 break;
8704 #if defined (ARRAY_VARS)
8705 case VT_ARRAYVAR:
8706 temp1 = array_transform (xc, v, starsub, quoted);
8707 if (temp1 && quoted == 0 && ifs_is_null)
8708 {
8709 /* Posix interp 888 */
8710 }
8711 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
8712 {
8713 val = quote_escapes (temp1);
8714 free (temp1);
8715 temp1 = val;
8716 }
8717 break;
8718 #endif
8719 case VT_POSPARMS:
8720 temp1 = parameter_list_transform (xc, varname[0], quoted);
8721 if (temp1 && quoted == 0 && ifs_is_null)
8722 {
8723 /* Posix interp 888 */
8724 }
8725 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
8726 {
8727 val = quote_escapes (temp1);
8728 free (temp1);
8729 temp1 = val;
8730 }
8731 break;
8732 }
8733
8734 this_command_name = oname;
8735 return temp1;
8736 }
8737
8738 /******************************************************/
8739 /* */
8740 /* Functions to extract substrings of variable values */
8741 /* */
8742 /******************************************************/
8743
8744 #if defined (HANDLE_MULTIBYTE)
8745 /* Character-oriented rather than strictly byte-oriented substrings. S and
8746 E, rather being strict indices into STRING, indicate character (possibly
8747 multibyte character) positions that require calculation.
8748 Used by the ${param:offset[:length]} expansion. */
8749 static char *
8750 mb_substring (string, s, e)
8751 char *string;
8752 int s, e;
8753 {
8754 char *tt;
8755 int start, stop, i;
8756 size_t slen;
8757 DECLARE_MBSTATE;
8758
8759 start = 0;
8760 /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
8761 slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
8762
8763 i = s;
8764 while (string[start] && i--)
8765 ADVANCE_CHAR (string, slen, start);
8766 stop = start;
8767 i = e - s;
8768 while (string[stop] && i--)
8769 ADVANCE_CHAR (string, slen, stop);
8770 tt = substring (string, start, stop);
8771 return tt;
8772 }
8773 #endif
8774
8775 /* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
8776 is `@', use the positional parameters; otherwise, use the value of
8777 VARNAME. If VARNAME is an array variable, use the array elements. */
8778
8779 static char *
8780 parameter_brace_substring (varname, value, estatep, substr, quoted, pflags, flags)
8781 char *varname, *value;
8782 array_eltstate_t *estatep;
8783 char *substr;
8784 int quoted, pflags, flags;
8785 {
8786 intmax_t e1, e2;
8787 int vtype, r, starsub;
8788 char *temp, *val, *tt, *oname;
8789 SHELL_VAR *v;
8790
8791 if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1]))
8792 return ((char *)NULL);
8793
8794 oname = this_command_name;
8795 this_command_name = varname;
8796
8797 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
8798 if (vtype == -1)
8799 {
8800 this_command_name = oname;
8801 return ((char *)NULL);
8802 }
8803
8804 starsub = vtype & VT_STARSUB;
8805 vtype &= ~VT_STARSUB;
8806
8807 r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
8808 this_command_name = oname;
8809 if (r <= 0)
8810 {
8811 if (vtype == VT_VARIABLE)
8812 FREE (val);
8813 return ((r == 0) ? &expand_param_error : (char *)NULL);
8814 }
8815
8816 switch (vtype)
8817 {
8818 case VT_VARIABLE:
8819 case VT_ARRAYMEMBER:
8820 #if defined (HANDLE_MULTIBYTE)
8821 if (MB_CUR_MAX > 1)
8822 tt = mb_substring (val, e1, e2);
8823 else
8824 #endif
8825 tt = substring (val, e1, e2);
8826
8827 if (vtype == VT_VARIABLE)
8828 FREE (val);
8829 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8830 temp = quote_string (tt);
8831 else
8832 temp = tt ? quote_escapes (tt) : (char *)NULL;
8833 FREE (tt);
8834 break;
8835 case VT_POSPARMS:
8836 case VT_ARRAYVAR:
8837 if (vtype == VT_POSPARMS)
8838 tt = pos_params (varname, e1, e2, quoted, pflags);
8839 #if defined (ARRAY_VARS)
8840 /* assoc_subrange and array_subrange both call string_list_pos_params,
8841 so we can treat this case just like VT_POSPARAMS. */
8842 else if (assoc_p (v))
8843 /* we convert to list and take first e2 elements starting at e1th
8844 element -- officially undefined for now */
8845 tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags);
8846 else
8847 /* We want E2 to be the number of elements desired (arrays can be
8848 sparse, so verify_substring_values just returns the numbers
8849 specified and we rely on array_subrange to understand how to
8850 deal with them). */
8851 tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags);
8852 #endif
8853 /* We want to leave this alone in every case where pos_params/
8854 string_list_pos_params quotes the list members */
8855 if (tt && quoted == 0 && ifs_is_null)
8856 {
8857 temp = tt; /* Posix interp 888 */
8858 }
8859 else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS))
8860 {
8861 temp = tt; /* Posix interp 888 */
8862 }
8863 else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
8864 {
8865 temp = tt ? quote_escapes (tt) : (char *)NULL;
8866 FREE (tt);
8867 }
8868 else
8869 temp = tt;
8870 break;
8871
8872 default:
8873 temp = (char *)NULL;
8874 }
8875
8876 return temp;
8877 }
8878
8879 /****************************************************************/
8880 /* */
8881 /* Functions to perform pattern substitution on variable values */
8882 /* */
8883 /****************************************************************/
8884
8885 static int
8886 shouldexp_replacement (s)
8887 char *s;
8888 {
8889 size_t slen;
8890 int sindex, c;
8891 DECLARE_MBSTATE;
8892
8893 sindex = 0;
8894 slen = STRLEN (s);
8895 while (c = s[sindex])
8896 {
8897 if (c == '\\')
8898 {
8899 sindex++;
8900 if (s[sindex] == 0)
8901 return 0;
8902 /* We want to remove this backslash because we treat it as special
8903 in this context. THIS ASSUMES THE STRING IS PROCESSED BY
8904 strcreplace() OR EQUIVALENT that handles removing backslashes
8905 preceding the special character. */
8906 if (s[sindex] == '&')
8907 return 1;
8908 if (s[sindex] == '\\')
8909 return 1;
8910 }
8911 else if (c == '&')
8912 return 1;
8913 ADVANCE_CHAR (s, slen, sindex);
8914 }
8915 return 0;
8916 }
8917
8918 char *
8919 pat_subst (string, pat, rep, mflags)
8920 char *string, *pat, *rep;
8921 int mflags;
8922 {
8923 char *ret, *s, *e, *str, *rstr, *mstr, *send;
8924 int rptr, mtype, rxpand, mlen;
8925 size_t rsize, l, replen, rslen;
8926 DECLARE_MBSTATE;
8927
8928 if (string == 0)
8929 return (savestring (""));
8930
8931 mtype = mflags & MATCH_TYPEMASK;
8932 rxpand = mflags & MATCH_EXPREP;
8933
8934 /* Special cases:
8935 * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
8936 * with REP and return the result.
8937 * 2. A null pattern with mtype == MATCH_END means to append REP to
8938 * STRING and return the result.
8939 * 3. A null STRING with a matching pattern means to append REP to
8940 * STRING and return the result.
8941 *
8942 * These process `&' in the replacement string, like `sed' does when
8943 * presented with a BRE of `^' or `$'.
8944 */
8945 if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
8946 {
8947 rstr = (mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2) : rep;
8948 rslen = STRLEN (rstr);
8949 l = STRLEN (string);
8950 ret = (char *)xmalloc (rslen + l + 2);
8951 if (rslen == 0)
8952 strcpy (ret, string);
8953 else if (mtype == MATCH_BEG)
8954 {
8955 strcpy (ret, rstr);
8956 strcpy (ret + rslen, string);
8957 }
8958 else
8959 {
8960 strcpy (ret, string);
8961 strcpy (ret + l, rstr);
8962 }
8963 if (rstr != rep)
8964 free (rstr);
8965 return (ret);
8966 }
8967 else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
8968 return ((mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2) : savestring (rep));
8969
8970 ret = (char *)xmalloc (rsize = 64);
8971 ret[0] = '\0';
8972 send = string + strlen (string);
8973
8974 for (replen = STRLEN (rep), rptr = 0, str = string; *str;)
8975 {
8976 if (match_pattern (str, pat, mtype, &s, &e) == 0)
8977 break;
8978 l = s - str;
8979
8980 if (rep && rxpand)
8981 {
8982 int x;
8983 mlen = e - s;
8984 mstr = xmalloc (mlen + 1);
8985 for (x = 0; x < mlen; x++)
8986 mstr[x] = s[x];
8987 mstr[mlen] = '\0';
8988 rstr = strcreplace (rep, '&', mstr, 2);
8989 free (mstr);
8990 rslen = strlen (rstr);
8991 }
8992 else
8993 {
8994 rstr = rep;
8995 rslen = replen;
8996 }
8997
8998 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
8999
9000 /* OK, now copy the leading unmatched portion of the string (from
9001 str to s) to ret starting at rptr (the current offset). Then copy
9002 the replacement string at ret + rptr + (s - str). Increment
9003 rptr (if necessary) and str and go on. */
9004 if (l)
9005 {
9006 strncpy (ret + rptr, str, l);
9007 rptr += l;
9008 }
9009 if (replen)
9010 {
9011 strncpy (ret + rptr, rstr, rslen);
9012 rptr += rslen;
9013 }
9014 str = e; /* e == end of match */
9015
9016 if (rstr != rep)
9017 free (rstr);
9018
9019 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
9020 break;
9021
9022 if (s == e)
9023 {
9024 /* On a zero-length match, make sure we copy one character, since
9025 we increment one character to avoid infinite recursion. */
9026 char *p, *origp, *origs;
9027 size_t clen;
9028
9029 RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64);
9030 #if defined (HANDLE_MULTIBYTE)
9031 p = origp = ret + rptr;
9032 origs = str;
9033 COPY_CHAR_P (p, str, send);
9034 rptr += p - origp;
9035 e += str - origs;
9036 #else
9037 ret[rptr++] = *str++;
9038 e++; /* avoid infinite recursion on zero-length match */
9039 #endif
9040 }
9041 }
9042
9043 /* Now copy the unmatched portion of the input string */
9044 if (str && *str)
9045 {
9046 l = send - str + 1;
9047 RESIZE_MALLOCED_BUFFER (ret, rptr, l, rsize, 64);
9048 strcpy (ret + rptr, str);
9049 }
9050 else
9051 ret[rptr] = '\0';
9052
9053 return ret;
9054 }
9055
9056 /* Do pattern match and replacement on the positional parameters. */
9057 static char *
9058 pos_params_pat_subst (string, pat, rep, mflags)
9059 char *string, *pat, *rep;
9060 int mflags;
9061 {
9062 WORD_LIST *save, *params;
9063 WORD_DESC *w;
9064 char *ret;
9065 int pchar, qflags, pflags;
9066
9067 save = params = list_rest_of_args ();
9068 if (save == 0)
9069 return ((char *)NULL);
9070
9071 for ( ; params; params = params->next)
9072 {
9073 ret = pat_subst (params->word->word, pat, rep, mflags);
9074 w = alloc_word_desc ();
9075 w->word = ret ? ret : savestring ("");
9076 dispose_word (params->word);
9077 params->word = w;
9078 }
9079
9080 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
9081 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
9082 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
9083
9084 /* If we are expanding in a context where word splitting will not be
9085 performed, treat as quoted. This changes how $* will be expanded. */
9086 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null)
9087 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
9088
9089 ret = string_list_pos_params (pchar, save, qflags, pflags);
9090 dispose_words (save);
9091
9092 return (ret);
9093 }
9094
9095 /* Perform pattern substitution on VALUE, which is the expansion of
9096 VARNAME. PATSUB is an expression supplying the pattern to match
9097 and the string to substitute. QUOTED is a flags word containing
9098 the type of quoting currently in effect. */
9099 static char *
9100 parameter_brace_patsub (varname, value, estatep, patsub, quoted, pflags, flags)
9101 char *varname, *value;
9102 array_eltstate_t *estatep;
9103 char *patsub;
9104 int quoted, pflags, flags;
9105 {
9106 int vtype, mflags, starsub, delim;
9107 char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname;
9108 SHELL_VAR *v;
9109
9110 if (value == 0)
9111 return ((char *)NULL);
9112
9113 oname = this_command_name;
9114 this_command_name = varname; /* error messages */
9115
9116 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
9117 if (vtype == -1)
9118 {
9119 this_command_name = oname;
9120 return ((char *)NULL);
9121 }
9122
9123 starsub = vtype & VT_STARSUB;
9124 vtype &= ~VT_STARSUB;
9125
9126 mflags = 0;
9127 /* PATSUB is never NULL when this is called. */
9128 if (*patsub == '/')
9129 {
9130 mflags |= MATCH_GLOBREP;
9131 patsub++;
9132 }
9133
9134 /* Malloc this because expand_string_if_necessary or one of the expansion
9135 functions in its call chain may free it on a substitution error. */
9136 lpatsub = savestring (patsub);
9137
9138 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9139 mflags |= MATCH_QUOTED;
9140
9141 if (starsub)
9142 mflags |= MATCH_STARSUB;
9143
9144 if (pflags & PF_ASSIGNRHS)
9145 mflags |= MATCH_ASSIGNRHS;
9146
9147 /* If the pattern starts with a `/', make sure we skip over it when looking
9148 for the replacement delimiter. */
9149 delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
9150 if (lpatsub[delim] == '/')
9151 {
9152 lpatsub[delim] = 0;
9153 rep = lpatsub + delim + 1;
9154 }
9155 else
9156 rep = (char *)NULL;
9157
9158 if (rep && *rep == '\0')
9159 rep = (char *)NULL;
9160
9161 /* Perform the same expansions on the pattern as performed by the
9162 pattern removal expansions. */
9163 pat = getpattern (lpatsub, quoted, 1);
9164
9165 if (rep)
9166 {
9167 /* We want to perform quote removal on the expanded replacement even if
9168 the entire expansion is double-quoted because the parser and string
9169 extraction functions treated quotes in the replacement string as
9170 special. THIS IS NOT BACKWARDS COMPATIBLE WITH BASH-4.2. */
9171 if (shell_compatibility_level > 42 && patsub_replacement == 0)
9172 rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
9173 else if (shell_compatibility_level > 42 && patsub_replacement)
9174 rep = expand_string_for_patsub (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT));
9175 /* This is the bash-4.2 code. */
9176 else if ((mflags & MATCH_QUOTED) == 0)
9177 rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
9178 else
9179 rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
9180
9181 /* Check whether or not to replace `&' in the replacement string after
9182 expanding it, since we want to treat backslashes quoting the `&'
9183 consistently. */
9184 if (patsub_replacement && rep && *rep && shouldexp_replacement (rep))
9185 mflags |= MATCH_EXPREP;
9186
9187 }
9188
9189 /* ksh93 doesn't allow the match specifier to be a part of the expanded
9190 pattern. This is an extension. Make sure we don't anchor the pattern
9191 at the beginning or end of the string if we're doing global replacement,
9192 though. */
9193 p = pat;
9194 if (mflags & MATCH_GLOBREP)
9195 mflags |= MATCH_ANY;
9196 else if (pat && pat[0] == '#')
9197 {
9198 mflags |= MATCH_BEG;
9199 p++;
9200 }
9201 else if (pat && pat[0] == '%')
9202 {
9203 mflags |= MATCH_END;
9204 p++;
9205 }
9206 else
9207 mflags |= MATCH_ANY;
9208
9209 /* OK, we now want to substitute REP for PAT in VAL. If
9210 flags & MATCH_GLOBREP is non-zero, the substitution is done
9211 everywhere, otherwise only the first occurrence of PAT is
9212 replaced. The pattern matching code doesn't understand
9213 CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
9214 values passed in (VT_VARIABLE) so the pattern substitution
9215 code works right. We need to requote special chars after
9216 we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
9217 other cases if QUOTED == 0, since the posparams and arrays
9218 indexed by * or @ do special things when QUOTED != 0. */
9219
9220 switch (vtype)
9221 {
9222 case VT_VARIABLE:
9223 case VT_ARRAYMEMBER:
9224 temp = pat_subst (val, p, rep, mflags);
9225 if (vtype == VT_VARIABLE)
9226 FREE (val);
9227 if (temp)
9228 {
9229 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
9230 free (temp);
9231 temp = tt;
9232 }
9233 break;
9234 case VT_POSPARMS:
9235 /* This does the right thing for the case where we are not performing
9236 word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and
9237 pos_params_pat_subst/string_list_pos_params will do the right thing
9238 in turn for the case where ifs_is_null. Posix interp 888 */
9239 if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB))
9240 mflags |= MATCH_ASSIGNRHS;
9241 temp = pos_params_pat_subst (val, p, rep, mflags);
9242 if (temp && quoted == 0 && ifs_is_null)
9243 {
9244 /* Posix interp 888 */
9245 }
9246 else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS))
9247 {
9248 /* Posix interp 888 */
9249 }
9250 else if (temp && (mflags & MATCH_QUOTED) == 0)
9251 {
9252 tt = quote_escapes (temp);
9253 free (temp);
9254 temp = tt;
9255 }
9256 break;
9257 #if defined (ARRAY_VARS)
9258 case VT_ARRAYVAR:
9259 /* If we are expanding in a context where word splitting will not be
9260 performed, treat as quoted. This changes how ${A[*]} will be
9261 expanded to make it identical to $*. */
9262 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9263 mflags |= MATCH_QUOTED; /* Posix interp 888 */
9264
9265 /* these eventually call string_list_pos_params */
9266 if (assoc_p (v))
9267 temp = assoc_patsub (assoc_cell (v), p, rep, mflags);
9268 else
9269 temp = array_patsub (array_cell (v), p, rep, mflags);
9270
9271 if (temp && quoted == 0 && ifs_is_null)
9272 {
9273 /* Posix interp 888 */
9274 }
9275 else if (temp && (mflags & MATCH_QUOTED) == 0)
9276 {
9277 tt = quote_escapes (temp);
9278 free (temp);
9279 temp = tt;
9280 }
9281 break;
9282 #endif
9283 }
9284
9285 FREE (pat);
9286 FREE (rep);
9287 free (lpatsub);
9288
9289 this_command_name = oname;
9290
9291 return temp;
9292 }
9293
9294 /****************************************************************/
9295 /* */
9296 /* Functions to perform case modification on variable values */
9297 /* */
9298 /****************************************************************/
9299
9300 /* Do case modification on the positional parameters. */
9301
9302 static char *
9303 pos_params_modcase (string, pat, modop, mflags)
9304 char *string, *pat;
9305 int modop;
9306 int mflags;
9307 {
9308 WORD_LIST *save, *params;
9309 WORD_DESC *w;
9310 char *ret;
9311 int pchar, qflags, pflags;
9312
9313 save = params = list_rest_of_args ();
9314 if (save == 0)
9315 return ((char *)NULL);
9316
9317 for ( ; params; params = params->next)
9318 {
9319 ret = sh_modcase (params->word->word, pat, modop);
9320 w = alloc_word_desc ();
9321 w->word = ret ? ret : savestring ("");
9322 dispose_word (params->word);
9323 params->word = w;
9324 }
9325
9326 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
9327 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
9328 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
9329
9330 /* If we are expanding in a context where word splitting will not be
9331 performed, treat as quoted. This changes how $* will be expanded. */
9332 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9333 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
9334
9335 ret = string_list_pos_params (pchar, save, qflags, pflags);
9336 dispose_words (save);
9337
9338 return (ret);
9339 }
9340
9341 /* Perform case modification on VALUE, which is the expansion of
9342 VARNAME. MODSPEC is an expression supplying the type of modification
9343 to perform. QUOTED is a flags word containing the type of quoting
9344 currently in effect. */
9345 static char *
9346 parameter_brace_casemod (varname, value, estatep, modspec, patspec, quoted, pflags, flags)
9347 char *varname, *value;
9348 array_eltstate_t *estatep;
9349 int modspec;
9350 char *patspec;
9351 int quoted, pflags, flags;
9352 {
9353 int vtype, starsub, modop, mflags, x;
9354 char *val, *temp, *pat, *p, *lpat, *tt, *oname;
9355 SHELL_VAR *v;
9356
9357 if (value == 0)
9358 return ((char *)NULL);
9359
9360 oname = this_command_name;
9361 this_command_name = varname;
9362
9363 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
9364 if (vtype == -1)
9365 {
9366 this_command_name = oname;
9367 return ((char *)NULL);
9368 }
9369
9370 starsub = vtype & VT_STARSUB;
9371 vtype &= ~VT_STARSUB;
9372
9373 modop = 0;
9374 mflags = 0;
9375 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9376 mflags |= MATCH_QUOTED;
9377 if (starsub)
9378 mflags |= MATCH_STARSUB;
9379 if (pflags & PF_ASSIGNRHS)
9380 mflags |= MATCH_ASSIGNRHS;
9381
9382 p = patspec;
9383 if (modspec == '^')
9384 {
9385 x = p && p[0] == modspec;
9386 modop = x ? CASE_UPPER : CASE_UPFIRST;
9387 p += x;
9388 }
9389 else if (modspec == ',')
9390 {
9391 x = p && p[0] == modspec;
9392 modop = x ? CASE_LOWER : CASE_LOWFIRST;
9393 p += x;
9394 }
9395 else if (modspec == '~')
9396 {
9397 x = p && p[0] == modspec;
9398 modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
9399 p += x;
9400 }
9401
9402 lpat = p ? savestring (p) : 0;
9403 /* Perform the same expansions on the pattern as performed by the
9404 pattern removal expansions. */
9405 pat = lpat ? getpattern (lpat, quoted, 1) : 0;
9406
9407 /* OK, now we do the case modification. */
9408 switch (vtype)
9409 {
9410 case VT_VARIABLE:
9411 case VT_ARRAYMEMBER:
9412 temp = sh_modcase (val, pat, modop);
9413 if (vtype == VT_VARIABLE)
9414 FREE (val);
9415 if (temp)
9416 {
9417 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
9418 free (temp);
9419 temp = tt;
9420 }
9421 break;
9422
9423 case VT_POSPARMS:
9424 temp = pos_params_modcase (val, pat, modop, mflags);
9425 if (temp && quoted == 0 && ifs_is_null)
9426 {
9427 /* Posix interp 888 */
9428 }
9429 else if (temp && (mflags & MATCH_QUOTED) == 0)
9430 {
9431 tt = quote_escapes (temp);
9432 free (temp);
9433 temp = tt;
9434 }
9435 break;
9436
9437 #if defined (ARRAY_VARS)
9438 case VT_ARRAYVAR:
9439 /* If we are expanding in a context where word splitting will not be
9440 performed, treat as quoted. This changes how ${A[*]} will be
9441 expanded to make it identical to $*. */
9442 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9443 mflags |= MATCH_QUOTED; /* Posix interp 888 */
9444
9445 temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
9446 : array_modcase (array_cell (v), pat, modop, mflags);
9447
9448 if (temp && quoted == 0 && ifs_is_null)
9449 {
9450 /* Posix interp 888 */
9451 }
9452 else if (temp && (mflags & MATCH_QUOTED) == 0)
9453 {
9454 tt = quote_escapes (temp);
9455 free (temp);
9456 temp = tt;
9457 }
9458
9459 break;
9460 #endif
9461 }
9462
9463 FREE (pat);
9464 free (lpat);
9465
9466 this_command_name = oname;
9467
9468 return temp;
9469 }
9470
9471 /* Check for unbalanced parens in S, which is the contents of $(( ... )). If
9472 any occur, this must be a nested command substitution, so return 0.
9473 Otherwise, return 1. A valid arithmetic expression must always have a
9474 ( before a matching ), so any cases where there are more right parens
9475 means that this must not be an arithmetic expression, though the parser
9476 will not accept it without a balanced total number of parens. */
9477 static int
9478 chk_arithsub (s, len)
9479 const char *s;
9480 int len;
9481 {
9482 int i, count;
9483 DECLARE_MBSTATE;
9484
9485 i = count = 0;
9486 while (i < len)
9487 {
9488 if (s[i] == LPAREN)
9489 count++;
9490 else if (s[i] == RPAREN)
9491 {
9492 count--;
9493 if (count < 0)
9494 return 0;
9495 }
9496
9497 switch (s[i])
9498 {
9499 default:
9500 ADVANCE_CHAR (s, len, i);
9501 break;
9502
9503 case '\\':
9504 i++;
9505 if (s[i])
9506 ADVANCE_CHAR (s, len, i);
9507 break;
9508
9509 case '\'':
9510 i = skip_single_quoted (s, len, ++i, 0);
9511 break;
9512
9513 case '"':
9514 i = skip_double_quoted ((char *)s, len, ++i, 0);
9515 break;
9516 }
9517 }
9518
9519 return (count == 0);
9520 }
9521
9522 /****************************************************************/
9523 /* */
9524 /* Functions to perform parameter expansion on a string */
9525 /* */
9526 /****************************************************************/
9527
9528 /* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
9529 static WORD_DESC *
9530 parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
9531 char *string;
9532 int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at;
9533 {
9534 int check_nullness, var_is_set, var_is_null, var_is_special;
9535 int want_substring, want_indir, want_patsub, want_casemod, want_attributes;
9536 char *name, *value, *temp, *temp1;
9537 WORD_DESC *tdesc, *ret;
9538 int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref;
9539 intmax_t number;
9540 array_eltstate_t es;
9541
9542 temp = temp1 = value = (char *)NULL;
9543 var_is_set = var_is_null = var_is_special = check_nullness = 0;
9544 want_substring = want_indir = want_patsub = want_casemod = want_attributes = 0;
9545
9546 local_pflags = 0;
9547 all_element_arrayref = 0;
9548
9549 sindex = *indexp;
9550 t_index = ++sindex;
9551 /* ${#var} doesn't have any of the other parameter expansions on it. */
9552 if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
9553 name = string_extract (string, &t_index, "}", SX_VARNAME);
9554 else
9555 #if defined (CASEMOD_EXPANSIONS)
9556 /* To enable case-toggling expansions using the `~' operator character
9557 define CASEMOD_TOGGLECASE in config-top.h */
9558 # if defined (CASEMOD_TOGGLECASE)
9559 name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME);
9560 # else
9561 name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME);
9562 # endif /* CASEMOD_TOGGLECASE */
9563 #else
9564 name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME);
9565 #endif /* CASEMOD_EXPANSIONS */
9566
9567 /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly
9568 the cleanest code ever. */
9569 if (*name == 0 && sindex == t_index && string[sindex] == '@')
9570 {
9571 name = (char *)xrealloc (name, 2);
9572 name[0] = '@';
9573 name[1] = '\0';
9574 t_index++;
9575 }
9576 else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE)
9577 {
9578 name = (char *)xrealloc (name, t_index - sindex + 2);
9579 name[t_index - sindex] = '@';
9580 name[t_index - sindex + 1] = '\0';
9581 t_index++;
9582 }
9583
9584 ret = 0;
9585 tflag = 0;
9586
9587 #if defined (ARRAY_VARS)
9588 init_eltstate (&es);
9589 #endif
9590 es.ind = INTMAX_MIN; /* XXX */
9591
9592 /* If the name really consists of a special variable, then make sure
9593 that we have the entire name. We don't allow indirect references
9594 to special variables except `#', `?', `@' and `*'. This clause is
9595 designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more
9596 general. */
9597 if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
9598 (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) ||
9599 (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
9600 {
9601 t_index++;
9602 temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0);
9603 name = (char *)xrealloc (name, 3 + (strlen (temp1)));
9604 *name = string[sindex];
9605 if (string[sindex] == '!')
9606 {
9607 /* indirect reference of $#, $?, $@, or $* */
9608 name[1] = string[sindex + 1];
9609 strcpy (name + 2, temp1);
9610 }
9611 else
9612 strcpy (name + 1, temp1);
9613 free (temp1);
9614 }
9615 sindex = t_index;
9616
9617 /* Find out what character ended the variable name. Then
9618 do the appropriate thing. */
9619 if (c = string[sindex])
9620 sindex++;
9621
9622 /* If c is followed by one of the valid parameter expansion
9623 characters, move past it as normal. If not, assume that
9624 a substring specification is being given, and do not move
9625 past it. */
9626 if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
9627 {
9628 check_nullness++;
9629 if (c = string[sindex])
9630 sindex++;
9631 }
9632 else if (c == ':' && string[sindex] != RBRACE)
9633 want_substring = 1;
9634 else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */
9635 want_patsub = 1;
9636 #if defined (CASEMOD_EXPANSIONS)
9637 else if (c == '^' || c == ',' || c == '~')
9638 {
9639 modspec = c;
9640 want_casemod = 1;
9641 }
9642 #endif
9643 else if (c == '@' && (string[sindex] == 'a' || string[sindex] == 'A') && string[sindex+1] == RBRACE)
9644 {
9645 /* special case because we do not want to shortcut foo as foo[0] here */
9646 want_attributes = 1;
9647 local_pflags |= PF_ALLINDS;
9648 }
9649
9650 /* Catch the valid and invalid brace expressions that made it through the
9651 tests above. */
9652 /* ${#-} is a valid expansion and means to take the length of $-.
9653 Similarly for ${#?} and ${##}... */
9654 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
9655 VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
9656 {
9657 name = (char *)xrealloc (name, 3);
9658 name[1] = c;
9659 name[2] = '\0';
9660 c = string[sindex++];
9661 }
9662
9663 /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
9664 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
9665 member (c, "%:=+/") && string[sindex] == RBRACE)
9666 {
9667 temp = (char *)NULL;
9668 goto bad_substitution; /* XXX - substitution error */
9669 }
9670
9671 /* Indirect expansion begins with a `!'. A valid indirect expansion is
9672 either a variable name, one of the positional parameters or a special
9673 variable that expands to one of the positional parameters. */
9674 want_indir = *name == '!' &&
9675 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
9676 || VALID_INDIR_PARAM (name[1]));
9677
9678 /* Determine the value of this variable whose name is NAME. */
9679
9680 /* Check for special variables, directly referenced. */
9681 if (SPECIAL_VAR (name, want_indir))
9682 var_is_special++;
9683
9684 /* Check for special expansion things, like the length of a parameter */
9685 if (*name == '#' && name[1])
9686 {
9687 /* If we are not pointing at the character just after the
9688 closing brace, then we haven't gotten all of the name.
9689 Since it begins with a special character, this is a bad
9690 substitution. Also check NAME for validity before trying
9691 to go on. */
9692 if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
9693 {
9694 temp = (char *)NULL;
9695 goto bad_substitution; /* substitution error */
9696 }
9697
9698 number = parameter_brace_expand_length (name);
9699 if (number == INTMAX_MIN && unbound_vars_is_error)
9700 {
9701 set_exit_status (EXECUTION_FAILURE);
9702 err_unboundvar (name+1);
9703 free (name);
9704 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9705 }
9706 free (name);
9707
9708 *indexp = sindex;
9709 if (number < 0)
9710 return (&expand_wdesc_error);
9711 else
9712 {
9713 ret = alloc_word_desc ();
9714 ret->word = itos (number);
9715 return ret;
9716 }
9717 }
9718
9719 /* ${@} is identical to $@. */
9720 if (name[0] == '@' && name[1] == '\0')
9721 {
9722 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9723 *quoted_dollar_atp = 1;
9724
9725 if (contains_dollar_at)
9726 *contains_dollar_at = 1;
9727
9728 tflag |= W_DOLLARAT;
9729 }
9730
9731 /* Process ${!PREFIX*} expansion. */
9732 if (want_indir && string[sindex - 1] == RBRACE &&
9733 (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
9734 legal_variable_starter ((unsigned char) name[1]))
9735 {
9736 char **x;
9737 WORD_LIST *xlist;
9738
9739 temp1 = savestring (name + 1);
9740 number = strlen (temp1);
9741 temp1[number - 1] = '\0';
9742 x = all_variables_matching_prefix (temp1);
9743 xlist = strvec_to_word_list (x, 0, 0);
9744 if (string[sindex - 2] == '*')
9745 temp = string_list_dollar_star (xlist, quoted, 0);
9746 else
9747 {
9748 temp = string_list_dollar_at (xlist, quoted, 0);
9749 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9750 *quoted_dollar_atp = 1;
9751 if (contains_dollar_at)
9752 *contains_dollar_at = 1;
9753
9754 tflag |= W_DOLLARAT;
9755 }
9756 free (x);
9757 dispose_words (xlist);
9758 free (temp1);
9759 *indexp = sindex;
9760
9761 free (name);
9762
9763 ret = alloc_word_desc ();
9764 ret->word = temp;
9765 ret->flags = tflag; /* XXX */
9766 return ret;
9767 }
9768
9769 #if defined (ARRAY_VARS)
9770 /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */
9771 if (want_indir && string[sindex - 1] == RBRACE &&
9772 string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0))
9773 {
9774 char *x, *x1;
9775
9776 temp1 = savestring (name + 1);
9777 x = array_variable_name (temp1, 0, &x1, (int *)0);
9778 FREE (x);
9779 if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK)
9780 {
9781 temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */
9782 if (x1[0] == '@')
9783 {
9784 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9785 *quoted_dollar_atp = 1;
9786 if (contains_dollar_at)
9787 *contains_dollar_at = 1;
9788
9789 tflag |= W_DOLLARAT;
9790 }
9791
9792 free (name);
9793 free (temp1);
9794 *indexp = sindex;
9795
9796 ret = alloc_word_desc ();
9797 ret->word = temp;
9798 ret->flags = tflag; /* XXX */
9799 return ret;
9800 }
9801
9802 free (temp1);
9803 }
9804 #endif /* ARRAY_VARS */
9805
9806 /* Make sure that NAME is valid before trying to go on. */
9807 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
9808 var_is_special) == 0)
9809 {
9810 temp = (char *)NULL;
9811 goto bad_substitution; /* substitution error */
9812 }
9813
9814 if (want_indir)
9815 {
9816 tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags|local_pflags, quoted_dollar_atp, contains_dollar_at);
9817 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9818 {
9819 temp = (char *)NULL;
9820 goto bad_substitution;
9821 }
9822
9823 /* Turn off the W_ARRAYIND flag because there is no way for this function
9824 to return the index we're supposed to be using. */
9825 if (tdesc && tdesc->flags)
9826 tdesc->flags &= ~W_ARRAYIND;
9827
9828 /* If the indir expansion contains $@/$*, extend the special treatment
9829 of the case of no positional parameters and `set -u' to it. */
9830 if (contains_dollar_at && *contains_dollar_at)
9831 all_element_arrayref = 1;
9832 }
9833 else
9834 {
9835 local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS));
9836 tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &es);
9837 }
9838
9839 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9840 {
9841 tflag = 0;
9842 tdesc = 0;
9843 }
9844
9845 if (tdesc)
9846 {
9847 temp = tdesc->word;
9848 tflag = tdesc->flags;
9849 dispose_word_desc (tdesc);
9850 }
9851 else
9852 temp = (char *)0;
9853
9854 if (temp == &expand_param_error || temp == &expand_param_fatal)
9855 {
9856 FREE (name);
9857 FREE (value);
9858 return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9859 }
9860
9861 #if defined (ARRAY_VARS)
9862 if (valid_array_reference (name, 0))
9863 {
9864 int qflags;
9865 char *t;
9866
9867 qflags = quoted;
9868 /* If in a context where word splitting will not take place, treat as
9869 if double-quoted. Has effects with $* and ${array[*]} */
9870
9871 if (pflags & PF_ASSIGNRHS)
9872 qflags |= Q_DOUBLE_QUOTES;
9873 /* We duplicate a little code here */
9874 t = mbschr (name, LBRACK);
9875 if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK)
9876 {
9877 all_element_arrayref = 1;
9878 if (expand_no_split_dollar_star && t[1] == '*') /* XXX */
9879 qflags |= Q_DOUBLE_QUOTES;
9880 }
9881 chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at);
9882 }
9883 #endif
9884
9885 var_is_set = temp != (char *)0;
9886 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
9887 /* XXX - this may not need to be restricted to special variables */
9888 if (check_nullness)
9889 var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp);
9890 #if defined (ARRAY_VARS)
9891 if (check_nullness)
9892 var_is_null |= var_is_set &&
9893 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) &&
9894 QUOTED_NULL (temp) &&
9895 valid_array_reference (name, 0) &&
9896 chk_atstar (name, 0, 0, (int *)0, (int *)0);
9897 #endif
9898
9899 /* Get the rest of the stuff inside the braces. */
9900 if (c && c != RBRACE)
9901 {
9902 /* Extract the contents of the ${ ... } expansion
9903 according to the Posix.2 rules. */
9904 value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
9905 if (string[sindex] == RBRACE)
9906 sindex++;
9907 else
9908 goto bad_substitution; /* substitution error */
9909 }
9910 else
9911 value = (char *)NULL;
9912
9913 *indexp = sindex;
9914
9915 /* All the cases where an expansion can possibly generate an unbound
9916 variable error. */
9917 if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE)
9918 {
9919 if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0)
9920 {
9921 set_exit_status (EXECUTION_FAILURE);
9922 err_unboundvar (name);
9923 FREE (value);
9924 FREE (temp);
9925 free (name);
9926 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9927 }
9928 }
9929
9930 /* If this is a substring spec, process it and add the result. */
9931 if (want_substring)
9932 {
9933 temp1 = parameter_brace_substring (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9934 FREE (value);
9935 FREE (temp);
9936 #if defined (ARRAY_VARS)
9937 flush_eltstate (&es);
9938 #endif
9939
9940 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9941 {
9942 FREE (name);
9943 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9944 }
9945
9946 ret = alloc_word_desc ();
9947 ret->word = temp1;
9948 /* We test quoted_dollar_atp because we want variants with double-quoted
9949 "$@" to take a different code path. In fact, we make sure at the end
9950 of expand_word_internal that we're only looking at these flags if
9951 quoted_dollar_at == 0. */
9952 if (temp1 &&
9953 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9954 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9955 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9956 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 &&
9957 (pflags & PF_ASSIGNRHS))
9958 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9959 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9960 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9961 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9962
9963 FREE (name);
9964 return ret;
9965 }
9966 else if (want_patsub)
9967 {
9968 temp1 = parameter_brace_patsub (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9969 FREE (value);
9970 FREE (temp);
9971 #if defined (ARRAY_VARS)
9972 flush_eltstate (&es);
9973 #endif
9974
9975 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9976 {
9977 FREE (name);
9978 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9979 }
9980
9981 ret = alloc_word_desc ();
9982 ret->word = temp1;
9983 if (temp1 &&
9984 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9985 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9986 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9987 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9988 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9989 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9990
9991 FREE (name);
9992 return ret;
9993 }
9994 #if defined (CASEMOD_EXPANSIONS)
9995 else if (want_casemod)
9996 {
9997 temp1 = parameter_brace_casemod (name, temp, &es, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9998 FREE (value);
9999 FREE (temp);
10000 #if defined (ARRAY_VARS)
10001 flush_eltstate (&es);
10002 #endif
10003
10004 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
10005 {
10006 FREE (name);
10007 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
10008 }
10009
10010 ret = alloc_word_desc ();
10011 ret->word = temp1;
10012 if (temp1 &&
10013 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
10014 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10015 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
10016 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10017 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10018 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10019
10020 FREE (name);
10021 return ret;
10022 }
10023 #endif
10024
10025 /* Do the right thing based on which character ended the variable name. */
10026 switch (c)
10027 {
10028 default:
10029 case '\0':
10030 bad_substitution:
10031 set_exit_status (EXECUTION_FAILURE);
10032 report_error (_("%s: bad substitution"), string ? string : "??");
10033 FREE (value);
10034 FREE (temp);
10035 free (name);
10036 #if defined (ARRAY_VARS)
10037 flush_eltstate (&es);
10038 #endif
10039 if (shell_compatibility_level <= 43)
10040 return &expand_wdesc_error;
10041 else
10042 return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error);
10043
10044 case RBRACE:
10045 break;
10046
10047 case '@':
10048 temp1 = parameter_brace_transform (name, temp, &es, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
10049 free (temp);
10050 free (value);
10051 #if defined (ARRAY_VARS)
10052 flush_eltstate (&es);
10053 #endif
10054
10055 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
10056 {
10057 free (name);
10058 set_exit_status (EXECUTION_FAILURE);
10059 report_error (_("%s: bad substitution"), string ? string : "??");
10060 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
10061 }
10062
10063 ret = alloc_word_desc ();
10064 ret->word = temp1;
10065 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10066 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
10067 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10068 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10069 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10070
10071 free (name);
10072 return ret;
10073
10074 case '#': /* ${param#[#]pattern} */
10075 case '%': /* ${param%[%]pattern} */
10076 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
10077 {
10078 FREE (value);
10079 break;
10080 }
10081 temp1 = parameter_brace_remove_pattern (name, temp, &es, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
10082 free (temp);
10083 free (value);
10084 #if defined (ARRAY_VARS)
10085 flush_eltstate (&es);
10086 #endif
10087
10088 ret = alloc_word_desc ();
10089 ret->word = temp1;
10090 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10091 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
10092 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10093 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10094 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10095
10096 free (name);
10097 return ret;
10098
10099 case '-':
10100 case '=':
10101 case '?':
10102 case '+':
10103 if (var_is_set && var_is_null == 0)
10104 {
10105 /* If the operator is `+', we don't want the value of the named
10106 variable for anything, just the value of the right hand side. */
10107 if (c == '+')
10108 {
10109 /* XXX -- if we're double-quoted and the named variable is "$@",
10110 we want to turn off any special handling of "$@" --
10111 we're not using it, so whatever is on the rhs applies. */
10112 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
10113 *quoted_dollar_atp = 0;
10114 if (contains_dollar_at)
10115 *contains_dollar_at = 0;
10116
10117 FREE (temp);
10118 if (value)
10119 {
10120 /* From Posix discussion on austin-group list. Issue 221
10121 requires that backslashes escaping `}' inside
10122 double-quoted ${...} be removed. */
10123 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10124 quoted |= Q_DOLBRACE;
10125 ret = parameter_brace_expand_rhs (name, value, c,
10126 quoted,
10127 pflags,
10128 quoted_dollar_atp,
10129 contains_dollar_at);
10130 /* XXX - fix up later, esp. noting presence of
10131 W_HASQUOTEDNULL in ret->flags */
10132 free (value);
10133 }
10134 else
10135 temp = (char *)NULL;
10136 }
10137 else
10138 {
10139 FREE (value);
10140 }
10141 /* Otherwise do nothing; just use the value in TEMP. */
10142 }
10143 else /* VAR not set or VAR is NULL. */
10144 {
10145 /* If we're freeing a quoted null here, we need to remember we saw
10146 it so we can restore it later if needed, or the caller can note it.
10147 The check against `+' doesn't really matter, since the other cases
10148 don't use or return TFLAG, but it's good for clarity. */
10149 if (c == '+' && temp && QUOTED_NULL (temp) &&
10150 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
10151 tflag |= W_HASQUOTEDNULL;
10152
10153 FREE (temp);
10154 temp = (char *)NULL;
10155 if (c == '=' && var_is_special)
10156 {
10157 set_exit_status (EXECUTION_FAILURE);
10158 report_error (_("$%s: cannot assign in this way"), name);
10159 free (name);
10160 free (value);
10161 #if defined (ARRAY_VARS)
10162 flush_eltstate (&es);
10163 #endif
10164 return &expand_wdesc_error;
10165 }
10166 else if (c == '?')
10167 {
10168 parameter_brace_expand_error (name, value, check_nullness);
10169 #if defined (ARRAY_VARS)
10170 flush_eltstate (&es);
10171 #endif
10172 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10173 }
10174 else if (c != '+')
10175 {
10176 /* XXX -- if we're double-quoted and the named variable is "$@",
10177 we want to turn off any special handling of "$@" --
10178 we're not using it, so whatever is on the rhs applies. */
10179 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
10180 *quoted_dollar_atp = 0;
10181 if (contains_dollar_at)
10182 *contains_dollar_at = 0;
10183
10184 /* From Posix discussion on austin-group list. Issue 221 requires
10185 that backslashes escaping `}' inside double-quoted ${...} be
10186 removed. */
10187 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10188 quoted |= Q_DOLBRACE;
10189 ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags,
10190 quoted_dollar_atp,
10191 contains_dollar_at);
10192 /* XXX - fix up later, esp. noting presence of
10193 W_HASQUOTEDNULL in tdesc->flags */
10194 }
10195 free (value);
10196 }
10197
10198 break;
10199 }
10200 free (name);
10201 #if defined (ARRAY_VARS)
10202 flush_eltstate (&es);
10203 #endif
10204
10205 if (ret == 0)
10206 {
10207 ret = alloc_word_desc ();
10208 ret->flags = tflag;
10209 ret->word = temp;
10210 }
10211 return (ret);
10212 }
10213
10214 /* Expand a single ${xxx} expansion. The braces are optional. When
10215 the braces are used, parameter_brace_expand() does the work,
10216 possibly calling param_expand recursively. */
10217 static WORD_DESC *
10218 param_expand (string, sindex, quoted, expanded_something,
10219 contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
10220 pflags)
10221 char *string;
10222 int *sindex, quoted, *expanded_something, *contains_dollar_at;
10223 int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
10224 {
10225 char *temp, *temp1, uerror[3], *savecmd;
10226 int zindex, t_index, expok, eflag;
10227 unsigned char c;
10228 intmax_t number;
10229 SHELL_VAR *var;
10230 WORD_LIST *list, *l;
10231 WORD_DESC *tdesc, *ret;
10232 int tflag, nullarg;
10233
10234 /*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/
10235 zindex = *sindex;
10236 c = string[++zindex];
10237
10238 temp = (char *)NULL;
10239 ret = tdesc = (WORD_DESC *)NULL;
10240 tflag = 0;
10241
10242 /* Do simple cases first. Switch on what follows '$'. */
10243 switch (c)
10244 {
10245 /* $0 .. $9? */
10246 case '0':
10247 case '1':
10248 case '2':
10249 case '3':
10250 case '4':
10251 case '5':
10252 case '6':
10253 case '7':
10254 case '8':
10255 case '9':
10256 temp1 = dollar_vars[TODIGIT (c)];
10257 /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */
10258 if (unbound_vars_is_error && temp1 == (char *)NULL)
10259 {
10260 uerror[0] = '$';
10261 uerror[1] = c;
10262 uerror[2] = '\0';
10263 set_exit_status (EXECUTION_FAILURE);
10264 err_unboundvar (uerror);
10265 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10266 }
10267 if (temp1)
10268 temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10269 ? quote_string (temp1)
10270 : quote_escapes (temp1);
10271 else
10272 temp = (char *)NULL;
10273
10274 break;
10275
10276 /* $$ -- pid of the invoking shell. */
10277 case '$':
10278 temp = itos (dollar_dollar_pid);
10279 break;
10280
10281 /* $# -- number of positional parameters. */
10282 case '#':
10283 temp = itos (number_of_args ());
10284 break;
10285
10286 /* $? -- return value of the last synchronous command. */
10287 case '?':
10288 temp = itos (last_command_exit_value);
10289 break;
10290
10291 /* $- -- flags supplied to the shell on invocation or by `set'. */
10292 case '-':
10293 temp = which_set_flags ();
10294 break;
10295
10296 /* $! -- Pid of the last asynchronous command. */
10297 case '!':
10298 /* If no asynchronous pids have been created, expand to nothing.
10299 If `set -u' has been executed, and no async processes have
10300 been created, this is an expansion error. */
10301 if (last_asynchronous_pid == NO_PID)
10302 {
10303 if (expanded_something)
10304 *expanded_something = 0;
10305 temp = (char *)NULL;
10306 if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
10307 {
10308 uerror[0] = '$';
10309 uerror[1] = c;
10310 uerror[2] = '\0';
10311 set_exit_status (EXECUTION_FAILURE);
10312 err_unboundvar (uerror);
10313 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10314 }
10315 }
10316 else
10317 temp = itos (last_asynchronous_pid);
10318 break;
10319
10320 /* The only difference between this and $@ is when the arg is quoted. */
10321 case '*': /* `$*' */
10322 list = list_rest_of_args ();
10323
10324 #if 0
10325 /* According to austin-group posix proposal by Geoff Clare in
10326 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
10327
10328 "The shell shall write a message to standard error and
10329 immediately exit when it tries to expand an unset parameter
10330 other than the '@' and '*' special parameters."
10331 */
10332
10333 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
10334 {
10335 uerror[0] = '$';
10336 uerror[1] = '*';
10337 uerror[2] = '\0';
10338 set_exit_status (EXECUTION_FAILURE);
10339 err_unboundvar (uerror);
10340 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10341 }
10342 #endif
10343
10344 /* If there are no command-line arguments, this should just
10345 disappear if there are other characters in the expansion,
10346 even if it's quoted. */
10347 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
10348 temp = (char *)NULL;
10349 else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
10350 {
10351 /* If we have "$*" we want to make a string of the positional
10352 parameters, separated by the first character of $IFS, and
10353 quote the whole string, including the separators. If IFS
10354 is unset, the parameters are separated by ' '; if $IFS is
10355 null, the parameters are concatenated. */
10356 temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list);
10357 if (temp)
10358 {
10359 temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp;
10360 if (*temp == 0)
10361 tflag |= W_HASQUOTEDNULL;
10362 if (temp != temp1)
10363 free (temp);
10364 temp = temp1;
10365 }
10366 }
10367 else
10368 {
10369 /* We check whether or not we're eventually going to split $* here,
10370 for example when IFS is empty and we are processing the rhs of
10371 an assignment statement. In that case, we don't separate the
10372 arguments at all. Otherwise, if the $* is not quoted it is
10373 identical to $@ */
10374 if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS))
10375 {
10376 /* Posix interp 888: RHS of assignment, IFS unset: no splitting,
10377 separate with space */
10378 temp1 = string_list_dollar_star (list, quoted, pflags);
10379 temp = temp1 ? quote_string (temp1) : temp1;
10380 /* XXX - tentative - note that we saw a quoted null here */
10381 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
10382 tflag |= W_SAWQUOTEDNULL;
10383 FREE (temp1);
10384 }
10385 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS))
10386 {
10387 /* Posix interp 888: RHS of assignment, IFS set to '' */
10388 temp1 = string_list_dollar_star (list, quoted, pflags);
10389 temp = temp1 ? quote_escapes (temp1) : temp1;
10390 FREE (temp1);
10391 }
10392 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS))
10393 {
10394 /* Posix interp 888: RHS of assignment, IFS set to non-null value */
10395 temp1 = string_list_dollar_star (list, quoted, pflags);
10396 temp = temp1 ? quote_string (temp1) : temp1;
10397
10398 /* XXX - tentative - note that we saw a quoted null here */
10399 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
10400 tflag |= W_SAWQUOTEDNULL;
10401 FREE (temp1);
10402 }
10403 /* XXX - should we check ifs_is_set here as well? */
10404 # if defined (HANDLE_MULTIBYTE)
10405 else if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
10406 # else
10407 else if (expand_no_split_dollar_star && ifs_firstc == 0)
10408 # endif
10409 /* Posix interp 888: not RHS, no splitting, IFS set to '' */
10410 temp = string_list_dollar_star (list, quoted, 0);
10411 else
10412 {
10413 temp = string_list_dollar_at (list, quoted, 0);
10414 /* Set W_SPLITSPACE to make sure the individual positional
10415 parameters are split into separate arguments */
10416 #if 0
10417 if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null))
10418 #else /* change with bash-5.0 */
10419 if (quoted == 0 && ifs_is_null)
10420 #endif
10421 tflag |= W_SPLITSPACE;
10422 /* If we're not quoted but we still don't want word splitting, make
10423 we quote the IFS characters to protect them from splitting (e.g.,
10424 when $@ is in the string as well). */
10425 else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS))
10426 {
10427 temp1 = quote_string (temp);
10428 free (temp);
10429 temp = temp1;
10430 }
10431 }
10432
10433 if (expand_no_split_dollar_star == 0 && contains_dollar_at)
10434 *contains_dollar_at = 1;
10435 }
10436
10437 dispose_words (list);
10438 break;
10439
10440 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
10441 means that we have to turn quoting off after we split into
10442 the individually quoted arguments so that the final split
10443 on the first character of $IFS is still done. */
10444 case '@': /* `$@' */
10445 list = list_rest_of_args ();
10446
10447 #if 0
10448 /* According to austin-group posix proposal by Geoff Clare in
10449 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
10450
10451 "The shell shall write a message to standard error and
10452 immediately exit when it tries to expand an unset parameter
10453 other than the '@' and '*' special parameters."
10454 */
10455
10456 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
10457 {
10458 uerror[0] = '$';
10459 uerror[1] = '@';
10460 uerror[2] = '\0';
10461 set_exit_status (EXECUTION_FAILURE);
10462 err_unboundvar (uerror);
10463 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10464 }
10465 #endif
10466
10467 for (nullarg = 0, l = list; l; l = l->next)
10468 {
10469 if (l->word && (l->word->word == 0 || l->word->word[0] == 0))
10470 nullarg = 1;
10471 }
10472
10473 /* We want to flag the fact that we saw this. We can't turn
10474 off quoting entirely, because other characters in the
10475 string might need it (consider "\"$@\""), but we need some
10476 way to signal that the final split on the first character
10477 of $IFS should be done, even though QUOTED is 1. */
10478 /* XXX - should this test include Q_PATQUOTE? */
10479 if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10480 *quoted_dollar_at_p = 1;
10481 if (contains_dollar_at)
10482 *contains_dollar_at = 1;
10483
10484 /* We want to separate the positional parameters with the first
10485 character of $IFS in case $IFS is something other than a space.
10486 We also want to make sure that splitting is done no matter what --
10487 according to POSIX.2, this expands to a list of the positional
10488 parameters no matter what IFS is set to. */
10489 /* XXX - what to do when in a context where word splitting is not
10490 performed? Even when IFS is not the default, posix seems to imply
10491 that we have to expand $@ to all the positional parameters and
10492 separate them with spaces, which are preserved because word splitting
10493 doesn't take place. See below for how we use PF_NOSPLIT2 here. */
10494
10495 /* These are the cases where word splitting will not be performed. */
10496 if (pflags & PF_ASSIGNRHS)
10497 {
10498 temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags);
10499 if (nullarg)
10500 tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */
10501 }
10502
10503 /* This needs to match what expand_word_internal does with non-quoted $@
10504 does with separating with spaces. Passing Q_DOUBLE_QUOTES means that
10505 the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that
10506 they will separated by spaces. After doing this, we need the special
10507 handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC
10508 quotes. */
10509 else if (pflags & PF_NOSPLIT2)
10510 {
10511 #if defined (HANDLE_MULTIBYTE)
10512 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
10513 #else
10514 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
10515 #endif
10516 /* Posix interp 888 */
10517 temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags);
10518 else
10519 temp = string_list_dollar_at (list, quoted, pflags);
10520 }
10521 else
10522 temp = string_list_dollar_at (list, quoted, pflags);
10523
10524 tflag |= W_DOLLARAT;
10525 dispose_words (list);
10526 break;
10527
10528 case LBRACE:
10529 tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
10530 quoted_dollar_at_p,
10531 contains_dollar_at);
10532
10533 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
10534 return (tdesc);
10535 temp = tdesc ? tdesc->word : (char *)0;
10536
10537 /* XXX */
10538 /* Quoted nulls should be removed if there is anything else
10539 in the string. */
10540 /* Note that we saw the quoted null so we can add one back at
10541 the end of this function if there are no other characters
10542 in the string, discard TEMP, and go on. The exception to
10543 this is when we have "${@}" and $1 is '', since $@ needs
10544 special handling. */
10545 if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
10546 {
10547 if (had_quoted_null_p)
10548 *had_quoted_null_p = 1;
10549 if (*quoted_dollar_at_p == 0)
10550 {
10551 free (temp);
10552 tdesc->word = temp = (char *)NULL;
10553 }
10554
10555 }
10556
10557 ret = tdesc;
10558 goto return0;
10559
10560 /* Do command or arithmetic substitution. */
10561 case LPAREN:
10562 /* We have to extract the contents of this paren substitution. */
10563 t_index = zindex + 1;
10564 /* XXX - might want to check for string[t_index+2] == LPAREN and parse
10565 as arithmetic substitution immediately. */
10566 temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0);
10567 zindex = t_index;
10568
10569 /* For Posix.2-style `$(( ))' arithmetic substitution,
10570 extract the expression and pass it to the evaluator. */
10571 if (temp && *temp == LPAREN)
10572 {
10573 char *temp2;
10574 temp1 = temp + 1;
10575 temp2 = savestring (temp1);
10576 t_index = strlen (temp2) - 1;
10577
10578 if (temp2[t_index] != RPAREN)
10579 {
10580 free (temp2);
10581 goto comsub;
10582 }
10583
10584 /* Cut off ending `)' */
10585 temp2[t_index] = '\0';
10586
10587 if (chk_arithsub (temp2, t_index) == 0)
10588 {
10589 free (temp2);
10590 #if 0
10591 internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
10592 #endif
10593 goto comsub;
10594 }
10595
10596 /* Expand variables found inside the expression. */
10597 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
10598 free (temp2);
10599
10600 arithsub:
10601 /* No error messages. */
10602 savecmd = this_command_name;
10603 this_command_name = (char *)NULL;
10604
10605 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
10606 number = evalexp (temp1, eflag, &expok);
10607 this_command_name = savecmd;
10608 free (temp);
10609 free (temp1);
10610 if (expok == 0)
10611 {
10612 if (interactive_shell == 0 && posixly_correct)
10613 {
10614 set_exit_status (EXECUTION_FAILURE);
10615 return (&expand_wdesc_fatal);
10616 }
10617 else
10618 return (&expand_wdesc_error);
10619 }
10620 temp = itos (number);
10621 break;
10622 }
10623
10624 comsub:
10625 if (pflags & PF_NOCOMSUB)
10626 /* we need zindex+1 because string[zindex] == RPAREN */
10627 temp1 = substring (string, *sindex, zindex+1);
10628 else
10629 {
10630 tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS);
10631 temp1 = tdesc ? tdesc->word : (char *)NULL;
10632 if (tdesc)
10633 dispose_word_desc (tdesc);
10634 }
10635 FREE (temp);
10636 temp = temp1;
10637 break;
10638
10639 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
10640 away in a future bash release. */
10641 case '[': /*]*/
10642 /* Extract the contents of this arithmetic substitution. */
10643 t_index = zindex + 1;
10644 temp = extract_arithmetic_subst (string, &t_index);
10645 zindex = t_index;
10646 if (temp == 0)
10647 {
10648 temp = savestring (string);
10649 if (expanded_something)
10650 *expanded_something = 0;
10651 goto return0;
10652 }
10653
10654 /* Do initial variable expansion. */
10655 temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH);
10656
10657 goto arithsub;
10658
10659 default:
10660 /* Find the variable in VARIABLE_LIST. */
10661 temp = (char *)NULL;
10662
10663 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
10664 ;
10665 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
10666
10667 /* If this isn't a variable name, then just output the `$'. */
10668 if (temp1 == 0 || *temp1 == '\0')
10669 {
10670 FREE (temp1);
10671 temp = (char *)xmalloc (2);
10672 temp[0] = '$';
10673 temp[1] = '\0';
10674 if (expanded_something)
10675 *expanded_something = 0;
10676 goto return0;
10677 }
10678
10679 /* If the variable exists, return its value cell. */
10680 var = find_variable (temp1);
10681
10682 if (var && invisible_p (var) == 0 && var_isset (var))
10683 {
10684 #if defined (ARRAY_VARS)
10685 if (assoc_p (var) || array_p (var))
10686 {
10687 temp = array_p (var) ? array_reference (array_cell (var), 0)
10688 : assoc_reference (assoc_cell (var), "0");
10689 if (temp)
10690 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10691 ? quote_string (temp)
10692 : quote_escapes (temp);
10693 else if (unbound_vars_is_error)
10694 goto unbound_variable;
10695 }
10696 else
10697 #endif
10698 {
10699 temp = value_cell (var);
10700
10701 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10702 ? quote_string (temp)
10703 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
10704 : quote_escapes (temp));
10705 }
10706
10707 free (temp1);
10708
10709 goto return0;
10710 }
10711 else if (var && (invisible_p (var) || var_isset (var) == 0))
10712 temp = (char *)NULL;
10713 else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0)
10714 {
10715 temp = nameref_cell (var);
10716 #if defined (ARRAY_VARS)
10717 if (temp && *temp && valid_array_reference (temp, 0))
10718 {
10719 chk_atstar (temp, quoted, pflags, quoted_dollar_at_p, contains_dollar_at);
10720 tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, 0);
10721 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
10722 return (tdesc);
10723 ret = tdesc;
10724 goto return0;
10725 }
10726 else
10727 #endif
10728 /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */
10729 if (temp && *temp && legal_identifier (temp) == 0)
10730 {
10731 set_exit_status (EXECUTION_FAILURE);
10732 report_error (_("%s: invalid variable name for name reference"), temp);
10733 return (&expand_wdesc_error); /* XXX */
10734 }
10735 else
10736 temp = (char *)NULL;
10737 }
10738
10739 temp = (char *)NULL;
10740
10741 unbound_variable:
10742 if (unbound_vars_is_error)
10743 {
10744 set_exit_status (EXECUTION_FAILURE);
10745 err_unboundvar (temp1);
10746 }
10747 else
10748 {
10749 free (temp1);
10750 goto return0;
10751 }
10752
10753 free (temp1);
10754 set_exit_status (EXECUTION_FAILURE);
10755 return ((unbound_vars_is_error && interactive_shell == 0)
10756 ? &expand_wdesc_fatal
10757 : &expand_wdesc_error);
10758 }
10759
10760 if (string[zindex])
10761 zindex++;
10762
10763 return0:
10764 *sindex = zindex;
10765
10766 if (ret == 0)
10767 {
10768 ret = alloc_word_desc ();
10769 ret->flags = tflag; /* XXX */
10770 ret->word = temp;
10771 }
10772 return ret;
10773 }
10774
10775 #if defined (ARRAY_VARS)
10776 /* Characters that need to be backslash-quoted after expanding array subscripts */
10777 static char abstab[256] = { '\1' };
10778
10779 /* Run an array subscript through the appropriate word expansions. */
10780 char *
10781 expand_subscript_string (string, quoted)
10782 char *string;
10783 int quoted;
10784 {
10785 WORD_DESC td;
10786 WORD_LIST *tlist;
10787 int oe;
10788 char *ret;
10789
10790 if (string == 0 || *string == 0)
10791 return (char *)NULL;
10792
10793 oe = expand_no_split_dollar_star;
10794 ret = (char *)NULL;
10795
10796 td.flags = W_NOPROCSUB|W_NOTILDE|W_NOSPLIT2; /* XXX - W_NOCOMSUB? */
10797 td.word = savestring (string); /* in case it's freed on error */
10798
10799 expand_no_split_dollar_star = 1;
10800 tlist = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
10801 expand_no_split_dollar_star = oe;
10802
10803 if (tlist)
10804 {
10805 if (tlist->word)
10806 {
10807 remove_quoted_nulls (tlist->word->word);
10808 tlist->word->flags &= ~W_HASQUOTEDNULL;
10809 }
10810 dequote_list (tlist);
10811 ret = string_list (tlist);
10812 dispose_words (tlist);
10813 }
10814
10815 free (td.word);
10816 return (ret);
10817 }
10818
10819 /* Expand the subscript in STRING, which is an array reference. To ensure we
10820 only expand it once, we quote the characters that would start another
10821 expansion and the bracket characters that are special to array subscripts. */
10822 static char *
10823 expand_array_subscript (string, sindex, quoted, flags)
10824 char *string;
10825 int *sindex;
10826 int quoted, flags;
10827 {
10828 char *ret, *exp, *t;
10829 size_t slen;
10830 int si, ni;
10831
10832 si = *sindex;
10833 slen = STRLEN (string);
10834
10835 if (abstab[0] == '\1')
10836 {
10837 /* These are basically the characters that start shell expansions plus
10838 the characters that delimit subscripts. */
10839 memset (abstab, '\0', sizeof (abstab));
10840 abstab[LBRACK] = abstab[RBRACK] = 1;
10841 abstab['$'] = abstab['`'] = abstab['~'] = 1;
10842 abstab['\\'] = abstab['\''] = 1;
10843 abstab['"'] = 1; /* XXX */
10844 /* We don't quote `@' or `*' in the subscript at all. */
10845 }
10846
10847 /* string[si] == LBRACK */
10848 ni = skipsubscript (string, si, 0);
10849 /* These checks mirror the ones in valid_array_reference. The check for
10850 (ni - si) == 1 checks for empty subscripts. We don't check that the
10851 subscript is a separate word if we're parsing an arithmetic expression. */
10852 if (ni >= slen || string[ni] != RBRACK || (ni - si) == 1 ||
10853 (string[ni+1] != '\0' && (quoted & Q_ARITH) == 0))
10854 {
10855 /* let's check and see what fails this check */
10856 INTERNAL_DEBUG (("expand_array_subscript: bad subscript string: `%s'", string+si));
10857 ret = (char *)xmalloc (2); /* badly-formed subscript */
10858 ret[0] = string[si];
10859 ret[1] = '\0';
10860 *sindex = si + 1;
10861 return ret;
10862 }
10863
10864 /* STRING[ni] == RBRACK */
10865 exp = substring (string, si+1, ni);
10866 t = expand_subscript_string (exp, quoted & ~(Q_ARITH|Q_DOUBLE_QUOTES));
10867 free (exp);
10868 exp = t ? sh_backslash_quote (t, abstab, 0) : savestring ("");
10869 free (t);
10870
10871 slen = STRLEN (exp);
10872 ret = xmalloc (slen + 2 + 1);
10873 ret[0] ='[';
10874 strcpy (ret + 1, exp);
10875 ret[slen + 1] = ']';
10876 ret[slen + 2] = '\0';
10877
10878 free (exp);
10879 *sindex = ni + 1;
10880
10881 return ret;
10882 }
10883 #endif
10884
10885 void
10886 invalidate_cached_quoted_dollar_at ()
10887 {
10888 dispose_words (cached_quoted_dollar_at);
10889 cached_quoted_dollar_at = 0;
10890 }
10891
10892 /* Make a word list which is the result of parameter and variable
10893 expansion, command substitution, arithmetic substitution, and
10894 quote removal of WORD. Return a pointer to a WORD_LIST which is
10895 the result of the expansion. If WORD contains a null word, the
10896 word list returned is also null.
10897
10898 QUOTED contains flag values defined in shell.h.
10899
10900 ISEXP is used to tell expand_word_internal that the word should be
10901 treated as the result of an expansion. This has implications for
10902 how IFS characters in the word are treated.
10903
10904 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
10905 they point to an integer value which receives information about expansion.
10906 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
10907 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
10908 else zero.
10909
10910 This only does word splitting in the case of $@ expansion. In that
10911 case, we split on ' '. */
10912
10913 /* Values for the local variable quoted_state. */
10914 #define UNQUOTED 0
10915 #define PARTIALLY_QUOTED 1
10916 #define WHOLLY_QUOTED 2
10917
10918 static WORD_LIST *
10919 expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
10920 WORD_DESC *word;
10921 int quoted, isexp;
10922 int *contains_dollar_at;
10923 int *expanded_something;
10924 {
10925 WORD_LIST *list;
10926 WORD_DESC *tword;
10927
10928 /* The intermediate string that we build while expanding. */
10929 char *istring;
10930
10931 /* The current size of the above object. */
10932 size_t istring_size;
10933
10934 /* Index into ISTRING. */
10935 size_t istring_index;
10936
10937 /* Temporary string storage. */
10938 char *temp, *temp1;
10939
10940 /* The text of WORD. */
10941 register char *string;
10942
10943 /* The size of STRING. */
10944 size_t string_size;
10945
10946 /* The index into STRING. */
10947 int sindex;
10948
10949 /* This gets 1 if we see a $@ while quoted. */
10950 int quoted_dollar_at;
10951
10952 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
10953 whether WORD contains no quoting characters, a partially quoted
10954 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
10955 int quoted_state;
10956
10957 /* State flags */
10958 int had_quoted_null;
10959 int has_quoted_ifs; /* did we add a quoted $IFS character here? */
10960 int has_dollar_at, temp_has_dollar_at;
10961 int internal_tilde;
10962 int split_on_spaces;
10963 int local_expanded;
10964 int tflag;
10965 int pflags; /* flags passed to param_expand */
10966 int mb_cur_max;
10967
10968 int assignoff; /* If assignment, offset of `=' */
10969
10970 register unsigned char c; /* Current character. */
10971 int t_index; /* For calls to string_extract_xxx. */
10972
10973 char twochars[2];
10974
10975 DECLARE_MBSTATE;
10976
10977 /* OK, let's see if we can optimize a common idiom: "$@". This needs to make sure
10978 that all of the flags callers care about (e.g., W_HASQUOTEDNULL) are set in
10979 list->flags. */
10980 if (STREQ (word->word, "\"$@\"") &&
10981 (word->flags == (W_HASDOLLAR|W_QUOTED)) &&
10982 dollar_vars[1]) /* XXX - check IFS here as well? */
10983 {
10984 if (contains_dollar_at)
10985 *contains_dollar_at = 1;
10986 if (expanded_something)
10987 *expanded_something = 1;
10988 if (cached_quoted_dollar_at)
10989 return (copy_word_list (cached_quoted_dollar_at));
10990 list = list_rest_of_args ();
10991 list = quote_list (list);
10992 cached_quoted_dollar_at = copy_word_list (list);
10993 return (list);
10994 }
10995
10996 istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
10997 istring[istring_index = 0] = '\0';
10998 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
10999 has_quoted_ifs = 0;
11000 split_on_spaces = 0;
11001 internal_tilde = 0; /* expanding =~ or :~ */
11002 quoted_state = UNQUOTED;
11003
11004 string = word->word;
11005 if (string == 0)
11006 goto finished_with_string;
11007 mb_cur_max = MB_CUR_MAX;
11008
11009 /* Don't need the string length for the SADD... and COPY_ macros unless
11010 multibyte characters are possible, but do need it for bounds checking. */
11011 string_size = (mb_cur_max > 1) ? strlen (string) : 1;
11012
11013 if (contains_dollar_at)
11014 *contains_dollar_at = 0;
11015
11016 assignoff = -1;
11017
11018 /* Begin the expansion. */
11019
11020 for (sindex = 0; ;)
11021 {
11022 c = string[sindex];
11023
11024 /* Case on top-level character. */
11025 switch (c)
11026 {
11027 case '\0':
11028 goto finished_with_string;
11029
11030 case CTLESC:
11031 sindex++;
11032 #if HANDLE_MULTIBYTE
11033 if (mb_cur_max > 1 && string[sindex])
11034 {
11035 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
11036 }
11037 else
11038 #endif
11039 {
11040 temp = (char *)xmalloc (3);
11041 temp[0] = CTLESC;
11042 temp[1] = c = string[sindex];
11043 temp[2] = '\0';
11044 }
11045
11046 dollar_add_string:
11047 if (string[sindex])
11048 sindex++;
11049
11050 add_string:
11051 if (temp)
11052 {
11053 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
11054 temp = (char *)0;
11055 }
11056
11057 break;
11058
11059 #if defined (PROCESS_SUBSTITUTION)
11060 /* Process substitution. */
11061 case '<':
11062 case '>':
11063 {
11064 /* XXX - technically this should only be expanded at the start
11065 of a word */
11066 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & W_NOPROCSUB))
11067 {
11068 sindex--; /* add_character: label increments sindex */
11069 goto add_character;
11070 }
11071 else
11072 t_index = sindex + 1; /* skip past both '<' and LPAREN */
11073
11074 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/
11075 sindex = t_index;
11076
11077 /* If the process substitution specification is `<()', we want to
11078 open the pipe for writing in the child and produce output; if
11079 it is `>()', we want to open the pipe for reading in the child
11080 and consume input. */
11081 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
11082
11083 FREE (temp1);
11084
11085 goto dollar_add_string;
11086 }
11087 #endif /* PROCESS_SUBSTITUTION */
11088
11089 #if defined (ARRAY_VARS)
11090 case '[': /*]*/
11091 if ((quoted & Q_ARITH) == 0 || shell_compatibility_level <= 51)
11092 {
11093 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
11094 goto add_ifs_character;
11095 else
11096 goto add_character;
11097 }
11098 else
11099 {
11100 temp = expand_array_subscript (string, &sindex, quoted, word->flags);
11101 goto add_string;
11102 }
11103 #endif
11104
11105 case '=':
11106 /* Posix.2 section 3.6.1 says that tildes following `=' in words
11107 which are not assignment statements are not expanded. If the
11108 shell isn't in posix mode, though, we perform tilde expansion
11109 on `likely candidate' unquoted assignment statements (flags
11110 include W_ASSIGNMENT but not W_QUOTED). A likely candidate
11111 contains an unquoted :~ or =~. Something to think about: we
11112 now have a flag that says to perform tilde expansion on arguments
11113 to `assignment builtins' like declare and export that look like
11114 assignment statements. We now do tilde expansion on such words
11115 even in POSIX mode. */
11116 if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
11117 {
11118 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11119 goto add_ifs_character;
11120 else
11121 goto add_character;
11122 }
11123 /* If we're not in posix mode or forcing assignment-statement tilde
11124 expansion, note where the first `=' appears in the word and prepare
11125 to do tilde expansion following the first `='. We have to keep
11126 track of the first `=' (using assignoff) to avoid being confused
11127 by an `=' in the rhs of the assignment statement. */
11128 if ((word->flags & W_ASSIGNMENT) &&
11129 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
11130 assignoff == -1 && sindex > 0)
11131 assignoff = sindex;
11132 if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
11133 internal_tilde = 1;
11134
11135 if (word->flags & W_ASSIGNARG)
11136 word->flags |= W_ASSIGNRHS; /* affects $@ */
11137
11138 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11139 {
11140 has_quoted_ifs++;
11141 goto add_ifs_character;
11142 }
11143 else
11144 goto add_character;
11145
11146 case ':':
11147 if (word->flags & (W_NOTILDE|W_NOASSNTILDE))
11148 {
11149 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11150 goto add_ifs_character;
11151 else
11152 goto add_character;
11153 }
11154
11155 if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) &&
11156 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
11157 string[sindex+1] == '~')
11158 internal_tilde = 1;
11159
11160 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11161 goto add_ifs_character;
11162 else
11163 goto add_character;
11164
11165 case '~':
11166 /* If the word isn't supposed to be tilde expanded, or we're not
11167 at the start of a word or after an unquoted : or = in an
11168 assignment statement, we don't do tilde expansion. We don't
11169 do tilde expansion if quoted or in an arithmetic context. */
11170
11171 if ((word->flags & W_NOTILDE) ||
11172 (sindex > 0 && (internal_tilde == 0)) ||
11173 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
11174 {
11175 internal_tilde = 0;
11176 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
11177 goto add_ifs_character;
11178 else
11179 goto add_character;
11180 }
11181
11182 if (word->flags & W_ASSIGNRHS)
11183 tflag = 2;
11184 else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
11185 tflag = 1;
11186 else
11187 tflag = 0;
11188
11189 temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
11190
11191 internal_tilde = 0;
11192
11193 if (temp && *temp && t_index > 0)
11194 {
11195 temp1 = bash_tilde_expand (temp, tflag);
11196 if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
11197 {
11198 FREE (temp);
11199 FREE (temp1);
11200 goto add_character; /* tilde expansion failed */
11201 }
11202 free (temp);
11203 temp = temp1;
11204 sindex += t_index;
11205 goto add_quoted_string; /* XXX was add_string */
11206 }
11207 else
11208 {
11209 FREE (temp);
11210 goto add_character;
11211 }
11212
11213 case '$':
11214 if (expanded_something)
11215 *expanded_something = 1;
11216 local_expanded = 1;
11217
11218 temp_has_dollar_at = 0;
11219 pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
11220 if (word->flags & W_NOSPLIT2)
11221 pflags |= PF_NOSPLIT2;
11222 if (word->flags & W_ASSIGNRHS)
11223 pflags |= PF_ASSIGNRHS;
11224 if (word->flags & W_COMPLETE)
11225 pflags |= PF_COMPLETE;
11226
11227 tword = param_expand (string, &sindex, quoted, expanded_something,
11228 &temp_has_dollar_at, &quoted_dollar_at,
11229 &had_quoted_null, pflags);
11230 has_dollar_at += temp_has_dollar_at;
11231 split_on_spaces += (tword->flags & W_SPLITSPACE);
11232
11233 if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
11234 {
11235 free (string);
11236 free (istring);
11237 return ((tword == &expand_wdesc_error) ? &expand_word_error
11238 : &expand_word_fatal);
11239 }
11240 if (contains_dollar_at && has_dollar_at)
11241 *contains_dollar_at = 1;
11242
11243 if (tword && (tword->flags & W_HASQUOTEDNULL))
11244 had_quoted_null = 1; /* note for later */
11245 if (tword && (tword->flags & W_SAWQUOTEDNULL))
11246 had_quoted_null = 1; /* XXX */
11247
11248 temp = tword ? tword->word : (char *)NULL;
11249 dispose_word_desc (tword);
11250
11251 /* Kill quoted nulls; we will add them back at the end of
11252 expand_word_internal if nothing else in the string */
11253 if (had_quoted_null && temp && QUOTED_NULL (temp))
11254 {
11255 FREE (temp);
11256 temp = (char *)NULL;
11257 }
11258
11259 goto add_string;
11260 break;
11261
11262 case '`': /* Backquoted command substitution. */
11263 {
11264 t_index = sindex++;
11265
11266 temp = string_extract (string, &sindex, "`", (word->flags & W_COMPLETE) ? SX_COMPLETE : SX_REQMATCH);
11267 /* The test of sindex against t_index is to allow bare instances of
11268 ` to pass through, for backwards compatibility. */
11269 if (temp == &extract_string_error || temp == &extract_string_fatal)
11270 {
11271 if (sindex - 1 == t_index)
11272 {
11273 sindex = t_index;
11274 goto add_character;
11275 }
11276 set_exit_status (EXECUTION_FAILURE);
11277 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
11278 free (string);
11279 free (istring);
11280 return ((temp == &extract_string_error) ? &expand_word_error
11281 : &expand_word_fatal);
11282 }
11283
11284 if (expanded_something)
11285 *expanded_something = 1;
11286 local_expanded = 1;
11287
11288 if (word->flags & W_NOCOMSUB)
11289 /* sindex + 1 because string[sindex] == '`' */
11290 temp1 = substring (string, t_index, sindex + 1);
11291 else
11292 {
11293 de_backslash (temp);
11294 tword = command_substitute (temp, quoted, 0);
11295 temp1 = tword ? tword->word : (char *)NULL;
11296 if (tword)
11297 dispose_word_desc (tword);
11298 }
11299 FREE (temp);
11300 temp = temp1;
11301 goto dollar_add_string;
11302 }
11303
11304 case '\\':
11305 if (string[sindex + 1] == '\n')
11306 {
11307 sindex += 2;
11308 continue;
11309 }
11310
11311 c = string[++sindex];
11312
11313 /* "However, the double-quote character ( '"' ) shall not be treated
11314 specially within a here-document, except when the double-quote
11315 appears within "$()", "``", or "${}"." */
11316 if ((quoted & Q_HERE_DOCUMENT) && (quoted & Q_DOLBRACE) && c == '"')
11317 tflag = CBSDQUOTE; /* special case */
11318 else if (quoted & Q_HERE_DOCUMENT)
11319 tflag = CBSHDOC;
11320 else if (quoted & Q_DOUBLE_QUOTES)
11321 tflag = CBSDQUOTE;
11322 else
11323 tflag = 0;
11324
11325 /* From Posix discussion on austin-group list: Backslash escaping
11326 a } in ${...} is removed. Issue 0000221 */
11327 if ((quoted & Q_DOLBRACE) && c == RBRACE)
11328 {
11329 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11330 }
11331 /* This is the fix for " $@\ " */
11332 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c))
11333 {
11334 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11335 DEFAULT_ARRAY_SIZE);
11336 istring[istring_index++] = CTLESC;
11337 istring[istring_index++] = '\\';
11338 istring[istring_index] = '\0';
11339
11340 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11341 }
11342 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0)
11343 {
11344 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11345 DEFAULT_ARRAY_SIZE);
11346 istring[istring_index++] = CTLESC;
11347 istring[istring_index++] = '\\';
11348 istring[istring_index] = '\0';
11349 break;
11350 }
11351 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
11352 {
11353 SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
11354 }
11355 else if (c == 0)
11356 {
11357 c = CTLNUL;
11358 sindex--; /* add_character: label increments sindex */
11359 goto add_character;
11360 }
11361 else
11362 {
11363 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11364 }
11365
11366 sindex++;
11367 add_twochars:
11368 /* BEFORE jumping here, we need to increment sindex if appropriate */
11369 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11370 DEFAULT_ARRAY_SIZE);
11371 istring[istring_index++] = twochars[0];
11372 istring[istring_index++] = twochars[1];
11373 istring[istring_index] = '\0';
11374
11375 break;
11376
11377 case '"':
11378 /* XXX - revisit this */
11379 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0))
11380 goto add_character;
11381
11382 t_index = ++sindex;
11383 temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0);
11384
11385 /* If the quotes surrounded the entire string, then the
11386 whole word was quoted. */
11387 quoted_state = (t_index == 1 && string[sindex] == '\0')
11388 ? WHOLLY_QUOTED
11389 : PARTIALLY_QUOTED;
11390
11391 if (temp && *temp)
11392 {
11393 tword = alloc_word_desc ();
11394 tword->word = temp;
11395
11396 if (word->flags & W_ASSIGNARG)
11397 tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */
11398 if (word->flags & W_COMPLETE)
11399 tword->flags |= W_COMPLETE; /* for command substitutions */
11400 if (word->flags & W_NOCOMSUB)
11401 tword->flags |= W_NOCOMSUB;
11402 if (word->flags & W_NOPROCSUB)
11403 tword->flags |= W_NOPROCSUB;
11404
11405 if (word->flags & W_ASSIGNRHS)
11406 tword->flags |= W_ASSIGNRHS;
11407
11408 temp = (char *)NULL;
11409
11410 temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */
11411 /* Need to get W_HASQUOTEDNULL flag through this function. */
11412 /* XXX - preserve Q_ARITH here? */
11413 list = expand_word_internal (tword, Q_DOUBLE_QUOTES|(quoted&Q_ARITH), 0, &temp_has_dollar_at, (int *)NULL);
11414 has_dollar_at += temp_has_dollar_at;
11415
11416 if (list == &expand_word_error || list == &expand_word_fatal)
11417 {
11418 free (istring);
11419 free (string);
11420 /* expand_word_internal has already freed temp_word->word
11421 for us because of the way it prints error messages. */
11422 tword->word = (char *)NULL;
11423 dispose_word (tword);
11424 return list;
11425 }
11426
11427 dispose_word (tword);
11428
11429 /* "$@" (a double-quoted dollar-at) expands into nothing,
11430 not even a NULL word, when there are no positional
11431 parameters. Posix interp 888 says that other parts of the
11432 word that expand to quoted nulls result in quoted nulls, so
11433 we can't just throw the entire word away if we have "$@"
11434 anywhere in it. We use had_quoted_null to keep track */
11435 if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */
11436 {
11437 quoted_dollar_at++;
11438 break;
11439 }
11440
11441 /* If this list comes back with a quoted null from expansion,
11442 we have either "$x" or "$@" with $1 == ''. In either case,
11443 we need to make sure we add a quoted null argument and
11444 disable the special handling that "$@" gets. */
11445 if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL))
11446 {
11447 if (had_quoted_null && temp_has_dollar_at)
11448 quoted_dollar_at++;
11449 had_quoted_null = 1; /* XXX */
11450 }
11451
11452 /* If we get "$@", we know we have expanded something, so we
11453 need to remember it for the final split on $IFS. This is
11454 a special case; it's the only case where a quoted string
11455 can expand into more than one word. It's going to come back
11456 from the above call to expand_word_internal as a list with
11457 multiple words. */
11458 if (list)
11459 dequote_list (list);
11460
11461 if (temp_has_dollar_at) /* XXX - was has_dollar_at */
11462 {
11463 quoted_dollar_at++;
11464 if (contains_dollar_at)
11465 *contains_dollar_at = 1;
11466 if (expanded_something)
11467 *expanded_something = 1;
11468 local_expanded = 1;
11469 }
11470 }
11471 else
11472 {
11473 /* What we have is "". This is a minor optimization. */
11474 FREE (temp);
11475 list = (WORD_LIST *)NULL;
11476 had_quoted_null = 1; /* note for later */
11477 }
11478
11479 /* The code above *might* return a list (consider the case of "$@",
11480 where it returns "$1", "$2", etc.). We can't throw away the
11481 rest of the list, and we have to make sure each word gets added
11482 as quoted. We test on tresult->next: if it is non-NULL, we
11483 quote the whole list, save it to a string with string_list, and
11484 add that string. We don't need to quote the results of this
11485 (and it would be wrong, since that would quote the separators
11486 as well), so we go directly to add_string. */
11487 if (list)
11488 {
11489 if (list->next)
11490 {
11491 /* Testing quoted_dollar_at makes sure that "$@" is
11492 split correctly when $IFS does not contain a space. */
11493 temp = quoted_dollar_at
11494 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0)
11495 : string_list (quote_list (list));
11496 dispose_words (list);
11497 goto add_string;
11498 }
11499 else
11500 {
11501 temp = savestring (list->word->word);
11502 tflag = list->word->flags;
11503 dispose_words (list);
11504
11505 /* If the string is not a quoted null string, we want
11506 to remove any embedded unquoted CTLNUL characters.
11507 We do not want to turn quoted null strings back into
11508 the empty string, though. We do this because we
11509 want to remove any quoted nulls from expansions that
11510 contain other characters. For example, if we have
11511 x"$*"y or "x$*y" and there are no positional parameters,
11512 the $* should expand into nothing. */
11513 /* We use the W_HASQUOTEDNULL flag to differentiate the
11514 cases: a quoted null character as above and when
11515 CTLNUL is contained in the (non-null) expansion
11516 of some variable. We use the had_quoted_null flag to
11517 pass the value through this function to its caller. */
11518 if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
11519 remove_quoted_nulls (temp); /* XXX */
11520 }
11521 }
11522 else
11523 temp = (char *)NULL;
11524
11525 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
11526 had_quoted_null = 1; /* note for later */
11527
11528 /* We do not want to add quoted nulls to strings that are only
11529 partially quoted; we can throw them away. The exception to
11530 this is when we are going to be performing word splitting,
11531 since we have to preserve a null argument if the next character
11532 will cause word splitting. */
11533 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
11534 {
11535 c = CTLNUL;
11536 sindex--;
11537 had_quoted_null = 1;
11538 goto add_character;
11539 }
11540 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
11541 continue;
11542
11543 add_quoted_string:
11544
11545 if (temp)
11546 {
11547 temp1 = temp;
11548 temp = quote_string (temp);
11549 free (temp1);
11550 goto add_string;
11551 }
11552 else
11553 {
11554 /* Add NULL arg. */
11555 c = CTLNUL;
11556 sindex--; /* add_character: label increments sindex */
11557 had_quoted_null = 1; /* note for later */
11558 goto add_character;
11559 }
11560
11561 /* break; */
11562
11563 case '\'':
11564 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
11565 goto add_character;
11566
11567 t_index = ++sindex;
11568 temp = string_extract_single_quoted (string, &sindex, 0);
11569
11570 /* If the entire STRING was surrounded by single quotes,
11571 then the string is wholly quoted. */
11572 quoted_state = (t_index == 1 && string[sindex] == '\0')
11573 ? WHOLLY_QUOTED
11574 : PARTIALLY_QUOTED;
11575
11576 /* If all we had was '', it is a null expansion. */
11577 if (*temp == '\0')
11578 {
11579 free (temp);
11580 temp = (char *)NULL;
11581 }
11582 else
11583 remove_quoted_escapes (temp); /* ??? */
11584
11585 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
11586 had_quoted_null = 1; /* note for later */
11587
11588 /* We do not want to add quoted nulls to strings that are only
11589 partially quoted; such nulls are discarded. See above for the
11590 exception, which is when the string is going to be split.
11591 Posix interp 888/1129 */
11592 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
11593 {
11594 c = CTLNUL;
11595 sindex--;
11596 goto add_character;
11597 }
11598
11599 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
11600 continue;
11601
11602 /* If we have a quoted null expansion, add a quoted NULL to istring. */
11603 if (temp == 0)
11604 {
11605 c = CTLNUL;
11606 sindex--; /* add_character: label increments sindex */
11607 goto add_character;
11608 }
11609 else
11610 goto add_quoted_string;
11611
11612 /* break; */
11613
11614 case ' ':
11615 /* If we are in a context where the word is not going to be split, but
11616 we need to account for $@ and $* producing one word for each
11617 positional parameter, add quoted spaces so the spaces in the
11618 expansion of "$@", if any, behave correctly. We still may need to
11619 split if we are expanding the rhs of a word expansion. */
11620 if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0))
11621 {
11622 if (string[sindex])
11623 sindex++;
11624 twochars[0] = CTLESC;
11625 twochars[1] = c;
11626 goto add_twochars;
11627 }
11628 /* FALLTHROUGH */
11629
11630 default:
11631 /* This is the fix for " $@ " */
11632 add_ifs_character:
11633 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0))
11634 {
11635 if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)
11636 has_quoted_ifs++;
11637 add_quoted_character:
11638 if (string[sindex]) /* from old goto dollar_add_string */
11639 sindex++;
11640 if (c == 0)
11641 {
11642 c = CTLNUL;
11643 goto add_character;
11644 }
11645 else
11646 {
11647 #if HANDLE_MULTIBYTE
11648 /* XXX - should make sure that c is actually multibyte,
11649 otherwise we can use the twochars branch */
11650 if (mb_cur_max > 1)
11651 sindex--;
11652
11653 if (mb_cur_max > 1)
11654 {
11655 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
11656 }
11657 else
11658 #endif
11659 {
11660 twochars[0] = CTLESC;
11661 twochars[1] = c;
11662 goto add_twochars;
11663 }
11664 }
11665 }
11666
11667 SADD_MBCHAR (temp, string, sindex, string_size);
11668
11669 add_character:
11670 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
11671 DEFAULT_ARRAY_SIZE);
11672 istring[istring_index++] = c;
11673 istring[istring_index] = '\0';
11674
11675 /* Next character. */
11676 sindex++;
11677 }
11678 }
11679
11680 finished_with_string:
11681 /* OK, we're ready to return. If we have a quoted string, and
11682 quoted_dollar_at is not set, we do no splitting at all; otherwise
11683 we split on ' '. The routines that call this will handle what to
11684 do if nothing has been expanded. */
11685
11686 /* Partially and wholly quoted strings which expand to the empty
11687 string are retained as an empty arguments. Unquoted strings
11688 which expand to the empty string are discarded. The single
11689 exception is the case of expanding "$@" when there are no
11690 positional parameters. In that case, we discard the expansion. */
11691
11692 /* Because of how the code that handles "" and '' in partially
11693 quoted strings works, we need to make ISTRING into a QUOTED_NULL
11694 if we saw quoting characters, but the expansion was empty.
11695 "" and '' are tossed away before we get to this point when
11696 processing partially quoted strings. This makes "" and $xxx""
11697 equivalent when xxx is unset. We also look to see whether we
11698 saw a quoted null from a ${} expansion and add one back if we
11699 need to. */
11700
11701 /* If we expand to nothing and there were no single or double quotes
11702 in the word, we throw it away. Otherwise, we return a NULL word.
11703 The single exception is for $@ surrounded by double quotes when
11704 there are no positional parameters. In that case, we also throw
11705 the word away. */
11706
11707 if (*istring == '\0')
11708 {
11709 #if 0
11710 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
11711 #else
11712 if (had_quoted_null || (quoted_dollar_at == 0 && quoted_state == PARTIALLY_QUOTED))
11713 #endif
11714 {
11715 istring[0] = CTLNUL;
11716 istring[1] = '\0';
11717 tword = alloc_word_desc ();
11718 tword->word = istring;
11719 istring = 0; /* avoid later free() */
11720 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11721 list = make_word_list (tword, (WORD_LIST *)NULL);
11722 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
11723 tword->flags |= W_QUOTED;
11724 }
11725 /* According to sh, ksh, and Posix.2, if a word expands into nothing
11726 and a double-quoted "$@" appears anywhere in it, then the entire
11727 word is removed. */
11728 /* XXX - exception appears to be that quoted null strings result in
11729 null arguments */
11730 else if (quoted_state == UNQUOTED || quoted_dollar_at)
11731 list = (WORD_LIST *)NULL;
11732 else
11733 list = (WORD_LIST *)NULL;
11734 }
11735 else if (word->flags & W_NOSPLIT)
11736 {
11737 tword = alloc_word_desc ();
11738 tword->word = istring;
11739 if (had_quoted_null && QUOTED_NULL (istring))
11740 tword->flags |= W_HASQUOTEDNULL;
11741 istring = 0; /* avoid later free() */
11742 if (word->flags & W_ASSIGNMENT)
11743 tword->flags |= W_ASSIGNMENT; /* XXX */
11744 if (word->flags & W_COMPASSIGN)
11745 tword->flags |= W_COMPASSIGN; /* XXX */
11746 if (word->flags & W_NOGLOB)
11747 tword->flags |= W_NOGLOB; /* XXX */
11748 if (word->flags & W_NOBRACE)
11749 tword->flags |= W_NOBRACE; /* XXX */
11750 if (word->flags & W_ARRAYREF)
11751 tword->flags |= W_ARRAYREF;
11752 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
11753 tword->flags |= W_QUOTED;
11754 list = make_word_list (tword, (WORD_LIST *)NULL);
11755 }
11756 else if (word->flags & W_ASSIGNRHS)
11757 {
11758 list = list_string (istring, "", quoted);
11759 tword = list->word;
11760 if (had_quoted_null && QUOTED_NULL (istring))
11761 tword->flags |= W_HASQUOTEDNULL;
11762 free (list);
11763 free (istring);
11764 istring = 0; /* avoid later free() */
11765 goto set_word_flags;
11766 }
11767 else
11768 {
11769 char *ifs_chars;
11770
11771 ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
11772
11773 /* If we have $@, we need to split the results no matter what. If
11774 IFS is unset or NULL, string_list_dollar_at has separated the
11775 positional parameters with a space, so we split on space (we have
11776 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
11777 string_list_dollar_at has separated the positional parameters
11778 with the first character of $IFS, so we split on $IFS. If
11779 SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
11780 unset or null, and we want to make sure that we split on spaces
11781 regardless of what else has happened to IFS since the expansion,
11782 or we expanded "$@" with IFS null and we need to split the positional
11783 parameters into separate words. */
11784 if (split_on_spaces)
11785 {
11786 /* If IFS is not set, and the word is not quoted, we want to split
11787 the individual words on $' \t\n'. We rely on previous steps to
11788 quote the portions of the word that should not be split */
11789 if (ifs_is_set == 0)
11790 list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */
11791 else
11792 list = list_string (istring, " ", 1); /* XXX quoted == 1? */
11793 }
11794
11795 /* If we have $@ (has_dollar_at != 0) and we are in a context where we
11796 don't want to split the result (W_NOSPLIT2), and we are not quoted,
11797 we have already separated the arguments with the first character of
11798 $IFS. In this case, we want to return a list with a single word
11799 with the separator possibly replaced with a space (it's what other
11800 shells seem to do).
11801 quoted_dollar_at is internal to this function and is set if we are
11802 passed an argument that is unquoted (quoted == 0) but we encounter a
11803 double-quoted $@ while expanding it. */
11804 else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2))
11805 {
11806 tword = alloc_word_desc ();
11807 /* Only split and rejoin if we have to */
11808 if (*ifs_chars && *ifs_chars != ' ')
11809 {
11810 /* list_string dequotes CTLESCs in the string it's passed, so we
11811 need it to get the space separation right if space isn't the
11812 first character in IFS (but is present) and to remove the
11813 quoting we added back in param_expand(). */
11814 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
11815 /* This isn't exactly right in the case where we're expanding
11816 the RHS of an expansion like ${var-$@} where IFS=: (for
11817 example). The W_NOSPLIT2 means we do the separation with :;
11818 the list_string removes the quotes and breaks the string into
11819 a list, and the string_list rejoins it on spaces. When we
11820 return, we expect to be able to split the results, but the
11821 space separation means the right split doesn't happen. */
11822 tword->word = string_list (list);
11823 }
11824 else
11825 tword->word = istring;
11826 if (had_quoted_null && QUOTED_NULL (istring))
11827 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11828 if (tword->word != istring)
11829 free (istring);
11830 istring = 0; /* avoid later free() */
11831 goto set_word_flags;
11832 }
11833 else if (has_dollar_at && ifs_chars)
11834 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
11835 else
11836 {
11837 tword = alloc_word_desc ();
11838 if (expanded_something && *expanded_something == 0 && has_quoted_ifs)
11839 tword->word = remove_quoted_ifs (istring);
11840 else
11841 tword->word = istring;
11842 if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */
11843 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11844 else if (had_quoted_null)
11845 tword->flags |= W_SAWQUOTEDNULL; /* XXX */
11846 if (tword->word != istring)
11847 free (istring);
11848 istring = 0; /* avoid later free() */
11849 set_word_flags:
11850 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
11851 tword->flags |= W_QUOTED;
11852 if (word->flags & W_ASSIGNMENT)
11853 tword->flags |= W_ASSIGNMENT;
11854 if (word->flags & W_COMPASSIGN)
11855 tword->flags |= W_COMPASSIGN;
11856 if (word->flags & W_NOGLOB)
11857 tword->flags |= W_NOGLOB;
11858 if (word->flags & W_NOBRACE)
11859 tword->flags |= W_NOBRACE;
11860 if (word->flags & W_ARRAYREF)
11861 tword->flags |= W_ARRAYREF;
11862 list = make_word_list (tword, (WORD_LIST *)NULL);
11863 }
11864 }
11865
11866 free (istring);
11867 return (list);
11868 }
11869
11870 /* **************************************************************** */
11871 /* */
11872 /* Functions for Quote Removal */
11873 /* */
11874 /* **************************************************************** */
11875
11876 /* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
11877 backslash quoting rules for within double quotes or a here document. */
11878 char *
11879 string_quote_removal (string, quoted)
11880 char *string;
11881 int quoted;
11882 {
11883 size_t slen;
11884 char *r, *result_string, *temp, *send;
11885 int sindex, tindex, dquote;
11886 unsigned char c;
11887 DECLARE_MBSTATE;
11888
11889 /* The result can be no longer than the original string. */
11890 slen = strlen (string);
11891 send = string + slen;
11892
11893 r = result_string = (char *)xmalloc (slen + 1);
11894
11895 for (dquote = sindex = 0; c = string[sindex];)
11896 {
11897 switch (c)
11898 {
11899 case '\\':
11900 c = string[++sindex];
11901 if (c == 0)
11902 {
11903 *r++ = '\\';
11904 break;
11905 }
11906 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
11907 *r++ = '\\';
11908 /* FALLTHROUGH */
11909
11910 default:
11911 SCOPY_CHAR_M (r, string, send, sindex);
11912 break;
11913
11914 case '\'':
11915 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
11916 {
11917 *r++ = c;
11918 sindex++;
11919 break;
11920 }
11921 tindex = sindex + 1;
11922 temp = string_extract_single_quoted (string, &tindex, 0);
11923 if (temp)
11924 {
11925 strcpy (r, temp);
11926 r += strlen (r);
11927 free (temp);
11928 }
11929 sindex = tindex;
11930 break;
11931
11932 case '"':
11933 dquote = 1 - dquote;
11934 sindex++;
11935 break;
11936 }
11937 }
11938 *r = '\0';
11939 return (result_string);
11940 }
11941
11942 #if 0
11943 /* UNUSED */
11944 /* Perform quote removal on word WORD. This allocates and returns a new
11945 WORD_DESC *. */
11946 WORD_DESC *
11947 word_quote_removal (word, quoted)
11948 WORD_DESC *word;
11949 int quoted;
11950 {
11951 WORD_DESC *w;
11952 char *t;
11953
11954 t = string_quote_removal (word->word, quoted);
11955 w = alloc_word_desc ();
11956 w->word = t ? t : savestring ("");
11957 return (w);
11958 }
11959
11960 /* Perform quote removal on all words in LIST. If QUOTED is non-zero,
11961 the members of the list are treated as if they are surrounded by
11962 double quotes. Return a new list, or NULL if LIST is NULL. */
11963 WORD_LIST *
11964 word_list_quote_removal (list, quoted)
11965 WORD_LIST *list;
11966 int quoted;
11967 {
11968 WORD_LIST *result, *t, *tresult, *e;
11969
11970 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
11971 {
11972 tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
11973 #if 0
11974 result = (WORD_LIST *) list_append (result, tresult);
11975 #else
11976 if (result == 0)
11977 result = e = tresult;
11978 else
11979 {
11980 e->next = tresult;
11981 while (e->next)
11982 e = e->next;
11983 }
11984 #endif
11985 }
11986 return (result);
11987 }
11988 #endif
11989
11990 /*******************************************
11991 * *
11992 * Functions to perform word splitting *
11993 * *
11994 *******************************************/
11995
11996 void
11997 setifs (v)
11998 SHELL_VAR *v;
11999 {
12000 char *t;
12001 unsigned char uc;
12002
12003 ifs_var = v;
12004 ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
12005
12006 ifs_is_set = ifs_var != 0;
12007 ifs_is_null = ifs_is_set && (*ifs_value == 0);
12008
12009 /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
12010 handle multibyte chars in IFS */
12011 memset (ifs_cmap, '\0', sizeof (ifs_cmap));
12012 for (t = ifs_value ; t && *t; t++)
12013 {
12014 uc = *t;
12015 ifs_cmap[uc] = 1;
12016 }
12017
12018 #if defined (HANDLE_MULTIBYTE)
12019 if (ifs_value == 0)
12020 {
12021 ifs_firstc[0] = '\0'; /* XXX - ? */
12022 ifs_firstc_len = 1;
12023 }
12024 else
12025 {
12026 if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value))
12027 ifs_firstc_len = (*ifs_value != 0) ? 1 : 0;
12028 else
12029 {
12030 size_t ifs_len;
12031 ifs_len = strnlen (ifs_value, MB_CUR_MAX);
12032 ifs_firstc_len = MBLEN (ifs_value, ifs_len);
12033 }
12034 if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
12035 {
12036 ifs_firstc[0] = ifs_value[0];
12037 ifs_firstc[1] = '\0';
12038 ifs_firstc_len = 1;
12039 }
12040 else
12041 memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
12042 }
12043 #else
12044 ifs_firstc = ifs_value ? *ifs_value : 0;
12045 #endif
12046 }
12047
12048 char *
12049 getifs ()
12050 {
12051 return ifs_value;
12052 }
12053
12054 /* This splits a single word into a WORD LIST on $IFS, but only if the word
12055 is not quoted. list_string () performs quote removal for us, even if we
12056 don't do any splitting. */
12057 WORD_LIST *
12058 word_split (w, ifs_chars)
12059 WORD_DESC *w;
12060 char *ifs_chars;
12061 {
12062 WORD_LIST *result;
12063
12064 if (w)
12065 {
12066 char *xifs;
12067
12068 xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
12069 result = list_string (w->word, xifs, w->flags & W_QUOTED);
12070 }
12071 else
12072 result = (WORD_LIST *)NULL;
12073
12074 return (result);
12075 }
12076
12077 /* Perform word splitting on LIST and return the RESULT. It is possible
12078 to return (WORD_LIST *)NULL. */
12079 static WORD_LIST *
12080 word_list_split (list)
12081 WORD_LIST *list;
12082 {
12083 WORD_LIST *result, *t, *tresult, *e;
12084 WORD_DESC *w;
12085
12086 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
12087 {
12088 tresult = word_split (t->word, ifs_value);
12089 /* POSIX 2.6: "If the complete expansion appropriate for a word results
12090 in an empty field, that empty field shall be deleted from the list
12091 of fields that form the completely expanded command, unless the
12092 original word contained single-quote or double-quote characters."
12093 This is where we handle these words that contain quoted null strings
12094 and other characters that expand to nothing after word splitting. */
12095 if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */
12096 {
12097 w = alloc_word_desc ();
12098 w->word = (char *)xmalloc (1);
12099 w->word[0] = '\0';
12100 tresult = make_word_list (w, (WORD_LIST *)NULL);
12101 }
12102 #if defined (ARRAY_VARS)
12103 /* pass W_ARRAYREF through for words that are not split and are
12104 identical to the original word. */
12105 if (tresult && tresult->next == 0 && t->next == 0 && (t->word->flags & W_ARRAYREF) && STREQ (t->word->word, tresult->word->word))
12106 tresult->word->flags |= W_ARRAYREF;
12107 #endif
12108 if (result == 0)
12109 result = e = tresult;
12110 else
12111 {
12112 e->next = tresult;
12113 while (e->next)
12114 e = e->next;
12115 }
12116 }
12117 return (result);
12118 }
12119
12120 /**************************************************
12121 * *
12122 * Functions to expand an entire WORD_LIST *
12123 * *
12124 **************************************************/
12125
12126 /* Do any word-expansion-specific cleanup and jump to top_level */
12127 static void
12128 exp_jump_to_top_level (v)
12129 int v;
12130 {
12131 set_pipestatus_from_exit (last_command_exit_value);
12132
12133 /* Cleanup code goes here. */
12134 expand_no_split_dollar_star = 0; /* XXX */
12135 if (expanding_redir)
12136 undo_partial_redirects ();
12137 expanding_redir = 0;
12138 assigning_in_environment = 0;
12139
12140 if (parse_and_execute_level == 0)
12141 top_level_cleanup (); /* from sig.c */
12142
12143 jump_to_top_level (v);
12144 }
12145
12146 /* Put NLIST (which is a WORD_LIST * of only one element) at the front of
12147 ELIST, and set ELIST to the new list. */
12148 #define PREPEND_LIST(nlist, elist) \
12149 do { nlist->next = elist; elist = nlist; } while (0)
12150
12151 /* Separate out any initial variable assignments from TLIST. If set -k has
12152 been executed, remove all assignment statements from TLIST. Initial
12153 variable assignments and other environment assignments are placed
12154 on SUBST_ASSIGN_VARLIST. */
12155 static WORD_LIST *
12156 separate_out_assignments (tlist)
12157 WORD_LIST *tlist;
12158 {
12159 register WORD_LIST *vp, *lp;
12160
12161 if (tlist == 0)
12162 return ((WORD_LIST *)NULL);
12163
12164 if (subst_assign_varlist)
12165 dispose_words (subst_assign_varlist); /* Clean up after previous error */
12166
12167 subst_assign_varlist = (WORD_LIST *)NULL;
12168 vp = lp = tlist;
12169
12170 /* Separate out variable assignments at the start of the command.
12171 Loop invariant: vp->next == lp
12172 Loop postcondition:
12173 lp = list of words left after assignment statements skipped
12174 tlist = original list of words
12175 */
12176 while (lp && (lp->word->flags & W_ASSIGNMENT))
12177 {
12178 vp = lp;
12179 lp = lp->next;
12180 }
12181
12182 /* If lp != tlist, we have some initial assignment statements.
12183 We make SUBST_ASSIGN_VARLIST point to the list of assignment
12184 words and TLIST point to the remaining words. */
12185 if (lp != tlist)
12186 {
12187 subst_assign_varlist = tlist;
12188 /* ASSERT(vp->next == lp); */
12189 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
12190 tlist = lp; /* remainder of word list */
12191 }
12192
12193 /* vp == end of variable list */
12194 /* tlist == remainder of original word list without variable assignments */
12195 if (!tlist)
12196 /* All the words in tlist were assignment statements */
12197 return ((WORD_LIST *)NULL);
12198
12199 /* ASSERT(tlist != NULL); */
12200 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
12201
12202 /* If the -k option is in effect, we need to go through the remaining
12203 words, separate out the assignment words, and place them on
12204 SUBST_ASSIGN_VARLIST. */
12205 if (place_keywords_in_env)
12206 {
12207 WORD_LIST *tp; /* tp == running pointer into tlist */
12208
12209 tp = tlist;
12210 lp = tlist->next;
12211
12212 /* Loop Invariant: tp->next == lp */
12213 /* Loop postcondition: tlist == word list without assignment statements */
12214 while (lp)
12215 {
12216 if (lp->word->flags & W_ASSIGNMENT)
12217 {
12218 /* Found an assignment statement, add this word to end of
12219 subst_assign_varlist (vp). */
12220 if (!subst_assign_varlist)
12221 subst_assign_varlist = vp = lp;
12222 else
12223 {
12224 vp->next = lp;
12225 vp = lp;
12226 }
12227
12228 /* Remove the word pointed to by LP from TLIST. */
12229 tp->next = lp->next;
12230 /* ASSERT(vp == lp); */
12231 lp->next = (WORD_LIST *)NULL;
12232 lp = tp->next;
12233 }
12234 else
12235 {
12236 tp = lp;
12237 lp = lp->next;
12238 }
12239 }
12240 }
12241 return (tlist);
12242 }
12243
12244 #define WEXP_VARASSIGN 0x001
12245 #define WEXP_BRACEEXP 0x002
12246 #define WEXP_TILDEEXP 0x004
12247 #define WEXP_PARAMEXP 0x008
12248 #define WEXP_PATHEXP 0x010
12249
12250 /* All of the expansions, including variable assignments at the start of
12251 the list. */
12252 #define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
12253
12254 /* All of the expansions except variable assignments at the start of
12255 the list. */
12256 #define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
12257
12258 /* All of the `shell expansions': brace expansion, tilde expansion, parameter
12259 expansion, command substitution, arithmetic expansion, word splitting, and
12260 quote removal. */
12261 #define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
12262
12263 /* Take the list of words in LIST and do the various substitutions. Return
12264 a new list of words which is the expanded list, and without things like
12265 variable assignments. */
12266
12267 WORD_LIST *
12268 expand_words (list)
12269 WORD_LIST *list;
12270 {
12271 return (expand_word_list_internal (list, WEXP_ALL));
12272 }
12273
12274 /* Same as expand_words (), but doesn't hack variable or environment
12275 variables. */
12276 WORD_LIST *
12277 expand_words_no_vars (list)
12278 WORD_LIST *list;
12279 {
12280 return (expand_word_list_internal (list, WEXP_NOVARS));
12281 }
12282
12283 WORD_LIST *
12284 expand_words_shellexp (list)
12285 WORD_LIST *list;
12286 {
12287 return (expand_word_list_internal (list, WEXP_SHELLEXP));
12288 }
12289
12290 static WORD_LIST *
12291 glob_expand_word_list (tlist, eflags)
12292 WORD_LIST *tlist;
12293 int eflags;
12294 {
12295 char **glob_array, *temp_string;
12296 register int glob_index;
12297 WORD_LIST *glob_list, *output_list, *disposables, *next;
12298 WORD_DESC *tword;
12299 int x;
12300
12301 output_list = disposables = (WORD_LIST *)NULL;
12302 glob_array = (char **)NULL;
12303 while (tlist)
12304 {
12305 /* For each word, either globbing is attempted or the word is
12306 added to orig_list. If globbing succeeds, the results are
12307 added to orig_list and the word (tlist) is added to the list
12308 of disposable words. If globbing fails and failed glob
12309 expansions are left unchanged (the shell default), the
12310 original word is added to orig_list. If globbing fails and
12311 failed glob expansions are removed, the original word is
12312 added to the list of disposable words. orig_list ends up
12313 in reverse order and requires a call to REVERSE_LIST to
12314 be set right. After all words are examined, the disposable
12315 words are freed. */
12316 next = tlist->next;
12317
12318 /* If the word isn't an assignment and contains an unquoted
12319 pattern matching character, then glob it. */
12320 if ((tlist->word->flags & W_NOGLOB) == 0 &&
12321 unquoted_glob_pattern_p (tlist->word->word))
12322 {
12323 glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */
12324
12325 /* Handle error cases.
12326 I don't think we should report errors like "No such file
12327 or directory". However, I would like to report errors
12328 like "Read failed". */
12329
12330 if (glob_array == 0 || GLOB_FAILED (glob_array))
12331 {
12332 glob_array = (char **)xmalloc (sizeof (char *));
12333 glob_array[0] = (char *)NULL;
12334 }
12335
12336 /* Dequote the current word in case we have to use it. */
12337 if (glob_array[0] == NULL)
12338 {
12339 temp_string = dequote_string (tlist->word->word);
12340 free (tlist->word->word);
12341 tlist->word->word = temp_string;
12342 }
12343
12344 /* Make the array into a word list. */
12345 glob_list = (WORD_LIST *)NULL;
12346 for (glob_index = 0; glob_array[glob_index]; glob_index++)
12347 {
12348 tword = make_bare_word (glob_array[glob_index]);
12349 glob_list = make_word_list (tword, glob_list);
12350 }
12351
12352 if (glob_list)
12353 {
12354 output_list = (WORD_LIST *)list_append (glob_list, output_list);
12355 PREPEND_LIST (tlist, disposables);
12356 }
12357 else if (fail_glob_expansion != 0)
12358 {
12359 last_command_exit_value = EXECUTION_FAILURE;
12360 report_error (_("no match: %s"), tlist->word->word);
12361 exp_jump_to_top_level (DISCARD);
12362 }
12363 else if (allow_null_glob_expansion == 0)
12364 {
12365 /* Failed glob expressions are left unchanged. */
12366 PREPEND_LIST (tlist, output_list);
12367 }
12368 else
12369 {
12370 /* Failed glob expressions are removed. */
12371 PREPEND_LIST (tlist, disposables);
12372 }
12373 }
12374 else
12375 {
12376 /* Dequote the string. */
12377 temp_string = dequote_string (tlist->word->word);
12378 free (tlist->word->word);
12379 tlist->word->word = temp_string;
12380 PREPEND_LIST (tlist, output_list);
12381 }
12382
12383 strvec_dispose (glob_array);
12384 glob_array = (char **)NULL;
12385
12386 tlist = next;
12387 }
12388
12389 if (disposables)
12390 dispose_words (disposables);
12391
12392 if (output_list)
12393 output_list = REVERSE_LIST (output_list, WORD_LIST *);
12394
12395 return (output_list);
12396 }
12397
12398 #if defined (BRACE_EXPANSION)
12399 static WORD_LIST *
12400 brace_expand_word_list (tlist, eflags)
12401 WORD_LIST *tlist;
12402 int eflags;
12403 {
12404 register char **expansions;
12405 char *temp_string;
12406 WORD_LIST *disposables, *output_list, *next;
12407 WORD_DESC *w;
12408 int eindex;
12409
12410 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
12411 {
12412 next = tlist->next;
12413
12414 if (tlist->word->flags & W_NOBRACE)
12415 {
12416 /*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/
12417 PREPEND_LIST (tlist, output_list);
12418 continue;
12419 }
12420
12421 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
12422 {
12423 /*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
12424 PREPEND_LIST (tlist, output_list);
12425 continue;
12426 }
12427
12428 /* Only do brace expansion if the word has a brace character. If
12429 not, just add the word list element to BRACES and continue. In
12430 the common case, at least when running shell scripts, this will
12431 degenerate to a bunch of calls to `mbschr', and then what is
12432 basically a reversal of TLIST into BRACES, which is corrected
12433 by a call to REVERSE_LIST () on BRACES when the end of TLIST
12434 is reached. */
12435 if (mbschr (tlist->word->word, LBRACE))
12436 {
12437 expansions = brace_expand (tlist->word->word);
12438
12439 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
12440 {
12441 w = alloc_word_desc ();
12442 w->word = temp_string;
12443
12444 /* If brace expansion didn't change the word, preserve
12445 the flags. We may want to preserve the flags
12446 unconditionally someday -- XXX */
12447 if (STREQ (temp_string, tlist->word->word))
12448 w->flags = tlist->word->flags;
12449 else
12450 w = make_word_flags (w, temp_string);
12451
12452 output_list = make_word_list (w, output_list);
12453 }
12454 free (expansions);
12455
12456 /* Add TLIST to the list of words to be freed after brace
12457 expansion has been performed. */
12458 PREPEND_LIST (tlist, disposables);
12459 }
12460 else
12461 PREPEND_LIST (tlist, output_list);
12462 }
12463
12464 if (disposables)
12465 dispose_words (disposables);
12466
12467 if (output_list)
12468 output_list = REVERSE_LIST (output_list, WORD_LIST *);
12469
12470 return (output_list);
12471 }
12472 #endif
12473
12474 #if defined (ARRAY_VARS)
12475 /* Take WORD, a compound array assignment, and internally run (for example),
12476 'declare -A w', where W is the variable name portion of WORD. OPTION is
12477 the list of options to supply to `declare'. CMD is the declaration command
12478 we are expanding right now; it's unused currently. */
12479 static int
12480 make_internal_declare (word, option, cmd)
12481 char *word;
12482 char *option;
12483 char *cmd;
12484 {
12485 int t, r;
12486 WORD_LIST *wl;
12487 WORD_DESC *w;
12488
12489 w = make_word (word);
12490
12491 t = assignment (w->word, 0);
12492 if (w->word[t] == '=')
12493 {
12494 w->word[t] = '\0';
12495 if (w->word[t - 1] == '+') /* cut off any append op */
12496 w->word[t - 1] = '\0';
12497 }
12498
12499 wl = make_word_list (w, (WORD_LIST *)NULL);
12500 wl = make_word_list (make_word (option), wl);
12501
12502 r = declare_builtin (wl);
12503
12504 dispose_words (wl);
12505 return r;
12506 }
12507
12508 /* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME
12509 is an associative array.
12510
12511 If we are processing an indexed array, expand_compound_array_assignment
12512 will expand all the individual words and quote_compound_array_list will
12513 single-quote them. If we are processing an associative array, we use
12514 parse_string_to_word_list to split VALUE into a list of words instead of
12515 faking up a shell variable and calling expand_compound_array_assignment.
12516 expand_and_quote_assoc_word expands and single-quotes each word in VALUE
12517 together so we don't have problems finding the end of the subscript when
12518 quoting it.
12519
12520 Words in VALUE can be individual words, which are expanded and single-quoted,
12521 or words of the form [IND]=VALUE, which end up as explained below, as
12522 ['expanded-ind']='expanded-value'. */
12523
12524 static WORD_LIST *
12525 expand_oneword (value, flags)
12526 char *value;
12527 int flags;
12528 {
12529 WORD_LIST *l, *nl;
12530 char *t;
12531 int kvpair;
12532
12533 if (flags == 0)
12534 {
12535 /* Indexed array */
12536 l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags);
12537 /* Now we quote the results of the expansion above to prevent double
12538 expansion. */
12539 quote_compound_array_list (l, flags);
12540 return l;
12541 }
12542 else
12543 {
12544 /* Associative array */
12545 l = parse_string_to_word_list (value, 1, "array assign");
12546 #if ASSOC_KVPAIR_ASSIGNMENT
12547 kvpair = kvpair_assignment_p (l);
12548 #endif
12549
12550 /* For associative arrays, with their arbitrary subscripts, we have to
12551 expand and quote in one step so we don't have to search for the
12552 closing right bracket more than once. */
12553 for (nl = l; nl; nl = nl->next)
12554 {
12555 #if ASSOC_KVPAIR_ASSIGNMENT
12556 if (kvpair)
12557 /* keys and values undergo the same set of expansions */
12558 t = expand_and_quote_kvpair_word (nl->word->word);
12559 else
12560 #endif
12561 if ((nl->word->flags & W_ASSIGNMENT) == 0)
12562 t = sh_single_quote (nl->word->word ? nl->word->word : "");
12563 else
12564 t = expand_and_quote_assoc_word (nl->word->word, flags);
12565 free (nl->word->word);
12566 nl->word->word = t;
12567 }
12568 return l;
12569 }
12570 }
12571
12572 /* Expand a single compound assignment argument to a declaration builtin.
12573 This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through
12574 unchanged. The VALUE is expanded and each word in the result is single-
12575 quoted. Words of the form [key]=value end up as
12576 ['expanded-key']='expanded-value'. Associative arrays have special
12577 handling, see expand_oneword() above. The return value is
12578 NAME[+]=( expanded-and-quoted-VALUE ). */
12579 static void
12580 expand_compound_assignment_word (tlist, flags)
12581 WORD_LIST *tlist;
12582 int flags;
12583 {
12584 WORD_LIST *l;
12585 int wlen, oind, t;
12586 char *value, *temp;
12587
12588 /*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/
12589 t = assignment (tlist->word->word, 0);
12590
12591 /* value doesn't have the open and close parens */
12592 oind = 1;
12593 value = extract_array_assignment_list (tlist->word->word + t + 1, &oind);
12594 /* This performs one round of expansion on the index/key and value and
12595 single-quotes each word in the result. */
12596 l = expand_oneword (value, flags);
12597 free (value);
12598
12599 value = string_list (l);
12600 dispose_words (l);
12601
12602 wlen = STRLEN (value);
12603
12604 /* Now, let's rebuild the string */
12605 temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */
12606 memcpy (temp, tlist->word->word, ++t);
12607 temp[t++] = '(';
12608 if (value)
12609 memcpy (temp + t, value, wlen);
12610 t += wlen;
12611 temp[t++] = ')';
12612 temp[t] = '\0';
12613 /*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/
12614
12615 free (tlist->word->word);
12616 tlist->word->word = temp;
12617
12618 free (value);
12619 }
12620
12621 /* Expand and process an argument to a declaration command. We have already
12622 set flags in TLIST->word->flags depending on the declaration command
12623 (declare, local, etc.) and the options supplied to it (-a, -A, etc.).
12624 TLIST->word->word is of the form NAME[+]=( VALUE ).
12625
12626 This does several things, all using pieces of other functions to get the
12627 evaluation sequence right. It's called for compound array assignments with
12628 the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs).
12629 It parses out which flags need to be set for declare to create the variable
12630 correctly, then calls declare internally (make_internal_declare) to make
12631 sure the variable exists with the correct attributes. Before the variable
12632 is created, it calls expand_compound_assignment_word to expand VALUE to a
12633 list of words, appropriately quoted for further evaluation. This preserves
12634 the semantics of word-expansion-before-calling-builtins. Finally, it calls
12635 do_word_assignment to perform the expansion and assignment with the same
12636 expansion semantics as a standalone assignment statement (no word splitting,
12637 etc.) even though the word is single-quoted so all that needs to happen is
12638 quote removal. */
12639 static WORD_LIST *
12640 expand_declaration_argument (tlist, wcmd)
12641 WORD_LIST *tlist, *wcmd;
12642 {
12643 char opts[16], omap[128];
12644 int t, opti, oind, skip, inheriting;
12645 WORD_LIST *l;
12646
12647 inheriting = localvar_inherit;
12648 opti = 0;
12649 if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY))
12650 opts[opti++] = '-';
12651
12652 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
12653 {
12654 opts[opti++] = 'g';
12655 opts[opti++] = 'A';
12656 }
12657 else if (tlist->word->flags & W_ASSIGNASSOC)
12658 {
12659 opts[opti++] = 'A';
12660 }
12661 else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
12662 {
12663 opts[opti++] = 'g';
12664 opts[opti++] = 'a';
12665 }
12666 else if (tlist->word->flags & W_ASSIGNARRAY)
12667 {
12668 opts[opti++] = 'a';
12669 }
12670 else if (tlist->word->flags & W_ASSNGLOBAL)
12671 opts[opti++] = 'g';
12672
12673 if (tlist->word->flags & W_CHKLOCAL)
12674 opts[opti++] = 'G';
12675
12676 /* If we have special handling note the integer attribute and others
12677 that transform the value upon assignment. What we do is take all
12678 of the option arguments and scan through them looking for options
12679 that cause such transformations, and add them to the `opts' array. */
12680
12681 memset (omap, '\0', sizeof (omap));
12682 for (l = wcmd->next; l != tlist; l = l->next)
12683 {
12684 int optchar;
12685
12686 if (l->word->word[0] != '-' && l->word->word[0] != '+')
12687 break; /* non-option argument */
12688 if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0)
12689 break; /* -- signals end of options */
12690 optchar = l->word->word[0];
12691 for (oind = 1; l->word->word[oind]; oind++)
12692 switch (l->word->word[oind])
12693 {
12694 case 'I':
12695 inheriting = 1;
12696 case 'i':
12697 case 'l':
12698 case 'u':
12699 case 'c':
12700 omap[l->word->word[oind]] = 1;
12701 if (opti == 0)
12702 opts[opti++] = optchar;
12703 break;
12704 default:
12705 break;
12706 }
12707 }
12708
12709 for (oind = 0; oind < sizeof (omap); oind++)
12710 if (omap[oind])
12711 opts[opti++] = oind;
12712
12713 /* If there are no -a/-A options, but we have a compound assignment,
12714 we have a choice: we can set opts[0]='-', opts[1]='a', since the
12715 default is to create an indexed array, and call
12716 make_internal_declare with that, or we can just skip the -a and let
12717 declare_builtin deal with it. Once we're here, we're better set
12718 up for the latter, since we don't want to deal with looking up
12719 any existing variable here -- better to let declare_builtin do it.
12720 We need the variable created, though, especially if it's local, so
12721 we get the scoping right before we call do_word_assignment.
12722 To ensure that make_local_declare gets called, we add `--' if there
12723 aren't any options. */
12724 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0)
12725 {
12726 if (opti == 0)
12727 {
12728 opts[opti++] = '-';
12729 opts[opti++] = '-';
12730 }
12731 }
12732 opts[opti] = '\0';
12733
12734 /* This isn't perfect, but it's a start. Improvements later. We expand
12735 tlist->word->word and single-quote the results to avoid multiple
12736 expansions by, say, do_assignment_internal(). We have to weigh the
12737 cost of reconstructing the compound assignment string with its single
12738 quoting and letting the declare builtin handle it. The single quotes
12739 will prevent any unwanted additional expansion or word splitting. */
12740 expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0);
12741
12742 skip = 0;
12743 if (opti > 0)
12744 {
12745 t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0);
12746 if (t != EXECUTION_SUCCESS)
12747 {
12748 last_command_exit_value = t;
12749 if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */
12750 skip = 1;
12751 else
12752 exp_jump_to_top_level (DISCARD);
12753 }
12754 }
12755
12756 if (skip == 0)
12757 {
12758 t = do_word_assignment (tlist->word, 0);
12759 if (t == 0)
12760 {
12761 last_command_exit_value = EXECUTION_FAILURE;
12762 exp_jump_to_top_level (DISCARD);
12763 }
12764 }
12765
12766 /* Now transform the word as ksh93 appears to do and go on */
12767 t = assignment (tlist->word->word, 0);
12768 tlist->word->word[t] = '\0';
12769 if (tlist->word->word[t - 1] == '+')
12770 tlist->word->word[t - 1] = '\0'; /* cut off append op */
12771 tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
12772
12773 return (tlist);
12774 }
12775 #endif /* ARRAY_VARS */
12776
12777 static WORD_LIST *
12778 shell_expand_word_list (tlist, eflags)
12779 WORD_LIST *tlist;
12780 int eflags;
12781 {
12782 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd;
12783 int expanded_something, has_dollar_at;
12784
12785 /* We do tilde expansion all the time. This is what 1003.2 says. */
12786 wcmd = new_list = (WORD_LIST *)NULL;
12787
12788 for (orig_list = tlist; tlist; tlist = next)
12789 {
12790 if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN))
12791 wcmd = tlist;
12792
12793 next = tlist->next;
12794
12795 #if defined (ARRAY_VARS)
12796 /* If this is a compound array assignment to a builtin that accepts
12797 such assignments (e.g., `declare'), take the assignment and perform
12798 it separately, handling the semantics of declarations inside shell
12799 functions. This avoids the double-evaluation of such arguments,
12800 because `declare' does some evaluation of compound assignments on
12801 its own. */
12802 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
12803 expand_declaration_argument (tlist, wcmd);
12804 #endif
12805
12806 expanded_something = 0;
12807 expanded = expand_word_internal
12808 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
12809
12810 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
12811 {
12812 /* By convention, each time this error is returned,
12813 tlist->word->word has already been freed. */
12814 tlist->word->word = (char *)NULL;
12815
12816 /* Dispose our copy of the original list. */
12817 dispose_words (orig_list);
12818 /* Dispose the new list we're building. */
12819 dispose_words (new_list);
12820
12821 last_command_exit_value = EXECUTION_FAILURE;
12822 if (expanded == &expand_word_error)
12823 exp_jump_to_top_level (DISCARD);
12824 else
12825 exp_jump_to_top_level (FORCE_EOF);
12826 }
12827
12828 /* Don't split words marked W_NOSPLIT. */
12829 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
12830 {
12831 temp_list = word_list_split (expanded);
12832 dispose_words (expanded);
12833 }
12834 else
12835 {
12836 /* If no parameter expansion, command substitution, process
12837 substitution, or arithmetic substitution took place, then
12838 do not do word splitting. We still have to remove quoted
12839 null characters from the result. */
12840 word_list_remove_quoted_nulls (expanded);
12841 temp_list = expanded;
12842 }
12843
12844 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
12845 new_list = (WORD_LIST *)list_append (expanded, new_list);
12846 }
12847
12848 if (orig_list)
12849 dispose_words (orig_list);
12850
12851 if (new_list)
12852 new_list = REVERSE_LIST (new_list, WORD_LIST *);
12853
12854 return (new_list);
12855 }
12856
12857 /* Perform assignment statements optionally preceding a command name COMMAND.
12858 If COMMAND == NULL, is_nullcmd usually == 1. Follow the POSIX rules for
12859 variable assignment errors. */
12860 static int
12861 do_assignment_statements (varlist, command, is_nullcmd)
12862 WORD_LIST *varlist;
12863 char *command;
12864 int is_nullcmd;
12865 {
12866 WORD_LIST *temp_list;
12867 char *savecmd;
12868 sh_wassign_func_t *assign_func;
12869 int is_special_builtin, is_builtin_or_func, tint;
12870
12871 /* If the remainder of the words expand to nothing, Posix.2 requires
12872 that the variable and environment assignments affect the shell's
12873 environment (do_word_assignment). */
12874 assign_func = is_nullcmd ? do_word_assignment : assign_in_env;
12875 tempenv_assign_error = 0;
12876
12877 is_builtin_or_func = command && (find_shell_builtin (command) || find_function (command));
12878 /* Posix says that special builtins exit if a variable assignment error
12879 occurs in an assignment preceding it. (XXX - this is old -- current Posix
12880 says that any variable assignment error causes a non-interactive shell
12881 to exit. See the STRICT_POSIX checks below. */
12882 is_special_builtin = posixly_correct && command && find_special_builtin (command);
12883
12884 savecmd = this_command_name;
12885 for (temp_list = varlist; temp_list; temp_list = temp_list->next)
12886 {
12887 this_command_name = (char *)NULL;
12888 assigning_in_environment = is_nullcmd == 0;
12889 tint = (*assign_func) (temp_list->word, is_builtin_or_func);
12890 assigning_in_environment = 0;
12891 this_command_name = savecmd;
12892
12893 /* Variable assignment errors in non-interactive shells running
12894 in posix mode cause the shell to exit. */
12895 if (tint == 0)
12896 {
12897 if (is_nullcmd) /* assignment statement */
12898 {
12899 last_command_exit_value = EXECUTION_FAILURE;
12900 #if defined (STRICT_POSIX)
12901 if (posixly_correct && interactive_shell == 0)
12902 #else
12903 if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
12904 #endif
12905 exp_jump_to_top_level (FORCE_EOF);
12906 else
12907 exp_jump_to_top_level (DISCARD);
12908 }
12909 /* In posix mode, assignment errors in the temporary environment
12910 cause a non-interactive shell executing a special builtin to
12911 exit and a non-interactive shell to otherwise jump back to the
12912 top level. This is what POSIX says to do for variable assignment
12913 errors, and POSIX says errors in assigning to the temporary
12914 environment are treated as variable assignment errors.
12915 (XXX - this is not what current POSIX says - look at the
12916 STRICT_POSIX defines. */
12917 else if (posixly_correct)
12918 {
12919 last_command_exit_value = EXECUTION_FAILURE;
12920 #if defined (STRICT_POSIX)
12921 exp_jump_to_top_level ((interactive_shell == 0) ? FORCE_EOF : DISCARD);
12922 #else
12923 if (interactive_shell == 0 && is_special_builtin)
12924 exp_jump_to_top_level (FORCE_EOF);
12925 else if (interactive_shell == 0)
12926 exp_jump_to_top_level (DISCARD); /* XXX - maybe change later */
12927 else
12928 exp_jump_to_top_level (DISCARD);
12929 #endif
12930 }
12931 else
12932 tempenv_assign_error++;
12933 }
12934 }
12935 return (tempenv_assign_error);
12936 }
12937
12938 /* The workhorse for expand_words () and expand_words_no_vars ().
12939 First arg is LIST, a WORD_LIST of words.
12940 Second arg EFLAGS is a flags word controlling which expansions are
12941 performed.
12942
12943 This does all of the substitutions: brace expansion, tilde expansion,
12944 parameter expansion, command substitution, arithmetic expansion,
12945 process substitution, word splitting, and pathname expansion, according
12946 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
12947 set, or for which no expansion is done, do not undergo word splitting.
12948 Words with the W_NOGLOB bit set do not undergo pathname expansion; words
12949 with W_NOBRACE set do not undergo brace expansion (see
12950 brace_expand_word_list above). */
12951 static WORD_LIST *
12952 expand_word_list_internal (list, eflags)
12953 WORD_LIST *list;
12954 int eflags;
12955 {
12956 WORD_LIST *new_list, *temp_list;
12957
12958 tempenv_assign_error = 0;
12959 if (list == 0)
12960 return ((WORD_LIST *)NULL);
12961
12962 garglist = new_list = copy_word_list (list);
12963 if (eflags & WEXP_VARASSIGN)
12964 {
12965 garglist = new_list = separate_out_assignments (new_list);
12966 if (new_list == 0)
12967 {
12968 if (subst_assign_varlist)
12969 do_assignment_statements (subst_assign_varlist, (char *)NULL, 1);
12970
12971 dispose_words (subst_assign_varlist);
12972 subst_assign_varlist = (WORD_LIST *)NULL;
12973
12974 return ((WORD_LIST *)NULL);
12975 }
12976 }
12977
12978 /* Begin expanding the words that remain. The expansions take place on
12979 things that aren't really variable assignments. */
12980
12981 #if defined (BRACE_EXPANSION)
12982 /* Do brace expansion on this word if there are any brace characters
12983 in the string. */
12984 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
12985 new_list = brace_expand_word_list (new_list, eflags);
12986 #endif /* BRACE_EXPANSION */
12987
12988 /* Perform the `normal' shell expansions: tilde expansion, parameter and
12989 variable substitution, command substitution, arithmetic expansion,
12990 and word splitting. */
12991 new_list = shell_expand_word_list (new_list, eflags);
12992
12993 /* Okay, we're almost done. Now let's just do some filename
12994 globbing. */
12995 if (new_list)
12996 {
12997 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
12998 /* Glob expand the word list unless globbing has been disabled. */
12999 new_list = glob_expand_word_list (new_list, eflags);
13000 else
13001 /* Dequote the words, because we're not performing globbing. */
13002 new_list = dequote_list (new_list);
13003 }
13004
13005 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
13006 {
13007 do_assignment_statements (subst_assign_varlist, (new_list && new_list->word) ? new_list->word->word : (char *)NULL, new_list == 0);
13008
13009 dispose_words (subst_assign_varlist);
13010 subst_assign_varlist = (WORD_LIST *)NULL;
13011 }
13012
13013 return (new_list);
13014 }