]> git.ipfire.org Git - thirdparty/bash.git/blob - subst.c
Bash-5.2 patch 21: fix for expanding command substitutions in a word expansion in...
[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 - 2;
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 - 2;
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 /* We don't perform process substitution in arithmetic expressions, so don't
3823 bother checking for it. */
3824 #define ARITH_EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
3825
3826 /* If there are any characters in STRING that require full expansion,
3827 then call FUNC to expand STRING; otherwise just perform quote
3828 removal if necessary. This returns a new string. */
3829 static char *
3830 expand_string_if_necessary (string, quoted, func)
3831 char *string;
3832 int quoted;
3833 EXPFUNC *func;
3834 {
3835 WORD_LIST *list;
3836 size_t slen;
3837 int i, saw_quote;
3838 char *ret;
3839 DECLARE_MBSTATE;
3840
3841 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3842 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
3843 i = saw_quote = 0;
3844 while (string[i])
3845 {
3846 if (EXP_CHAR (string[i]))
3847 break;
3848 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3849 saw_quote = 1;
3850 ADVANCE_CHAR (string, slen, i);
3851 }
3852
3853 if (string[i])
3854 {
3855 list = (*func) (string, quoted);
3856 if (list)
3857 {
3858 ret = string_list (list);
3859 dispose_words (list);
3860 }
3861 else
3862 ret = (char *)NULL;
3863 }
3864 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3865 ret = string_quote_removal (string, quoted);
3866 else
3867 ret = savestring (string);
3868
3869 return ret;
3870 }
3871
3872 static inline char *
3873 expand_string_to_string_internal (string, quoted, func)
3874 char *string;
3875 int quoted;
3876 EXPFUNC *func;
3877 {
3878 WORD_LIST *list;
3879 char *ret;
3880
3881 if (string == 0 || *string == '\0')
3882 return ((char *)NULL);
3883
3884 list = (*func) (string, quoted);
3885 if (list)
3886 {
3887 ret = string_list (list);
3888 dispose_words (list);
3889 }
3890 else
3891 ret = (char *)NULL;
3892
3893 return (ret);
3894 }
3895
3896 char *
3897 expand_string_to_string (string, quoted)
3898 char *string;
3899 int quoted;
3900 {
3901 return (expand_string_to_string_internal (string, quoted, expand_string));
3902 }
3903
3904 char *
3905 expand_string_unsplit_to_string (string, quoted)
3906 char *string;
3907 int quoted;
3908 {
3909 return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
3910 }
3911
3912 char *
3913 expand_assignment_string_to_string (string, quoted)
3914 char *string;
3915 int quoted;
3916 {
3917 return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
3918 }
3919
3920 /* Kind of like a combination of dequote_string and quote_string_for_globbing;
3921 try to remove CTLESC quoting characters and convert CTLESC escaping a `&'
3922 or a backslash into a backslash. The output of this function must eventually
3923 be processed by strcreplace(). */
3924 static char *
3925 quote_string_for_repl (string, flags)
3926 char *string;
3927 int flags;
3928 {
3929 size_t slen;
3930 char *result, *t;
3931 const char *s, *send;
3932 DECLARE_MBSTATE;
3933
3934 slen = strlen (string);
3935 send = string + slen;
3936
3937 result = (char *)xmalloc (slen * 2 + 1);
3938
3939 if (string[0] == CTLESC && string[1] == 0)
3940 {
3941 result[0] = CTLESC;
3942 result[1] = '\0';
3943 return (result);
3944 }
3945
3946 /* This is awkward. We want to translate CTLESC-\ to \\ if we will
3947 eventually send this string through strcreplace(), which we will do
3948 only if shouldexp_replacement() determines that there is something
3949 to replace. We can either make sure to escape backslashes here and
3950 have shouldexp_replacement() signal that we should send the string to
3951 strcreplace() if it sees an escaped backslash, or we can scan the
3952 string before copying it and turn CTLESC-\ into \\ only if we encounter
3953 a CTLESC-& or a &. This does the former and changes shouldexp_replacement().
3954 If we double the backslashes here, we'll get doubled backslashes in any
3955 result that doesn't get passed to strcreplace(). */
3956
3957 for (s = string, t = result; *s; )
3958 {
3959 /* This function's result has to be processed by strcreplace() */
3960 if (*s == CTLESC && (s[1] == '&' || s[1] == '\\'))
3961 {
3962 *t++ = '\\';
3963 s++;
3964 *t++ = *s++;
3965 continue;
3966 }
3967 /* Dequote it */
3968 if (*s == CTLESC)
3969 {
3970 s++;
3971 if (*s == '\0')
3972 break;
3973 }
3974 COPY_CHAR_P (t, s, send);
3975 }
3976
3977 *t = '\0';
3978 return (result);
3979 }
3980
3981 /* This does not perform word splitting on the WORD_LIST it returns and
3982 it treats $* as if it were quoted. It dequotes the WORD_LIST, adds
3983 backslash escapes before CTLESC-quoted backslash and `& if
3984 patsub_replacement is enabled. */
3985 static char *
3986 expand_string_for_patsub (string, quoted)
3987 char *string;
3988 int quoted;
3989 {
3990 WORD_LIST *value;
3991 char *ret, *t;
3992
3993 if (string == 0 || *string == '\0')
3994 return (char *)NULL;
3995
3996 value = expand_string_for_pat (string, quoted, (int *)0, (int *)0);
3997
3998 if (value && value->word)
3999 {
4000 remove_quoted_nulls (value->word->word); /* XXX */
4001 value->word->flags &= ~W_HASQUOTEDNULL;
4002 }
4003
4004 if (value)
4005 {
4006 t = (value->next) ? string_list (value) : value->word->word;
4007 ret = quote_string_for_repl (t, quoted);
4008 if (t != value->word->word)
4009 free (t);
4010 dispose_words (value);
4011 }
4012 else
4013 ret = (char *)NULL;
4014
4015 return (ret);
4016 }
4017
4018 char *
4019 expand_arith_string (string, quoted)
4020 char *string;
4021 int quoted;
4022 {
4023 WORD_DESC td;
4024 WORD_LIST *list, *tlist;
4025 size_t slen;
4026 int i, saw_quote;
4027 char *ret;
4028 DECLARE_MBSTATE;
4029
4030 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
4031 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
4032 i = saw_quote = 0;
4033 while (string[i])
4034 {
4035 if (ARITH_EXP_CHAR (string[i]))
4036 break;
4037 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
4038 saw_quote = string[i];
4039 ADVANCE_CHAR (string, slen, i);
4040 }
4041
4042 if (string[i])
4043 {
4044 /* This is expanded version of expand_string_internal as it's called by
4045 expand_string_leave_quoted */
4046 td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */
4047 #if 0 /* TAG: bash-5.2 */
4048 if (quoted & Q_ARRAYSUB)
4049 td.flags |= W_NOCOMSUB;
4050 #endif
4051 td.word = savestring (string);
4052 list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4053 /* This takes care of the calls from expand_string_leave_quoted and
4054 expand_string */
4055 if (list)
4056 {
4057 tlist = word_list_split (list);
4058 dispose_words (list);
4059 list = tlist;
4060 if (list)
4061 dequote_list (list);
4062 }
4063 /* This comes from expand_string_if_necessary */
4064 if (list)
4065 {
4066 ret = string_list (list);
4067 dispose_words (list);
4068 }
4069 else
4070 ret = (char *)NULL;
4071 FREE (td.word);
4072 }
4073 else if (saw_quote && (quoted & Q_ARITH))
4074 ret = string_quote_removal (string, quoted);
4075 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4076 ret = string_quote_removal (string, quoted);
4077 else
4078 ret = savestring (string);
4079
4080 return ret;
4081 }
4082
4083 #if defined (COND_COMMAND)
4084 /* Just remove backslashes in STRING. Returns a new string. */
4085 char *
4086 remove_backslashes (string)
4087 char *string;
4088 {
4089 char *r, *ret, *s;
4090
4091 r = ret = (char *)xmalloc (strlen (string) + 1);
4092 for (s = string; s && *s; )
4093 {
4094 if (*s == '\\')
4095 s++;
4096 if (*s == 0)
4097 break;
4098 *r++ = *s++;
4099 }
4100 *r = '\0';
4101 return ret;
4102 }
4103
4104 /* This needs better error handling. */
4105 /* Expand W for use as an argument to a unary or binary operator in a
4106 [[...]] expression. If SPECIAL is 1, this is the rhs argument
4107 to the != or == operator, and should be treated as a pattern. In
4108 this case, we quote the string specially for the globbing code. If
4109 SPECIAL is 2, this is an rhs argument for the =~ operator, and should
4110 be quoted appropriately for regcomp/regexec. If SPECIAL is 3, this is
4111 an array subscript and should be quoted after expansion so it's only
4112 expanded once (Q_ARITH). The caller is responsible
4113 for removing the backslashes if the unquoted word is needed later. In
4114 any case, since we don't perform word splitting, we need to do quoted
4115 null character removal. */
4116 char *
4117 cond_expand_word (w, special)
4118 WORD_DESC *w;
4119 int special;
4120 {
4121 char *r, *p;
4122 WORD_LIST *l;
4123 int qflags;
4124
4125 if (w->word == 0 || w->word[0] == '\0')
4126 return ((char *)NULL);
4127
4128 expand_no_split_dollar_star = 1;
4129 w->flags |= W_NOSPLIT2;
4130 qflags = (special == 3) ? Q_ARITH : 0;
4131 l = call_expand_word_internal (w, qflags, 0, (int *)0, (int *)0);
4132 expand_no_split_dollar_star = 0;
4133 if (l)
4134 {
4135 if (special == 0) /* LHS */
4136 {
4137 if (l->word)
4138 word_list_remove_quoted_nulls (l);
4139 dequote_list (l);
4140 r = string_list (l);
4141 }
4142 else if (special == 3) /* arithmetic expression, Q_ARITH */
4143 {
4144 if (l->word)
4145 word_list_remove_quoted_nulls (l); /* for now */
4146 dequote_list (l);
4147 r = string_list (l);
4148 }
4149 else
4150 {
4151 /* Need to figure out whether or not we should call dequote_escapes
4152 or a new dequote_ctlnul function here, and under what
4153 circumstances. */
4154 qflags = QGLOB_CVTNULL|QGLOB_CTLESC;
4155 if (special == 2)
4156 qflags |= QGLOB_REGEXP;
4157 word_list_remove_quoted_nulls (l);
4158 p = string_list (l);
4159 r = quote_string_for_globbing (p, qflags);
4160 free (p);
4161 }
4162 dispose_words (l);
4163 }
4164 else
4165 r = (char *)NULL;
4166
4167 return r;
4168 }
4169 #endif
4170
4171 /* Expand $'...' and $"..." in a string for code paths that don't do it. The
4172 FLAGS argument is 1 if this function should treat CTLESC as a quote
4173 character (e.g., for here-documents) or not (e.g., for shell_expand_line). */
4174 char *
4175 expand_string_dollar_quote (string, flags)
4176 char *string;
4177 int flags;
4178 {
4179 size_t slen, retind, retsize;
4180 int sindex, c, translen, peekc, news;
4181 char *ret, *trans, *send, *t;
4182 DECLARE_MBSTATE;
4183
4184 slen = strlen (string);
4185 send = string + slen;
4186 sindex = 0;
4187
4188 retsize = slen + 1;
4189 ret = xmalloc (retsize);
4190 retind = 0;
4191
4192 while (c = string[sindex])
4193 {
4194 switch (c)
4195 {
4196 default:
4197 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 1, retsize, 64);
4198 COPY_CHAR_I (ret, retind, string, send, sindex);
4199 break;
4200
4201 case '\\':
4202 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 2, retsize, 64);
4203 ret[retind++] = string[sindex++];
4204
4205 if (string[sindex])
4206 COPY_CHAR_I (ret, retind, string, send, sindex);
4207 break;
4208
4209 case '\'':
4210 case '"':
4211 if (c == '\'')
4212 news = skip_single_quoted (string, slen, ++sindex, SX_COMPLETE);
4213 else
4214 news = skip_double_quoted (string, slen, ++sindex, SX_COMPLETE);
4215 translen = news - sindex - 1;
4216 RESIZE_MALLOCED_BUFFER (ret, retind, translen + 3, retsize, 64);
4217 ret[retind++] = c;
4218 if (translen > 0)
4219 {
4220 strncpy (ret + retind, string + sindex, translen);
4221 retind += translen;
4222 }
4223 if (news > sindex && string[news - 1] == c)
4224 ret[retind++] = c;
4225 sindex = news;
4226 break;
4227
4228 case CTLESC:
4229 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 2, retsize, 64);
4230 if (flags)
4231 ret[retind++] = string[sindex++];
4232 if (string[sindex])
4233 COPY_CHAR_I (ret, retind, string, send, sindex);
4234 break;
4235
4236 case '$':
4237 peekc = string[++sindex];
4238 #if defined (TRANSLATABLE_STRINGS)
4239 if (peekc != '\'' && peekc != '"')
4240 #else
4241 if (peekc != '\'')
4242 #endif
4243 {
4244 RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 16);
4245 ret[retind++] = c;
4246 break;
4247 }
4248 if (string[sindex + 1] == '\0') /* don't bother */
4249 {
4250 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4251 ret[retind++] = c;
4252 ret[retind++] = peekc;
4253 sindex++;
4254 break;
4255 }
4256 if (peekc == '\'')
4257 {
4258 /* SX_COMPLETE is the equivalent of ALLOWESC here */
4259 /* We overload SX_COMPLETE below */
4260 news = skip_single_quoted (string, slen, ++sindex, SX_COMPLETE);
4261 /* Check for unclosed string and don't bother if so */
4262 if (news > sindex && string[news] == '\0' && string[news-1] != peekc)
4263 {
4264 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4265 ret[retind++] = c;
4266 ret[retind++] = peekc;
4267 continue;
4268 }
4269 t = substring (string, sindex, news - 1);
4270 trans = ansiexpand (t, 0, news-sindex-1, &translen);
4271 free (t);
4272 t = sh_single_quote (trans);
4273 sindex = news;
4274 }
4275 #if defined (TRANSLATABLE_STRINGS)
4276 else
4277 {
4278 news = ++sindex;
4279 t = string_extract_double_quoted (string, &news, SX_COMPLETE);
4280 /* Check for unclosed string and don't bother if so */
4281 if (news > sindex && string[news] == '\0' && string[news-1] != peekc)
4282 {
4283 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4284 ret[retind++] = c;
4285 ret[retind++] = peekc;
4286 free (t);
4287 continue;
4288 }
4289 trans = locale_expand (t, 0, news-sindex, 0, &translen);
4290 free (t);
4291 if (singlequote_translations &&
4292 ((news-sindex-1) != translen || STREQN (t, trans, translen) == 0))
4293 t = sh_single_quote (trans);
4294 else
4295 t = sh_mkdoublequoted (trans, translen, 0);
4296 sindex = news;
4297 }
4298 #endif /* TRANSLATABLE_STRINGS */
4299 free (trans);
4300 trans = t;
4301 translen = strlen (trans);
4302
4303 RESIZE_MALLOCED_BUFFER (ret, retind, translen + 1, retsize, 128);
4304 strcpy (ret + retind, trans);
4305 retind += translen;
4306 FREE (trans);
4307 break;
4308 }
4309 }
4310
4311 ret[retind] = 0;
4312 return ret;
4313 }
4314
4315 /* Call expand_word_internal to expand W and handle error returns.
4316 A convenience function for functions that don't want to handle
4317 any errors or free any memory before aborting. */
4318 static WORD_LIST *
4319 call_expand_word_internal (w, q, i, c, e)
4320 WORD_DESC *w;
4321 int q, i, *c, *e;
4322 {
4323 WORD_LIST *result;
4324
4325 result = expand_word_internal (w, q, i, c, e);
4326 if (result == &expand_word_error || result == &expand_word_fatal)
4327 {
4328 /* By convention, each time this error is returned, w->word has
4329 already been freed (it sometimes may not be in the fatal case,
4330 but that doesn't result in a memory leak because we're going
4331 to exit in most cases). */
4332 w->word = (char *)NULL;
4333 last_command_exit_value = EXECUTION_FAILURE;
4334 exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
4335 /* NOTREACHED */
4336 return (NULL);
4337 }
4338 else
4339 return (result);
4340 }
4341
4342 /* Perform parameter expansion, command substitution, and arithmetic
4343 expansion on STRING, as if it were a word. Leave the result quoted.
4344 Since this does not perform word splitting, it leaves quoted nulls
4345 in the result. */
4346 static WORD_LIST *
4347 expand_string_internal (string, quoted)
4348 char *string;
4349 int quoted;
4350 {
4351 WORD_DESC td;
4352 WORD_LIST *tresult;
4353
4354 if (string == 0 || *string == 0)
4355 return ((WORD_LIST *)NULL);
4356
4357 td.flags = 0;
4358 td.word = savestring (string);
4359
4360 tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4361
4362 FREE (td.word);
4363 return (tresult);
4364 }
4365
4366 /* Expand STRING by performing parameter expansion, command substitution,
4367 and arithmetic expansion. Dequote the resulting WORD_LIST before
4368 returning it, but do not perform word splitting. The call to
4369 remove_quoted_nulls () is in here because word splitting normally
4370 takes care of quote removal. */
4371 WORD_LIST *
4372 expand_string_unsplit (string, quoted)
4373 char *string;
4374 int quoted;
4375 {
4376 WORD_LIST *value;
4377
4378 if (string == 0 || *string == '\0')
4379 return ((WORD_LIST *)NULL);
4380
4381 expand_no_split_dollar_star = 1;
4382 value = expand_string_internal (string, quoted);
4383 expand_no_split_dollar_star = 0;
4384
4385 if (value)
4386 {
4387 if (value->word)
4388 {
4389 remove_quoted_nulls (value->word->word); /* XXX */
4390 value->word->flags &= ~W_HASQUOTEDNULL;
4391 }
4392 dequote_list (value);
4393 }
4394 return (value);
4395 }
4396
4397 /* Expand the rhs of an assignment statement */
4398 WORD_LIST *
4399 expand_string_assignment (string, quoted)
4400 char *string;
4401 int quoted;
4402 {
4403 WORD_DESC td;
4404 WORD_LIST *value;
4405
4406 if (string == 0 || *string == '\0')
4407 return ((WORD_LIST *)NULL);
4408
4409 expand_no_split_dollar_star = 1;
4410
4411 #if 0
4412 /* Other shells (ksh93) do it this way, which affects how $@ is expanded
4413 in constructs like bar=${@#0} (preserves the spaces resulting from the
4414 expansion of $@ in a context where you don't do word splitting); Posix
4415 interp 888 makes the expansion of $@ in contexts where word splitting
4416 is not performed unspecified. */
4417 td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */
4418 #else
4419 td.flags = W_ASSIGNRHS;
4420 #endif
4421 td.flags |= (W_NOGLOB|W_TILDEEXP);
4422 td.word = savestring (string);
4423 value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4424 FREE (td.word);
4425
4426 expand_no_split_dollar_star = 0;
4427
4428 if (value)
4429 {
4430 if (value->word)
4431 {
4432 remove_quoted_nulls (value->word->word); /* XXX */
4433 value->word->flags &= ~W_HASQUOTEDNULL;
4434 }
4435 dequote_list (value);
4436 }
4437 return (value);
4438 }
4439
4440 /* Expand one of the PS? prompt strings. This is a sort of combination of
4441 expand_string_unsplit and expand_string_internal, but returns the
4442 passed string when an error occurs. Might want to trap other calls
4443 to jump_to_top_level here so we don't endlessly loop. */
4444 WORD_LIST *
4445 expand_prompt_string (string, quoted, wflags)
4446 char *string;
4447 int quoted;
4448 int wflags;
4449 {
4450 WORD_LIST *value;
4451 WORD_DESC td;
4452
4453 if (string == 0 || *string == 0)
4454 return ((WORD_LIST *)NULL);
4455
4456 td.flags = wflags;
4457 td.word = savestring (string);
4458
4459 no_longjmp_on_fatal_error = 1;
4460 value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4461 no_longjmp_on_fatal_error = 0;
4462
4463 if (value == &expand_word_error || value == &expand_word_fatal)
4464 {
4465 value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
4466 return value;
4467 }
4468 FREE (td.word);
4469 if (value)
4470 {
4471 if (value->word)
4472 {
4473 remove_quoted_nulls (value->word->word); /* XXX */
4474 value->word->flags &= ~W_HASQUOTEDNULL;
4475 }
4476 dequote_list (value);
4477 }
4478 return (value);
4479 }
4480
4481 /* Expand STRING just as if you were expanding a word, but do not dequote
4482 the resultant WORD_LIST. This is called only from within this file,
4483 and is used to correctly preserve quoted characters when expanding
4484 things like ${1+"$@"}. This does parameter expansion, command
4485 substitution, arithmetic expansion, and word splitting. */
4486 static WORD_LIST *
4487 expand_string_leave_quoted (string, quoted)
4488 char *string;
4489 int quoted;
4490 {
4491 WORD_LIST *tlist;
4492 WORD_LIST *tresult;
4493
4494 if (string == 0 || *string == '\0')
4495 return ((WORD_LIST *)NULL);
4496
4497 tlist = expand_string_internal (string, quoted);
4498
4499 if (tlist)
4500 {
4501 tresult = word_list_split (tlist);
4502 dispose_words (tlist);
4503 return (tresult);
4504 }
4505 return ((WORD_LIST *)NULL);
4506 }
4507
4508 /* This does not perform word splitting or dequote the WORD_LIST
4509 it returns. */
4510 static WORD_LIST *
4511 expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p)
4512 char *string;
4513 int quoted, op, pflags;
4514 int *dollar_at_p, *expanded_p;
4515 {
4516 WORD_DESC td;
4517 WORD_LIST *tresult;
4518 int old_nosplit;
4519
4520 if (string == 0 || *string == '\0')
4521 return (WORD_LIST *)NULL;
4522
4523 /* We want field splitting to be determined by what is going to be done with
4524 the entire ${parameterOPword} expansion, so we don't want to split the RHS
4525 we expand here. However, the expansion of $* is determined by whether we
4526 are going to eventually perform word splitting, so we want to set this
4527 depending on whether or not are are going to be splitting: if the expansion
4528 is quoted, if the OP is `=', or if IFS is set to the empty string, we
4529 are not going to be splitting, so we set expand_no_split_dollar_star to
4530 note this to callees.
4531 We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an
4532 assignment statement. */
4533 /* The updated treatment of $* is the result of Posix interp 888 */
4534 /* This was further clarified on the austin-group list in March, 2017 and
4535 in Posix bug 1129 */
4536 old_nosplit = expand_no_split_dollar_star;
4537 expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */
4538 td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */
4539 td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */
4540 if (pflags & PF_ASSIGNRHS) /* pass through */
4541 td.flags |= W_ASSIGNRHS;
4542 if (op == '=')
4543 #if 0
4544 td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */
4545 #else
4546 td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */
4547 #endif
4548 td.word = savestring (string);
4549 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
4550 expand_no_split_dollar_star = old_nosplit;
4551 free (td.word);
4552
4553 return (tresult);
4554 }
4555
4556 /* This does not perform word splitting or dequote the WORD_LIST
4557 it returns and it treats $* as if it were quoted. */
4558 static WORD_LIST *
4559 expand_string_for_pat (string, quoted, dollar_at_p, expanded_p)
4560 char *string;
4561 int quoted, *dollar_at_p, *expanded_p;
4562 {
4563 WORD_DESC td;
4564 WORD_LIST *tresult;
4565 int oexp;
4566
4567 if (string == 0 || *string == '\0')
4568 return (WORD_LIST *)NULL;
4569
4570 oexp = expand_no_split_dollar_star;
4571 expand_no_split_dollar_star = 1;
4572 td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */
4573 td.word = savestring (string);
4574 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
4575 expand_no_split_dollar_star = oexp;
4576 free (td.word);
4577
4578 return (tresult);
4579 }
4580
4581 /* Expand STRING just as if you were expanding a word. This also returns
4582 a list of words. Note that filename globbing is *NOT* done for word
4583 or string expansion, just when the shell is expanding a command. This
4584 does parameter expansion, command substitution, arithmetic expansion,
4585 and word splitting. Dequote the resultant WORD_LIST before returning. */
4586 WORD_LIST *
4587 expand_string (string, quoted)
4588 char *string;
4589 int quoted;
4590 {
4591 WORD_LIST *result;
4592
4593 if (string == 0 || *string == '\0')
4594 return ((WORD_LIST *)NULL);
4595
4596 result = expand_string_leave_quoted (string, quoted);
4597 return (result ? dequote_list (result) : result);
4598 }
4599
4600 /*******************************************
4601 * *
4602 * Functions to expand WORD_DESCs *
4603 * *
4604 *******************************************/
4605
4606 /* Expand WORD, performing word splitting on the result. This does
4607 parameter expansion, command substitution, arithmetic expansion,
4608 word splitting, and quote removal. */
4609
4610 WORD_LIST *
4611 expand_word (word, quoted)
4612 WORD_DESC *word;
4613 int quoted;
4614 {
4615 WORD_LIST *result, *tresult;
4616
4617 tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4618 result = word_list_split (tresult);
4619 dispose_words (tresult);
4620 return (result ? dequote_list (result) : result);
4621 }
4622
4623 /* Expand WORD, but do not perform word splitting on the result. This
4624 does parameter expansion, command substitution, arithmetic expansion,
4625 and quote removal. */
4626 WORD_LIST *
4627 expand_word_unsplit (word, quoted)
4628 WORD_DESC *word;
4629 int quoted;
4630 {
4631 WORD_LIST *result;
4632
4633 result = expand_word_leave_quoted (word, quoted);
4634 return (result ? dequote_list (result) : result);
4635 }
4636
4637 /* Perform shell expansions on WORD, but do not perform word splitting or
4638 quote removal on the result. Virtually identical to expand_word_unsplit;
4639 could be combined if implementations don't diverge. */
4640 WORD_LIST *
4641 expand_word_leave_quoted (word, quoted)
4642 WORD_DESC *word;
4643 int quoted;
4644 {
4645 WORD_LIST *result;
4646
4647 expand_no_split_dollar_star = 1;
4648 if (ifs_is_null)
4649 word->flags |= W_NOSPLIT;
4650 word->flags |= W_NOSPLIT2;
4651 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4652 expand_no_split_dollar_star = 0;
4653
4654 return result;
4655 }
4656
4657 /***************************************************
4658 * *
4659 * Functions to handle quoting chars *
4660 * *
4661 ***************************************************/
4662
4663 /* Conventions:
4664
4665 A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
4666 The parser passes CTLNUL as CTLESC CTLNUL. */
4667
4668 /* Quote escape characters in string s, but no other characters. This is
4669 used to protect CTLESC and CTLNUL in variable values from the rest of
4670 the word expansion process after the variable is expanded (word splitting
4671 and filename generation). If IFS is null, we quote spaces as well, just
4672 in case we split on spaces later (in the case of unquoted $@, we will
4673 eventually attempt to split the entire word on spaces). Corresponding
4674 code exists in dequote_escapes. Even if we don't end up splitting on
4675 spaces, quoting spaces is not a problem. This should never be called on
4676 a string that is quoted with single or double quotes or part of a here
4677 document (effectively double-quoted).
4678 FLAGS says whether or not we are going to split the result. If we are not,
4679 and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL,
4680 respectively, to prevent them from being removed as part of dequoting. */
4681 static char *
4682 quote_escapes_internal (string, flags)
4683 const char *string;
4684 int flags;
4685 {
4686 const char *s, *send;
4687 char *t, *result;
4688 size_t slen;
4689 int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit;
4690 DECLARE_MBSTATE;
4691
4692 slen = strlen (string);
4693 send = string + slen;
4694
4695 quote_spaces = (ifs_value && *ifs_value == 0);
4696 nosplit = (flags & PF_NOSPLIT2);
4697
4698 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
4699 {
4700 skip_ctlesc |= (nosplit == 0 && *s == CTLESC);
4701 skip_ctlnul |= (nosplit == 0 && *s == CTLNUL);
4702 }
4703
4704 t = result = (char *)xmalloc ((slen * 2) + 1);
4705 s = string;
4706
4707 while (*s)
4708 {
4709 if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
4710 *t++ = CTLESC;
4711 COPY_CHAR_P (t, s, send);
4712 }
4713 *t = '\0';
4714
4715 return (result);
4716 }
4717
4718 char *
4719 quote_escapes (string)
4720 const char *string;
4721 {
4722 return (quote_escapes_internal (string, 0));
4723 }
4724
4725 char *
4726 quote_rhs (string)
4727 const char *string;
4728 {
4729 return (quote_escapes_internal (string, PF_NOSPLIT2));
4730 }
4731
4732 static WORD_LIST *
4733 list_quote_escapes (list)
4734 WORD_LIST *list;
4735 {
4736 register WORD_LIST *w;
4737 char *t;
4738
4739 for (w = list; w; w = w->next)
4740 {
4741 t = w->word->word;
4742 w->word->word = quote_escapes (t);
4743 free (t);
4744 }
4745 return list;
4746 }
4747
4748 /* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
4749
4750 The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
4751 This is necessary to make unquoted CTLESC and CTLNUL characters in the
4752 data stream pass through properly.
4753
4754 We need to remove doubled CTLESC characters inside quoted strings before
4755 quoting the entire string, so we do not double the number of CTLESC
4756 characters.
4757
4758 Also used by parts of the pattern substitution code. */
4759 char *
4760 dequote_escapes (string)
4761 const char *string;
4762 {
4763 const char *s, *send;
4764 char *t, *result;
4765 size_t slen;
4766 int quote_spaces;
4767 DECLARE_MBSTATE;
4768
4769 if (string == 0)
4770 return (char *)0;
4771
4772 slen = strlen (string);
4773 send = string + slen;
4774
4775 t = result = (char *)xmalloc (slen + 1);
4776
4777 if (strchr (string, CTLESC) == 0)
4778 return (strcpy (result, string));
4779
4780 quote_spaces = (ifs_value && *ifs_value == 0);
4781
4782 s = string;
4783 while (*s)
4784 {
4785 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
4786 {
4787 s++;
4788 if (*s == '\0')
4789 break;
4790 }
4791 COPY_CHAR_P (t, s, send);
4792 }
4793 *t = '\0';
4794
4795 return result;
4796 }
4797
4798 #if defined (INCLUDE_UNUSED)
4799 static WORD_LIST *
4800 list_dequote_escapes (list)
4801 WORD_LIST *list;
4802 {
4803 register WORD_LIST *w;
4804 char *t;
4805
4806 for (w = list; w; w = w->next)
4807 {
4808 t = w->word->word;
4809 w->word->word = dequote_escapes (t);
4810 free (t);
4811 }
4812 return list;
4813 }
4814 #endif
4815
4816 /* Return a new string with the quoted representation of character C.
4817 This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
4818 set in any resultant WORD_DESC where this value is the word. */
4819 static char *
4820 make_quoted_char (c)
4821 int c;
4822 {
4823 char *temp;
4824
4825 temp = (char *)xmalloc (3);
4826 if (c == 0)
4827 {
4828 temp[0] = CTLNUL;
4829 temp[1] = '\0';
4830 }
4831 else
4832 {
4833 temp[0] = CTLESC;
4834 temp[1] = c;
4835 temp[2] = '\0';
4836 }
4837 return (temp);
4838 }
4839
4840 /* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so
4841 the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
4842 this value is the word. */
4843 char *
4844 quote_string (string)
4845 char *string;
4846 {
4847 register char *t;
4848 size_t slen;
4849 char *result, *send;
4850
4851 if (*string == 0)
4852 {
4853 result = (char *)xmalloc (2);
4854 result[0] = CTLNUL;
4855 result[1] = '\0';
4856 }
4857 else
4858 {
4859 DECLARE_MBSTATE;
4860
4861 slen = strlen (string);
4862 send = string + slen;
4863
4864 result = (char *)xmalloc ((slen * 2) + 1);
4865
4866 for (t = result; string < send; )
4867 {
4868 *t++ = CTLESC;
4869 COPY_CHAR_P (t, string, send);
4870 }
4871 *t = '\0';
4872 }
4873 return (result);
4874 }
4875
4876 /* De-quote quoted characters in STRING. */
4877 char *
4878 dequote_string (string)
4879 char *string;
4880 {
4881 register char *s, *t;
4882 size_t slen;
4883 char *result, *send;
4884 DECLARE_MBSTATE;
4885
4886 if (string[0] == CTLESC && string[1] == 0)
4887 internal_debug ("dequote_string: string with bare CTLESC");
4888
4889 slen = STRLEN (string);
4890
4891 t = result = (char *)xmalloc (slen + 1);
4892
4893 if (QUOTED_NULL (string))
4894 {
4895 result[0] = '\0';
4896 return (result);
4897 }
4898
4899 /* A string consisting of only a single CTLESC should pass through unchanged */
4900 if (string[0] == CTLESC && string[1] == 0)
4901 {
4902 result[0] = CTLESC;
4903 result[1] = '\0';
4904 return (result);
4905 }
4906
4907 /* If no character in the string can be quoted, don't bother examining
4908 each character. Just return a copy of the string passed to us. */
4909 if (strchr (string, CTLESC) == NULL)
4910 return (strcpy (result, string));
4911
4912 send = string + slen;
4913 s = string;
4914 while (*s)
4915 {
4916 if (*s == CTLESC)
4917 {
4918 s++;
4919 if (*s == '\0')
4920 break;
4921 }
4922 COPY_CHAR_P (t, s, send);
4923 }
4924
4925 *t = '\0';
4926 return (result);
4927 }
4928
4929 /* Quote the entire WORD_LIST list. */
4930 static WORD_LIST *
4931 quote_list (list)
4932 WORD_LIST *list;
4933 {
4934 register WORD_LIST *w;
4935 char *t;
4936
4937 for (w = list; w; w = w->next)
4938 {
4939 t = w->word->word;
4940 w->word->word = quote_string (t);
4941 if (*t == 0)
4942 w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
4943 w->word->flags |= W_QUOTED;
4944 free (t);
4945 }
4946 return list;
4947 }
4948
4949 WORD_DESC *
4950 dequote_word (word)
4951 WORD_DESC *word;
4952 {
4953 register char *s;
4954
4955 s = dequote_string (word->word);
4956 if (QUOTED_NULL (word->word))
4957 word->flags &= ~W_HASQUOTEDNULL;
4958 free (word->word);
4959 word->word = s;
4960
4961 return word;
4962 }
4963
4964 /* De-quote quoted characters in each word in LIST. */
4965 WORD_LIST *
4966 dequote_list (list)
4967 WORD_LIST *list;
4968 {
4969 register char *s;
4970 register WORD_LIST *tlist;
4971
4972 for (tlist = list; tlist; tlist = tlist->next)
4973 {
4974 s = dequote_string (tlist->word->word);
4975 if (QUOTED_NULL (tlist->word->word))
4976 tlist->word->flags &= ~W_HASQUOTEDNULL;
4977 free (tlist->word->word);
4978 tlist->word->word = s;
4979 }
4980 return list;
4981 }
4982
4983 /* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
4984 string. */
4985 char *
4986 remove_quoted_escapes (string)
4987 char *string;
4988 {
4989 char *t;
4990
4991 if (string)
4992 {
4993 t = dequote_escapes (string);
4994 strcpy (string, t);
4995 free (t);
4996 }
4997
4998 return (string);
4999 }
5000
5001 /* Remove quoted $IFS characters from STRING. Quoted IFS characters are
5002 added to protect them from word splitting, but we need to remove them
5003 if no word splitting takes place. This returns newly-allocated memory,
5004 so callers can use it to replace savestring(). */
5005 char *
5006 remove_quoted_ifs (string)
5007 char *string;
5008 {
5009 register size_t slen;
5010 register int i, j;
5011 char *ret, *send;
5012 DECLARE_MBSTATE;
5013
5014 slen = strlen (string);
5015 send = string + slen;
5016
5017 i = j = 0;
5018 ret = (char *)xmalloc (slen + 1);
5019
5020 while (i < slen)
5021 {
5022 if (string[i] == CTLESC)
5023 {
5024 i++;
5025 if (string[i] == 0 || isifs (string[i]) == 0)
5026 ret[j++] = CTLESC;
5027 if (i == slen)
5028 break;
5029 }
5030
5031 COPY_CHAR_I (ret, j, string, send, i);
5032 }
5033 ret[j] = '\0';
5034
5035 return (ret);
5036 }
5037
5038 char *
5039 remove_quoted_nulls (string)
5040 char *string;
5041 {
5042 register size_t slen;
5043 register int i, j, prev_i;
5044 DECLARE_MBSTATE;
5045
5046 if (strchr (string, CTLNUL) == 0) /* XXX */
5047 return string; /* XXX */
5048
5049 slen = strlen (string);
5050 i = j = 0;
5051
5052 while (i < slen)
5053 {
5054 if (string[i] == CTLESC)
5055 {
5056 /* Old code had j++, but we cannot assume that i == j at this
5057 point -- what if a CTLNUL has already been removed from the
5058 string? We don't want to drop the CTLESC or recopy characters
5059 that we've already copied down. */
5060 i++;
5061 string[j++] = CTLESC;
5062 if (i == slen)
5063 break;
5064 }
5065 else if (string[i] == CTLNUL)
5066 {
5067 i++;
5068 continue;
5069 }
5070
5071 prev_i = i;
5072 ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */
5073 if (j < prev_i)
5074 {
5075 do string[j++] = string[prev_i++]; while (prev_i < i);
5076 }
5077 else
5078 j = i;
5079 }
5080 string[j] = '\0';
5081
5082 return (string);
5083 }
5084
5085 /* Perform quoted null character removal on each element of LIST.
5086 This modifies LIST. */
5087 void
5088 word_list_remove_quoted_nulls (list)
5089 WORD_LIST *list;
5090 {
5091 register WORD_LIST *t;
5092
5093 for (t = list; t; t = t->next)
5094 {
5095 remove_quoted_nulls (t->word->word);
5096 t->word->flags &= ~W_HASQUOTEDNULL;
5097 }
5098 }
5099
5100 /* **************************************************************** */
5101 /* */
5102 /* Functions for Matching and Removing Patterns */
5103 /* */
5104 /* **************************************************************** */
5105
5106 #if defined (HANDLE_MULTIBYTE)
5107 # ifdef INCLUDE_UNUSED
5108 static unsigned char *
5109 mb_getcharlens (string, len)
5110 char *string;
5111 int len;
5112 {
5113 int i, offset, last;
5114 unsigned char *ret;
5115 char *p;
5116 DECLARE_MBSTATE;
5117
5118 i = offset = 0;
5119 last = 0;
5120 ret = (unsigned char *)xmalloc (len);
5121 memset (ret, 0, len);
5122 while (string[last])
5123 {
5124 ADVANCE_CHAR (string, len, offset);
5125 ret[last] = offset - last;
5126 last = offset;
5127 }
5128 return ret;
5129 }
5130 # endif
5131 #endif
5132
5133 /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
5134 can have one of 4 values:
5135 RP_LONG_LEFT remove longest matching portion at start of PARAM
5136 RP_SHORT_LEFT remove shortest matching portion at start of PARAM
5137 RP_LONG_RIGHT remove longest matching portion at end of PARAM
5138 RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
5139 */
5140
5141 #define RP_LONG_LEFT 1
5142 #define RP_SHORT_LEFT 2
5143 #define RP_LONG_RIGHT 3
5144 #define RP_SHORT_RIGHT 4
5145
5146 /* Returns its first argument if nothing matched; new memory otherwise */
5147 static char *
5148 remove_upattern (param, pattern, op)
5149 char *param, *pattern;
5150 int op;
5151 {
5152 register size_t len;
5153 register char *end;
5154 register char *p, *ret, c;
5155
5156 len = STRLEN (param);
5157 end = param + len;
5158
5159 switch (op)
5160 {
5161 case RP_LONG_LEFT: /* remove longest match at start */
5162 for (p = end; p >= param; p--)
5163 {
5164 c = *p; *p = '\0';
5165 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5166 {
5167 *p = c;
5168 return (savestring (p));
5169 }
5170 *p = c;
5171
5172 }
5173 break;
5174
5175 case RP_SHORT_LEFT: /* remove shortest match at start */
5176 for (p = param; p <= end; p++)
5177 {
5178 c = *p; *p = '\0';
5179 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5180 {
5181 *p = c;
5182 return (savestring (p));
5183 }
5184 *p = c;
5185 }
5186 break;
5187
5188 case RP_LONG_RIGHT: /* remove longest match at end */
5189 for (p = param; p <= end; p++)
5190 {
5191 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5192 {
5193 c = *p; *p = '\0';
5194 ret = savestring (param);
5195 *p = c;
5196 return (ret);
5197 }
5198 }
5199 break;
5200
5201 case RP_SHORT_RIGHT: /* remove shortest match at end */
5202 for (p = end; p >= param; p--)
5203 {
5204 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5205 {
5206 c = *p; *p = '\0';
5207 ret = savestring (param);
5208 *p = c;
5209 return (ret);
5210 }
5211 }
5212 break;
5213 }
5214
5215 return (param); /* no match, return original string */
5216 }
5217
5218 #if defined (HANDLE_MULTIBYTE)
5219 /* Returns its first argument if nothing matched; new memory otherwise */
5220 static wchar_t *
5221 remove_wpattern (wparam, wstrlen, wpattern, op)
5222 wchar_t *wparam;
5223 size_t wstrlen;
5224 wchar_t *wpattern;
5225 int op;
5226 {
5227 wchar_t wc, *ret;
5228 int n;
5229
5230 switch (op)
5231 {
5232 case RP_LONG_LEFT: /* remove longest match at start */
5233 for (n = wstrlen; n >= 0; n--)
5234 {
5235 wc = wparam[n]; wparam[n] = L'\0';
5236 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5237 {
5238 wparam[n] = wc;
5239 return (wcsdup (wparam + n));
5240 }
5241 wparam[n] = wc;
5242 }
5243 break;
5244
5245 case RP_SHORT_LEFT: /* remove shortest match at start */
5246 for (n = 0; n <= wstrlen; n++)
5247 {
5248 wc = wparam[n]; wparam[n] = L'\0';
5249 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5250 {
5251 wparam[n] = wc;
5252 return (wcsdup (wparam + n));
5253 }
5254 wparam[n] = wc;
5255 }
5256 break;
5257
5258 case RP_LONG_RIGHT: /* remove longest match at end */
5259 for (n = 0; n <= wstrlen; n++)
5260 {
5261 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5262 {
5263 wc = wparam[n]; wparam[n] = L'\0';
5264 ret = wcsdup (wparam);
5265 wparam[n] = wc;
5266 return (ret);
5267 }
5268 }
5269 break;
5270
5271 case RP_SHORT_RIGHT: /* remove shortest match at end */
5272 for (n = wstrlen; n >= 0; n--)
5273 {
5274 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5275 {
5276 wc = wparam[n]; wparam[n] = L'\0';
5277 ret = wcsdup (wparam);
5278 wparam[n] = wc;
5279 return (ret);
5280 }
5281 }
5282 break;
5283 }
5284
5285 return (wparam); /* no match, return original string */
5286 }
5287 #endif /* HANDLE_MULTIBYTE */
5288
5289 static char *
5290 remove_pattern (param, pattern, op)
5291 char *param, *pattern;
5292 int op;
5293 {
5294 char *xret;
5295
5296 if (param == NULL)
5297 return (param);
5298 if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
5299 return (savestring (param));
5300
5301 #if defined (HANDLE_MULTIBYTE)
5302 if (MB_CUR_MAX > 1)
5303 {
5304 wchar_t *ret, *oret;
5305 size_t n;
5306 wchar_t *wparam, *wpattern;
5307 mbstate_t ps;
5308
5309 /* XXX - could optimize here by checking param and pattern for multibyte
5310 chars with mbsmbchar and calling remove_upattern. */
5311
5312 n = xdupmbstowcs (&wpattern, NULL, pattern);
5313 if (n == (size_t)-1)
5314 {
5315 xret = remove_upattern (param, pattern, op);
5316 return ((xret == param) ? savestring (param) : xret);
5317 }
5318 n = xdupmbstowcs (&wparam, NULL, param);
5319
5320 if (n == (size_t)-1)
5321 {
5322 free (wpattern);
5323 xret = remove_upattern (param, pattern, op);
5324 return ((xret == param) ? savestring (param) : xret);
5325 }
5326 oret = ret = remove_wpattern (wparam, n, wpattern, op);
5327 /* Don't bother to convert wparam back to multibyte string if nothing
5328 matched; just return copy of original string */
5329 if (ret == wparam)
5330 {
5331 free (wparam);
5332 free (wpattern);
5333 return (savestring (param));
5334 }
5335
5336 free (wparam);
5337 free (wpattern);
5338
5339 n = strlen (param);
5340 xret = (char *)xmalloc (n + 1);
5341 memset (&ps, '\0', sizeof (mbstate_t));
5342 n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
5343 xret[n] = '\0'; /* just to make sure */
5344 free (oret);
5345 return xret;
5346 }
5347 else
5348 #endif
5349 {
5350 xret = remove_upattern (param, pattern, op);
5351 return ((xret == param) ? savestring (param) : xret);
5352 }
5353 }
5354
5355 /* Match PAT anywhere in STRING and return the match boundaries.
5356 This returns 1 in case of a successful match, 0 otherwise. SP
5357 and EP are pointers into the string where the match begins and
5358 ends, respectively. MTYPE controls what kind of match is attempted.
5359 MATCH_BEG and MATCH_END anchor the match at the beginning and end
5360 of the string, respectively. The longest match is returned. */
5361 static int
5362 match_upattern (string, pat, mtype, sp, ep)
5363 char *string, *pat;
5364 int mtype;
5365 char **sp, **ep;
5366 {
5367 int c, mlen;
5368 size_t len;
5369 register char *p, *p1, *npat;
5370 char *end;
5371
5372 /* If the pattern doesn't match anywhere in the string, go ahead and
5373 short-circuit right away. A minor optimization, saves a bunch of
5374 unnecessary calls to strmatch (up to N calls for a string of N
5375 characters) if the match is unsuccessful. To preserve the semantics
5376 of the substring matches below, we make sure that the pattern has
5377 `*' as first and last character, making a new pattern if necessary. */
5378 /* XXX - check this later if I ever implement `**' with special meaning,
5379 since this will potentially result in `**' at the beginning or end */
5380 len = STRLEN (pat);
5381 if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
5382 {
5383 int unescaped_backslash;
5384 char *pp;
5385
5386 p = npat = (char *)xmalloc (len + 3);
5387 p1 = pat;
5388 if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob)))
5389 *p++ = '*';
5390 while (*p1)
5391 *p++ = *p1++;
5392 #if 1
5393 /* Need to also handle a pattern that ends with an unescaped backslash.
5394 For right now, we ignore it because the pattern matching code will
5395 fail the match anyway */
5396 /* If the pattern ends with a `*' we leave it alone if it's preceded by
5397 an even number of backslashes, but if it's escaped by a backslash
5398 we need to add another `*'. */
5399 if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\')))
5400 {
5401 pp = p1 - 3;
5402 while (pp >= pat && *pp-- == '\\')
5403 unescaped_backslash = 1 - unescaped_backslash;
5404 if (unescaped_backslash)
5405 *p++ = '*';
5406 }
5407 else if (mtype != MATCH_END && p1[-1] != '*')
5408 *p++ = '*';
5409 #else
5410 if (p1[-1] != '*' || p1[-2] == '\\')
5411 *p++ = '*';
5412 #endif
5413 *p = '\0';
5414 }
5415 else
5416 npat = pat;
5417 c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
5418 if (npat != pat)
5419 free (npat);
5420 if (c == FNM_NOMATCH)
5421 return (0);
5422
5423 len = STRLEN (string);
5424 end = string + len;
5425
5426 mlen = umatchlen (pat, len);
5427 if (mlen > (int)len)
5428 return (0);
5429
5430 switch (mtype)
5431 {
5432 case MATCH_ANY:
5433 for (p = string; p <= end; p++)
5434 {
5435 if (match_pattern_char (pat, p, FNMATCH_IGNCASE))
5436 {
5437 p1 = (mlen == -1) ? end : p + mlen;
5438 /* p1 - p = length of portion of string to be considered
5439 p = current position in string
5440 mlen = number of characters consumed by match (-1 for entire string)
5441 end = end of string
5442 we want to break immediately if the potential match len
5443 is greater than the number of characters remaining in the
5444 string
5445 */
5446 if (p1 > end)
5447 break;
5448 for ( ; p1 >= p; p1--)
5449 {
5450 c = *p1; *p1 = '\0';
5451 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5452 {
5453 *p1 = c;
5454 *sp = p;
5455 *ep = p1;
5456 return 1;
5457 }
5458 *p1 = c;
5459 #if 1
5460 /* If MLEN != -1, we have a fixed length pattern. */
5461 if (mlen != -1)
5462 break;
5463 #endif
5464 }
5465 }
5466 }
5467
5468 return (0);
5469
5470 case MATCH_BEG:
5471 if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0)
5472 return (0);
5473
5474 for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
5475 {
5476 c = *p; *p = '\0';
5477 if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5478 {
5479 *p = c;
5480 *sp = string;
5481 *ep = p;
5482 return 1;
5483 }
5484 *p = c;
5485 /* If MLEN != -1, we have a fixed length pattern. */
5486 if (mlen != -1)
5487 break;
5488 }
5489
5490 return (0);
5491
5492 case MATCH_END:
5493 for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
5494 {
5495 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5496 {
5497 *sp = p;
5498 *ep = end;
5499 return 1;
5500 }
5501 /* If MLEN != -1, we have a fixed length pattern. */
5502 if (mlen != -1)
5503 break;
5504 }
5505
5506 return (0);
5507 }
5508
5509 return (0);
5510 }
5511
5512 #if defined (HANDLE_MULTIBYTE)
5513
5514 #define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c))
5515
5516 /* Match WPAT anywhere in WSTRING and return the match boundaries.
5517 This returns 1 in case of a successful match, 0 otherwise. Wide
5518 character version. */
5519 static int
5520 match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
5521 wchar_t *wstring;
5522 char **indices;
5523 size_t wstrlen;
5524 wchar_t *wpat;
5525 int mtype;
5526 char **sp, **ep;
5527 {
5528 wchar_t wc, *wp, *nwpat, *wp1;
5529 size_t len;
5530 int mlen;
5531 int n, n1, n2, simple;
5532
5533 simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
5534 #if defined (EXTENDED_GLOB)
5535 if (extended_glob)
5536 simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
5537 #endif
5538
5539 /* If the pattern doesn't match anywhere in the string, go ahead and
5540 short-circuit right away. A minor optimization, saves a bunch of
5541 unnecessary calls to strmatch (up to N calls for a string of N
5542 characters) if the match is unsuccessful. To preserve the semantics
5543 of the substring matches below, we make sure that the pattern has
5544 `*' as first and last character, making a new pattern if necessary. */
5545 len = wcslen (wpat);
5546 if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
5547 {
5548 int unescaped_backslash;
5549 wchar_t *wpp;
5550
5551 wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
5552 wp1 = wpat;
5553 if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
5554 *wp++ = L'*';
5555 while (*wp1 != L'\0')
5556 *wp++ = *wp1++;
5557 #if 1
5558 /* See comments above in match_upattern. */
5559 if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\'))
5560 {
5561 wpp = wp1 - 3;
5562 while (wpp >= wpat && *wpp-- == L'\\')
5563 unescaped_backslash = 1 - unescaped_backslash;
5564 if (unescaped_backslash)
5565 *wp++ = L'*';
5566 }
5567 else if (wp1[-1] != L'*')
5568 *wp++ = L'*';
5569 #else
5570 if (wp1[-1] != L'*' || wp1[-2] == L'\\')
5571 *wp++ = L'*';
5572 #endif
5573 *wp = '\0';
5574 }
5575 else
5576 nwpat = wpat;
5577 len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
5578 if (nwpat != wpat)
5579 free (nwpat);
5580 if (len == FNM_NOMATCH)
5581 return (0);
5582
5583 mlen = wmatchlen (wpat, wstrlen);
5584 if (mlen > (int)wstrlen)
5585 return (0);
5586
5587 /* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
5588 switch (mtype)
5589 {
5590 case MATCH_ANY:
5591 for (n = 0; n <= wstrlen; n++)
5592 {
5593 n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE);
5594 if (n2)
5595 {
5596 n1 = (mlen == -1) ? wstrlen : n + mlen;
5597 if (n1 > wstrlen)
5598 break;
5599
5600 for ( ; n1 >= n; n1--)
5601 {
5602 wc = wstring[n1]; wstring[n1] = L'\0';
5603 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5604 {
5605 wstring[n1] = wc;
5606 *sp = indices[n];
5607 *ep = indices[n1];
5608 return 1;
5609 }
5610 wstring[n1] = wc;
5611 /* If MLEN != -1, we have a fixed length pattern. */
5612 if (mlen != -1)
5613 break;
5614 }
5615 }
5616 }
5617
5618 return (0);
5619
5620 case MATCH_BEG:
5621 if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0)
5622 return (0);
5623
5624 for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
5625 {
5626 wc = wstring[n]; wstring[n] = L'\0';
5627 if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5628 {
5629 wstring[n] = wc;
5630 *sp = indices[0];
5631 *ep = indices[n];
5632 return 1;
5633 }
5634 wstring[n] = wc;
5635 /* If MLEN != -1, we have a fixed length pattern. */
5636 if (mlen != -1)
5637 break;
5638 }
5639
5640 return (0);
5641
5642 case MATCH_END:
5643 for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
5644 {
5645 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5646 {
5647 *sp = indices[n];
5648 *ep = indices[wstrlen];
5649 return 1;
5650 }
5651 /* If MLEN != -1, we have a fixed length pattern. */
5652 if (mlen != -1)
5653 break;
5654 }
5655
5656 return (0);
5657 }
5658
5659 return (0);
5660 }
5661 #undef WFOLD
5662 #endif /* HANDLE_MULTIBYTE */
5663
5664 static int
5665 match_pattern (string, pat, mtype, sp, ep)
5666 char *string, *pat;
5667 int mtype;
5668 char **sp, **ep;
5669 {
5670 #if defined (HANDLE_MULTIBYTE)
5671 int ret;
5672 size_t n;
5673 wchar_t *wstring, *wpat;
5674 char **indices;
5675 #endif
5676
5677 if (string == 0 || pat == 0 || *pat == 0)
5678 return (0);
5679
5680 #if defined (HANDLE_MULTIBYTE)
5681 if (MB_CUR_MAX > 1)
5682 {
5683 if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
5684 return (match_upattern (string, pat, mtype, sp, ep));
5685
5686 n = xdupmbstowcs (&wpat, NULL, pat);
5687 if (n == (size_t)-1)
5688 return (match_upattern (string, pat, mtype, sp, ep));
5689 n = xdupmbstowcs (&wstring, &indices, string);
5690 if (n == (size_t)-1)
5691 {
5692 free (wpat);
5693 return (match_upattern (string, pat, mtype, sp, ep));
5694 }
5695 ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
5696
5697 free (wpat);
5698 free (wstring);
5699 free (indices);
5700
5701 return (ret);
5702 }
5703 else
5704 #endif
5705 return (match_upattern (string, pat, mtype, sp, ep));
5706 }
5707
5708 static int
5709 getpatspec (c, value)
5710 int c;
5711 char *value;
5712 {
5713 if (c == '#')
5714 return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
5715 else /* c == '%' */
5716 return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
5717 }
5718
5719 /* Posix.2 says that the WORD should be run through tilde expansion,
5720 parameter expansion, command substitution and arithmetic expansion.
5721 This leaves the result quoted, so quote_string_for_globbing () has
5722 to be called to fix it up for strmatch (). If QUOTED is non-zero,
5723 it means that the entire expression was enclosed in double quotes.
5724 This means that quoting characters in the pattern do not make any
5725 special pattern characters quoted. For example, the `*' in the
5726 following retains its special meaning: "${foo#'*'}". */
5727 static char *
5728 getpattern (value, quoted, expandpat)
5729 char *value;
5730 int quoted, expandpat;
5731 {
5732 char *pat, *tword;
5733 WORD_LIST *l;
5734 #if 0
5735 int i;
5736 #endif
5737 /* There is a problem here: how to handle single or double quotes in the
5738 pattern string when the whole expression is between double quotes?
5739 POSIX.2 says that enclosing double quotes do not cause the pattern to
5740 be quoted, but does that leave us a problem with @ and array[@] and their
5741 expansions inside a pattern? */
5742 #if 0
5743 if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
5744 {
5745 i = 0;
5746 pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ);
5747 free (tword);
5748 tword = pat;
5749 }
5750 #endif
5751
5752 /* expand_string_for_pat () leaves WORD quoted and does not perform
5753 word splitting. */
5754 l = *value ? expand_string_for_pat (value,
5755 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
5756 (int *)NULL, (int *)NULL)
5757 : (WORD_LIST *)0;
5758 if (l)
5759 word_list_remove_quoted_nulls (l);
5760 pat = string_list (l);
5761 dispose_words (l);
5762 if (pat)
5763 {
5764 tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
5765 free (pat);
5766 pat = tword;
5767 }
5768 return (pat);
5769 }
5770
5771 #if 0
5772 /* Handle removing a pattern from a string as a result of ${name%[%]value}
5773 or ${name#[#]value}. */
5774 static char *
5775 variable_remove_pattern (value, pattern, patspec, quoted)
5776 char *value, *pattern;
5777 int patspec, quoted;
5778 {
5779 char *tword;
5780
5781 tword = remove_pattern (value, pattern, patspec);
5782
5783 return (tword);
5784 }
5785 #endif
5786
5787 static char *
5788 list_remove_pattern (list, pattern, patspec, itype, quoted)
5789 WORD_LIST *list;
5790 char *pattern;
5791 int patspec, itype, quoted;
5792 {
5793 WORD_LIST *new, *l;
5794 WORD_DESC *w;
5795 char *tword;
5796
5797 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
5798 {
5799 tword = remove_pattern (l->word->word, pattern, patspec);
5800 w = alloc_word_desc ();
5801 w->word = tword ? tword : savestring ("");
5802 new = make_word_list (w, new);
5803 }
5804
5805 l = REVERSE_LIST (new, WORD_LIST *);
5806 tword = string_list_pos_params (itype, l, quoted, 0);
5807 dispose_words (l);
5808
5809 return (tword);
5810 }
5811
5812 static char *
5813 parameter_list_remove_pattern (itype, pattern, patspec, quoted)
5814 int itype;
5815 char *pattern;
5816 int patspec, quoted;
5817 {
5818 char *ret;
5819 WORD_LIST *list;
5820
5821 list = list_rest_of_args ();
5822 if (list == 0)
5823 return ((char *)NULL);
5824 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5825 dispose_words (list);
5826 return (ret);
5827 }
5828
5829 #if defined (ARRAY_VARS)
5830 static char *
5831 array_remove_pattern (var, pattern, patspec, starsub, quoted)
5832 SHELL_VAR *var;
5833 char *pattern;
5834 int patspec;
5835 int starsub; /* so we can figure out how it's indexed */
5836 int quoted;
5837 {
5838 ARRAY *a;
5839 HASH_TABLE *h;
5840 int itype;
5841 char *ret;
5842 WORD_LIST *list;
5843 SHELL_VAR *v;
5844
5845 v = var; /* XXX - for now */
5846
5847 itype = starsub ? '*' : '@';
5848
5849 a = (v && array_p (v)) ? array_cell (v) : 0;
5850 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
5851
5852 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
5853 if (list == 0)
5854 return ((char *)NULL);
5855 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5856 dispose_words (list);
5857
5858 return ret;
5859 }
5860 #endif /* ARRAY_VARS */
5861
5862 static char *
5863 parameter_brace_remove_pattern (varname, value, estatep, patstr, rtype, quoted, flags)
5864 char *varname, *value;
5865 array_eltstate_t *estatep;
5866 char *patstr;
5867 int rtype, quoted, flags;
5868 {
5869 int vtype, patspec, starsub;
5870 char *temp1, *val, *pattern, *oname;
5871 SHELL_VAR *v;
5872
5873 if (value == 0)
5874 return ((char *)NULL);
5875
5876 oname = this_command_name;
5877 this_command_name = varname;
5878
5879 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
5880 if (vtype == -1)
5881 {
5882 this_command_name = oname;
5883 return ((char *)NULL);
5884 }
5885
5886 starsub = vtype & VT_STARSUB;
5887 vtype &= ~VT_STARSUB;
5888
5889 patspec = getpatspec (rtype, patstr);
5890 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
5891 patstr++;
5892
5893 /* Need to pass getpattern newly-allocated memory in case of expansion --
5894 the expansion code will free the passed string on an error. */
5895 temp1 = savestring (patstr);
5896 pattern = getpattern (temp1, quoted, 1);
5897 free (temp1);
5898
5899 temp1 = (char *)NULL; /* shut up gcc */
5900 switch (vtype)
5901 {
5902 case VT_VARIABLE:
5903 case VT_ARRAYMEMBER:
5904 temp1 = remove_pattern (val, pattern, patspec);
5905 if (vtype == VT_VARIABLE)
5906 FREE (val);
5907 if (temp1)
5908 {
5909 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5910 ? quote_string (temp1)
5911 : quote_escapes (temp1);
5912 free (temp1);
5913 temp1 = val;
5914 }
5915 break;
5916 #if defined (ARRAY_VARS)
5917 case VT_ARRAYVAR:
5918 temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted);
5919 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5920 {
5921 val = quote_escapes (temp1);
5922 free (temp1);
5923 temp1 = val;
5924 }
5925 break;
5926 #endif
5927 case VT_POSPARMS:
5928 temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
5929 if (temp1 && quoted == 0 && ifs_is_null)
5930 {
5931 /* Posix interp 888 */
5932 }
5933 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5934 {
5935 val = quote_escapes (temp1);
5936 free (temp1);
5937 temp1 = val;
5938 }
5939 break;
5940 }
5941
5942 this_command_name = oname;
5943
5944 FREE (pattern);
5945 return temp1;
5946 }
5947
5948 #if defined (PROCESS_SUBSTITUTION)
5949
5950 static void reap_some_procsubs PARAMS((int));
5951
5952 /*****************************************************************/
5953 /* */
5954 /* Hacking Process Substitution */
5955 /* */
5956 /*****************************************************************/
5957
5958 #if !defined (HAVE_DEV_FD)
5959 /* Named pipes must be removed explicitly with `unlink'. This keeps a list
5960 of FIFOs the shell has open. unlink_fifo_list will walk the list and
5961 unlink the ones that don't have a living process on the other end.
5962 unlink_all_fifos will walk the list and unconditionally unlink them, trying
5963 to open and close the FIFO first to release any child processes sleeping on
5964 the FIFO. add_fifo_list adds the name of an open FIFO to the list.
5965 NFIFO is a count of the number of FIFOs in the list. */
5966 #define FIFO_INCR 20
5967
5968 /* PROC value of -1 means the process has been reaped and the FIFO needs to
5969 be removed. PROC value of 0 means the slot is unused. */
5970 struct temp_fifo {
5971 char *file;
5972 pid_t proc;
5973 };
5974
5975 static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
5976 static int nfifo;
5977 static int fifo_list_size;
5978
5979 void
5980 clear_fifo_list ()
5981 {
5982 int i;
5983
5984 for (i = 0; i < fifo_list_size; i++)
5985 {
5986 if (fifo_list[i].file)
5987 free (fifo_list[i].file);
5988 fifo_list[i].file = NULL;
5989 fifo_list[i].proc = 0;
5990 }
5991 nfifo = 0;
5992 }
5993
5994 void *
5995 copy_fifo_list (sizep)
5996 int *sizep;
5997 {
5998 if (sizep)
5999 *sizep = 0;
6000 return (void *)NULL;
6001 }
6002
6003 static void
6004 add_fifo_list (pathname)
6005 char *pathname;
6006 {
6007 int osize, i;
6008
6009 if (nfifo >= fifo_list_size - 1)
6010 {
6011 osize = fifo_list_size;
6012 fifo_list_size += FIFO_INCR;
6013 fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
6014 fifo_list_size * sizeof (struct temp_fifo));
6015 for (i = osize; i < fifo_list_size; i++)
6016 {
6017 fifo_list[i].file = (char *)NULL;
6018 fifo_list[i].proc = 0; /* unused */
6019 }
6020 }
6021
6022 fifo_list[nfifo].file = savestring (pathname);
6023 nfifo++;
6024 }
6025
6026 void
6027 unlink_fifo (i)
6028 int i;
6029 {
6030 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
6031 {
6032 unlink (fifo_list[i].file);
6033 free (fifo_list[i].file);
6034 fifo_list[i].file = (char *)NULL;
6035 fifo_list[i].proc = 0;
6036 }
6037 }
6038
6039 void
6040 unlink_fifo_list ()
6041 {
6042 int saved, i, j;
6043
6044 if (nfifo == 0)
6045 return;
6046
6047 for (i = saved = 0; i < nfifo; i++)
6048 {
6049 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
6050 {
6051 unlink (fifo_list[i].file);
6052 free (fifo_list[i].file);
6053 fifo_list[i].file = (char *)NULL;
6054 fifo_list[i].proc = 0;
6055 }
6056 else
6057 saved++;
6058 }
6059
6060 /* If we didn't remove some of the FIFOs, compact the list. */
6061 if (saved)
6062 {
6063 for (i = j = 0; i < nfifo; i++)
6064 if (fifo_list[i].file)
6065 {
6066 if (i != j)
6067 {
6068 fifo_list[j].file = fifo_list[i].file;
6069 fifo_list[j].proc = fifo_list[i].proc;
6070 fifo_list[i].file = (char *)NULL;
6071 fifo_list[i].proc = 0;
6072 }
6073 j++;
6074 }
6075 nfifo = j;
6076 }
6077 else
6078 nfifo = 0;
6079 }
6080
6081 void
6082 unlink_all_fifos ()
6083 {
6084 int i, fd;
6085
6086 if (nfifo == 0)
6087 return;
6088
6089 for (i = 0; i < nfifo; i++)
6090 {
6091 fifo_list[i].proc = (pid_t)-1;
6092 #if defined (O_NONBLOCK)
6093 fd = open (fifo_list[i].file, O_RDWR|O_NONBLOCK);
6094 #else
6095 fd = -1;
6096 #endif
6097 unlink_fifo (i);
6098 if (fd >= 0)
6099 close (fd);
6100 }
6101
6102 nfifo = 0;
6103 }
6104
6105 /* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
6106 from some point in the past, and close all open FIFOs in fifo_list
6107 that are not marked as active in LIST. If LIST is NULL, close
6108 everything in fifo_list. LSIZE is the number of elements in LIST, in
6109 case it's larger than fifo_list_size (size of fifo_list). */
6110 void
6111 close_new_fifos (list, lsize)
6112 void *list;
6113 int lsize;
6114 {
6115 int i;
6116 char *plist;
6117
6118 if (list == 0)
6119 {
6120 unlink_fifo_list ();
6121 return;
6122 }
6123
6124 for (plist = (char *)list, i = 0; i < lsize; i++)
6125 if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
6126 unlink_fifo (i);
6127
6128 for (i = lsize; i < fifo_list_size; i++)
6129 unlink_fifo (i);
6130 }
6131
6132 int
6133 find_procsub_child (pid)
6134 pid_t pid;
6135 {
6136 int i;
6137
6138 for (i = 0; i < nfifo; i++)
6139 if (fifo_list[i].proc == pid)
6140 return i;
6141 return -1;
6142 }
6143
6144 void
6145 set_procsub_status (ind, pid, status)
6146 int ind;
6147 pid_t pid;
6148 int status;
6149 {
6150 if (ind >= 0 && ind < nfifo)
6151 fifo_list[ind].proc = (pid_t)-1; /* sentinel */
6152 }
6153
6154 /* If we've marked the process for this procsub as dead, close the
6155 associated file descriptor and delete the FIFO. */
6156 static void
6157 reap_some_procsubs (max)
6158 int max;
6159 {
6160 int i;
6161
6162 for (i = 0; i < max; i++)
6163 if (fifo_list[i].proc == (pid_t)-1) /* reaped */
6164 unlink_fifo (i);
6165 }
6166
6167 void
6168 reap_procsubs ()
6169 {
6170 reap_some_procsubs (nfifo);
6171 }
6172
6173 #if 0
6174 /* UNUSED */
6175 void
6176 wait_procsubs ()
6177 {
6178 int i, r;
6179
6180 for (i = 0; i < nfifo; i++)
6181 {
6182 if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0)
6183 {
6184 r = wait_for (fifo_list[i].proc, 0);
6185 save_proc_status (fifo_list[i].proc, r);
6186 fifo_list[i].proc = (pid_t)-1;
6187 }
6188 }
6189 }
6190 #endif
6191
6192 int
6193 fifos_pending ()
6194 {
6195 return nfifo;
6196 }
6197
6198 int
6199 num_fifos ()
6200 {
6201 return nfifo;
6202 }
6203
6204 static char *
6205 make_named_pipe ()
6206 {
6207 char *tname;
6208
6209 tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
6210 if (mkfifo (tname, 0600) < 0)
6211 {
6212 free (tname);
6213 return ((char *)NULL);
6214 }
6215
6216 add_fifo_list (tname);
6217 return (tname);
6218 }
6219
6220 #else /* HAVE_DEV_FD */
6221
6222 /* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
6223 has open to children. NFDS is a count of the number of bits currently
6224 set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
6225 of open files. */
6226 /* dev_fd_list[I] value of -1 means the process has been reaped and file
6227 descriptor I needs to be closed. Value of 0 means the slot is unused. */
6228
6229 static pid_t *dev_fd_list = (pid_t *)NULL;
6230 static int nfds;
6231 static int totfds; /* The highest possible number of open files. */
6232
6233 void
6234 clear_fifo (i)
6235 int i;
6236 {
6237 if (dev_fd_list[i])
6238 {
6239 dev_fd_list[i] = 0;
6240 nfds--;
6241 }
6242 }
6243
6244 void
6245 clear_fifo_list ()
6246 {
6247 register int i;
6248
6249 if (nfds == 0)
6250 return;
6251
6252 for (i = 0; nfds && i < totfds; i++)
6253 clear_fifo (i);
6254
6255 nfds = 0;
6256 }
6257
6258 void *
6259 copy_fifo_list (sizep)
6260 int *sizep;
6261 {
6262 void *ret;
6263
6264 if (nfds == 0 || totfds == 0)
6265 {
6266 if (sizep)
6267 *sizep = 0;
6268 return (void *)NULL;
6269 }
6270
6271 if (sizep)
6272 *sizep = totfds;
6273 ret = xmalloc (totfds * sizeof (pid_t));
6274 return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t)));
6275 }
6276
6277 static void
6278 add_fifo_list (fd)
6279 int fd;
6280 {
6281 if (dev_fd_list == 0 || fd >= totfds)
6282 {
6283 int ofds;
6284
6285 ofds = totfds;
6286 totfds = getdtablesize ();
6287 if (totfds < 0 || totfds > 256)
6288 totfds = 256;
6289 if (fd >= totfds)
6290 totfds = fd + 2;
6291
6292 dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0]));
6293 /* XXX - might need a loop for this */
6294 memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t));
6295 }
6296
6297 dev_fd_list[fd] = 1; /* marker; updated later */
6298 nfds++;
6299 }
6300
6301 int
6302 fifos_pending ()
6303 {
6304 return 0; /* used for cleanup; not needed with /dev/fd */
6305 }
6306
6307 int
6308 num_fifos ()
6309 {
6310 return nfds;
6311 }
6312
6313 void
6314 unlink_fifo (fd)
6315 int fd;
6316 {
6317 if (dev_fd_list[fd])
6318 {
6319 close (fd);
6320 dev_fd_list[fd] = 0;
6321 nfds--;
6322 }
6323 }
6324
6325 void
6326 unlink_fifo_list ()
6327 {
6328 register int i;
6329
6330 if (nfds == 0)
6331 return;
6332
6333 for (i = totfds-1; nfds && i >= 0; i--)
6334 unlink_fifo (i);
6335
6336 nfds = 0;
6337 }
6338
6339 void
6340 unlink_all_fifos ()
6341 {
6342 unlink_fifo_list ();
6343 }
6344
6345 /* Take LIST, which is a snapshot copy of dev_fd_list from some point in
6346 the past, and close all open fds in dev_fd_list that are not marked
6347 as open in LIST. If LIST is NULL, close everything in dev_fd_list.
6348 LSIZE is the number of elements in LIST, in case it's larger than
6349 totfds (size of dev_fd_list). */
6350 void
6351 close_new_fifos (list, lsize)
6352 void *list;
6353 int lsize;
6354 {
6355 int i;
6356 pid_t *plist;
6357
6358 if (list == 0)
6359 {
6360 unlink_fifo_list ();
6361 return;
6362 }
6363
6364 for (plist = (pid_t *)list, i = 0; i < lsize; i++)
6365 if (plist[i] == 0 && i < totfds && dev_fd_list[i])
6366 unlink_fifo (i);
6367
6368 for (i = lsize; i < totfds; i++)
6369 unlink_fifo (i);
6370 }
6371
6372 int
6373 find_procsub_child (pid)
6374 pid_t pid;
6375 {
6376 int i;
6377
6378 if (nfds == 0)
6379 return -1;
6380
6381 for (i = 0; i < totfds; i++)
6382 if (dev_fd_list[i] == pid)
6383 return i;
6384
6385 return -1;
6386 }
6387
6388 void
6389 set_procsub_status (ind, pid, status)
6390 int ind;
6391 pid_t pid;
6392 int status;
6393 {
6394 if (ind >= 0 && ind < totfds)
6395 dev_fd_list[ind] = (pid_t)-1; /* sentinel */
6396 }
6397
6398 /* If we've marked the process for this procsub as dead, close the
6399 associated file descriptor. */
6400 static void
6401 reap_some_procsubs (max)
6402 int max;
6403 {
6404 int i;
6405
6406 for (i = 0; nfds > 0 && i < max; i++)
6407 if (dev_fd_list[i] == (pid_t)-1)
6408 unlink_fifo (i);
6409 }
6410
6411 void
6412 reap_procsubs ()
6413 {
6414 reap_some_procsubs (totfds);
6415 }
6416
6417 #if 0
6418 /* UNUSED */
6419 void
6420 wait_procsubs ()
6421 {
6422 int i, r;
6423
6424 for (i = 0; nfds > 0 && i < totfds; i++)
6425 {
6426 if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0)
6427 {
6428 r = wait_for (dev_fd_list[i], 0);
6429 save_proc_status (dev_fd_list[i], r);
6430 dev_fd_list[i] = (pid_t)-1;
6431 }
6432 }
6433 }
6434 #endif
6435
6436 #if defined (NOTDEF)
6437 print_dev_fd_list ()
6438 {
6439 register int i;
6440
6441 fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
6442 fflush (stderr);
6443
6444 for (i = 0; i < totfds; i++)
6445 {
6446 if (dev_fd_list[i])
6447 fprintf (stderr, " %d", i);
6448 }
6449 fprintf (stderr, "\n");
6450 }
6451 #endif /* NOTDEF */
6452
6453 static char *
6454 make_dev_fd_filename (fd)
6455 int fd;
6456 {
6457 char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
6458
6459 ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
6460
6461 strcpy (ret, DEV_FD_PREFIX);
6462 p = inttostr (fd, intbuf, sizeof (intbuf));
6463 strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
6464
6465 add_fifo_list (fd);
6466 return (ret);
6467 }
6468
6469 #endif /* HAVE_DEV_FD */
6470
6471 /* Return a filename that will open a connection to the process defined by
6472 executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
6473 a filename in /dev/fd corresponding to a descriptor that is one of the
6474 ends of the pipe. If not defined, we use named pipes on systems that have
6475 them. Systems without /dev/fd and named pipes are out of luck.
6476
6477 OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
6478 use the read end of the pipe and dup that file descriptor to fd 0 in
6479 the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
6480 writing or use the write end of the pipe in the child, and dup that
6481 file descriptor to fd 1 in the child. The parent does the opposite. */
6482
6483 static char *
6484 process_substitute (string, open_for_read_in_child)
6485 char *string;
6486 int open_for_read_in_child;
6487 {
6488 char *pathname;
6489 int fd, result, rc, function_value;
6490 pid_t old_pid, pid;
6491 #if defined (HAVE_DEV_FD)
6492 int parent_pipe_fd, child_pipe_fd;
6493 int fildes[2];
6494 #endif /* HAVE_DEV_FD */
6495 #if defined (JOB_CONTROL)
6496 pid_t old_pipeline_pgrp;
6497 #endif
6498
6499 if (!string || !*string || wordexp_only)
6500 return ((char *)NULL);
6501
6502 #if !defined (HAVE_DEV_FD)
6503 pathname = make_named_pipe ();
6504 #else /* HAVE_DEV_FD */
6505 if (pipe (fildes) < 0)
6506 {
6507 sys_error ("%s", _("cannot make pipe for process substitution"));
6508 return ((char *)NULL);
6509 }
6510 /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
6511 the pipe in the parent, otherwise the read end. */
6512 parent_pipe_fd = fildes[open_for_read_in_child];
6513 child_pipe_fd = fildes[1 - open_for_read_in_child];
6514 /* Move the parent end of the pipe to some high file descriptor, to
6515 avoid clashes with FDs used by the script. */
6516 parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
6517
6518 pathname = make_dev_fd_filename (parent_pipe_fd);
6519 #endif /* HAVE_DEV_FD */
6520
6521 if (pathname == 0)
6522 {
6523 sys_error ("%s", _("cannot make pipe for process substitution"));
6524 return ((char *)NULL);
6525 }
6526
6527 old_pid = last_made_pid;
6528
6529 #if defined (JOB_CONTROL)
6530 old_pipeline_pgrp = pipeline_pgrp;
6531 if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0)
6532 pipeline_pgrp = shell_pgrp;
6533 save_pipeline (1);
6534 #endif /* JOB_CONTROL */
6535
6536 pid = make_child ((char *)NULL, FORK_ASYNC);
6537 if (pid == 0)
6538 {
6539 #if 0
6540 int old_interactive;
6541
6542 old_interactive = interactive;
6543 #endif
6544 /* The currently-executing shell is not interactive */
6545 interactive = 0;
6546
6547 reset_terminating_signals (); /* XXX */
6548 free_pushed_string_input ();
6549 /* Cancel traps, in trap.c. */
6550 restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */
6551 subshell_environment &= ~SUBSHELL_IGNTRAP;
6552 QUIT; /* catch any interrupts we got post-fork */
6553 setup_async_signals ();
6554 #if 0
6555 if (open_for_read_in_child == 0 && old_interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))
6556 async_redirect_stdin ();
6557 #endif
6558
6559 subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB|SUBSHELL_ASYNC;
6560
6561 /* We don't inherit the verbose option for command substitutions now, so
6562 let's try it for process substitutions. */
6563 change_flag ('v', FLAG_OFF);
6564
6565 /* if we're expanding a redirection, we shouldn't have access to the
6566 temporary environment, but commands in the subshell should have
6567 access to their own temporary environment. */
6568 if (expanding_redir)
6569 flush_temporary_env ();
6570 }
6571
6572 #if defined (JOB_CONTROL)
6573 set_sigchld_handler ();
6574 stop_making_children ();
6575 /* XXX - should we only do this in the parent? (as in command subst) */
6576 pipeline_pgrp = old_pipeline_pgrp;
6577 #else
6578 stop_making_children ();
6579 #endif /* JOB_CONTROL */
6580
6581 if (pid < 0)
6582 {
6583 sys_error ("%s", _("cannot make child for process substitution"));
6584 free (pathname);
6585 #if defined (HAVE_DEV_FD)
6586 close (parent_pipe_fd);
6587 close (child_pipe_fd);
6588 #endif /* HAVE_DEV_FD */
6589 #if defined (JOB_CONTROL)
6590 restore_pipeline (1);
6591 #endif
6592 return ((char *)NULL);
6593 }
6594
6595 if (pid > 0)
6596 {
6597 #if defined (JOB_CONTROL)
6598 last_procsub_child = restore_pipeline (0);
6599 /* We assume that last_procsub_child->next == last_procsub_child because
6600 of how jobs.c:add_process() works. */
6601 last_procsub_child->next = 0;
6602 procsub_add (last_procsub_child);
6603 #endif
6604
6605 #if defined (HAVE_DEV_FD)
6606 dev_fd_list[parent_pipe_fd] = pid;
6607 #else
6608 fifo_list[nfifo-1].proc = pid;
6609 #endif
6610
6611 last_made_pid = old_pid;
6612
6613 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
6614 close_pgrp_pipe ();
6615 #endif /* JOB_CONTROL && PGRP_PIPE */
6616
6617 #if defined (HAVE_DEV_FD)
6618 close (child_pipe_fd);
6619 #endif /* HAVE_DEV_FD */
6620
6621 return (pathname);
6622 }
6623
6624 set_sigint_handler ();
6625
6626 #if defined (JOB_CONTROL)
6627 /* make sure we don't have any job control */
6628 set_job_control (0);
6629
6630 /* Clear out any existing list of process substitutions */
6631 procsub_clear ();
6632
6633 /* The idea is that we want all the jobs we start from an async process
6634 substitution to be in the same process group, but not the same pgrp
6635 as our parent shell, since we don't want to affect our parent shell's
6636 jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example.
6637 If pipeline_pgrp != shell_pgrp, we assume that there is a job control
6638 shell somewhere in our parent process chain (since make_child initializes
6639 pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this
6640 case is to set pipeline_pgrp to our PID, so all jobs started by this
6641 process have that same pgrp and we are basically the process group leader.
6642 This should not have negative effects on child processes surviving
6643 after we exit, since we wait for the children we create, but that is
6644 something to watch for. */
6645
6646 if (pipeline_pgrp != shell_pgrp)
6647 pipeline_pgrp = getpid ();
6648 #endif /* JOB_CONTROL */
6649
6650 #if !defined (HAVE_DEV_FD)
6651 /* Open the named pipe in the child. */
6652 fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY);
6653 if (fd < 0)
6654 {
6655 /* Two separate strings for ease of translation. */
6656 if (open_for_read_in_child)
6657 sys_error (_("cannot open named pipe %s for reading"), pathname);
6658 else
6659 sys_error (_("cannot open named pipe %s for writing"), pathname);
6660
6661 exit (127);
6662 }
6663 if (open_for_read_in_child)
6664 {
6665 if (sh_unset_nodelay_mode (fd) < 0)
6666 {
6667 sys_error (_("cannot reset nodelay mode for fd %d"), fd);
6668 exit (127);
6669 }
6670 }
6671 #else /* HAVE_DEV_FD */
6672 fd = child_pipe_fd;
6673 #endif /* HAVE_DEV_FD */
6674
6675 /* Discard buffered stdio output before replacing the underlying file
6676 descriptor. */
6677 if (open_for_read_in_child == 0)
6678 fpurge (stdout);
6679
6680 if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
6681 {
6682 sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
6683 open_for_read_in_child ? 0 : 1);
6684 exit (127);
6685 }
6686
6687 if (fd != (open_for_read_in_child ? 0 : 1))
6688 close (fd);
6689
6690 /* Need to close any files that this process has open to pipes inherited
6691 from its parent. */
6692 if (current_fds_to_close)
6693 {
6694 close_fd_bitmap (current_fds_to_close);
6695 current_fds_to_close = (struct fd_bitmap *)NULL;
6696 }
6697
6698 #if defined (HAVE_DEV_FD)
6699 /* Make sure we close the parent's end of the pipe and clear the slot
6700 in the fd list so it is not closed later, if reallocated by, for
6701 instance, pipe(2). */
6702 close (parent_pipe_fd);
6703 dev_fd_list[parent_pipe_fd] = 0;
6704 #endif /* HAVE_DEV_FD */
6705
6706 /* subshells shouldn't have this flag, which controls using the temporary
6707 environment for variable lookups. We have already flushed the temporary
6708 environment above in the case we're expanding a redirection, so processes
6709 executed by this command need to be able to set it independently of their
6710 parent. */
6711 expanding_redir = 0;
6712
6713 remove_quoted_escapes (string);
6714
6715 startup_state = 2; /* see if we can avoid a fork */
6716 parse_and_execute_level = 0;
6717
6718 /* Give process substitution a place to jump back to on failure,
6719 so we don't go back up to main (). */
6720 result = setjmp_nosigs (top_level);
6721
6722 /* If we're running a process substitution inside a shell function,
6723 trap `return' so we don't return from the function in the subshell
6724 and go off to never-never land. */
6725 if (result == 0 && return_catch_flag)
6726 function_value = setjmp_nosigs (return_catch);
6727 else
6728 function_value = 0;
6729
6730 if (result == ERREXIT)
6731 rc = last_command_exit_value;
6732 else if (result == EXITPROG || result == EXITBLTIN)
6733 rc = last_command_exit_value;
6734 else if (result)
6735 rc = EXECUTION_FAILURE;
6736 else if (function_value)
6737 rc = return_catch_value;
6738 else
6739 {
6740 subshell_level++;
6741 rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
6742 /* leave subshell level intact for any exit trap */
6743 }
6744
6745 #if !defined (HAVE_DEV_FD)
6746 /* Make sure we close the named pipe in the child before we exit. */
6747 close (open_for_read_in_child ? 0 : 1);
6748 #endif /* !HAVE_DEV_FD */
6749
6750 last_command_exit_value = rc;
6751 rc = run_exit_trap ();
6752 exit (rc);
6753 /*NOTREACHED*/
6754 }
6755 #endif /* PROCESS_SUBSTITUTION */
6756
6757 /***********************************/
6758 /* */
6759 /* Command Substitution */
6760 /* */
6761 /***********************************/
6762
6763 #define COMSUB_PIPEBUF 4096
6764
6765 static char *
6766 optimize_cat_file (r, quoted, flags, flagp)
6767 REDIRECT *r;
6768 int quoted, flags, *flagp;
6769 {
6770 char *ret;
6771 int fd;
6772
6773 fd = open_redir_file (r, (char **)0);
6774 if (fd < 0)
6775 return &expand_param_error;
6776
6777 ret = read_comsub (fd, quoted, flags, flagp);
6778 close (fd);
6779
6780 return ret;
6781 }
6782
6783 static char *
6784 read_comsub (fd, quoted, flags, rflag)
6785 int fd, quoted, flags;
6786 int *rflag;
6787 {
6788 char *istring, buf[COMSUB_PIPEBUF], *bufp;
6789 int c, tflag, skip_ctlesc, skip_ctlnul;
6790 int mb_cur_max;
6791 size_t istring_index;
6792 size_t istring_size;
6793 ssize_t bufn;
6794 int nullbyte;
6795 #if defined (HANDLE_MULTIBYTE)
6796 mbstate_t ps;
6797 wchar_t wc;
6798 size_t mblen;
6799 int i;
6800 #endif
6801
6802 istring = (char *)NULL;
6803 istring_index = istring_size = bufn = tflag = 0;
6804
6805 skip_ctlesc = ifs_cmap[CTLESC];
6806 skip_ctlnul = ifs_cmap[CTLNUL];
6807
6808 mb_cur_max = MB_CUR_MAX;
6809 nullbyte = 0;
6810
6811 /* Read the output of the command through the pipe. */
6812 while (1)
6813 {
6814 if (fd < 0)
6815 break;
6816 if (--bufn <= 0)
6817 {
6818 bufn = zread (fd, buf, sizeof (buf));
6819 if (bufn <= 0)
6820 break;
6821 bufp = buf;
6822 }
6823 c = *bufp++;
6824
6825 if (c == 0)
6826 {
6827 #if 1
6828 if (nullbyte == 0)
6829 {
6830 internal_warning ("%s", _("command substitution: ignored null byte in input"));
6831 nullbyte = 1;
6832 }
6833 #endif
6834 continue;
6835 }
6836
6837 /* Add the character to ISTRING, possibly after resizing it. */
6838 RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512);
6839
6840 /* This is essentially quote_string inline */
6841 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
6842 istring[istring_index++] = CTLESC;
6843 else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC)
6844 istring[istring_index++] = CTLESC;
6845 /* Escape CTLESC and CTLNUL in the output to protect those characters
6846 from the rest of the word expansions (word splitting and globbing.)
6847 This is essentially quote_escapes inline. */
6848 else if (skip_ctlesc == 0 && c == CTLESC)
6849 istring[istring_index++] = CTLESC;
6850 else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
6851 istring[istring_index++] = CTLESC;
6852
6853 #if defined (HANDLE_MULTIBYTE)
6854 if ((locale_utf8locale && (c & 0x80)) ||
6855 (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127))
6856 {
6857 /* read a multibyte character from buf */
6858 /* punt on the hard case for now */
6859 memset (&ps, '\0', sizeof (mbstate_t));
6860 mblen = mbrtowc (&wc, bufp-1, bufn, &ps);
6861 if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1)
6862 istring[istring_index++] = c;
6863 else
6864 {
6865 istring[istring_index++] = c;
6866 for (i = 0; i < mblen-1; i++)
6867 istring[istring_index++] = *bufp++;
6868 bufn -= mblen - 1;
6869 }
6870 continue;
6871 }
6872 #endif
6873
6874 istring[istring_index++] = c;
6875 }
6876
6877 if (istring)
6878 istring[istring_index] = '\0';
6879
6880 /* If we read no output, just return now and save ourselves some
6881 trouble. */
6882 if (istring_index == 0)
6883 {
6884 FREE (istring);
6885 if (rflag)
6886 *rflag = tflag;
6887 return (char *)NULL;
6888 }
6889
6890 /* Strip trailing newlines from the output of the command. */
6891 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6892 {
6893 while (istring_index > 0)
6894 {
6895 if (istring[istring_index - 1] == '\n')
6896 {
6897 --istring_index;
6898
6899 /* If the newline was quoted, remove the quoting char. */
6900 if (istring[istring_index - 1] == CTLESC)
6901 --istring_index;
6902 }
6903 else
6904 break;
6905 }
6906 istring[istring_index] = '\0';
6907 }
6908 else
6909 strip_trailing (istring, istring_index - 1, 1);
6910
6911 if (rflag)
6912 *rflag = tflag;
6913 return istring;
6914 }
6915
6916 /* Perform command substitution on STRING. This returns a WORD_DESC * with the
6917 contained string possibly quoted. */
6918 WORD_DESC *
6919 command_substitute (string, quoted, flags)
6920 char *string;
6921 int quoted;
6922 int flags;
6923 {
6924 pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
6925 char *istring, *s;
6926 int result, fildes[2], function_value, pflags, rc, tflag, fork_flags;
6927 WORD_DESC *ret;
6928 sigset_t set, oset;
6929
6930 istring = (char *)NULL;
6931
6932 /* Don't fork () if there is no need to. In the case of no command to
6933 run, just return NULL. */
6934 for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++)
6935 ;
6936 if (s == 0 || *s == 0)
6937 return ((WORD_DESC *)NULL);
6938
6939 if (*s == '<' && (s[1] != '<' && s[1] != '>' && s[1] != '&'))
6940 {
6941 COMMAND *cmd;
6942
6943 cmd = parse_string_to_command (string, 0); /* XXX - flags */
6944 if (cmd && can_optimize_cat_file (cmd))
6945 {
6946 tflag = 0;
6947 istring = optimize_cat_file (cmd->value.Simple->redirects, quoted, flags, &tflag);
6948 if (istring == &expand_param_error)
6949 {
6950 last_command_exit_value = EXECUTION_FAILURE;
6951 istring = 0;
6952 }
6953 else
6954 last_command_exit_value = EXECUTION_SUCCESS; /* compat */
6955 last_command_subst_pid = dollar_dollar_pid;
6956
6957 dispose_command (cmd);
6958 ret = alloc_word_desc ();
6959 ret->word = istring;
6960 ret->flags = tflag;
6961
6962 return ret;
6963 }
6964 dispose_command (cmd);
6965 }
6966
6967 if (wordexp_only && read_but_dont_execute)
6968 {
6969 last_command_exit_value = EX_WEXPCOMSUB;
6970 jump_to_top_level (EXITPROG);
6971 }
6972
6973 /* We're making the assumption here that the command substitution will
6974 eventually run a command from the file system. Since we'll run
6975 maybe_make_export_env in this subshell before executing that command,
6976 the parent shell and any other shells it starts will have to remake
6977 the environment. If we make it before we fork, other shells won't
6978 have to. Don't bother if we have any temporary variable assignments,
6979 though, because the export environment will be remade after this
6980 command completes anyway, but do it if all the words to be expanded
6981 are variable assignments. */
6982 if (subst_assign_varlist == 0 || garglist == 0)
6983 maybe_make_export_env (); /* XXX */
6984
6985 /* Flags to pass to parse_and_execute() */
6986 pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
6987
6988 old_pid = last_made_pid;
6989
6990 /* Pipe the output of executing STRING into the current shell. */
6991 if (pipe (fildes) < 0)
6992 {
6993 sys_error ("%s", _("cannot make pipe for command substitution"));
6994 goto error_exit;
6995 }
6996
6997 #if defined (JOB_CONTROL)
6998 old_pipeline_pgrp = pipeline_pgrp;
6999 /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline or
7000 we've already forked to run a disk command (and are expanding redirections,
7001 for example). */
7002 if ((subshell_environment & (SUBSHELL_FORK|SUBSHELL_PIPE)) == 0)
7003 pipeline_pgrp = shell_pgrp;
7004 cleanup_the_pipeline ();
7005 #endif /* JOB_CONTROL */
7006
7007 old_async_pid = last_asynchronous_pid;
7008 fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0;
7009 pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM);
7010 last_asynchronous_pid = old_async_pid;
7011
7012 if (pid == 0)
7013 {
7014 /* Reset the signal handlers in the child, but don't free the
7015 trap strings. Set a flag noting that we have to free the
7016 trap strings if we run trap to change a signal disposition. */
7017 reset_signal_handlers ();
7018 if (ISINTERRUPT)
7019 {
7020 kill (getpid (), SIGINT);
7021 CLRINTERRUPT; /* if we're ignoring SIGINT somehow */
7022 }
7023 QUIT; /* catch any interrupts we got post-fork */
7024 subshell_environment |= SUBSHELL_RESETTRAP;
7025 subshell_environment &= ~SUBSHELL_IGNTRAP;
7026 }
7027
7028 #if defined (JOB_CONTROL)
7029 /* XXX DO THIS ONLY IN PARENT ? XXX */
7030 set_sigchld_handler ();
7031 stop_making_children ();
7032 if (pid != 0)
7033 pipeline_pgrp = old_pipeline_pgrp;
7034 #else
7035 stop_making_children ();
7036 #endif /* JOB_CONTROL */
7037
7038 if (pid < 0)
7039 {
7040 sys_error (_("cannot make child for command substitution"));
7041 error_exit:
7042
7043 last_made_pid = old_pid;
7044
7045 FREE (istring);
7046 close (fildes[0]);
7047 close (fildes[1]);
7048 return ((WORD_DESC *)NULL);
7049 }
7050
7051 if (pid == 0)
7052 {
7053 /* The currently executing shell is not interactive. */
7054 interactive = 0;
7055
7056 #if defined (JOB_CONTROL)
7057 /* Invariant: in child processes started to run command substitutions,
7058 pipeline_pgrp == shell_pgrp. Other parts of the shell assume this. */
7059 if (pipeline_pgrp > 0 && pipeline_pgrp != shell_pgrp)
7060 shell_pgrp = pipeline_pgrp;
7061 #endif
7062
7063 set_sigint_handler (); /* XXX */
7064
7065 free_pushed_string_input ();
7066
7067 /* Discard buffered stdio output before replacing the underlying file
7068 descriptor. */
7069 fpurge (stdout);
7070
7071 if (dup2 (fildes[1], 1) < 0)
7072 {
7073 sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1"));
7074 exit (EXECUTION_FAILURE);
7075 }
7076
7077 /* If standard output is closed in the parent shell
7078 (such as after `exec >&-'), file descriptor 1 will be
7079 the lowest available file descriptor, and end up in
7080 fildes[0]. This can happen for stdin and stderr as well,
7081 but stdout is more important -- it will cause no output
7082 to be generated from this command. */
7083 if ((fildes[1] != fileno (stdin)) &&
7084 (fildes[1] != fileno (stdout)) &&
7085 (fildes[1] != fileno (stderr)))
7086 close (fildes[1]);
7087
7088 if ((fildes[0] != fileno (stdin)) &&
7089 (fildes[0] != fileno (stdout)) &&
7090 (fildes[0] != fileno (stderr)))
7091 close (fildes[0]);
7092
7093 #ifdef __CYGWIN__
7094 /* Let stdio know the fd may have changed from text to binary mode, and
7095 make sure to preserve stdout line buffering. */
7096 freopen (NULL, "w", stdout);
7097 sh_setlinebuf (stdout);
7098 #endif /* __CYGWIN__ */
7099
7100 /* This is a subshell environment. */
7101 subshell_environment |= SUBSHELL_COMSUB;
7102
7103 /* Many shells do not appear to inherit the -v option for command
7104 substitutions. */
7105 change_flag ('v', FLAG_OFF);
7106
7107 /* When inherit_errexit option is not enabled, command substitution does
7108 not inherit the -e flag. It is enabled when Posix mode is enabled */
7109 if (inherit_errexit == 0)
7110 {
7111 builtin_ignoring_errexit = 0;
7112 change_flag ('e', FLAG_OFF);
7113 }
7114 set_shellopts ();
7115
7116 /* If we are expanding a redirection, we can dispose of any temporary
7117 environment we received, since redirections are not supposed to have
7118 access to the temporary environment. We will have to see whether this
7119 affects temporary environments supplied to `eval', but the temporary
7120 environment gets copied to builtin_env at some point. */
7121 if (expanding_redir)
7122 {
7123 flush_temporary_env ();
7124 expanding_redir = 0;
7125 }
7126
7127 remove_quoted_escapes (string);
7128
7129 /* We want to expand aliases on this pass if we are not in posix mode
7130 for backwards compatibility. parse_and_execute() takes care of
7131 setting expand_aliases back to the global value when executing the
7132 parsed string. We only do this for $(...) command substitution,
7133 since that is what parse_comsub handles; `` comsubs are processed
7134 using parse.y:parse_matched_pair(). */
7135 if (expand_aliases && (flags & PF_BACKQUOTE) == 0)
7136 expand_aliases = posixly_correct == 0;
7137
7138 startup_state = 2; /* see if we can avoid a fork */
7139 parse_and_execute_level = 0;
7140
7141 /* Give command substitution a place to jump back to on failure,
7142 so we don't go back up to main (). */
7143 result = setjmp_nosigs (top_level);
7144
7145 /* If we're running a command substitution inside a shell function,
7146 trap `return' so we don't return from the function in the subshell
7147 and go off to never-never land. */
7148 if (result == 0 && return_catch_flag)
7149 function_value = setjmp_nosigs (return_catch);
7150 else
7151 function_value = 0;
7152
7153 if (result == ERREXIT)
7154 rc = last_command_exit_value;
7155 else if (result == EXITPROG || result == EXITBLTIN)
7156 rc = last_command_exit_value;
7157 else if (result)
7158 rc = EXECUTION_FAILURE;
7159 else if (function_value)
7160 rc = return_catch_value;
7161 else
7162 {
7163 subshell_level++;
7164 rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
7165 /* leave subshell level intact for any exit trap */
7166 }
7167
7168 last_command_exit_value = rc;
7169 rc = run_exit_trap ();
7170 #if defined (PROCESS_SUBSTITUTION)
7171 unlink_fifo_list ();
7172 #endif
7173 exit (rc);
7174 }
7175 else
7176 {
7177 int dummyfd;
7178
7179 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
7180 close_pgrp_pipe ();
7181 #endif /* JOB_CONTROL && PGRP_PIPE */
7182
7183 close (fildes[1]);
7184
7185 begin_unwind_frame ("read-comsub");
7186 dummyfd = fildes[0];
7187 add_unwind_protect (close, dummyfd);
7188
7189 /* Block SIGINT while we're reading from the pipe. If the child
7190 process gets a SIGINT, it will either handle it or die, and the
7191 read will return. */
7192 BLOCK_SIGNAL (SIGINT, set, oset);
7193 tflag = 0;
7194 istring = read_comsub (fildes[0], quoted, flags, &tflag);
7195
7196 close (fildes[0]);
7197 discard_unwind_frame ("read-comsub");
7198 UNBLOCK_SIGNAL (oset);
7199
7200 current_command_subst_pid = pid;
7201 last_command_exit_value = wait_for (pid, JWAIT_NOTERM);
7202 last_command_subst_pid = pid;
7203 last_made_pid = old_pid;
7204
7205 #if defined (JOB_CONTROL)
7206 /* If last_command_exit_value > 128, then the substituted command
7207 was terminated by a signal. If that signal was SIGINT, then send
7208 SIGINT to ourselves. This will break out of loops, for instance. */
7209 if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
7210 kill (getpid (), SIGINT);
7211 #endif /* JOB_CONTROL */
7212
7213 ret = alloc_word_desc ();
7214 ret->word = istring;
7215 ret->flags = tflag;
7216
7217 return ret;
7218 }
7219 }
7220
7221 /********************************************************
7222 * *
7223 * Utility functions for parameter expansion *
7224 * *
7225 ********************************************************/
7226
7227 #if defined (ARRAY_VARS)
7228
7229 static arrayind_t
7230 array_length_reference (s)
7231 char *s;
7232 {
7233 int len;
7234 arrayind_t ind;
7235 char *akey;
7236 char *t, c;
7237 ARRAY *array;
7238 HASH_TABLE *h;
7239 SHELL_VAR *var;
7240
7241 var = array_variable_part (s, 0, &t, &len);
7242
7243 /* If unbound variables should generate an error, report one and return
7244 failure. */
7245 if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
7246 {
7247 c = *--t;
7248 *t = '\0';
7249 set_exit_status (EXECUTION_FAILURE);
7250 err_unboundvar (s);
7251 *t = c;
7252 return (-1);
7253 }
7254 else if (var == 0 || invisible_p (var))
7255 return 0;
7256
7257 /* We support a couple of expansions for variables that are not arrays.
7258 We'll return the length of the value for v[0], and 1 for v[@] or
7259 v[*]. Return 0 for everything else. */
7260
7261 array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
7262 h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
7263
7264 if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK)
7265 {
7266 if (assoc_p (var))
7267 return (h ? assoc_num_elements (h) : 0);
7268 else if (array_p (var))
7269 return (array ? array_num_elements (array) : 0);
7270 else
7271 return (var_isset (var) ? 1 : 0);
7272 }
7273
7274 if (assoc_p (var))
7275 {
7276 t[len - 1] = '\0';
7277 akey = expand_subscript_string (t, 0); /* [ */
7278 t[len - 1] = RBRACK;
7279 if (akey == 0 || *akey == 0)
7280 {
7281 err_badarraysub (t);
7282 FREE (akey);
7283 return (-1);
7284 }
7285 t = assoc_reference (assoc_cell (var), akey);
7286 free (akey);
7287 }
7288 else
7289 {
7290 ind = array_expand_index (var, t, len, 0);
7291 /* negative subscripts to indexed arrays count back from end */
7292 if (var && array_p (var) && ind < 0)
7293 ind = array_max_index (array_cell (var)) + 1 + ind;
7294 if (ind < 0)
7295 {
7296 err_badarraysub (t);
7297 return (-1);
7298 }
7299 if (array_p (var))
7300 t = array_reference (array, ind);
7301 else
7302 t = (ind == 0) ? value_cell (var) : (char *)NULL;
7303 }
7304
7305 len = MB_STRLEN (t);
7306 return (len);
7307 }
7308 #endif /* ARRAY_VARS */
7309
7310 static int
7311 valid_brace_expansion_word (name, var_is_special)
7312 char *name;
7313 int var_is_special;
7314 {
7315 if (DIGIT (*name) && all_digits (name))
7316 return 1;
7317 else if (var_is_special)
7318 return 1;
7319 #if defined (ARRAY_VARS)
7320 else if (valid_array_reference (name, 0))
7321 return 1;
7322 #endif /* ARRAY_VARS */
7323 else if (legal_identifier (name))
7324 return 1;
7325 else
7326 return 0;
7327 }
7328
7329 static int
7330 chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
7331 char *name;
7332 int quoted, pflags;
7333 int *quoted_dollar_atp, *contains_dollar_at;
7334 {
7335 char *temp1;
7336
7337 if (name == 0)
7338 {
7339 if (quoted_dollar_atp)
7340 *quoted_dollar_atp = 0;
7341 if (contains_dollar_at)
7342 *contains_dollar_at = 0;
7343 return 0;
7344 }
7345
7346 /* check for $@ and $* */
7347 if (name[0] == '@' && name[1] == 0)
7348 {
7349 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7350 *quoted_dollar_atp = 1;
7351 if (contains_dollar_at)
7352 *contains_dollar_at = 1;
7353 return 1;
7354 }
7355 else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
7356 {
7357 /* Need more checks here that parallel what string_list_pos_params and
7358 param_expand do. Check expand_no_split_dollar_star and ??? */
7359 if (contains_dollar_at && expand_no_split_dollar_star == 0)
7360 *contains_dollar_at = 1;
7361 return 1;
7362 }
7363
7364 /* Now check for ${array[@]} and ${array[*]} */
7365 #if defined (ARRAY_VARS)
7366 else if (valid_array_reference (name, 0))
7367 {
7368 temp1 = mbschr (name, LBRACK);
7369 if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK)
7370 {
7371 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7372 *quoted_dollar_atp = 1;
7373 if (contains_dollar_at)
7374 *contains_dollar_at = 1;
7375 return 1;
7376 }
7377 /* ${array[*]}, when unquoted, should be treated like ${array[@]},
7378 which should result in separate words even when IFS is unset. */
7379 if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0)
7380 {
7381 if (contains_dollar_at)
7382 *contains_dollar_at = 1;
7383 return 1;
7384 }
7385 }
7386 #endif
7387 return 0;
7388 }
7389
7390 /* Parameter expand NAME, and return a new string which is the expansion,
7391 or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}.
7392 VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
7393 the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
7394 NAME was found inside of a double-quoted expression. */
7395 static WORD_DESC *
7396 parameter_brace_expand_word (name, var_is_special, quoted, pflags, estatep)
7397 char *name;
7398 int var_is_special, quoted, pflags;
7399 array_eltstate_t *estatep;
7400 {
7401 WORD_DESC *ret;
7402 char *temp, *tt;
7403 intmax_t arg_index;
7404 SHELL_VAR *var;
7405 int rflags;
7406 array_eltstate_t es;
7407
7408 ret = 0;
7409 temp = 0;
7410 rflags = 0;
7411
7412 #if defined (ARRAY_VARS)
7413 if (estatep)
7414 es = *estatep; /* structure copy */
7415 else
7416 {
7417 init_eltstate (&es);
7418 es.ind = INTMAX_MIN;
7419 }
7420 #endif
7421
7422 /* Handle multiple digit arguments, as in ${11}. */
7423 if (legal_number (name, &arg_index))
7424 {
7425 tt = get_dollar_var_value (arg_index);
7426 if (tt)
7427 temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7428 ? quote_string (tt)
7429 : quote_escapes (tt);
7430 else
7431 temp = (char *)NULL;
7432 FREE (tt);
7433 }
7434 else if (var_is_special) /* ${@} */
7435 {
7436 int sindex;
7437 tt = (char *)xmalloc (2 + strlen (name));
7438 tt[sindex = 0] = '$';
7439 strcpy (tt + 1, name);
7440
7441 ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
7442 (int *)NULL, (int *)NULL, pflags);
7443
7444 /* Make sure we note that we saw a quoted null string and pass the flag back
7445 to the caller in addition to the value. */
7446 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && STR_DOLLAR_AT_STAR (name) &&
7447 ret && ret->word && QUOTED_NULL (ret->word))
7448 ret->flags |= W_HASQUOTEDNULL;
7449
7450 free (tt);
7451 }
7452 #if defined (ARRAY_VARS)
7453 else if (valid_array_reference (name, 0))
7454 {
7455 expand_arrayref:
7456 var = array_variable_part (name, 0, &tt, (int *)0);
7457 /* These are the cases where word splitting will not be performed */
7458 if (pflags & PF_ASSIGNRHS)
7459 {
7460 if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK)
7461 {
7462 /* Only treat as double quoted if array variable */
7463 if (var && (array_p (var) || assoc_p (var)))
7464 temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &es);
7465 else
7466 temp = array_value (name, quoted, 0, &es);
7467 }
7468 else
7469 temp = array_value (name, quoted, 0, &es);
7470 }
7471 /* Posix interp 888 */
7472 else if (pflags & PF_NOSPLIT2)
7473 {
7474 /* Special cases, then general case, for each of A[@], A[*], A[n] */
7475 #if defined (HANDLE_MULTIBYTE)
7476 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
7477 #else
7478 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
7479 #endif
7480 temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &es);
7481 else if (tt[0] == '@' && tt[1] == RBRACK)
7482 temp = array_value (name, quoted, 0, &es);
7483 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
7484 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &es);
7485 else if (tt[0] == '*' && tt[1] == RBRACK)
7486 temp = array_value (name, quoted, 0, &es);
7487 else
7488 temp = array_value (name, quoted, 0, &es);
7489 }
7490 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
7491 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &es);
7492 else
7493 temp = array_value (name, quoted, 0, &es);
7494 if (es.subtype == 0 && temp)
7495 {
7496 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7497 ? quote_string (temp)
7498 : quote_escapes (temp);
7499 rflags |= W_ARRAYIND;
7500 }
7501 /* Note that array[*] and array[@] expanded to a quoted null string by
7502 returning the W_HASQUOTEDNULL flag to the caller in addition to TEMP. */
7503 else if (es.subtype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7504 rflags |= W_HASQUOTEDNULL;
7505 else if (es.subtype == 2 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7506 rflags |= W_HASQUOTEDNULL;
7507
7508 if (estatep)
7509 *estatep = es; /* structure copy */
7510 else
7511 flush_eltstate (&es);
7512 }
7513 #endif
7514 else if (var = find_variable (name))
7515 {
7516 if (var_isset (var) && invisible_p (var) == 0)
7517 {
7518 #if defined (ARRAY_VARS)
7519 /* We avoid a memory leak by saving TT as the memory allocated by
7520 assoc_to_string or array_to_string and leaving it 0 otherwise,
7521 then freeing TT after quoting temp. */
7522 tt = (char *)NULL;
7523 if ((pflags & PF_ALLINDS) && assoc_p (var))
7524 tt = temp = assoc_empty (assoc_cell (var)) ? (char *)NULL : assoc_to_string (assoc_cell (var), " ", quoted);
7525 else if ((pflags & PF_ALLINDS) && array_p (var))
7526 tt = temp = array_empty (array_cell (var)) ? (char *)NULL : array_to_string (array_cell (var), " ", quoted);
7527 else if (assoc_p (var))
7528 temp = assoc_reference (assoc_cell (var), "0");
7529 else if (array_p (var))
7530 temp = array_reference (array_cell (var), 0);
7531 else
7532 temp = value_cell (var);
7533 #else
7534 temp = value_cell (var);
7535 #endif
7536
7537 if (temp)
7538 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7539 ? quote_string (temp)
7540 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
7541 : quote_escapes (temp));
7542 FREE (tt);
7543 }
7544 else
7545 temp = (char *)NULL;
7546 }
7547 else if (var = find_variable_last_nameref (name, 0))
7548 {
7549 temp = nameref_cell (var);
7550 #if defined (ARRAY_VARS)
7551 /* Handle expanding nameref whose value is x[n] */
7552 if (temp && *temp && valid_array_reference (temp, 0))
7553 {
7554 name = temp;
7555 goto expand_arrayref;
7556 }
7557 else
7558 #endif
7559 /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */
7560 if (temp && *temp && legal_identifier (temp) == 0)
7561 {
7562 set_exit_status (EXECUTION_FAILURE);
7563 report_error (_("%s: invalid variable name for name reference"), temp);
7564 temp = &expand_param_error;
7565 }
7566 else
7567 temp = (char *)NULL;
7568 }
7569 else
7570 temp = (char *)NULL;
7571
7572 if (ret == 0)
7573 {
7574 ret = alloc_word_desc ();
7575 ret->word = temp;
7576 ret->flags |= rflags;
7577 }
7578 return ret;
7579 }
7580
7581 static char *
7582 parameter_brace_find_indir (name, var_is_special, quoted, find_nameref)
7583 char *name;
7584 int var_is_special, quoted, find_nameref;
7585 {
7586 char *temp, *t;
7587 WORD_DESC *w;
7588 SHELL_VAR *v;
7589 int pflags, oldex;
7590
7591 if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) &&
7592 nameref_p (v) && (t = nameref_cell (v)) && *t)
7593 return (savestring (t));
7594
7595 /* If var_is_special == 0, and name is not an array reference, this does
7596 more expansion than necessary. It should really look up the variable's
7597 value and not try to expand it. */
7598 pflags = PF_IGNUNBOUND;
7599 /* Note that we're not going to be doing word splitting here */
7600 if (var_is_special)
7601 {
7602 pflags |= PF_ASSIGNRHS; /* suppresses word splitting */
7603 oldex = expand_no_split_dollar_star;
7604 expand_no_split_dollar_star = 1;
7605 }
7606 w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0);
7607 if (var_is_special)
7608 expand_no_split_dollar_star = oldex;
7609
7610 t = w->word;
7611 /* Have to dequote here if necessary */
7612 if (t)
7613 {
7614 temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special)
7615 ? dequote_string (t)
7616 : dequote_escapes (t);
7617 free (t);
7618 t = temp;
7619 }
7620 dispose_word_desc (w);
7621
7622 return t;
7623 }
7624
7625 /* Expand an indirect reference to a variable: ${!NAME} expands to the
7626 value of the variable whose name is the value of NAME. */
7627 static WORD_DESC *
7628 parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
7629 char *name;
7630 int var_is_special, quoted, pflags;
7631 int *quoted_dollar_atp, *contains_dollar_at;
7632 {
7633 char *t;
7634 WORD_DESC *w;
7635 SHELL_VAR *v;
7636
7637 /* See if it's a nameref first, behave in ksh93-compatible fashion.
7638 There is at least one incompatibility: given ${!foo[0]} where foo=bar,
7639 bash performs an indirect lookup on foo[0] and expands the result;
7640 ksh93 expands bar[0]. We could do that here -- there are enough usable
7641 primitives to do that -- but do not at this point. */
7642 if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0)))
7643 {
7644 if (nameref_p (v) && (t = nameref_cell (v)) && *t)
7645 {
7646 w = alloc_word_desc ();
7647 w->word = savestring (t);
7648 w->flags = 0;
7649 return w;
7650 }
7651 }
7652
7653 /* An indirect reference to a positional parameter or a special parameter
7654 is ok. Indirect references to array references, as explained above, are
7655 ok (currently). Only references to unset variables are errors at this
7656 point. */
7657 if (legal_identifier (name) && v == 0)
7658 {
7659 report_error (_("%s: invalid indirect expansion"), name);
7660 w = alloc_word_desc ();
7661 w->word = &expand_param_error;
7662 w->flags = 0;
7663 return (w);
7664 }
7665
7666 t = parameter_brace_find_indir (name, var_is_special, quoted, 0);
7667
7668 chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at);
7669
7670 #if defined (ARRAY_VARS)
7671 /* Array references to unset variables are also an error */
7672 if (t == 0 && valid_array_reference (name, 0))
7673 {
7674 v = array_variable_part (name, 0, (char **)0, (int *)0);
7675 if (v == 0)
7676 {
7677 report_error (_("%s: invalid indirect expansion"), name);
7678 w = alloc_word_desc ();
7679 w->word = &expand_param_error;
7680 w->flags = 0;
7681 return (w);
7682 }
7683 else
7684 return (WORD_DESC *)NULL;
7685 }
7686 #endif
7687
7688 if (t == 0)
7689 return (WORD_DESC *)NULL;
7690
7691 if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0)
7692 {
7693 report_error (_("%s: invalid variable name"), t);
7694 free (t);
7695 w = alloc_word_desc ();
7696 w->word = &expand_param_error;
7697 w->flags = 0;
7698 return (w);
7699 }
7700
7701 w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0);
7702 free (t);
7703
7704 return w;
7705 }
7706
7707 /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
7708 depending on the value of C, the separating character. C can be one of
7709 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
7710 between double quotes. */
7711 static WORD_DESC *
7712 parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat)
7713 char *name, *value;
7714 int op, quoted, pflags, *qdollaratp, *hasdollarat;
7715 {
7716 WORD_DESC *w;
7717 WORD_LIST *l, *tl;
7718 char *t, *t1, *temp, *vname, *newval;
7719 int l_hasdollat, sindex, arrayref;
7720 SHELL_VAR *v;
7721 array_eltstate_t es;
7722
7723 /*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/
7724 /* If the entire expression is between double quotes, we want to treat
7725 the value as a double-quoted string, with the exception that we strip
7726 embedded unescaped double quotes (for sh backwards compatibility). */
7727 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
7728 {
7729 sindex = 0;
7730 temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ);
7731 }
7732 else
7733 temp = value;
7734
7735 w = alloc_word_desc ();
7736 l_hasdollat = 0;
7737 l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL)
7738 : (WORD_LIST *)0;
7739 if (hasdollarat)
7740 *hasdollarat = l_hasdollat || (l && l->next);
7741 if (temp != value)
7742 free (temp);
7743
7744 /* list_string takes multiple CTLNULs and turns them into an empty word
7745 with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the
7746 rest of this function and the caller. */
7747 for (tl = l; tl; tl = tl->next)
7748 {
7749 if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) &&
7750 (tl->word->flags | W_SAWQUOTEDNULL))
7751 {
7752 t = make_quoted_char ('\0');
7753 FREE (tl->word->word);
7754 tl->word->word = t;
7755 tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL;
7756 tl->word->flags &= ~W_SAWQUOTEDNULL;
7757 }
7758 }
7759
7760 if (l)
7761 {
7762 /* If l->next is not null, we know that TEMP contained "$@", since that
7763 is the only expansion that creates more than one word. */
7764 if (qdollaratp && ((l_hasdollat && quoted) || l->next))
7765 {
7766 /*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/
7767 *qdollaratp = 1;
7768 }
7769
7770 /* The expansion of TEMP returned something. We need to treat things
7771 slightly differently if L_HASDOLLAT is non-zero. If we have "$@",
7772 the individual words have already been quoted. We need to turn them
7773 into a string with the words separated by the first character of
7774 $IFS without any additional quoting, so string_list_dollar_at won't
7775 do the right thing. If IFS is null, we want "$@" to split into
7776 separate arguments, not be concatenated, so we use string_list_internal
7777 and mark the word to be split on spaces later. We use
7778 string_list_dollar_star for "$@" otherwise. */
7779 if (l->next && ifs_is_null)
7780 {
7781 temp = string_list_internal (l, " ");
7782 w->flags |= W_SPLITSPACE;
7783 }
7784 else if (l_hasdollat || l->next)
7785 temp = string_list_dollar_star (l, quoted, 0);
7786 else
7787 {
7788 temp = string_list (l);
7789 if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL))
7790 w->flags |= W_SAWQUOTEDNULL; /* XXX */
7791 }
7792
7793 /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
7794 a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
7795 flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
7796 expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7797 (which is more paranoia than anything else), we need to return the
7798 quoted null string and set the flags to indicate it. */
7799 if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL))
7800 {
7801 w->flags |= W_HASQUOTEDNULL;
7802 /*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/
7803 /* If we return a quoted null with L_HASDOLLARAT, we either have a
7804 construct like "${@-$@}" or "${@-${@-$@}}" with no positional
7805 parameters or a quoted expansion of "$@" with $1 == ''. In either
7806 case, we don't want to enable special handling of $@. */
7807 if (qdollaratp && l_hasdollat)
7808 *qdollaratp = 0;
7809 }
7810 dispose_words (l);
7811 }
7812 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat)
7813 {
7814 /* Posix interp 221 changed the rules on this. The idea is that
7815 something like "$xxx$@" should expand the same as "${foo-$xxx$@}"
7816 when foo and xxx are unset. The problem is that it's not in any
7817 way backwards compatible and few other shells do it. We're eventually
7818 going to try and split the difference (heh) a little bit here. */
7819 /* l_hasdollat == 1 means we saw a quoted dollar at. */
7820
7821 /* The brace expansion occurred between double quotes and there was
7822 a $@ in TEMP. It does not matter if the $@ is quoted, as long as
7823 it does not expand to anything. In this case, we want to return
7824 a quoted empty string. Posix interp 888 */
7825 temp = make_quoted_char ('\0');
7826 w->flags |= W_HASQUOTEDNULL;
7827 /*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/
7828 }
7829 else
7830 temp = (char *)NULL;
7831
7832 if (op == '-' || op == '+')
7833 {
7834 w->word = temp;
7835 return w;
7836 }
7837
7838 /* op == '=' */
7839 t1 = temp ? dequote_string (temp) : savestring ("");
7840 free (temp);
7841
7842 /* bash-4.4/5.0 */
7843 vname = name;
7844 if (*name == '!' &&
7845 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1])))
7846 {
7847 vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1);
7848 if (vname == 0 || *vname == 0)
7849 {
7850 report_error (_("%s: invalid indirect expansion"), name);
7851 free (vname);
7852 free (t1);
7853 dispose_word (w);
7854 return &expand_wdesc_error;
7855 }
7856 if (legal_identifier (vname) == 0)
7857 {
7858 report_error (_("%s: invalid variable name"), vname);
7859 free (vname);
7860 free (t1);
7861 dispose_word (w);
7862 return &expand_wdesc_error;
7863 }
7864 }
7865
7866 arrayref = 0;
7867 #if defined (ARRAY_VARS)
7868 if (valid_array_reference (vname, 0))
7869 {
7870 init_eltstate (&es);
7871 v = assign_array_element (vname, t1, ASS_ALLOWALLSUB, &es);
7872 arrayref = 1;
7873 newval = es.value;
7874 }
7875 else
7876 #endif /* ARRAY_VARS */
7877 v = bind_variable (vname, t1, 0);
7878
7879 if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */
7880 {
7881 if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct)
7882 {
7883 last_command_exit_value = EXECUTION_FAILURE;
7884 exp_jump_to_top_level (FORCE_EOF);
7885 }
7886 else
7887 {
7888 if (vname != name)
7889 free (vname);
7890 last_command_exit_value = EX_BADUSAGE;
7891 exp_jump_to_top_level (DISCARD);
7892 }
7893 }
7894
7895 stupidly_hack_special_variables (vname);
7896
7897 /* "In all cases, the final value of parameter shall be substituted." */
7898 if (shell_compatibility_level > 51)
7899 {
7900 FREE (t1);
7901 #if defined (ARRAY_VARS)
7902 if (arrayref)
7903 {
7904 t1 = newval;
7905 flush_eltstate (&es);
7906 }
7907 else
7908 t1 = get_variable_value (v);
7909 #else
7910 t1 = value_cell (v);
7911 #endif
7912 }
7913
7914 if (vname != name)
7915 free (vname);
7916
7917 /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
7918
7919 /* If we are double-quoted or if we are not going to be performing word
7920 splitting, we want to quote the value we return appropriately, like
7921 the other expansions this function handles. */
7922 w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1);
7923 /* If we have something that's non-null, but not a quoted null string,
7924 and we're not going to be performing word splitting (we know we're not
7925 because the operator is `='), we can forget we saw a quoted null. */
7926 if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0)
7927 w->flags &= ~W_SAWQUOTEDNULL;
7928
7929 /* If we convert a null string into a quoted null, make sure the caller
7930 knows it. */
7931 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word))
7932 w->flags |= W_HASQUOTEDNULL;
7933
7934 return w;
7935 }
7936
7937 /* Deal with the right hand side of a ${name:?value} expansion in the case
7938 that NAME is null or not set. If VALUE is non-null it is expanded and
7939 used as the error message to print, otherwise a standard message is
7940 printed. */
7941 static void
7942 parameter_brace_expand_error (name, value, check_null)
7943 char *name, *value;
7944 int check_null;
7945 {
7946 WORD_LIST *l;
7947 char *temp;
7948
7949 set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */
7950 if (value && *value)
7951 {
7952 l = expand_string (value, 0);
7953 temp = string_list (l);
7954 report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
7955 FREE (temp);
7956 dispose_words (l);
7957 }
7958 else if (check_null == 0)
7959 report_error (_("%s: parameter not set"), name);
7960 else
7961 report_error (_("%s: parameter null or not set"), name);
7962
7963 /* Free the data we have allocated during this expansion, since we
7964 are about to longjmp out. */
7965 free (name);
7966 FREE (value);
7967 }
7968
7969 /* Return 1 if NAME is something for which parameter_brace_expand_length is
7970 OK to do. */
7971 static int
7972 valid_length_expression (name)
7973 char *name;
7974 {
7975 return (name[1] == '\0' || /* ${#} */
7976 ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */
7977 (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
7978 #if defined (ARRAY_VARS)
7979 valid_array_reference (name + 1, 0) || /* ${#a[7]} */
7980 #endif
7981 legal_identifier (name + 1)); /* ${#PS1} */
7982 }
7983
7984 /* Handle the parameter brace expansion that requires us to return the
7985 length of a parameter. */
7986 static intmax_t
7987 parameter_brace_expand_length (name)
7988 char *name;
7989 {
7990 char *t, *newname;
7991 intmax_t number, arg_index;
7992 WORD_LIST *list;
7993 SHELL_VAR *var;
7994
7995 var = (SHELL_VAR *)NULL;
7996
7997 if (name[1] == '\0') /* ${#} */
7998 number = number_of_args ();
7999 else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */
8000 number = number_of_args ();
8001 else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
8002 {
8003 /* Take the lengths of some of the shell's special parameters. */
8004 switch (name[1])
8005 {
8006 case '-':
8007 t = which_set_flags ();
8008 break;
8009 case '?':
8010 t = itos (last_command_exit_value);
8011 break;
8012 case '$':
8013 t = itos (dollar_dollar_pid);
8014 break;
8015 case '!':
8016 if (last_asynchronous_pid == NO_PID)
8017 t = (char *)NULL; /* XXX - error if set -u set? */
8018 else
8019 t = itos (last_asynchronous_pid);
8020 break;
8021 case '#':
8022 t = itos (number_of_args ());
8023 break;
8024 }
8025 number = STRLEN (t);
8026 FREE (t);
8027 }
8028 #if defined (ARRAY_VARS)
8029 else if (valid_array_reference (name + 1, 0))
8030 number = array_length_reference (name + 1);
8031 #endif /* ARRAY_VARS */
8032 else
8033 {
8034 number = 0;
8035
8036 if (legal_number (name + 1, &arg_index)) /* ${#1} */
8037 {
8038 t = get_dollar_var_value (arg_index);
8039 if (t == 0 && unbound_vars_is_error)
8040 return INTMAX_MIN;
8041 number = MB_STRLEN (t);
8042 FREE (t);
8043 }
8044 #if defined (ARRAY_VARS)
8045 else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
8046 {
8047 if (assoc_p (var))
8048 t = assoc_reference (assoc_cell (var), "0");
8049 else
8050 t = array_reference (array_cell (var), 0);
8051 if (t == 0 && unbound_vars_is_error)
8052 return INTMAX_MIN;
8053 number = MB_STRLEN (t);
8054 }
8055 #endif
8056 /* Fast path for the common case of taking the length of a non-dynamic
8057 scalar variable value. */
8058 else if ((var || (var = find_variable (name + 1))) &&
8059 invisible_p (var) == 0 &&
8060 array_p (var) == 0 && assoc_p (var) == 0 &&
8061 var->dynamic_value == 0)
8062 number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0;
8063 else if (var == 0 && unbound_vars_is_error == 0)
8064 number = 0;
8065 else /* ${#PS1} */
8066 {
8067 newname = savestring (name);
8068 newname[0] = '$';
8069 list = expand_string (newname, Q_DOUBLE_QUOTES);
8070 t = list ? string_list (list) : (char *)NULL;
8071 free (newname);
8072 if (list)
8073 dispose_words (list);
8074
8075 number = t ? MB_STRLEN (t) : 0;
8076 FREE (t);
8077 }
8078 }
8079
8080 return (number);
8081 }
8082
8083 /* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression,
8084 so we do some ad-hoc parsing of an arithmetic expression to find
8085 the first DELIM, instead of using strchr(3). Two rules:
8086 1. If the substring contains a `(', read until closing `)'.
8087 2. If the substring contains a `?', read past one `:' for each `?'.
8088 The SD_ARITHEXP flag to skip_to_delim takes care of doing this.
8089 */
8090
8091 static char *
8092 skiparith (substr, delim)
8093 char *substr;
8094 int delim;
8095 {
8096 int i;
8097 char delims[2];
8098
8099 delims[0] = delim;
8100 delims[1] = '\0';
8101
8102 i = skip_to_delim (substr, 0, delims, SD_ARITHEXP);
8103 return (substr + i);
8104 }
8105
8106 /* Verify and limit the start and end of the desired substring. If
8107 VTYPE == 0, a regular shell variable is being used; if it is 1,
8108 then the positional parameters are being used; if it is 2, then
8109 VALUE is really a pointer to an array variable that should be used.
8110 Return value is 1 if both values were OK, 0 if there was a problem
8111 with an invalid expression, or -1 if the values were out of range. */
8112 static int
8113 verify_substring_values (v, value, substr, vtype, e1p, e2p)
8114 SHELL_VAR *v;
8115 char *value, *substr;
8116 int vtype;
8117 intmax_t *e1p, *e2p;
8118 {
8119 char *t, *temp1, *temp2;
8120 arrayind_t len;
8121 int expok, eflag;
8122 #if defined (ARRAY_VARS)
8123 ARRAY *a;
8124 HASH_TABLE *h;
8125 #endif
8126
8127 /* duplicate behavior of strchr(3) */
8128 t = skiparith (substr, ':');
8129 if (*t && *t == ':')
8130 *t = '\0';
8131 else
8132 t = (char *)0;
8133
8134 temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES|Q_ARITH);
8135 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
8136
8137 *e1p = evalexp (temp1, eflag, &expok);
8138 free (temp1);
8139 if (expok == 0)
8140 return (0);
8141
8142 len = -1; /* paranoia */
8143 switch (vtype)
8144 {
8145 case VT_VARIABLE:
8146 case VT_ARRAYMEMBER:
8147 len = MB_STRLEN (value);
8148 break;
8149 case VT_POSPARMS:
8150 len = number_of_args () + 1;
8151 if (*e1p == 0)
8152 len++; /* add one arg if counting from $0 */
8153 break;
8154 #if defined (ARRAY_VARS)
8155 case VT_ARRAYVAR:
8156 /* For arrays, the first value deals with array indices. Negative
8157 offsets count from one past the array's maximum index. Associative
8158 arrays treat the number of elements as the maximum index. */
8159 if (assoc_p (v))
8160 {
8161 h = assoc_cell (v);
8162 len = assoc_num_elements (h) + (*e1p < 0);
8163 }
8164 else
8165 {
8166 a = (ARRAY *)value;
8167 len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
8168 }
8169 break;
8170 #endif
8171 }
8172
8173 if (len == -1) /* paranoia */
8174 return -1;
8175
8176 if (*e1p < 0) /* negative offsets count from end */
8177 *e1p += len;
8178
8179 if (*e1p > len || *e1p < 0)
8180 return (-1);
8181
8182 #if defined (ARRAY_VARS)
8183 /* For arrays, the second offset deals with the number of elements. */
8184 if (vtype == VT_ARRAYVAR)
8185 len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
8186 #endif
8187
8188 if (t)
8189 {
8190 t++;
8191 temp2 = savestring (t);
8192 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
8193 free (temp2);
8194 t[-1] = ':';
8195 *e2p = evalexp (temp1, eflag, &expok);
8196 free (temp1);
8197 if (expok == 0)
8198 return (0);
8199
8200 /* Should we allow positional parameter length < 0 to count backwards
8201 from end of positional parameters? */
8202 #if 1
8203 if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
8204 #else /* XXX - postponed; this isn't really a valuable feature */
8205 if (vtype == VT_ARRAYVAR && *e2p < 0)
8206 #endif
8207 {
8208 internal_error (_("%s: substring expression < 0"), t);
8209 return (0);
8210 }
8211 #if defined (ARRAY_VARS)
8212 /* In order to deal with sparse arrays, push the intelligence about how
8213 to deal with the number of elements desired down to the array-
8214 specific functions. */
8215 if (vtype != VT_ARRAYVAR)
8216 #endif
8217 {
8218 if (*e2p < 0)
8219 {
8220 *e2p += len;
8221 if (*e2p < 0 || *e2p < *e1p)
8222 {
8223 internal_error (_("%s: substring expression < 0"), t);
8224 return (0);
8225 }
8226 }
8227 else
8228 *e2p += *e1p; /* want E2 chars starting at E1 */
8229 if (*e2p > len)
8230 *e2p = len;
8231 }
8232 }
8233 else
8234 *e2p = len;
8235
8236 return (1);
8237 }
8238
8239 /* Return the type of variable specified by VARNAME (simple variable,
8240 positional param, or array variable). Also return the value specified
8241 by VARNAME (value of a variable or a reference to an array element).
8242 QUOTED is the standard description of quoting state, using Q_* defines.
8243 FLAGS is currently a set of flags to pass to array_value. If IND is
8244 not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
8245 passed to array_value so the array index is not computed again.
8246 If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
8247 characters in the value are quoted with CTLESC and takes appropriate
8248 steps. For convenience, *VALP is set to the dequoted VALUE. */
8249 static int
8250 get_var_and_type (varname, value, estatep, quoted, flags, varp, valp)
8251 char *varname, *value;
8252 array_eltstate_t *estatep;
8253 int quoted, flags;
8254 SHELL_VAR **varp;
8255 char **valp;
8256 {
8257 int vtype, want_indir;
8258 char *temp, *vname;
8259 SHELL_VAR *v;
8260
8261 want_indir = *varname == '!' &&
8262 (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1])
8263 || VALID_INDIR_PARAM (varname[1]));
8264 if (want_indir)
8265 vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1);
8266 /* XXX - what if vname == 0 || *vname == 0 ? */
8267 else
8268 vname = varname;
8269
8270 if (vname == 0)
8271 {
8272 vtype = VT_VARIABLE;
8273 *varp = (SHELL_VAR *)NULL;
8274 *valp = (char *)NULL;
8275 return (vtype);
8276 }
8277
8278 /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
8279 vtype = STR_DOLLAR_AT_STAR (vname);
8280 if (vtype == VT_POSPARMS && vname[0] == '*')
8281 vtype |= VT_STARSUB;
8282 *varp = (SHELL_VAR *)NULL;
8283
8284 #if defined (ARRAY_VARS)
8285 if (valid_array_reference (vname, 0))
8286 {
8287 v = array_variable_part (vname, 0, &temp, (int *)0);
8288 /* If we want to signal array_value to use an already-computed index,
8289 the caller will set ESTATEP->IND to that index and pass AV_USEIND in
8290 FLAGS. */
8291 if (estatep && (flags & AV_USEIND) == 0)
8292 estatep->ind = INTMAX_MIN;
8293
8294 if (v && invisible_p (v))
8295 {
8296 vtype = VT_ARRAYMEMBER;
8297 *varp = (SHELL_VAR *)NULL;
8298 *valp = (char *)NULL;
8299 }
8300 if (v && (array_p (v) || assoc_p (v)))
8301 {
8302 if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)
8303 {
8304 /* Callers have to differentiate between indexed and associative */
8305 vtype = VT_ARRAYVAR;
8306 if (temp[0] == '*')
8307 vtype |= VT_STARSUB;
8308 *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
8309 }
8310 else
8311 {
8312 vtype = VT_ARRAYMEMBER;
8313 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
8314 }
8315 *varp = v;
8316 }
8317 else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK))
8318 {
8319 vtype = VT_VARIABLE;
8320 *varp = v;
8321 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8322 *valp = value ? dequote_string (value) : (char *)NULL;
8323 else
8324 *valp = value ? dequote_escapes (value) : (char *)NULL;
8325 }
8326 else
8327 {
8328 vtype = VT_ARRAYMEMBER;
8329 *varp = v;
8330 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
8331 }
8332 }
8333 else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
8334 {
8335 vtype = VT_ARRAYMEMBER;
8336 *varp = v;
8337 *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
8338 }
8339 else
8340 #endif
8341 {
8342 if (value && vtype == VT_VARIABLE)
8343 {
8344 *varp = find_variable (vname);
8345 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8346 *valp = dequote_string (value);
8347 else
8348 *valp = dequote_escapes (value);
8349 }
8350 else
8351 *valp = value;
8352 }
8353
8354 if (want_indir)
8355 free (vname);
8356
8357 return vtype;
8358 }
8359
8360 /***********************************************************/
8361 /* */
8362 /* Functions to perform transformations on variable values */
8363 /* */
8364 /***********************************************************/
8365
8366 static char *
8367 string_var_assignment (v, s)
8368 SHELL_VAR *v;
8369 char *s;
8370 {
8371 char flags[MAX_ATTRIBUTES], *ret, *val;
8372 int i;
8373
8374 val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0);
8375 i = var_attribute_string (v, 0, flags);
8376 if (i == 0 && val == 0)
8377 return (char *)NULL;
8378
8379 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES);
8380 if (i > 0 && val == 0)
8381 sprintf (ret, "declare -%s %s", flags, v->name);
8382 else if (i > 0)
8383 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
8384 else
8385 sprintf (ret, "%s=%s", v->name, val);
8386 free (val);
8387 return ret;
8388 }
8389
8390 #if defined (ARRAY_VARS)
8391 static char *
8392 array_var_assignment (v, itype, quoted, atype)
8393 SHELL_VAR *v;
8394 int itype, quoted, atype;
8395 {
8396 char *ret, *val, flags[MAX_ATTRIBUTES];
8397 int i;
8398
8399 if (v == 0)
8400 return (char *)NULL;
8401 if (atype == 2)
8402 val = array_p (v) ? array_to_kvpair (array_cell (v), 0)
8403 : assoc_to_kvpair (assoc_cell (v), 0);
8404 else
8405 val = array_p (v) ? array_to_assign (array_cell (v), 0)
8406 : assoc_to_assign (assoc_cell (v), 0);
8407
8408 if (val == 0 && (invisible_p (v) || var_isset (v) == 0))
8409 ; /* placeholder */
8410 else if (val == 0)
8411 {
8412 val = (char *)xmalloc (3);
8413 val[0] = LPAREN;
8414 val[1] = RPAREN;
8415 val[2] = 0;
8416 }
8417 else
8418 {
8419 ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val);
8420 free (val);
8421 val = ret;
8422 }
8423
8424 if (atype == 2)
8425 return val;
8426
8427 i = var_attribute_string (v, 0, flags);
8428 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16);
8429 if (val)
8430 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
8431 else
8432 sprintf (ret, "declare -%s %s", flags, v->name);
8433 free (val);
8434 return ret;
8435 }
8436 #endif
8437
8438 static char *
8439 pos_params_assignment (list, itype, quoted)
8440 WORD_LIST *list;
8441 int itype;
8442 int quoted;
8443 {
8444 char *temp, *ret;
8445
8446 /* first, we transform the list to quote each word. */
8447 temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted);
8448 ret = (char *)xmalloc (strlen (temp) + 8);
8449 strcpy (ret, "set -- ");
8450 strcpy (ret + 7, temp);
8451 free (temp);
8452 return ret;
8453 }
8454
8455 static char *
8456 string_transform (xc, v, s)
8457 int xc;
8458 SHELL_VAR *v;
8459 char *s;
8460 {
8461 char *ret, flags[MAX_ATTRIBUTES], *t;
8462 int i;
8463
8464 if (((xc == 'A' || xc == 'a') && v == 0))
8465 return (char *)NULL;
8466 else if (xc != 'a' && xc != 'A' && s == 0)
8467 return (char *)NULL;
8468
8469 switch (xc)
8470 {
8471 /* Transformations that interrogate the variable */
8472 case 'a':
8473 i = var_attribute_string (v, 0, flags);
8474 ret = (i > 0) ? savestring (flags) : (char *)NULL;
8475 break;
8476 case 'A':
8477 ret = string_var_assignment (v, s);
8478 break;
8479 case 'K':
8480 case 'k':
8481 ret = sh_quote_reusable (s, 0);
8482 break;
8483 /* Transformations that modify the variable's value */
8484 case 'E':
8485 t = ansiexpand (s, 0, strlen (s), (int *)0);
8486 ret = dequote_escapes (t);
8487 free (t);
8488 break;
8489 case 'P':
8490 ret = decode_prompt_string (s);
8491 break;
8492 case 'Q':
8493 ret = sh_quote_reusable (s, 0);
8494 break;
8495 case 'U':
8496 ret = sh_modcase (s, 0, CASE_UPPER);
8497 break;
8498 case 'u':
8499 ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */
8500 break;
8501 case 'L':
8502 ret = sh_modcase (s, 0, CASE_LOWER);
8503 break;
8504 default:
8505 ret = (char *)NULL;
8506 break;
8507 }
8508 return ret;
8509 }
8510
8511 static char *
8512 list_transform (xc, v, list, itype, quoted)
8513 int xc;
8514 SHELL_VAR *v;
8515 WORD_LIST *list;
8516 int itype, quoted;
8517 {
8518 WORD_LIST *new, *l;
8519 WORD_DESC *w;
8520 char *tword;
8521 int qflags;
8522
8523 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
8524 {
8525 tword = string_transform (xc, v, l->word->word);
8526 w = alloc_word_desc ();
8527 w->word = tword ? tword : savestring (""); /* XXX */
8528 new = make_word_list (w, new);
8529 }
8530 l = REVERSE_LIST (new, WORD_LIST *);
8531
8532 qflags = quoted;
8533 /* If we are expanding in a context where word splitting will not be
8534 performed, treat as quoted. This changes how $* will be expanded. */
8535 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
8536 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8537
8538 tword = string_list_pos_params (itype, l, qflags, 0);
8539 dispose_words (l);
8540
8541 return (tword);
8542 }
8543
8544 static char *
8545 parameter_list_transform (xc, itype, quoted)
8546 int xc;
8547 int itype;
8548 int quoted;
8549 {
8550 char *ret;
8551 WORD_LIST *list;
8552
8553 list = list_rest_of_args ();
8554 if (list == 0)
8555 return ((char *)NULL);
8556 if (xc == 'A')
8557 ret = pos_params_assignment (list, itype, quoted);
8558 else
8559 ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted);
8560 dispose_words (list);
8561 return (ret);
8562 }
8563
8564 #if defined (ARRAY_VARS)
8565 static char *
8566 array_transform (xc, var, starsub, quoted)
8567 int xc;
8568 SHELL_VAR *var;
8569 int starsub; /* so we can figure out how it's indexed */
8570 int quoted;
8571 {
8572 ARRAY *a;
8573 HASH_TABLE *h;
8574 int itype, qflags;
8575 char *ret;
8576 WORD_LIST *list;
8577 SHELL_VAR *v;
8578
8579 v = var; /* XXX - for now */
8580
8581 itype = starsub ? '*' : '@';
8582
8583 if (xc == 'A')
8584 return (array_var_assignment (v, itype, quoted, 1));
8585 else if (xc == 'K')
8586 return (array_var_assignment (v, itype, quoted, 2));
8587
8588 /* special case for unset arrays and attributes */
8589 if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0))
8590 {
8591 char flags[MAX_ATTRIBUTES];
8592 int i;
8593
8594 i = var_attribute_string (v, 0, flags);
8595 return ((i > 0) ? savestring (flags) : (char *)NULL);
8596 }
8597
8598 a = (v && array_p (v)) ? array_cell (v) : 0;
8599 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
8600
8601 /* XXX - for now */
8602 if (xc == 'k')
8603 {
8604 if (v == 0)
8605 return ((char *)NULL);
8606 list = array_p (v) ? array_to_kvpair_list (a) : assoc_to_kvpair_list (h);
8607 qflags = quoted;
8608 /* If we are expanding in a context where word splitting will not be
8609 performed, treat as quoted. This changes how $* will be expanded. */
8610 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
8611 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8612
8613 ret = string_list_pos_params (itype, list, qflags, 0);
8614 dispose_words (list);
8615 return ret;
8616 }
8617
8618 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
8619 if (list == 0)
8620 return ((char *)NULL);
8621 ret = list_transform (xc, v, list, itype, quoted);
8622 dispose_words (list);
8623
8624 return ret;
8625 }
8626 #endif /* ARRAY_VARS */
8627
8628 static int
8629 valid_parameter_transform (xform)
8630 char *xform;
8631 {
8632 if (xform[1])
8633 return 0;
8634
8635 /* check for valid values of xform[0] */
8636 switch (xform[0])
8637 {
8638 case 'a': /* expand to a string with just attributes */
8639 case 'A': /* expand as an assignment statement with attributes */
8640 case 'K': /* expand assoc array to list of key/value pairs */
8641 case 'k': /* XXX - for now */
8642 case 'E': /* expand like $'...' */
8643 case 'P': /* expand like prompt string */
8644 case 'Q': /* quote reusably */
8645 case 'U': /* transform to uppercase */
8646 case 'u': /* transform by capitalizing */
8647 case 'L': /* transform to lowercase */
8648 return 1;
8649 default:
8650 return 0;
8651 }
8652 }
8653
8654 static char *
8655 parameter_brace_transform (varname, value, estatep, xform, rtype, quoted, pflags, flags)
8656 char *varname, *value;
8657 array_eltstate_t *estatep;
8658 char *xform;
8659 int rtype, quoted, pflags, flags;
8660 {
8661 int vtype, xc, starsub;
8662 char *temp1, *val, *oname;
8663 SHELL_VAR *v;
8664
8665 xc = xform[0];
8666 if (value == 0 && xc != 'A' && xc != 'a')
8667 return ((char *)NULL);
8668
8669 oname = this_command_name;
8670 this_command_name = varname;
8671
8672 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
8673 if (vtype == -1)
8674 {
8675 this_command_name = oname;
8676 return ((char *)NULL);
8677 }
8678
8679 if (xform[0] == 0 || valid_parameter_transform (xform) == 0)
8680 {
8681 this_command_name = oname;
8682 if (vtype == VT_VARIABLE)
8683 FREE (val);
8684 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
8685 }
8686
8687 starsub = vtype & VT_STARSUB;
8688 vtype &= ~VT_STARSUB;
8689
8690 /* If we are asked to display the attributes of an unset variable, V will
8691 be NULL after the call to get_var_and_type. Double-check here. */
8692 if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0)
8693 v = find_variable (varname);
8694
8695 temp1 = (char *)NULL; /* shut up gcc */
8696 switch (vtype)
8697 {
8698 case VT_VARIABLE:
8699 case VT_ARRAYMEMBER:
8700 temp1 = string_transform (xc, v, val);
8701 if (vtype == VT_VARIABLE)
8702 FREE (val);
8703 if (temp1)
8704 {
8705 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8706 ? quote_string (temp1)
8707 : quote_escapes (temp1);
8708 free (temp1);
8709 temp1 = val;
8710 }
8711 break;
8712 #if defined (ARRAY_VARS)
8713 case VT_ARRAYVAR:
8714 temp1 = array_transform (xc, v, starsub, quoted);
8715 if (temp1 && quoted == 0 && ifs_is_null)
8716 {
8717 /* Posix interp 888 */
8718 }
8719 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
8720 {
8721 val = quote_escapes (temp1);
8722 free (temp1);
8723 temp1 = val;
8724 }
8725 break;
8726 #endif
8727 case VT_POSPARMS:
8728 temp1 = parameter_list_transform (xc, varname[0], quoted);
8729 if (temp1 && quoted == 0 && ifs_is_null)
8730 {
8731 /* Posix interp 888 */
8732 }
8733 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
8734 {
8735 val = quote_escapes (temp1);
8736 free (temp1);
8737 temp1 = val;
8738 }
8739 break;
8740 }
8741
8742 this_command_name = oname;
8743 return temp1;
8744 }
8745
8746 /******************************************************/
8747 /* */
8748 /* Functions to extract substrings of variable values */
8749 /* */
8750 /******************************************************/
8751
8752 #if defined (HANDLE_MULTIBYTE)
8753 /* Character-oriented rather than strictly byte-oriented substrings. S and
8754 E, rather being strict indices into STRING, indicate character (possibly
8755 multibyte character) positions that require calculation.
8756 Used by the ${param:offset[:length]} expansion. */
8757 static char *
8758 mb_substring (string, s, e)
8759 char *string;
8760 int s, e;
8761 {
8762 char *tt;
8763 int start, stop, i;
8764 size_t slen;
8765 DECLARE_MBSTATE;
8766
8767 start = 0;
8768 /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
8769 slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
8770
8771 i = s;
8772 while (string[start] && i--)
8773 ADVANCE_CHAR (string, slen, start);
8774 stop = start;
8775 i = e - s;
8776 while (string[stop] && i--)
8777 ADVANCE_CHAR (string, slen, stop);
8778 tt = substring (string, start, stop);
8779 return tt;
8780 }
8781 #endif
8782
8783 /* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
8784 is `@', use the positional parameters; otherwise, use the value of
8785 VARNAME. If VARNAME is an array variable, use the array elements. */
8786
8787 static char *
8788 parameter_brace_substring (varname, value, estatep, substr, quoted, pflags, flags)
8789 char *varname, *value;
8790 array_eltstate_t *estatep;
8791 char *substr;
8792 int quoted, pflags, flags;
8793 {
8794 intmax_t e1, e2;
8795 int vtype, r, starsub;
8796 char *temp, *val, *tt, *oname;
8797 SHELL_VAR *v;
8798
8799 if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1]))
8800 return ((char *)NULL);
8801
8802 oname = this_command_name;
8803 this_command_name = varname;
8804
8805 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
8806 if (vtype == -1)
8807 {
8808 this_command_name = oname;
8809 return ((char *)NULL);
8810 }
8811
8812 starsub = vtype & VT_STARSUB;
8813 vtype &= ~VT_STARSUB;
8814
8815 r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
8816 this_command_name = oname;
8817 if (r <= 0)
8818 {
8819 if (vtype == VT_VARIABLE)
8820 FREE (val);
8821 return ((r == 0) ? &expand_param_error : (char *)NULL);
8822 }
8823
8824 switch (vtype)
8825 {
8826 case VT_VARIABLE:
8827 case VT_ARRAYMEMBER:
8828 #if defined (HANDLE_MULTIBYTE)
8829 if (MB_CUR_MAX > 1)
8830 tt = mb_substring (val, e1, e2);
8831 else
8832 #endif
8833 tt = substring (val, e1, e2);
8834
8835 if (vtype == VT_VARIABLE)
8836 FREE (val);
8837 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8838 temp = quote_string (tt);
8839 else
8840 temp = tt ? quote_escapes (tt) : (char *)NULL;
8841 FREE (tt);
8842 break;
8843 case VT_POSPARMS:
8844 case VT_ARRAYVAR:
8845 if (vtype == VT_POSPARMS)
8846 tt = pos_params (varname, e1, e2, quoted, pflags);
8847 #if defined (ARRAY_VARS)
8848 /* assoc_subrange and array_subrange both call string_list_pos_params,
8849 so we can treat this case just like VT_POSPARAMS. */
8850 else if (assoc_p (v))
8851 /* we convert to list and take first e2 elements starting at e1th
8852 element -- officially undefined for now */
8853 tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags);
8854 else
8855 /* We want E2 to be the number of elements desired (arrays can be
8856 sparse, so verify_substring_values just returns the numbers
8857 specified and we rely on array_subrange to understand how to
8858 deal with them). */
8859 tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags);
8860 #endif
8861 /* We want to leave this alone in every case where pos_params/
8862 string_list_pos_params quotes the list members */
8863 if (tt && quoted == 0 && ifs_is_null)
8864 {
8865 temp = tt; /* Posix interp 888 */
8866 }
8867 else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS))
8868 {
8869 temp = tt; /* Posix interp 888 */
8870 }
8871 else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
8872 {
8873 temp = tt ? quote_escapes (tt) : (char *)NULL;
8874 FREE (tt);
8875 }
8876 else
8877 temp = tt;
8878 break;
8879
8880 default:
8881 temp = (char *)NULL;
8882 }
8883
8884 return temp;
8885 }
8886
8887 /****************************************************************/
8888 /* */
8889 /* Functions to perform pattern substitution on variable values */
8890 /* */
8891 /****************************************************************/
8892
8893 static int
8894 shouldexp_replacement (s)
8895 char *s;
8896 {
8897 size_t slen;
8898 int sindex, c;
8899 DECLARE_MBSTATE;
8900
8901 sindex = 0;
8902 slen = STRLEN (s);
8903 while (c = s[sindex])
8904 {
8905 if (c == '\\')
8906 {
8907 sindex++;
8908 if (s[sindex] == 0)
8909 return 0;
8910 /* We want to remove this backslash because we treat it as special
8911 in this context. THIS ASSUMES THE STRING IS PROCESSED BY
8912 strcreplace() OR EQUIVALENT that handles removing backslashes
8913 preceding the special character. */
8914 if (s[sindex] == '&')
8915 return 1;
8916 if (s[sindex] == '\\')
8917 return 1;
8918 }
8919 else if (c == '&')
8920 return 1;
8921 ADVANCE_CHAR (s, slen, sindex);
8922 }
8923 return 0;
8924 }
8925
8926 char *
8927 pat_subst (string, pat, rep, mflags)
8928 char *string, *pat, *rep;
8929 int mflags;
8930 {
8931 char *ret, *s, *e, *str, *rstr, *mstr, *send;
8932 int rptr, mtype, rxpand, mlen;
8933 size_t rsize, l, replen, rslen;
8934 DECLARE_MBSTATE;
8935
8936 if (string == 0)
8937 return (savestring (""));
8938
8939 mtype = mflags & MATCH_TYPEMASK;
8940 rxpand = mflags & MATCH_EXPREP;
8941
8942 /* Special cases:
8943 * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
8944 * with REP and return the result.
8945 * 2. A null pattern with mtype == MATCH_END means to append REP to
8946 * STRING and return the result.
8947 * 3. A null STRING with a matching pattern means to append REP to
8948 * STRING and return the result.
8949 *
8950 * These process `&' in the replacement string, like `sed' does when
8951 * presented with a BRE of `^' or `$'.
8952 */
8953 if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
8954 {
8955 rstr = (mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2) : rep;
8956 rslen = STRLEN (rstr);
8957 l = STRLEN (string);
8958 ret = (char *)xmalloc (rslen + l + 2);
8959 if (rslen == 0)
8960 strcpy (ret, string);
8961 else if (mtype == MATCH_BEG)
8962 {
8963 strcpy (ret, rstr);
8964 strcpy (ret + rslen, string);
8965 }
8966 else
8967 {
8968 strcpy (ret, string);
8969 strcpy (ret + l, rstr);
8970 }
8971 if (rstr != rep)
8972 free (rstr);
8973 return (ret);
8974 }
8975 else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
8976 return (mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2)
8977 : (rep ? savestring (rep) : savestring (""));
8978
8979 ret = (char *)xmalloc (rsize = 64);
8980 ret[0] = '\0';
8981 send = string + strlen (string);
8982
8983 for (replen = STRLEN (rep), rptr = 0, str = string; *str;)
8984 {
8985 if (match_pattern (str, pat, mtype, &s, &e) == 0)
8986 break;
8987 l = s - str;
8988
8989 if (rep && rxpand)
8990 {
8991 int x;
8992 mlen = e - s;
8993 mstr = xmalloc (mlen + 1);
8994 for (x = 0; x < mlen; x++)
8995 mstr[x] = s[x];
8996 mstr[mlen] = '\0';
8997 rstr = strcreplace (rep, '&', mstr, 2);
8998 free (mstr);
8999 rslen = strlen (rstr);
9000 }
9001 else
9002 {
9003 rstr = rep;
9004 rslen = replen;
9005 }
9006
9007 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
9008
9009 /* OK, now copy the leading unmatched portion of the string (from
9010 str to s) to ret starting at rptr (the current offset). Then copy
9011 the replacement string at ret + rptr + (s - str). Increment
9012 rptr (if necessary) and str and go on. */
9013 if (l)
9014 {
9015 strncpy (ret + rptr, str, l);
9016 rptr += l;
9017 }
9018 if (replen)
9019 {
9020 strncpy (ret + rptr, rstr, rslen);
9021 rptr += rslen;
9022 }
9023 str = e; /* e == end of match */
9024
9025 if (rstr != rep)
9026 free (rstr);
9027
9028 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
9029 break;
9030
9031 if (s == e)
9032 {
9033 /* On a zero-length match, make sure we copy one character, since
9034 we increment one character to avoid infinite recursion. */
9035 char *p, *origp, *origs;
9036 size_t clen;
9037
9038 RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64);
9039 #if defined (HANDLE_MULTIBYTE)
9040 p = origp = ret + rptr;
9041 origs = str;
9042 COPY_CHAR_P (p, str, send);
9043 rptr += p - origp;
9044 e += str - origs;
9045 #else
9046 ret[rptr++] = *str++;
9047 e++; /* avoid infinite recursion on zero-length match */
9048 #endif
9049 }
9050 }
9051
9052 /* Now copy the unmatched portion of the input string */
9053 if (str && *str)
9054 {
9055 l = send - str + 1;
9056 RESIZE_MALLOCED_BUFFER (ret, rptr, l, rsize, 64);
9057 strcpy (ret + rptr, str);
9058 }
9059 else
9060 ret[rptr] = '\0';
9061
9062 return ret;
9063 }
9064
9065 /* Do pattern match and replacement on the positional parameters. */
9066 static char *
9067 pos_params_pat_subst (string, pat, rep, mflags)
9068 char *string, *pat, *rep;
9069 int mflags;
9070 {
9071 WORD_LIST *save, *params;
9072 WORD_DESC *w;
9073 char *ret;
9074 int pchar, qflags, pflags;
9075
9076 save = params = list_rest_of_args ();
9077 if (save == 0)
9078 return ((char *)NULL);
9079
9080 for ( ; params; params = params->next)
9081 {
9082 ret = pat_subst (params->word->word, pat, rep, mflags);
9083 w = alloc_word_desc ();
9084 w->word = ret ? ret : savestring ("");
9085 dispose_word (params->word);
9086 params->word = w;
9087 }
9088
9089 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
9090 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
9091 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
9092
9093 /* If we are expanding in a context where word splitting will not be
9094 performed, treat as quoted. This changes how $* will be expanded. */
9095 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null)
9096 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
9097
9098 ret = string_list_pos_params (pchar, save, qflags, pflags);
9099 dispose_words (save);
9100
9101 return (ret);
9102 }
9103
9104 /* Perform pattern substitution on VALUE, which is the expansion of
9105 VARNAME. PATSUB is an expression supplying the pattern to match
9106 and the string to substitute. QUOTED is a flags word containing
9107 the type of quoting currently in effect. */
9108 static char *
9109 parameter_brace_patsub (varname, value, estatep, patsub, quoted, pflags, flags)
9110 char *varname, *value;
9111 array_eltstate_t *estatep;
9112 char *patsub;
9113 int quoted, pflags, flags;
9114 {
9115 int vtype, mflags, starsub, delim;
9116 char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname;
9117 SHELL_VAR *v;
9118
9119 if (value == 0)
9120 return ((char *)NULL);
9121
9122 oname = this_command_name;
9123 this_command_name = varname; /* error messages */
9124
9125 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
9126 if (vtype == -1)
9127 {
9128 this_command_name = oname;
9129 return ((char *)NULL);
9130 }
9131
9132 starsub = vtype & VT_STARSUB;
9133 vtype &= ~VT_STARSUB;
9134
9135 mflags = 0;
9136 /* PATSUB is never NULL when this is called. */
9137 if (*patsub == '/')
9138 {
9139 mflags |= MATCH_GLOBREP;
9140 patsub++;
9141 }
9142
9143 /* Malloc this because expand_string_if_necessary or one of the expansion
9144 functions in its call chain may free it on a substitution error. */
9145 lpatsub = savestring (patsub);
9146
9147 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9148 mflags |= MATCH_QUOTED;
9149
9150 if (starsub)
9151 mflags |= MATCH_STARSUB;
9152
9153 if (pflags & PF_ASSIGNRHS)
9154 mflags |= MATCH_ASSIGNRHS;
9155
9156 /* If the pattern starts with a `/', make sure we skip over it when looking
9157 for the replacement delimiter. */
9158 delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
9159 if (lpatsub[delim] == '/')
9160 {
9161 lpatsub[delim] = 0;
9162 rep = lpatsub + delim + 1;
9163 }
9164 else
9165 rep = (char *)NULL;
9166
9167 if (rep && *rep == '\0')
9168 rep = (char *)NULL;
9169
9170 /* Perform the same expansions on the pattern as performed by the
9171 pattern removal expansions. */
9172 pat = getpattern (lpatsub, quoted, 1);
9173
9174 if (rep)
9175 {
9176 /* We want to perform quote removal on the expanded replacement even if
9177 the entire expansion is double-quoted because the parser and string
9178 extraction functions treated quotes in the replacement string as
9179 special. THIS IS NOT BACKWARDS COMPATIBLE WITH BASH-4.2. */
9180 if (shell_compatibility_level > 42 && patsub_replacement == 0)
9181 rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
9182 else if (shell_compatibility_level > 42 && patsub_replacement)
9183 rep = expand_string_for_patsub (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT));
9184 /* This is the bash-4.2 code. */
9185 else if ((mflags & MATCH_QUOTED) == 0)
9186 rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
9187 else
9188 rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
9189
9190 /* Check whether or not to replace `&' in the replacement string after
9191 expanding it, since we want to treat backslashes quoting the `&'
9192 consistently. */
9193 if (patsub_replacement && rep && *rep && shouldexp_replacement (rep))
9194 mflags |= MATCH_EXPREP;
9195
9196 }
9197
9198 /* ksh93 doesn't allow the match specifier to be a part of the expanded
9199 pattern. This is an extension. Make sure we don't anchor the pattern
9200 at the beginning or end of the string if we're doing global replacement,
9201 though. */
9202 p = pat;
9203 if (mflags & MATCH_GLOBREP)
9204 mflags |= MATCH_ANY;
9205 else if (pat && pat[0] == '#')
9206 {
9207 mflags |= MATCH_BEG;
9208 p++;
9209 }
9210 else if (pat && pat[0] == '%')
9211 {
9212 mflags |= MATCH_END;
9213 p++;
9214 }
9215 else
9216 mflags |= MATCH_ANY;
9217
9218 /* OK, we now want to substitute REP for PAT in VAL. If
9219 flags & MATCH_GLOBREP is non-zero, the substitution is done
9220 everywhere, otherwise only the first occurrence of PAT is
9221 replaced. The pattern matching code doesn't understand
9222 CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
9223 values passed in (VT_VARIABLE) so the pattern substitution
9224 code works right. We need to requote special chars after
9225 we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
9226 other cases if QUOTED == 0, since the posparams and arrays
9227 indexed by * or @ do special things when QUOTED != 0. */
9228
9229 switch (vtype)
9230 {
9231 case VT_VARIABLE:
9232 case VT_ARRAYMEMBER:
9233 temp = pat_subst (val, p, rep, mflags);
9234 if (vtype == VT_VARIABLE)
9235 FREE (val);
9236 if (temp)
9237 {
9238 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
9239 free (temp);
9240 temp = tt;
9241 }
9242 break;
9243 case VT_POSPARMS:
9244 /* This does the right thing for the case where we are not performing
9245 word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and
9246 pos_params_pat_subst/string_list_pos_params will do the right thing
9247 in turn for the case where ifs_is_null. Posix interp 888 */
9248 if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB))
9249 mflags |= MATCH_ASSIGNRHS;
9250 temp = pos_params_pat_subst (val, p, rep, mflags);
9251 if (temp && quoted == 0 && ifs_is_null)
9252 {
9253 /* Posix interp 888 */
9254 }
9255 else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS))
9256 {
9257 /* Posix interp 888 */
9258 }
9259 else if (temp && (mflags & MATCH_QUOTED) == 0)
9260 {
9261 tt = quote_escapes (temp);
9262 free (temp);
9263 temp = tt;
9264 }
9265 break;
9266 #if defined (ARRAY_VARS)
9267 case VT_ARRAYVAR:
9268 /* If we are expanding in a context where word splitting will not be
9269 performed, treat as quoted. This changes how ${A[*]} will be
9270 expanded to make it identical to $*. */
9271 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9272 mflags |= MATCH_QUOTED; /* Posix interp 888 */
9273
9274 /* these eventually call string_list_pos_params */
9275 if (assoc_p (v))
9276 temp = assoc_patsub (assoc_cell (v), p, rep, mflags);
9277 else
9278 temp = array_patsub (array_cell (v), p, rep, mflags);
9279
9280 if (temp && quoted == 0 && ifs_is_null)
9281 {
9282 /* Posix interp 888 */
9283 }
9284 else if (temp && (mflags & MATCH_QUOTED) == 0)
9285 {
9286 tt = quote_escapes (temp);
9287 free (temp);
9288 temp = tt;
9289 }
9290 break;
9291 #endif
9292 }
9293
9294 FREE (pat);
9295 FREE (rep);
9296 free (lpatsub);
9297
9298 this_command_name = oname;
9299
9300 return temp;
9301 }
9302
9303 /****************************************************************/
9304 /* */
9305 /* Functions to perform case modification on variable values */
9306 /* */
9307 /****************************************************************/
9308
9309 /* Do case modification on the positional parameters. */
9310
9311 static char *
9312 pos_params_modcase (string, pat, modop, mflags)
9313 char *string, *pat;
9314 int modop;
9315 int mflags;
9316 {
9317 WORD_LIST *save, *params;
9318 WORD_DESC *w;
9319 char *ret;
9320 int pchar, qflags, pflags;
9321
9322 save = params = list_rest_of_args ();
9323 if (save == 0)
9324 return ((char *)NULL);
9325
9326 for ( ; params; params = params->next)
9327 {
9328 ret = sh_modcase (params->word->word, pat, modop);
9329 w = alloc_word_desc ();
9330 w->word = ret ? ret : savestring ("");
9331 dispose_word (params->word);
9332 params->word = w;
9333 }
9334
9335 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
9336 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
9337 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
9338
9339 /* If we are expanding in a context where word splitting will not be
9340 performed, treat as quoted. This changes how $* will be expanded. */
9341 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9342 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
9343
9344 ret = string_list_pos_params (pchar, save, qflags, pflags);
9345 dispose_words (save);
9346
9347 return (ret);
9348 }
9349
9350 /* Perform case modification on VALUE, which is the expansion of
9351 VARNAME. MODSPEC is an expression supplying the type of modification
9352 to perform. QUOTED is a flags word containing the type of quoting
9353 currently in effect. */
9354 static char *
9355 parameter_brace_casemod (varname, value, estatep, modspec, patspec, quoted, pflags, flags)
9356 char *varname, *value;
9357 array_eltstate_t *estatep;
9358 int modspec;
9359 char *patspec;
9360 int quoted, pflags, flags;
9361 {
9362 int vtype, starsub, modop, mflags, x;
9363 char *val, *temp, *pat, *p, *lpat, *tt, *oname;
9364 SHELL_VAR *v;
9365
9366 if (value == 0)
9367 return ((char *)NULL);
9368
9369 oname = this_command_name;
9370 this_command_name = varname;
9371
9372 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
9373 if (vtype == -1)
9374 {
9375 this_command_name = oname;
9376 return ((char *)NULL);
9377 }
9378
9379 starsub = vtype & VT_STARSUB;
9380 vtype &= ~VT_STARSUB;
9381
9382 modop = 0;
9383 mflags = 0;
9384 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9385 mflags |= MATCH_QUOTED;
9386 if (starsub)
9387 mflags |= MATCH_STARSUB;
9388 if (pflags & PF_ASSIGNRHS)
9389 mflags |= MATCH_ASSIGNRHS;
9390
9391 p = patspec;
9392 if (modspec == '^')
9393 {
9394 x = p && p[0] == modspec;
9395 modop = x ? CASE_UPPER : CASE_UPFIRST;
9396 p += x;
9397 }
9398 else if (modspec == ',')
9399 {
9400 x = p && p[0] == modspec;
9401 modop = x ? CASE_LOWER : CASE_LOWFIRST;
9402 p += x;
9403 }
9404 else if (modspec == '~')
9405 {
9406 x = p && p[0] == modspec;
9407 modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
9408 p += x;
9409 }
9410
9411 lpat = p ? savestring (p) : 0;
9412 /* Perform the same expansions on the pattern as performed by the
9413 pattern removal expansions. */
9414 pat = lpat ? getpattern (lpat, quoted, 1) : 0;
9415
9416 /* OK, now we do the case modification. */
9417 switch (vtype)
9418 {
9419 case VT_VARIABLE:
9420 case VT_ARRAYMEMBER:
9421 temp = sh_modcase (val, pat, modop);
9422 if (vtype == VT_VARIABLE)
9423 FREE (val);
9424 if (temp)
9425 {
9426 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
9427 free (temp);
9428 temp = tt;
9429 }
9430 break;
9431
9432 case VT_POSPARMS:
9433 temp = pos_params_modcase (val, pat, modop, mflags);
9434 if (temp && quoted == 0 && ifs_is_null)
9435 {
9436 /* Posix interp 888 */
9437 }
9438 else if (temp && (mflags & MATCH_QUOTED) == 0)
9439 {
9440 tt = quote_escapes (temp);
9441 free (temp);
9442 temp = tt;
9443 }
9444 break;
9445
9446 #if defined (ARRAY_VARS)
9447 case VT_ARRAYVAR:
9448 /* If we are expanding in a context where word splitting will not be
9449 performed, treat as quoted. This changes how ${A[*]} will be
9450 expanded to make it identical to $*. */
9451 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9452 mflags |= MATCH_QUOTED; /* Posix interp 888 */
9453
9454 temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
9455 : array_modcase (array_cell (v), pat, modop, mflags);
9456
9457 if (temp && quoted == 0 && ifs_is_null)
9458 {
9459 /* Posix interp 888 */
9460 }
9461 else if (temp && (mflags & MATCH_QUOTED) == 0)
9462 {
9463 tt = quote_escapes (temp);
9464 free (temp);
9465 temp = tt;
9466 }
9467
9468 break;
9469 #endif
9470 }
9471
9472 FREE (pat);
9473 free (lpat);
9474
9475 this_command_name = oname;
9476
9477 return temp;
9478 }
9479
9480 /* Check for unbalanced parens in S, which is the contents of $(( ... )). If
9481 any occur, this must be a nested command substitution, so return 0.
9482 Otherwise, return 1. A valid arithmetic expression must always have a
9483 ( before a matching ), so any cases where there are more right parens
9484 means that this must not be an arithmetic expression, though the parser
9485 will not accept it without a balanced total number of parens. */
9486 static int
9487 chk_arithsub (s, len)
9488 const char *s;
9489 int len;
9490 {
9491 int i, count;
9492 DECLARE_MBSTATE;
9493
9494 i = count = 0;
9495 while (i < len)
9496 {
9497 if (s[i] == LPAREN)
9498 count++;
9499 else if (s[i] == RPAREN)
9500 {
9501 count--;
9502 if (count < 0)
9503 return 0;
9504 }
9505
9506 switch (s[i])
9507 {
9508 default:
9509 ADVANCE_CHAR (s, len, i);
9510 break;
9511
9512 case '\\':
9513 i++;
9514 if (s[i])
9515 ADVANCE_CHAR (s, len, i);
9516 break;
9517
9518 case '\'':
9519 i = skip_single_quoted (s, len, ++i, 0);
9520 break;
9521
9522 case '"':
9523 i = skip_double_quoted ((char *)s, len, ++i, 0);
9524 break;
9525 }
9526 }
9527
9528 return (count == 0);
9529 }
9530
9531 /****************************************************************/
9532 /* */
9533 /* Functions to perform parameter expansion on a string */
9534 /* */
9535 /****************************************************************/
9536
9537 /* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
9538 static WORD_DESC *
9539 parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
9540 char *string;
9541 int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at;
9542 {
9543 int check_nullness, var_is_set, var_is_null, var_is_special;
9544 int want_substring, want_indir, want_patsub, want_casemod, want_attributes;
9545 char *name, *value, *temp, *temp1;
9546 WORD_DESC *tdesc, *ret;
9547 int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref;
9548 intmax_t number;
9549 array_eltstate_t es;
9550
9551 temp = temp1 = value = (char *)NULL;
9552 var_is_set = var_is_null = var_is_special = check_nullness = 0;
9553 want_substring = want_indir = want_patsub = want_casemod = want_attributes = 0;
9554
9555 local_pflags = 0;
9556 all_element_arrayref = 0;
9557
9558 sindex = *indexp;
9559 t_index = ++sindex;
9560 /* ${#var} doesn't have any of the other parameter expansions on it. */
9561 if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
9562 name = string_extract (string, &t_index, "}", SX_VARNAME);
9563 else
9564 #if defined (CASEMOD_EXPANSIONS)
9565 /* To enable case-toggling expansions using the `~' operator character
9566 define CASEMOD_TOGGLECASE in config-top.h */
9567 # if defined (CASEMOD_TOGGLECASE)
9568 name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME);
9569 # else
9570 name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME);
9571 # endif /* CASEMOD_TOGGLECASE */
9572 #else
9573 name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME);
9574 #endif /* CASEMOD_EXPANSIONS */
9575
9576 /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly
9577 the cleanest code ever. */
9578 if (*name == 0 && sindex == t_index && string[sindex] == '@')
9579 {
9580 name = (char *)xrealloc (name, 2);
9581 name[0] = '@';
9582 name[1] = '\0';
9583 t_index++;
9584 }
9585 else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE)
9586 {
9587 name = (char *)xrealloc (name, t_index - sindex + 2);
9588 name[t_index - sindex] = '@';
9589 name[t_index - sindex + 1] = '\0';
9590 t_index++;
9591 }
9592
9593 ret = 0;
9594 tflag = 0;
9595
9596 #if defined (ARRAY_VARS)
9597 init_eltstate (&es);
9598 #endif
9599 es.ind = INTMAX_MIN; /* XXX */
9600
9601 /* If the name really consists of a special variable, then make sure
9602 that we have the entire name. We don't allow indirect references
9603 to special variables except `#', `?', `@' and `*'. This clause is
9604 designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more
9605 general. */
9606 if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
9607 (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) ||
9608 (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
9609 {
9610 t_index++;
9611 temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0);
9612 name = (char *)xrealloc (name, 3 + (strlen (temp1)));
9613 *name = string[sindex];
9614 if (string[sindex] == '!')
9615 {
9616 /* indirect reference of $#, $?, $@, or $* */
9617 name[1] = string[sindex + 1];
9618 strcpy (name + 2, temp1);
9619 }
9620 else
9621 strcpy (name + 1, temp1);
9622 free (temp1);
9623 }
9624 sindex = t_index;
9625
9626 /* Find out what character ended the variable name. Then
9627 do the appropriate thing. */
9628 if (c = string[sindex])
9629 sindex++;
9630
9631 /* If c is followed by one of the valid parameter expansion
9632 characters, move past it as normal. If not, assume that
9633 a substring specification is being given, and do not move
9634 past it. */
9635 if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
9636 {
9637 check_nullness++;
9638 if (c = string[sindex])
9639 sindex++;
9640 }
9641 else if (c == ':' && string[sindex] != RBRACE)
9642 want_substring = 1;
9643 else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */
9644 want_patsub = 1;
9645 #if defined (CASEMOD_EXPANSIONS)
9646 else if (c == '^' || c == ',' || c == '~')
9647 {
9648 modspec = c;
9649 want_casemod = 1;
9650 }
9651 #endif
9652 else if (c == '@' && (string[sindex] == 'a' || string[sindex] == 'A') && string[sindex+1] == RBRACE)
9653 {
9654 /* special case because we do not want to shortcut foo as foo[0] here */
9655 want_attributes = 1;
9656 local_pflags |= PF_ALLINDS;
9657 }
9658
9659 /* Catch the valid and invalid brace expressions that made it through the
9660 tests above. */
9661 /* ${#-} is a valid expansion and means to take the length of $-.
9662 Similarly for ${#?} and ${##}... */
9663 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
9664 VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
9665 {
9666 name = (char *)xrealloc (name, 3);
9667 name[1] = c;
9668 name[2] = '\0';
9669 c = string[sindex++];
9670 }
9671
9672 /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
9673 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
9674 member (c, "%:=+/") && string[sindex] == RBRACE)
9675 {
9676 temp = (char *)NULL;
9677 goto bad_substitution; /* XXX - substitution error */
9678 }
9679
9680 /* Indirect expansion begins with a `!'. A valid indirect expansion is
9681 either a variable name, one of the positional parameters or a special
9682 variable that expands to one of the positional parameters. */
9683 want_indir = *name == '!' &&
9684 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
9685 || VALID_INDIR_PARAM (name[1]));
9686
9687 /* Determine the value of this variable whose name is NAME. */
9688
9689 /* Check for special variables, directly referenced. */
9690 if (SPECIAL_VAR (name, want_indir))
9691 var_is_special++;
9692
9693 /* Check for special expansion things, like the length of a parameter */
9694 if (*name == '#' && name[1])
9695 {
9696 /* If we are not pointing at the character just after the
9697 closing brace, then we haven't gotten all of the name.
9698 Since it begins with a special character, this is a bad
9699 substitution. Also check NAME for validity before trying
9700 to go on. */
9701 if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
9702 {
9703 temp = (char *)NULL;
9704 goto bad_substitution; /* substitution error */
9705 }
9706
9707 number = parameter_brace_expand_length (name);
9708 if (number == INTMAX_MIN && unbound_vars_is_error)
9709 {
9710 set_exit_status (EXECUTION_FAILURE);
9711 err_unboundvar (name+1);
9712 free (name);
9713 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9714 }
9715 free (name);
9716
9717 *indexp = sindex;
9718 if (number < 0)
9719 return (&expand_wdesc_error);
9720 else
9721 {
9722 ret = alloc_word_desc ();
9723 ret->word = itos (number);
9724 return ret;
9725 }
9726 }
9727
9728 /* ${@} is identical to $@. */
9729 if (name[0] == '@' && name[1] == '\0')
9730 {
9731 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9732 *quoted_dollar_atp = 1;
9733
9734 if (contains_dollar_at)
9735 *contains_dollar_at = 1;
9736
9737 tflag |= W_DOLLARAT;
9738 }
9739
9740 /* Process ${!PREFIX*} expansion. */
9741 if (want_indir && string[sindex - 1] == RBRACE &&
9742 (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
9743 legal_variable_starter ((unsigned char) name[1]))
9744 {
9745 char **x;
9746 WORD_LIST *xlist;
9747
9748 temp1 = savestring (name + 1);
9749 number = strlen (temp1);
9750 temp1[number - 1] = '\0';
9751 x = all_variables_matching_prefix (temp1);
9752 xlist = strvec_to_word_list (x, 0, 0);
9753 if (string[sindex - 2] == '*')
9754 temp = string_list_dollar_star (xlist, quoted, 0);
9755 else
9756 {
9757 temp = string_list_dollar_at (xlist, quoted, 0);
9758 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9759 *quoted_dollar_atp = 1;
9760 if (contains_dollar_at)
9761 *contains_dollar_at = 1;
9762
9763 tflag |= W_DOLLARAT;
9764 }
9765 free (x);
9766 dispose_words (xlist);
9767 free (temp1);
9768 *indexp = sindex;
9769
9770 free (name);
9771
9772 ret = alloc_word_desc ();
9773 ret->word = temp;
9774 ret->flags = tflag; /* XXX */
9775 return ret;
9776 }
9777
9778 #if defined (ARRAY_VARS)
9779 /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */
9780 if (want_indir && string[sindex - 1] == RBRACE &&
9781 string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0))
9782 {
9783 char *x, *x1;
9784
9785 temp1 = savestring (name + 1);
9786 x = array_variable_name (temp1, 0, &x1, (int *)0);
9787 FREE (x);
9788 if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK)
9789 {
9790 temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */
9791 if (x1[0] == '@')
9792 {
9793 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9794 *quoted_dollar_atp = 1;
9795 if (contains_dollar_at)
9796 *contains_dollar_at = 1;
9797
9798 tflag |= W_DOLLARAT;
9799 }
9800
9801 free (name);
9802 free (temp1);
9803 *indexp = sindex;
9804
9805 ret = alloc_word_desc ();
9806 ret->word = temp;
9807 ret->flags = tflag; /* XXX */
9808 return ret;
9809 }
9810
9811 free (temp1);
9812 }
9813 #endif /* ARRAY_VARS */
9814
9815 /* Make sure that NAME is valid before trying to go on. */
9816 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
9817 var_is_special) == 0)
9818 {
9819 temp = (char *)NULL;
9820 goto bad_substitution; /* substitution error */
9821 }
9822
9823 if (want_indir)
9824 {
9825 tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags|local_pflags, quoted_dollar_atp, contains_dollar_at);
9826 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9827 {
9828 temp = (char *)NULL;
9829 goto bad_substitution;
9830 }
9831
9832 /* Turn off the W_ARRAYIND flag because there is no way for this function
9833 to return the index we're supposed to be using. */
9834 if (tdesc && tdesc->flags)
9835 tdesc->flags &= ~W_ARRAYIND;
9836
9837 /* If the indir expansion contains $@/$*, extend the special treatment
9838 of the case of no positional parameters and `set -u' to it. */
9839 if (contains_dollar_at && *contains_dollar_at)
9840 all_element_arrayref = 1;
9841 }
9842 else
9843 {
9844 local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS));
9845 tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &es);
9846 }
9847
9848 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9849 {
9850 tflag = 0;
9851 tdesc = 0;
9852 }
9853
9854 if (tdesc)
9855 {
9856 temp = tdesc->word;
9857 tflag = tdesc->flags;
9858 dispose_word_desc (tdesc);
9859 }
9860 else
9861 temp = (char *)0;
9862
9863 if (temp == &expand_param_error || temp == &expand_param_fatal)
9864 {
9865 FREE (name);
9866 FREE (value);
9867 return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9868 }
9869
9870 #if defined (ARRAY_VARS)
9871 if (valid_array_reference (name, 0))
9872 {
9873 int qflags;
9874 char *t;
9875
9876 qflags = quoted;
9877 /* If in a context where word splitting will not take place, treat as
9878 if double-quoted. Has effects with $* and ${array[*]} */
9879
9880 if (pflags & PF_ASSIGNRHS)
9881 qflags |= Q_DOUBLE_QUOTES;
9882 /* We duplicate a little code here */
9883 t = mbschr (name, LBRACK);
9884 if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK)
9885 {
9886 all_element_arrayref = 1;
9887 if (expand_no_split_dollar_star && t[1] == '*') /* XXX */
9888 qflags |= Q_DOUBLE_QUOTES;
9889 }
9890 chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at);
9891 }
9892 #endif
9893
9894 var_is_set = temp != (char *)0;
9895 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
9896 /* XXX - this may not need to be restricted to special variables */
9897 if (check_nullness)
9898 var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp);
9899 #if defined (ARRAY_VARS)
9900 if (check_nullness)
9901 var_is_null |= var_is_set &&
9902 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) &&
9903 QUOTED_NULL (temp) &&
9904 valid_array_reference (name, 0) &&
9905 chk_atstar (name, 0, 0, (int *)0, (int *)0);
9906 #endif
9907
9908 /* Get the rest of the stuff inside the braces. */
9909 if (c && c != RBRACE)
9910 {
9911 /* Extract the contents of the ${ ... } expansion
9912 according to the Posix.2 rules. */
9913 value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
9914 if (string[sindex] == RBRACE)
9915 sindex++;
9916 else
9917 goto bad_substitution; /* substitution error */
9918 }
9919 else
9920 value = (char *)NULL;
9921
9922 *indexp = sindex;
9923
9924 /* All the cases where an expansion can possibly generate an unbound
9925 variable error. */
9926 if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE)
9927 {
9928 if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0)
9929 {
9930 set_exit_status (EXECUTION_FAILURE);
9931 err_unboundvar (name);
9932 FREE (value);
9933 FREE (temp);
9934 free (name);
9935 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9936 }
9937 }
9938
9939 /* If this is a substring spec, process it and add the result. */
9940 if (want_substring)
9941 {
9942 temp1 = parameter_brace_substring (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9943 FREE (value);
9944 FREE (temp);
9945 #if defined (ARRAY_VARS)
9946 flush_eltstate (&es);
9947 #endif
9948
9949 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9950 {
9951 FREE (name);
9952 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9953 }
9954
9955 ret = alloc_word_desc ();
9956 ret->word = temp1;
9957 /* We test quoted_dollar_atp because we want variants with double-quoted
9958 "$@" to take a different code path. In fact, we make sure at the end
9959 of expand_word_internal that we're only looking at these flags if
9960 quoted_dollar_at == 0. */
9961 if (temp1 &&
9962 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9963 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9964 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9965 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 &&
9966 (pflags & PF_ASSIGNRHS))
9967 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9968 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9969 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9970 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9971
9972 FREE (name);
9973 return ret;
9974 }
9975 else if (want_patsub)
9976 {
9977 temp1 = parameter_brace_patsub (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9978 FREE (value);
9979 FREE (temp);
9980 #if defined (ARRAY_VARS)
9981 flush_eltstate (&es);
9982 #endif
9983
9984 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9985 {
9986 FREE (name);
9987 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9988 }
9989
9990 ret = alloc_word_desc ();
9991 ret->word = temp1;
9992 if (temp1 &&
9993 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9994 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9995 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9996 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9997 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9998 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9999
10000 FREE (name);
10001 return ret;
10002 }
10003 #if defined (CASEMOD_EXPANSIONS)
10004 else if (want_casemod)
10005 {
10006 temp1 = parameter_brace_casemod (name, temp, &es, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
10007 FREE (value);
10008 FREE (temp);
10009 #if defined (ARRAY_VARS)
10010 flush_eltstate (&es);
10011 #endif
10012
10013 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
10014 {
10015 FREE (name);
10016 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
10017 }
10018
10019 ret = alloc_word_desc ();
10020 ret->word = temp1;
10021 if (temp1 &&
10022 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
10023 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10024 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
10025 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10026 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10027 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10028
10029 FREE (name);
10030 return ret;
10031 }
10032 #endif
10033
10034 /* Do the right thing based on which character ended the variable name. */
10035 switch (c)
10036 {
10037 default:
10038 case '\0':
10039 bad_substitution:
10040 set_exit_status (EXECUTION_FAILURE);
10041 report_error (_("%s: bad substitution"), string ? string : "??");
10042 FREE (value);
10043 FREE (temp);
10044 free (name);
10045 #if defined (ARRAY_VARS)
10046 flush_eltstate (&es);
10047 #endif
10048 if (shell_compatibility_level <= 43)
10049 return &expand_wdesc_error;
10050 else
10051 return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error);
10052
10053 case RBRACE:
10054 break;
10055
10056 case '@':
10057 temp1 = parameter_brace_transform (name, temp, &es, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
10058 free (temp);
10059 free (value);
10060 #if defined (ARRAY_VARS)
10061 flush_eltstate (&es);
10062 #endif
10063
10064 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
10065 {
10066 free (name);
10067 set_exit_status (EXECUTION_FAILURE);
10068 report_error (_("%s: bad substitution"), string ? string : "??");
10069 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
10070 }
10071
10072 ret = alloc_word_desc ();
10073 ret->word = temp1;
10074 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10075 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
10076 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10077 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10078 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10079
10080 free (name);
10081 return ret;
10082
10083 case '#': /* ${param#[#]pattern} */
10084 case '%': /* ${param%[%]pattern} */
10085 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
10086 {
10087 FREE (value);
10088 break;
10089 }
10090 temp1 = parameter_brace_remove_pattern (name, temp, &es, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
10091 free (temp);
10092 free (value);
10093 #if defined (ARRAY_VARS)
10094 flush_eltstate (&es);
10095 #endif
10096
10097 ret = alloc_word_desc ();
10098 ret->word = temp1;
10099 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10100 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
10101 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10102 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10103 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10104
10105 free (name);
10106 return ret;
10107
10108 case '-':
10109 case '=':
10110 case '?':
10111 case '+':
10112 if (var_is_set && var_is_null == 0)
10113 {
10114 /* If the operator is `+', we don't want the value of the named
10115 variable for anything, just the value of the right hand side. */
10116 if (c == '+')
10117 {
10118 /* XXX -- if we're double-quoted and the named variable is "$@",
10119 we want to turn off any special handling of "$@" --
10120 we're not using it, so whatever is on the rhs applies. */
10121 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
10122 *quoted_dollar_atp = 0;
10123 if (contains_dollar_at)
10124 *contains_dollar_at = 0;
10125
10126 FREE (temp);
10127 if (value)
10128 {
10129 /* From Posix discussion on austin-group list. Issue 221
10130 requires that backslashes escaping `}' inside
10131 double-quoted ${...} be removed. */
10132 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10133 quoted |= Q_DOLBRACE;
10134 ret = parameter_brace_expand_rhs (name, value, c,
10135 quoted,
10136 pflags,
10137 quoted_dollar_atp,
10138 contains_dollar_at);
10139 /* XXX - fix up later, esp. noting presence of
10140 W_HASQUOTEDNULL in ret->flags */
10141 free (value);
10142 }
10143 else
10144 temp = (char *)NULL;
10145 }
10146 else
10147 {
10148 FREE (value);
10149 }
10150 /* Otherwise do nothing; just use the value in TEMP. */
10151 }
10152 else /* VAR not set or VAR is NULL. */
10153 {
10154 /* If we're freeing a quoted null here, we need to remember we saw
10155 it so we can restore it later if needed, or the caller can note it.
10156 The check against `+' doesn't really matter, since the other cases
10157 don't use or return TFLAG, but it's good for clarity. */
10158 if (c == '+' && temp && QUOTED_NULL (temp) &&
10159 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
10160 tflag |= W_HASQUOTEDNULL;
10161
10162 FREE (temp);
10163 temp = (char *)NULL;
10164 if (c == '=' && var_is_special)
10165 {
10166 set_exit_status (EXECUTION_FAILURE);
10167 report_error (_("$%s: cannot assign in this way"), name);
10168 free (name);
10169 free (value);
10170 #if defined (ARRAY_VARS)
10171 flush_eltstate (&es);
10172 #endif
10173 return &expand_wdesc_error;
10174 }
10175 else if (c == '?')
10176 {
10177 parameter_brace_expand_error (name, value, check_nullness);
10178 #if defined (ARRAY_VARS)
10179 flush_eltstate (&es);
10180 #endif
10181 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10182 }
10183 else if (c != '+')
10184 {
10185 /* XXX -- if we're double-quoted and the named variable is "$@",
10186 we want to turn off any special handling of "$@" --
10187 we're not using it, so whatever is on the rhs applies. */
10188 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
10189 *quoted_dollar_atp = 0;
10190 if (contains_dollar_at)
10191 *contains_dollar_at = 0;
10192
10193 /* From Posix discussion on austin-group list. Issue 221 requires
10194 that backslashes escaping `}' inside double-quoted ${...} be
10195 removed. */
10196 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10197 quoted |= Q_DOLBRACE;
10198 ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags,
10199 quoted_dollar_atp,
10200 contains_dollar_at);
10201 /* XXX - fix up later, esp. noting presence of
10202 W_HASQUOTEDNULL in tdesc->flags */
10203 }
10204 free (value);
10205 }
10206
10207 break;
10208 }
10209 free (name);
10210 #if defined (ARRAY_VARS)
10211 flush_eltstate (&es);
10212 #endif
10213
10214 if (ret == 0)
10215 {
10216 ret = alloc_word_desc ();
10217 ret->flags = tflag;
10218 ret->word = temp;
10219 }
10220 return (ret);
10221 }
10222
10223 /* Expand a single ${xxx} expansion. The braces are optional. When
10224 the braces are used, parameter_brace_expand() does the work,
10225 possibly calling param_expand recursively. */
10226 static WORD_DESC *
10227 param_expand (string, sindex, quoted, expanded_something,
10228 contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
10229 pflags)
10230 char *string;
10231 int *sindex, quoted, *expanded_something, *contains_dollar_at;
10232 int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
10233 {
10234 char *temp, *temp1, uerror[3], *savecmd;
10235 int zindex, t_index, expok, eflag;
10236 unsigned char c;
10237 intmax_t number;
10238 SHELL_VAR *var;
10239 WORD_LIST *list, *l;
10240 WORD_DESC *tdesc, *ret;
10241 int tflag, nullarg;
10242
10243 /*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/
10244 zindex = *sindex;
10245 c = string[++zindex];
10246
10247 temp = (char *)NULL;
10248 ret = tdesc = (WORD_DESC *)NULL;
10249 tflag = 0;
10250
10251 /* Do simple cases first. Switch on what follows '$'. */
10252 switch (c)
10253 {
10254 /* $0 .. $9? */
10255 case '0':
10256 case '1':
10257 case '2':
10258 case '3':
10259 case '4':
10260 case '5':
10261 case '6':
10262 case '7':
10263 case '8':
10264 case '9':
10265 temp1 = dollar_vars[TODIGIT (c)];
10266 /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */
10267 if (unbound_vars_is_error && temp1 == (char *)NULL)
10268 {
10269 uerror[0] = '$';
10270 uerror[1] = c;
10271 uerror[2] = '\0';
10272 set_exit_status (EXECUTION_FAILURE);
10273 err_unboundvar (uerror);
10274 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10275 }
10276 if (temp1)
10277 temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10278 ? quote_string (temp1)
10279 : quote_escapes (temp1);
10280 else
10281 temp = (char *)NULL;
10282
10283 break;
10284
10285 /* $$ -- pid of the invoking shell. */
10286 case '$':
10287 temp = itos (dollar_dollar_pid);
10288 break;
10289
10290 /* $# -- number of positional parameters. */
10291 case '#':
10292 temp = itos (number_of_args ());
10293 break;
10294
10295 /* $? -- return value of the last synchronous command. */
10296 case '?':
10297 temp = itos (last_command_exit_value);
10298 break;
10299
10300 /* $- -- flags supplied to the shell on invocation or by `set'. */
10301 case '-':
10302 temp = which_set_flags ();
10303 break;
10304
10305 /* $! -- Pid of the last asynchronous command. */
10306 case '!':
10307 /* If no asynchronous pids have been created, expand to nothing.
10308 If `set -u' has been executed, and no async processes have
10309 been created, this is an expansion error. */
10310 if (last_asynchronous_pid == NO_PID)
10311 {
10312 if (expanded_something)
10313 *expanded_something = 0;
10314 temp = (char *)NULL;
10315 if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
10316 {
10317 uerror[0] = '$';
10318 uerror[1] = c;
10319 uerror[2] = '\0';
10320 set_exit_status (EXECUTION_FAILURE);
10321 err_unboundvar (uerror);
10322 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10323 }
10324 }
10325 else
10326 temp = itos (last_asynchronous_pid);
10327 break;
10328
10329 /* The only difference between this and $@ is when the arg is quoted. */
10330 case '*': /* `$*' */
10331 list = list_rest_of_args ();
10332
10333 #if 0
10334 /* According to austin-group posix proposal by Geoff Clare in
10335 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
10336
10337 "The shell shall write a message to standard error and
10338 immediately exit when it tries to expand an unset parameter
10339 other than the '@' and '*' special parameters."
10340 */
10341
10342 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
10343 {
10344 uerror[0] = '$';
10345 uerror[1] = '*';
10346 uerror[2] = '\0';
10347 set_exit_status (EXECUTION_FAILURE);
10348 err_unboundvar (uerror);
10349 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10350 }
10351 #endif
10352
10353 /* If there are no command-line arguments, this should just
10354 disappear if there are other characters in the expansion,
10355 even if it's quoted. */
10356 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
10357 temp = (char *)NULL;
10358 else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
10359 {
10360 /* If we have "$*" we want to make a string of the positional
10361 parameters, separated by the first character of $IFS, and
10362 quote the whole string, including the separators. If IFS
10363 is unset, the parameters are separated by ' '; if $IFS is
10364 null, the parameters are concatenated. */
10365 temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list);
10366 if (temp)
10367 {
10368 temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp;
10369 if (*temp == 0)
10370 tflag |= W_HASQUOTEDNULL;
10371 if (temp != temp1)
10372 free (temp);
10373 temp = temp1;
10374 }
10375 }
10376 else
10377 {
10378 /* We check whether or not we're eventually going to split $* here,
10379 for example when IFS is empty and we are processing the rhs of
10380 an assignment statement. In that case, we don't separate the
10381 arguments at all. Otherwise, if the $* is not quoted it is
10382 identical to $@ */
10383 if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS))
10384 {
10385 /* Posix interp 888: RHS of assignment, IFS unset: no splitting,
10386 separate with space */
10387 temp1 = string_list_dollar_star (list, quoted, pflags);
10388 temp = temp1 ? quote_string (temp1) : temp1;
10389 /* XXX - tentative - note that we saw a quoted null here */
10390 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
10391 tflag |= W_SAWQUOTEDNULL;
10392 FREE (temp1);
10393 }
10394 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS))
10395 {
10396 /* Posix interp 888: RHS of assignment, IFS set to '' */
10397 temp1 = string_list_dollar_star (list, quoted, pflags);
10398 temp = temp1 ? quote_escapes (temp1) : temp1;
10399 FREE (temp1);
10400 }
10401 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS))
10402 {
10403 /* Posix interp 888: RHS of assignment, IFS set to non-null value */
10404 temp1 = string_list_dollar_star (list, quoted, pflags);
10405 temp = temp1 ? quote_string (temp1) : temp1;
10406
10407 /* XXX - tentative - note that we saw a quoted null here */
10408 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
10409 tflag |= W_SAWQUOTEDNULL;
10410 FREE (temp1);
10411 }
10412 /* XXX - should we check ifs_is_set here as well? */
10413 # if defined (HANDLE_MULTIBYTE)
10414 else if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
10415 # else
10416 else if (expand_no_split_dollar_star && ifs_firstc == 0)
10417 # endif
10418 /* Posix interp 888: not RHS, no splitting, IFS set to '' */
10419 temp = string_list_dollar_star (list, quoted, 0);
10420 else
10421 {
10422 temp = string_list_dollar_at (list, quoted, 0);
10423 /* Set W_SPLITSPACE to make sure the individual positional
10424 parameters are split into separate arguments */
10425 #if 0
10426 if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null))
10427 #else /* change with bash-5.0 */
10428 if (quoted == 0 && ifs_is_null)
10429 #endif
10430 tflag |= W_SPLITSPACE;
10431 /* If we're not quoted but we still don't want word splitting, make
10432 we quote the IFS characters to protect them from splitting (e.g.,
10433 when $@ is in the string as well). */
10434 else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS))
10435 {
10436 temp1 = quote_string (temp);
10437 free (temp);
10438 temp = temp1;
10439 }
10440 }
10441
10442 if (expand_no_split_dollar_star == 0 && contains_dollar_at)
10443 *contains_dollar_at = 1;
10444 }
10445
10446 dispose_words (list);
10447 break;
10448
10449 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
10450 means that we have to turn quoting off after we split into
10451 the individually quoted arguments so that the final split
10452 on the first character of $IFS is still done. */
10453 case '@': /* `$@' */
10454 list = list_rest_of_args ();
10455
10456 #if 0
10457 /* According to austin-group posix proposal by Geoff Clare in
10458 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
10459
10460 "The shell shall write a message to standard error and
10461 immediately exit when it tries to expand an unset parameter
10462 other than the '@' and '*' special parameters."
10463 */
10464
10465 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
10466 {
10467 uerror[0] = '$';
10468 uerror[1] = '@';
10469 uerror[2] = '\0';
10470 set_exit_status (EXECUTION_FAILURE);
10471 err_unboundvar (uerror);
10472 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10473 }
10474 #endif
10475
10476 for (nullarg = 0, l = list; l; l = l->next)
10477 {
10478 if (l->word && (l->word->word == 0 || l->word->word[0] == 0))
10479 nullarg = 1;
10480 }
10481
10482 /* We want to flag the fact that we saw this. We can't turn
10483 off quoting entirely, because other characters in the
10484 string might need it (consider "\"$@\""), but we need some
10485 way to signal that the final split on the first character
10486 of $IFS should be done, even though QUOTED is 1. */
10487 /* XXX - should this test include Q_PATQUOTE? */
10488 if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10489 *quoted_dollar_at_p = 1;
10490 if (contains_dollar_at)
10491 *contains_dollar_at = 1;
10492
10493 /* We want to separate the positional parameters with the first
10494 character of $IFS in case $IFS is something other than a space.
10495 We also want to make sure that splitting is done no matter what --
10496 according to POSIX.2, this expands to a list of the positional
10497 parameters no matter what IFS is set to. */
10498 /* XXX - what to do when in a context where word splitting is not
10499 performed? Even when IFS is not the default, posix seems to imply
10500 that we have to expand $@ to all the positional parameters and
10501 separate them with spaces, which are preserved because word splitting
10502 doesn't take place. See below for how we use PF_NOSPLIT2 here. */
10503
10504 /* These are the cases where word splitting will not be performed. */
10505 if (pflags & PF_ASSIGNRHS)
10506 {
10507 temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags);
10508 if (nullarg)
10509 tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */
10510 }
10511
10512 /* This needs to match what expand_word_internal does with non-quoted $@
10513 does with separating with spaces. Passing Q_DOUBLE_QUOTES means that
10514 the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that
10515 they will separated by spaces. After doing this, we need the special
10516 handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC
10517 quotes. */
10518 else if (pflags & PF_NOSPLIT2)
10519 {
10520 #if defined (HANDLE_MULTIBYTE)
10521 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
10522 #else
10523 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
10524 #endif
10525 /* Posix interp 888 */
10526 temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags);
10527 else
10528 temp = string_list_dollar_at (list, quoted, pflags);
10529 }
10530 else
10531 temp = string_list_dollar_at (list, quoted, pflags);
10532
10533 tflag |= W_DOLLARAT;
10534 dispose_words (list);
10535 break;
10536
10537 case LBRACE:
10538 tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
10539 quoted_dollar_at_p,
10540 contains_dollar_at);
10541
10542 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
10543 return (tdesc);
10544 temp = tdesc ? tdesc->word : (char *)0;
10545
10546 /* XXX */
10547 /* Quoted nulls should be removed if there is anything else
10548 in the string. */
10549 /* Note that we saw the quoted null so we can add one back at
10550 the end of this function if there are no other characters
10551 in the string, discard TEMP, and go on. The exception to
10552 this is when we have "${@}" and $1 is '', since $@ needs
10553 special handling. */
10554 if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
10555 {
10556 if (had_quoted_null_p)
10557 *had_quoted_null_p = 1;
10558 if (*quoted_dollar_at_p == 0)
10559 {
10560 free (temp);
10561 tdesc->word = temp = (char *)NULL;
10562 }
10563
10564 }
10565
10566 ret = tdesc;
10567 goto return0;
10568
10569 /* Do command or arithmetic substitution. */
10570 case LPAREN:
10571 /* We have to extract the contents of this paren substitution. */
10572 t_index = zindex + 1;
10573 /* XXX - might want to check for string[t_index+2] == LPAREN and parse
10574 as arithmetic substitution immediately. */
10575 temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0);
10576 zindex = t_index;
10577
10578 /* For Posix.2-style `$(( ))' arithmetic substitution,
10579 extract the expression and pass it to the evaluator. */
10580 if (temp && *temp == LPAREN)
10581 {
10582 char *temp2;
10583 temp1 = temp + 1;
10584 temp2 = savestring (temp1);
10585 t_index = strlen (temp2) - 1;
10586
10587 if (temp2[t_index] != RPAREN)
10588 {
10589 free (temp2);
10590 goto comsub;
10591 }
10592
10593 /* Cut off ending `)' */
10594 temp2[t_index] = '\0';
10595
10596 if (chk_arithsub (temp2, t_index) == 0)
10597 {
10598 free (temp2);
10599 #if 0
10600 internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
10601 #endif
10602 goto comsub;
10603 }
10604
10605 /* Expand variables found inside the expression. */
10606 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
10607 free (temp2);
10608
10609 arithsub:
10610 /* No error messages. */
10611 savecmd = this_command_name;
10612 this_command_name = (char *)NULL;
10613
10614 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
10615 number = evalexp (temp1, eflag, &expok);
10616 this_command_name = savecmd;
10617 free (temp);
10618 free (temp1);
10619 if (expok == 0)
10620 {
10621 if (interactive_shell == 0 && posixly_correct)
10622 {
10623 set_exit_status (EXECUTION_FAILURE);
10624 return (&expand_wdesc_fatal);
10625 }
10626 else
10627 return (&expand_wdesc_error);
10628 }
10629 temp = itos (number);
10630 break;
10631 }
10632
10633 comsub:
10634 if (pflags & PF_NOCOMSUB)
10635 /* we need zindex+1 because string[zindex] == RPAREN */
10636 temp1 = substring (string, *sindex, zindex+1);
10637 else
10638 {
10639 tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS);
10640 temp1 = tdesc ? tdesc->word : (char *)NULL;
10641 if (tdesc)
10642 dispose_word_desc (tdesc);
10643 }
10644 FREE (temp);
10645 temp = temp1;
10646 break;
10647
10648 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
10649 away in a future bash release. */
10650 case '[': /*]*/
10651 /* Extract the contents of this arithmetic substitution. */
10652 t_index = zindex + 1;
10653 temp = extract_arithmetic_subst (string, &t_index);
10654 zindex = t_index;
10655 if (temp == 0)
10656 {
10657 temp = savestring (string);
10658 if (expanded_something)
10659 *expanded_something = 0;
10660 goto return0;
10661 }
10662
10663 /* Do initial variable expansion. */
10664 temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH);
10665
10666 goto arithsub;
10667
10668 default:
10669 /* Find the variable in VARIABLE_LIST. */
10670 temp = (char *)NULL;
10671
10672 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
10673 ;
10674 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
10675
10676 /* If this isn't a variable name, then just output the `$'. */
10677 if (temp1 == 0 || *temp1 == '\0')
10678 {
10679 FREE (temp1);
10680 temp = (char *)xmalloc (2);
10681 temp[0] = '$';
10682 temp[1] = '\0';
10683 if (expanded_something)
10684 *expanded_something = 0;
10685 goto return0;
10686 }
10687
10688 /* If the variable exists, return its value cell. */
10689 var = find_variable (temp1);
10690
10691 if (var && invisible_p (var) == 0 && var_isset (var))
10692 {
10693 #if defined (ARRAY_VARS)
10694 if (assoc_p (var) || array_p (var))
10695 {
10696 temp = array_p (var) ? array_reference (array_cell (var), 0)
10697 : assoc_reference (assoc_cell (var), "0");
10698 if (temp)
10699 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10700 ? quote_string (temp)
10701 : quote_escapes (temp);
10702 else if (unbound_vars_is_error)
10703 goto unbound_variable;
10704 }
10705 else
10706 #endif
10707 {
10708 temp = value_cell (var);
10709
10710 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10711 ? quote_string (temp)
10712 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
10713 : quote_escapes (temp));
10714 }
10715
10716 free (temp1);
10717
10718 goto return0;
10719 }
10720 else if (var && (invisible_p (var) || var_isset (var) == 0))
10721 temp = (char *)NULL;
10722 else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0)
10723 {
10724 temp = nameref_cell (var);
10725 #if defined (ARRAY_VARS)
10726 if (temp && *temp && valid_array_reference (temp, 0))
10727 {
10728 chk_atstar (temp, quoted, pflags, quoted_dollar_at_p, contains_dollar_at);
10729 tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, 0);
10730 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
10731 return (tdesc);
10732 ret = tdesc;
10733 goto return0;
10734 }
10735 else
10736 #endif
10737 /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */
10738 if (temp && *temp && legal_identifier (temp) == 0)
10739 {
10740 set_exit_status (EXECUTION_FAILURE);
10741 report_error (_("%s: invalid variable name for name reference"), temp);
10742 return (&expand_wdesc_error); /* XXX */
10743 }
10744 else
10745 temp = (char *)NULL;
10746 }
10747
10748 temp = (char *)NULL;
10749
10750 unbound_variable:
10751 if (unbound_vars_is_error)
10752 {
10753 set_exit_status (EXECUTION_FAILURE);
10754 err_unboundvar (temp1);
10755 }
10756 else
10757 {
10758 free (temp1);
10759 goto return0;
10760 }
10761
10762 free (temp1);
10763 set_exit_status (EXECUTION_FAILURE);
10764 return ((unbound_vars_is_error && interactive_shell == 0)
10765 ? &expand_wdesc_fatal
10766 : &expand_wdesc_error);
10767 }
10768
10769 if (string[zindex])
10770 zindex++;
10771
10772 return0:
10773 *sindex = zindex;
10774
10775 if (ret == 0)
10776 {
10777 ret = alloc_word_desc ();
10778 ret->flags = tflag; /* XXX */
10779 ret->word = temp;
10780 }
10781 return ret;
10782 }
10783
10784 #if defined (ARRAY_VARS)
10785 /* Characters that need to be backslash-quoted after expanding array subscripts */
10786 static char abstab[256] = { '\1' };
10787
10788 /* Run an array subscript through the appropriate word expansions. */
10789 char *
10790 expand_subscript_string (string, quoted)
10791 char *string;
10792 int quoted;
10793 {
10794 WORD_DESC td;
10795 WORD_LIST *tlist;
10796 int oe;
10797 char *ret;
10798
10799 if (string == 0 || *string == 0)
10800 return (char *)NULL;
10801
10802 oe = expand_no_split_dollar_star;
10803 ret = (char *)NULL;
10804
10805 td.flags = W_NOPROCSUB|W_NOTILDE|W_NOSPLIT2; /* XXX - W_NOCOMSUB? */
10806 td.word = savestring (string); /* in case it's freed on error */
10807
10808 expand_no_split_dollar_star = 1;
10809 tlist = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
10810 expand_no_split_dollar_star = oe;
10811
10812 if (tlist)
10813 {
10814 if (tlist->word)
10815 {
10816 remove_quoted_nulls (tlist->word->word);
10817 tlist->word->flags &= ~W_HASQUOTEDNULL;
10818 }
10819 dequote_list (tlist);
10820 ret = string_list (tlist);
10821 dispose_words (tlist);
10822 }
10823
10824 free (td.word);
10825 return (ret);
10826 }
10827
10828 /* Expand the subscript in STRING, which is an array reference. To ensure we
10829 only expand it once, we quote the characters that would start another
10830 expansion and the bracket characters that are special to array subscripts. */
10831 static char *
10832 expand_array_subscript (string, sindex, quoted, flags)
10833 char *string;
10834 int *sindex;
10835 int quoted, flags;
10836 {
10837 char *ret, *exp, *t;
10838 size_t slen;
10839 int si, ni;
10840
10841 si = *sindex;
10842 slen = STRLEN (string);
10843
10844 if (abstab[0] == '\1')
10845 {
10846 /* These are basically the characters that start shell expansions plus
10847 the characters that delimit subscripts. */
10848 memset (abstab, '\0', sizeof (abstab));
10849 abstab[LBRACK] = abstab[RBRACK] = 1;
10850 abstab['$'] = abstab['`'] = abstab['~'] = 1;
10851 abstab['\\'] = abstab['\''] = 1;
10852 abstab['"'] = 1; /* XXX */
10853 /* We don't quote `@' or `*' in the subscript at all. */
10854 }
10855
10856 /* string[si] == LBRACK */
10857 ni = skipsubscript (string, si, 0);
10858 /* These checks mirror the ones in valid_array_reference. The check for
10859 (ni - si) == 1 checks for empty subscripts. We don't check that the
10860 subscript is a separate word if we're parsing an arithmetic expression. */
10861 if (ni >= slen || string[ni] != RBRACK || (ni - si) == 1 ||
10862 (string[ni+1] != '\0' && (quoted & Q_ARITH) == 0))
10863 {
10864 /* let's check and see what fails this check */
10865 INTERNAL_DEBUG (("expand_array_subscript: bad subscript string: `%s'", string+si));
10866 ret = (char *)xmalloc (2); /* badly-formed subscript */
10867 ret[0] = string[si];
10868 ret[1] = '\0';
10869 *sindex = si + 1;
10870 return ret;
10871 }
10872
10873 /* STRING[ni] == RBRACK */
10874 exp = substring (string, si+1, ni);
10875 t = expand_subscript_string (exp, quoted & ~(Q_ARITH|Q_DOUBLE_QUOTES));
10876 free (exp);
10877 exp = t ? sh_backslash_quote (t, abstab, 0) : savestring ("");
10878 free (t);
10879
10880 slen = STRLEN (exp);
10881 ret = xmalloc (slen + 2 + 1);
10882 ret[0] ='[';
10883 strcpy (ret + 1, exp);
10884 ret[slen + 1] = ']';
10885 ret[slen + 2] = '\0';
10886
10887 free (exp);
10888 *sindex = ni + 1;
10889
10890 return ret;
10891 }
10892 #endif
10893
10894 void
10895 invalidate_cached_quoted_dollar_at ()
10896 {
10897 dispose_words (cached_quoted_dollar_at);
10898 cached_quoted_dollar_at = 0;
10899 }
10900
10901 /* Make a word list which is the result of parameter and variable
10902 expansion, command substitution, arithmetic substitution, and
10903 quote removal of WORD. Return a pointer to a WORD_LIST which is
10904 the result of the expansion. If WORD contains a null word, the
10905 word list returned is also null.
10906
10907 QUOTED contains flag values defined in shell.h.
10908
10909 ISEXP is used to tell expand_word_internal that the word should be
10910 treated as the result of an expansion. This has implications for
10911 how IFS characters in the word are treated.
10912
10913 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
10914 they point to an integer value which receives information about expansion.
10915 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
10916 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
10917 else zero.
10918
10919 This only does word splitting in the case of $@ expansion. In that
10920 case, we split on ' '. */
10921
10922 /* Values for the local variable quoted_state. */
10923 #define UNQUOTED 0
10924 #define PARTIALLY_QUOTED 1
10925 #define WHOLLY_QUOTED 2
10926
10927 static WORD_LIST *
10928 expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
10929 WORD_DESC *word;
10930 int quoted, isexp;
10931 int *contains_dollar_at;
10932 int *expanded_something;
10933 {
10934 WORD_LIST *list;
10935 WORD_DESC *tword;
10936
10937 /* The intermediate string that we build while expanding. */
10938 char *istring;
10939
10940 /* The current size of the above object. */
10941 size_t istring_size;
10942
10943 /* Index into ISTRING. */
10944 size_t istring_index;
10945
10946 /* Temporary string storage. */
10947 char *temp, *temp1;
10948
10949 /* The text of WORD. */
10950 register char *string;
10951
10952 /* The size of STRING. */
10953 size_t string_size;
10954
10955 /* The index into STRING. */
10956 int sindex;
10957
10958 /* This gets 1 if we see a $@ while quoted. */
10959 int quoted_dollar_at;
10960
10961 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
10962 whether WORD contains no quoting characters, a partially quoted
10963 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
10964 int quoted_state;
10965
10966 /* State flags */
10967 int had_quoted_null;
10968 int has_quoted_ifs; /* did we add a quoted $IFS character here? */
10969 int has_dollar_at, temp_has_dollar_at;
10970 int internal_tilde;
10971 int split_on_spaces;
10972 int local_expanded;
10973 int tflag;
10974 int pflags; /* flags passed to param_expand */
10975 int mb_cur_max;
10976
10977 int assignoff; /* If assignment, offset of `=' */
10978
10979 register unsigned char c; /* Current character. */
10980 int t_index; /* For calls to string_extract_xxx. */
10981
10982 char twochars[2];
10983
10984 DECLARE_MBSTATE;
10985
10986 /* OK, let's see if we can optimize a common idiom: "$@". This needs to make sure
10987 that all of the flags callers care about (e.g., W_HASQUOTEDNULL) are set in
10988 list->flags. */
10989 if (STREQ (word->word, "\"$@\"") &&
10990 (word->flags == (W_HASDOLLAR|W_QUOTED)) &&
10991 dollar_vars[1]) /* XXX - check IFS here as well? */
10992 {
10993 if (contains_dollar_at)
10994 *contains_dollar_at = 1;
10995 if (expanded_something)
10996 *expanded_something = 1;
10997 if (cached_quoted_dollar_at)
10998 return (copy_word_list (cached_quoted_dollar_at));
10999 list = list_rest_of_args ();
11000 list = quote_list (list);
11001 cached_quoted_dollar_at = copy_word_list (list);
11002 return (list);
11003 }
11004
11005 istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
11006 istring[istring_index = 0] = '\0';
11007 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
11008 has_quoted_ifs = 0;
11009 split_on_spaces = 0;
11010 internal_tilde = 0; /* expanding =~ or :~ */
11011 quoted_state = UNQUOTED;
11012
11013 string = word->word;
11014 if (string == 0)
11015 goto finished_with_string;
11016 mb_cur_max = MB_CUR_MAX;
11017
11018 /* Don't need the string length for the SADD... and COPY_ macros unless
11019 multibyte characters are possible, but do need it for bounds checking. */
11020 string_size = (mb_cur_max > 1) ? strlen (string) : 1;
11021
11022 if (contains_dollar_at)
11023 *contains_dollar_at = 0;
11024
11025 assignoff = -1;
11026
11027 /* Begin the expansion. */
11028
11029 for (sindex = 0; ;)
11030 {
11031 c = string[sindex];
11032
11033 /* Case on top-level character. */
11034 switch (c)
11035 {
11036 case '\0':
11037 goto finished_with_string;
11038
11039 case CTLESC:
11040 sindex++;
11041 #if HANDLE_MULTIBYTE
11042 if (mb_cur_max > 1 && string[sindex])
11043 {
11044 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
11045 }
11046 else
11047 #endif
11048 {
11049 temp = (char *)xmalloc (3);
11050 temp[0] = CTLESC;
11051 temp[1] = c = string[sindex];
11052 temp[2] = '\0';
11053 }
11054
11055 dollar_add_string:
11056 if (string[sindex])
11057 sindex++;
11058
11059 add_string:
11060 if (temp)
11061 {
11062 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
11063 temp = (char *)0;
11064 }
11065
11066 break;
11067
11068 #if defined (PROCESS_SUBSTITUTION)
11069 /* Process substitution. */
11070 case '<':
11071 case '>':
11072 {
11073 /* XXX - technically this should only be expanded at the start
11074 of a word */
11075 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & W_NOPROCSUB))
11076 {
11077 sindex--; /* add_character: label increments sindex */
11078 goto add_character;
11079 }
11080 else
11081 t_index = sindex + 1; /* skip past both '<' and LPAREN */
11082
11083 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/
11084 sindex = t_index;
11085
11086 /* If the process substitution specification is `<()', we want to
11087 open the pipe for writing in the child and produce output; if
11088 it is `>()', we want to open the pipe for reading in the child
11089 and consume input. */
11090 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
11091
11092 FREE (temp1);
11093
11094 goto dollar_add_string;
11095 }
11096 #endif /* PROCESS_SUBSTITUTION */
11097
11098 #if defined (ARRAY_VARS)
11099 case '[': /*]*/
11100 if ((quoted & Q_ARITH) == 0 || shell_compatibility_level <= 51)
11101 {
11102 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
11103 goto add_ifs_character;
11104 else
11105 goto add_character;
11106 }
11107 else
11108 {
11109 temp = expand_array_subscript (string, &sindex, quoted, word->flags);
11110 goto add_string;
11111 }
11112 #endif
11113
11114 case '=':
11115 /* Posix.2 section 3.6.1 says that tildes following `=' in words
11116 which are not assignment statements are not expanded. If the
11117 shell isn't in posix mode, though, we perform tilde expansion
11118 on `likely candidate' unquoted assignment statements (flags
11119 include W_ASSIGNMENT but not W_QUOTED). A likely candidate
11120 contains an unquoted :~ or =~. Something to think about: we
11121 now have a flag that says to perform tilde expansion on arguments
11122 to `assignment builtins' like declare and export that look like
11123 assignment statements. We now do tilde expansion on such words
11124 even in POSIX mode. */
11125 if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
11126 {
11127 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11128 goto add_ifs_character;
11129 else
11130 goto add_character;
11131 }
11132 /* If we're not in posix mode or forcing assignment-statement tilde
11133 expansion, note where the first `=' appears in the word and prepare
11134 to do tilde expansion following the first `='. We have to keep
11135 track of the first `=' (using assignoff) to avoid being confused
11136 by an `=' in the rhs of the assignment statement. */
11137 if ((word->flags & W_ASSIGNMENT) &&
11138 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
11139 assignoff == -1 && sindex > 0)
11140 assignoff = sindex;
11141 if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
11142 internal_tilde = 1;
11143
11144 if (word->flags & W_ASSIGNARG)
11145 word->flags |= W_ASSIGNRHS; /* affects $@ */
11146
11147 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11148 {
11149 has_quoted_ifs++;
11150 goto add_ifs_character;
11151 }
11152 else
11153 goto add_character;
11154
11155 case ':':
11156 if (word->flags & (W_NOTILDE|W_NOASSNTILDE))
11157 {
11158 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11159 goto add_ifs_character;
11160 else
11161 goto add_character;
11162 }
11163
11164 if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) &&
11165 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
11166 string[sindex+1] == '~')
11167 internal_tilde = 1;
11168
11169 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11170 goto add_ifs_character;
11171 else
11172 goto add_character;
11173
11174 case '~':
11175 /* If the word isn't supposed to be tilde expanded, or we're not
11176 at the start of a word or after an unquoted : or = in an
11177 assignment statement, we don't do tilde expansion. We don't
11178 do tilde expansion if quoted or in an arithmetic context. */
11179
11180 if ((word->flags & W_NOTILDE) ||
11181 (sindex > 0 && (internal_tilde == 0)) ||
11182 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
11183 {
11184 internal_tilde = 0;
11185 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
11186 goto add_ifs_character;
11187 else
11188 goto add_character;
11189 }
11190
11191 if (word->flags & W_ASSIGNRHS)
11192 tflag = 2;
11193 else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
11194 tflag = 1;
11195 else
11196 tflag = 0;
11197
11198 temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
11199
11200 internal_tilde = 0;
11201
11202 if (temp && *temp && t_index > 0)
11203 {
11204 temp1 = bash_tilde_expand (temp, tflag);
11205 if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
11206 {
11207 FREE (temp);
11208 FREE (temp1);
11209 goto add_character; /* tilde expansion failed */
11210 }
11211 free (temp);
11212 temp = temp1;
11213 sindex += t_index;
11214 goto add_quoted_string; /* XXX was add_string */
11215 }
11216 else
11217 {
11218 FREE (temp);
11219 goto add_character;
11220 }
11221
11222 case '$':
11223 if (expanded_something)
11224 *expanded_something = 1;
11225 local_expanded = 1;
11226
11227 temp_has_dollar_at = 0;
11228 pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
11229 if (word->flags & W_NOSPLIT2)
11230 pflags |= PF_NOSPLIT2;
11231 if (word->flags & W_ASSIGNRHS)
11232 pflags |= PF_ASSIGNRHS;
11233 if (word->flags & W_COMPLETE)
11234 pflags |= PF_COMPLETE;
11235
11236 tword = param_expand (string, &sindex, quoted, expanded_something,
11237 &temp_has_dollar_at, &quoted_dollar_at,
11238 &had_quoted_null, pflags);
11239 has_dollar_at += temp_has_dollar_at;
11240 split_on_spaces += (tword->flags & W_SPLITSPACE);
11241
11242 if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
11243 {
11244 free (string);
11245 free (istring);
11246 return ((tword == &expand_wdesc_error) ? &expand_word_error
11247 : &expand_word_fatal);
11248 }
11249 if (contains_dollar_at && has_dollar_at)
11250 *contains_dollar_at = 1;
11251
11252 if (tword && (tword->flags & W_HASQUOTEDNULL))
11253 had_quoted_null = 1; /* note for later */
11254 if (tword && (tword->flags & W_SAWQUOTEDNULL))
11255 had_quoted_null = 1; /* XXX */
11256
11257 temp = tword ? tword->word : (char *)NULL;
11258 dispose_word_desc (tword);
11259
11260 /* Kill quoted nulls; we will add them back at the end of
11261 expand_word_internal if nothing else in the string */
11262 if (had_quoted_null && temp && QUOTED_NULL (temp))
11263 {
11264 FREE (temp);
11265 temp = (char *)NULL;
11266 }
11267
11268 goto add_string;
11269 break;
11270
11271 case '`': /* Backquoted command substitution. */
11272 {
11273 t_index = sindex++;
11274
11275 temp = string_extract (string, &sindex, "`", (word->flags & W_COMPLETE) ? SX_COMPLETE : SX_REQMATCH);
11276 /* The test of sindex against t_index is to allow bare instances of
11277 ` to pass through, for backwards compatibility. */
11278 if (temp == &extract_string_error || temp == &extract_string_fatal)
11279 {
11280 if (sindex - 1 == t_index)
11281 {
11282 sindex = t_index;
11283 goto add_character;
11284 }
11285 set_exit_status (EXECUTION_FAILURE);
11286 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
11287 free (string);
11288 free (istring);
11289 return ((temp == &extract_string_error) ? &expand_word_error
11290 : &expand_word_fatal);
11291 }
11292
11293 if (expanded_something)
11294 *expanded_something = 1;
11295 local_expanded = 1;
11296
11297 if (word->flags & W_NOCOMSUB)
11298 /* sindex + 1 because string[sindex] == '`' */
11299 temp1 = substring (string, t_index, sindex + 1);
11300 else
11301 {
11302 de_backslash (temp);
11303 tword = command_substitute (temp, quoted, PF_BACKQUOTE);
11304 temp1 = tword ? tword->word : (char *)NULL;
11305 if (tword)
11306 dispose_word_desc (tword);
11307 }
11308 FREE (temp);
11309 temp = temp1;
11310 goto dollar_add_string;
11311 }
11312
11313 case '\\':
11314 if (string[sindex + 1] == '\n')
11315 {
11316 sindex += 2;
11317 continue;
11318 }
11319
11320 c = string[++sindex];
11321
11322 /* "However, the double-quote character ( '"' ) shall not be treated
11323 specially within a here-document, except when the double-quote
11324 appears within "$()", "``", or "${}"." */
11325 if ((quoted & Q_HERE_DOCUMENT) && (quoted & Q_DOLBRACE) && c == '"')
11326 tflag = CBSDQUOTE; /* special case */
11327 else if (quoted & Q_HERE_DOCUMENT)
11328 tflag = CBSHDOC;
11329 else if (quoted & Q_DOUBLE_QUOTES)
11330 tflag = CBSDQUOTE;
11331 else
11332 tflag = 0;
11333
11334 /* From Posix discussion on austin-group list: Backslash escaping
11335 a } in ${...} is removed. Issue 0000221 */
11336 if ((quoted & Q_DOLBRACE) && c == RBRACE)
11337 {
11338 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11339 }
11340 /* This is the fix for " $@\ " */
11341 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c))
11342 {
11343 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11344 DEFAULT_ARRAY_SIZE);
11345 istring[istring_index++] = CTLESC;
11346 istring[istring_index++] = '\\';
11347 istring[istring_index] = '\0';
11348
11349 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11350 }
11351 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0)
11352 {
11353 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11354 DEFAULT_ARRAY_SIZE);
11355 istring[istring_index++] = CTLESC;
11356 istring[istring_index++] = '\\';
11357 istring[istring_index] = '\0';
11358 break;
11359 }
11360 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
11361 {
11362 SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
11363 }
11364 else if (c == 0)
11365 {
11366 c = CTLNUL;
11367 sindex--; /* add_character: label increments sindex */
11368 goto add_character;
11369 }
11370 else
11371 {
11372 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11373 }
11374
11375 sindex++;
11376 add_twochars:
11377 /* BEFORE jumping here, we need to increment sindex if appropriate */
11378 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11379 DEFAULT_ARRAY_SIZE);
11380 istring[istring_index++] = twochars[0];
11381 istring[istring_index++] = twochars[1];
11382 istring[istring_index] = '\0';
11383
11384 break;
11385
11386 case '"':
11387 /* XXX - revisit this */
11388 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0))
11389 goto add_character;
11390
11391 t_index = ++sindex;
11392 temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0);
11393
11394 /* If the quotes surrounded the entire string, then the
11395 whole word was quoted. */
11396 quoted_state = (t_index == 1 && string[sindex] == '\0')
11397 ? WHOLLY_QUOTED
11398 : PARTIALLY_QUOTED;
11399
11400 if (temp && *temp)
11401 {
11402 tword = alloc_word_desc ();
11403 tword->word = temp;
11404
11405 if (word->flags & W_ASSIGNARG)
11406 tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */
11407 if (word->flags & W_COMPLETE)
11408 tword->flags |= W_COMPLETE; /* for command substitutions */
11409 if (word->flags & W_NOCOMSUB)
11410 tword->flags |= W_NOCOMSUB;
11411 if (word->flags & W_NOPROCSUB)
11412 tword->flags |= W_NOPROCSUB;
11413
11414 if (word->flags & W_ASSIGNRHS)
11415 tword->flags |= W_ASSIGNRHS;
11416
11417 temp = (char *)NULL;
11418
11419 temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */
11420 /* Need to get W_HASQUOTEDNULL flag through this function. */
11421 /* XXX - preserve Q_ARITH here? */
11422 list = expand_word_internal (tword, Q_DOUBLE_QUOTES|(quoted&Q_ARITH), 0, &temp_has_dollar_at, (int *)NULL);
11423 has_dollar_at += temp_has_dollar_at;
11424
11425 if (list == &expand_word_error || list == &expand_word_fatal)
11426 {
11427 free (istring);
11428 free (string);
11429 /* expand_word_internal has already freed temp_word->word
11430 for us because of the way it prints error messages. */
11431 tword->word = (char *)NULL;
11432 dispose_word (tword);
11433 return list;
11434 }
11435
11436 dispose_word (tword);
11437
11438 /* "$@" (a double-quoted dollar-at) expands into nothing,
11439 not even a NULL word, when there are no positional
11440 parameters. Posix interp 888 says that other parts of the
11441 word that expand to quoted nulls result in quoted nulls, so
11442 we can't just throw the entire word away if we have "$@"
11443 anywhere in it. We use had_quoted_null to keep track */
11444 if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */
11445 {
11446 quoted_dollar_at++;
11447 break;
11448 }
11449
11450 /* If this list comes back with a quoted null from expansion,
11451 we have either "$x" or "$@" with $1 == ''. In either case,
11452 we need to make sure we add a quoted null argument and
11453 disable the special handling that "$@" gets. */
11454 if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL))
11455 {
11456 if (had_quoted_null && temp_has_dollar_at)
11457 quoted_dollar_at++;
11458 had_quoted_null = 1; /* XXX */
11459 }
11460
11461 /* If we get "$@", we know we have expanded something, so we
11462 need to remember it for the final split on $IFS. This is
11463 a special case; it's the only case where a quoted string
11464 can expand into more than one word. It's going to come back
11465 from the above call to expand_word_internal as a list with
11466 multiple words. */
11467 if (list)
11468 dequote_list (list);
11469
11470 if (temp_has_dollar_at) /* XXX - was has_dollar_at */
11471 {
11472 quoted_dollar_at++;
11473 if (contains_dollar_at)
11474 *contains_dollar_at = 1;
11475 if (expanded_something)
11476 *expanded_something = 1;
11477 local_expanded = 1;
11478 }
11479 }
11480 else
11481 {
11482 /* What we have is "". This is a minor optimization. */
11483 FREE (temp);
11484 list = (WORD_LIST *)NULL;
11485 had_quoted_null = 1; /* note for later */
11486 }
11487
11488 /* The code above *might* return a list (consider the case of "$@",
11489 where it returns "$1", "$2", etc.). We can't throw away the
11490 rest of the list, and we have to make sure each word gets added
11491 as quoted. We test on tresult->next: if it is non-NULL, we
11492 quote the whole list, save it to a string with string_list, and
11493 add that string. We don't need to quote the results of this
11494 (and it would be wrong, since that would quote the separators
11495 as well), so we go directly to add_string. */
11496 if (list)
11497 {
11498 if (list->next)
11499 {
11500 /* Testing quoted_dollar_at makes sure that "$@" is
11501 split correctly when $IFS does not contain a space. */
11502 temp = quoted_dollar_at
11503 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0)
11504 : string_list (quote_list (list));
11505 dispose_words (list);
11506 goto add_string;
11507 }
11508 else
11509 {
11510 temp = savestring (list->word->word);
11511 tflag = list->word->flags;
11512 dispose_words (list);
11513
11514 /* If the string is not a quoted null string, we want
11515 to remove any embedded unquoted CTLNUL characters.
11516 We do not want to turn quoted null strings back into
11517 the empty string, though. We do this because we
11518 want to remove any quoted nulls from expansions that
11519 contain other characters. For example, if we have
11520 x"$*"y or "x$*y" and there are no positional parameters,
11521 the $* should expand into nothing. */
11522 /* We use the W_HASQUOTEDNULL flag to differentiate the
11523 cases: a quoted null character as above and when
11524 CTLNUL is contained in the (non-null) expansion
11525 of some variable. We use the had_quoted_null flag to
11526 pass the value through this function to its caller. */
11527 if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
11528 remove_quoted_nulls (temp); /* XXX */
11529 }
11530 }
11531 else
11532 temp = (char *)NULL;
11533
11534 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
11535 had_quoted_null = 1; /* note for later */
11536
11537 /* We do not want to add quoted nulls to strings that are only
11538 partially quoted; we can throw them away. The exception to
11539 this is when we are going to be performing word splitting,
11540 since we have to preserve a null argument if the next character
11541 will cause word splitting. */
11542 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
11543 {
11544 c = CTLNUL;
11545 sindex--;
11546 had_quoted_null = 1;
11547 goto add_character;
11548 }
11549 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
11550 continue;
11551
11552 add_quoted_string:
11553
11554 if (temp)
11555 {
11556 temp1 = temp;
11557 temp = quote_string (temp);
11558 free (temp1);
11559 goto add_string;
11560 }
11561 else
11562 {
11563 /* Add NULL arg. */
11564 c = CTLNUL;
11565 sindex--; /* add_character: label increments sindex */
11566 had_quoted_null = 1; /* note for later */
11567 goto add_character;
11568 }
11569
11570 /* break; */
11571
11572 case '\'':
11573 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
11574 goto add_character;
11575
11576 t_index = ++sindex;
11577 temp = string_extract_single_quoted (string, &sindex, 0);
11578
11579 /* If the entire STRING was surrounded by single quotes,
11580 then the string is wholly quoted. */
11581 quoted_state = (t_index == 1 && string[sindex] == '\0')
11582 ? WHOLLY_QUOTED
11583 : PARTIALLY_QUOTED;
11584
11585 /* If all we had was '', it is a null expansion. */
11586 if (*temp == '\0')
11587 {
11588 free (temp);
11589 temp = (char *)NULL;
11590 }
11591 else
11592 remove_quoted_escapes (temp); /* ??? */
11593
11594 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
11595 had_quoted_null = 1; /* note for later */
11596
11597 /* We do not want to add quoted nulls to strings that are only
11598 partially quoted; such nulls are discarded. See above for the
11599 exception, which is when the string is going to be split.
11600 Posix interp 888/1129 */
11601 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
11602 {
11603 c = CTLNUL;
11604 sindex--;
11605 goto add_character;
11606 }
11607
11608 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
11609 continue;
11610
11611 /* If we have a quoted null expansion, add a quoted NULL to istring. */
11612 if (temp == 0)
11613 {
11614 c = CTLNUL;
11615 sindex--; /* add_character: label increments sindex */
11616 goto add_character;
11617 }
11618 else
11619 goto add_quoted_string;
11620
11621 /* break; */
11622
11623 case ' ':
11624 /* If we are in a context where the word is not going to be split, but
11625 we need to account for $@ and $* producing one word for each
11626 positional parameter, add quoted spaces so the spaces in the
11627 expansion of "$@", if any, behave correctly. We still may need to
11628 split if we are expanding the rhs of a word expansion. */
11629 if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0))
11630 {
11631 if (string[sindex])
11632 sindex++;
11633 twochars[0] = CTLESC;
11634 twochars[1] = c;
11635 goto add_twochars;
11636 }
11637 /* FALLTHROUGH */
11638
11639 default:
11640 /* This is the fix for " $@ " */
11641 add_ifs_character:
11642 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0))
11643 {
11644 if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)
11645 has_quoted_ifs++;
11646 add_quoted_character:
11647 if (string[sindex]) /* from old goto dollar_add_string */
11648 sindex++;
11649 if (c == 0)
11650 {
11651 c = CTLNUL;
11652 goto add_character;
11653 }
11654 else
11655 {
11656 #if HANDLE_MULTIBYTE
11657 /* XXX - should make sure that c is actually multibyte,
11658 otherwise we can use the twochars branch */
11659 if (mb_cur_max > 1)
11660 sindex--;
11661
11662 if (mb_cur_max > 1)
11663 {
11664 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
11665 }
11666 else
11667 #endif
11668 {
11669 twochars[0] = CTLESC;
11670 twochars[1] = c;
11671 goto add_twochars;
11672 }
11673 }
11674 }
11675
11676 SADD_MBCHAR (temp, string, sindex, string_size);
11677
11678 add_character:
11679 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
11680 DEFAULT_ARRAY_SIZE);
11681 istring[istring_index++] = c;
11682 istring[istring_index] = '\0';
11683
11684 /* Next character. */
11685 sindex++;
11686 }
11687 }
11688
11689 finished_with_string:
11690 /* OK, we're ready to return. If we have a quoted string, and
11691 quoted_dollar_at is not set, we do no splitting at all; otherwise
11692 we split on ' '. The routines that call this will handle what to
11693 do if nothing has been expanded. */
11694
11695 /* Partially and wholly quoted strings which expand to the empty
11696 string are retained as an empty arguments. Unquoted strings
11697 which expand to the empty string are discarded. The single
11698 exception is the case of expanding "$@" when there are no
11699 positional parameters. In that case, we discard the expansion. */
11700
11701 /* Because of how the code that handles "" and '' in partially
11702 quoted strings works, we need to make ISTRING into a QUOTED_NULL
11703 if we saw quoting characters, but the expansion was empty.
11704 "" and '' are tossed away before we get to this point when
11705 processing partially quoted strings. This makes "" and $xxx""
11706 equivalent when xxx is unset. We also look to see whether we
11707 saw a quoted null from a ${} expansion and add one back if we
11708 need to. */
11709
11710 /* If we expand to nothing and there were no single or double quotes
11711 in the word, we throw it away. Otherwise, we return a NULL word.
11712 The single exception is for $@ surrounded by double quotes when
11713 there are no positional parameters. In that case, we also throw
11714 the word away. */
11715
11716 if (*istring == '\0')
11717 {
11718 #if 0
11719 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
11720 #else
11721 if (had_quoted_null || (quoted_dollar_at == 0 && quoted_state == PARTIALLY_QUOTED))
11722 #endif
11723 {
11724 istring[0] = CTLNUL;
11725 istring[1] = '\0';
11726 tword = alloc_word_desc ();
11727 tword->word = istring;
11728 istring = 0; /* avoid later free() */
11729 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11730 list = make_word_list (tword, (WORD_LIST *)NULL);
11731 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
11732 tword->flags |= W_QUOTED;
11733 }
11734 /* According to sh, ksh, and Posix.2, if a word expands into nothing
11735 and a double-quoted "$@" appears anywhere in it, then the entire
11736 word is removed. */
11737 /* XXX - exception appears to be that quoted null strings result in
11738 null arguments */
11739 else if (quoted_state == UNQUOTED || quoted_dollar_at)
11740 list = (WORD_LIST *)NULL;
11741 else
11742 list = (WORD_LIST *)NULL;
11743 }
11744 else if (word->flags & W_NOSPLIT)
11745 {
11746 tword = alloc_word_desc ();
11747 tword->word = istring;
11748 if (had_quoted_null && QUOTED_NULL (istring))
11749 tword->flags |= W_HASQUOTEDNULL;
11750 istring = 0; /* avoid later free() */
11751 if (word->flags & W_ASSIGNMENT)
11752 tword->flags |= W_ASSIGNMENT; /* XXX */
11753 if (word->flags & W_COMPASSIGN)
11754 tword->flags |= W_COMPASSIGN; /* XXX */
11755 if (word->flags & W_NOGLOB)
11756 tword->flags |= W_NOGLOB; /* XXX */
11757 if (word->flags & W_NOBRACE)
11758 tword->flags |= W_NOBRACE; /* XXX */
11759 if (word->flags & W_ARRAYREF)
11760 tword->flags |= W_ARRAYREF;
11761 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
11762 tword->flags |= W_QUOTED;
11763 list = make_word_list (tword, (WORD_LIST *)NULL);
11764 }
11765 else if (word->flags & W_ASSIGNRHS)
11766 {
11767 list = list_string (istring, "", quoted);
11768 tword = list->word;
11769 if (had_quoted_null && QUOTED_NULL (istring))
11770 tword->flags |= W_HASQUOTEDNULL;
11771 free (list);
11772 free (istring);
11773 istring = 0; /* avoid later free() */
11774 goto set_word_flags;
11775 }
11776 else
11777 {
11778 char *ifs_chars;
11779
11780 ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
11781
11782 /* If we have $@, we need to split the results no matter what. If
11783 IFS is unset or NULL, string_list_dollar_at has separated the
11784 positional parameters with a space, so we split on space (we have
11785 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
11786 string_list_dollar_at has separated the positional parameters
11787 with the first character of $IFS, so we split on $IFS. If
11788 SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
11789 unset or null, and we want to make sure that we split on spaces
11790 regardless of what else has happened to IFS since the expansion,
11791 or we expanded "$@" with IFS null and we need to split the positional
11792 parameters into separate words. */
11793 if (split_on_spaces)
11794 {
11795 /* If IFS is not set, and the word is not quoted, we want to split
11796 the individual words on $' \t\n'. We rely on previous steps to
11797 quote the portions of the word that should not be split */
11798 if (ifs_is_set == 0)
11799 list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */
11800 else
11801 list = list_string (istring, " ", 1); /* XXX quoted == 1? */
11802 }
11803
11804 /* If we have $@ (has_dollar_at != 0) and we are in a context where we
11805 don't want to split the result (W_NOSPLIT2), and we are not quoted,
11806 we have already separated the arguments with the first character of
11807 $IFS. In this case, we want to return a list with a single word
11808 with the separator possibly replaced with a space (it's what other
11809 shells seem to do).
11810 quoted_dollar_at is internal to this function and is set if we are
11811 passed an argument that is unquoted (quoted == 0) but we encounter a
11812 double-quoted $@ while expanding it. */
11813 else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2))
11814 {
11815 tword = alloc_word_desc ();
11816 /* Only split and rejoin if we have to */
11817 if (*ifs_chars && *ifs_chars != ' ')
11818 {
11819 /* list_string dequotes CTLESCs in the string it's passed, so we
11820 need it to get the space separation right if space isn't the
11821 first character in IFS (but is present) and to remove the
11822 quoting we added back in param_expand(). */
11823 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
11824 /* This isn't exactly right in the case where we're expanding
11825 the RHS of an expansion like ${var-$@} where IFS=: (for
11826 example). The W_NOSPLIT2 means we do the separation with :;
11827 the list_string removes the quotes and breaks the string into
11828 a list, and the string_list rejoins it on spaces. When we
11829 return, we expect to be able to split the results, but the
11830 space separation means the right split doesn't happen. */
11831 tword->word = string_list (list);
11832 }
11833 else
11834 tword->word = istring;
11835 if (had_quoted_null && QUOTED_NULL (istring))
11836 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11837 if (tword->word != istring)
11838 free (istring);
11839 istring = 0; /* avoid later free() */
11840 goto set_word_flags;
11841 }
11842 else if (has_dollar_at && ifs_chars)
11843 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
11844 else
11845 {
11846 tword = alloc_word_desc ();
11847 if (expanded_something && *expanded_something == 0 && has_quoted_ifs)
11848 tword->word = remove_quoted_ifs (istring);
11849 else
11850 tword->word = istring;
11851 if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */
11852 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11853 else if (had_quoted_null)
11854 tword->flags |= W_SAWQUOTEDNULL; /* XXX */
11855 if (tword->word != istring)
11856 free (istring);
11857 istring = 0; /* avoid later free() */
11858 set_word_flags:
11859 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
11860 tword->flags |= W_QUOTED;
11861 if (word->flags & W_ASSIGNMENT)
11862 tword->flags |= W_ASSIGNMENT;
11863 if (word->flags & W_COMPASSIGN)
11864 tword->flags |= W_COMPASSIGN;
11865 if (word->flags & W_NOGLOB)
11866 tword->flags |= W_NOGLOB;
11867 if (word->flags & W_NOBRACE)
11868 tword->flags |= W_NOBRACE;
11869 if (word->flags & W_ARRAYREF)
11870 tword->flags |= W_ARRAYREF;
11871 list = make_word_list (tword, (WORD_LIST *)NULL);
11872 }
11873 }
11874
11875 free (istring);
11876 return (list);
11877 }
11878
11879 /* **************************************************************** */
11880 /* */
11881 /* Functions for Quote Removal */
11882 /* */
11883 /* **************************************************************** */
11884
11885 /* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
11886 backslash quoting rules for within double quotes or a here document. */
11887 char *
11888 string_quote_removal (string, quoted)
11889 char *string;
11890 int quoted;
11891 {
11892 size_t slen;
11893 char *r, *result_string, *temp, *send;
11894 int sindex, tindex, dquote;
11895 unsigned char c;
11896 DECLARE_MBSTATE;
11897
11898 /* The result can be no longer than the original string. */
11899 slen = strlen (string);
11900 send = string + slen;
11901
11902 r = result_string = (char *)xmalloc (slen + 1);
11903
11904 for (dquote = sindex = 0; c = string[sindex];)
11905 {
11906 switch (c)
11907 {
11908 case '\\':
11909 c = string[++sindex];
11910 if (c == 0)
11911 {
11912 *r++ = '\\';
11913 break;
11914 }
11915 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
11916 *r++ = '\\';
11917 /* FALLTHROUGH */
11918
11919 default:
11920 SCOPY_CHAR_M (r, string, send, sindex);
11921 break;
11922
11923 case '\'':
11924 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
11925 {
11926 *r++ = c;
11927 sindex++;
11928 break;
11929 }
11930 tindex = sindex + 1;
11931 temp = string_extract_single_quoted (string, &tindex, 0);
11932 if (temp)
11933 {
11934 strcpy (r, temp);
11935 r += strlen (r);
11936 free (temp);
11937 }
11938 sindex = tindex;
11939 break;
11940
11941 case '"':
11942 dquote = 1 - dquote;
11943 sindex++;
11944 break;
11945 }
11946 }
11947 *r = '\0';
11948 return (result_string);
11949 }
11950
11951 #if 0
11952 /* UNUSED */
11953 /* Perform quote removal on word WORD. This allocates and returns a new
11954 WORD_DESC *. */
11955 WORD_DESC *
11956 word_quote_removal (word, quoted)
11957 WORD_DESC *word;
11958 int quoted;
11959 {
11960 WORD_DESC *w;
11961 char *t;
11962
11963 t = string_quote_removal (word->word, quoted);
11964 w = alloc_word_desc ();
11965 w->word = t ? t : savestring ("");
11966 return (w);
11967 }
11968
11969 /* Perform quote removal on all words in LIST. If QUOTED is non-zero,
11970 the members of the list are treated as if they are surrounded by
11971 double quotes. Return a new list, or NULL if LIST is NULL. */
11972 WORD_LIST *
11973 word_list_quote_removal (list, quoted)
11974 WORD_LIST *list;
11975 int quoted;
11976 {
11977 WORD_LIST *result, *t, *tresult, *e;
11978
11979 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
11980 {
11981 tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
11982 #if 0
11983 result = (WORD_LIST *) list_append (result, tresult);
11984 #else
11985 if (result == 0)
11986 result = e = tresult;
11987 else
11988 {
11989 e->next = tresult;
11990 while (e->next)
11991 e = e->next;
11992 }
11993 #endif
11994 }
11995 return (result);
11996 }
11997 #endif
11998
11999 /*******************************************
12000 * *
12001 * Functions to perform word splitting *
12002 * *
12003 *******************************************/
12004
12005 void
12006 setifs (v)
12007 SHELL_VAR *v;
12008 {
12009 char *t;
12010 unsigned char uc;
12011
12012 ifs_var = v;
12013 ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
12014
12015 ifs_is_set = ifs_var != 0;
12016 ifs_is_null = ifs_is_set && (*ifs_value == 0);
12017
12018 /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
12019 handle multibyte chars in IFS */
12020 memset (ifs_cmap, '\0', sizeof (ifs_cmap));
12021 for (t = ifs_value ; t && *t; t++)
12022 {
12023 uc = *t;
12024 ifs_cmap[uc] = 1;
12025 }
12026
12027 #if defined (HANDLE_MULTIBYTE)
12028 if (ifs_value == 0)
12029 {
12030 ifs_firstc[0] = '\0'; /* XXX - ? */
12031 ifs_firstc_len = 1;
12032 }
12033 else
12034 {
12035 if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value))
12036 ifs_firstc_len = (*ifs_value != 0) ? 1 : 0;
12037 else
12038 {
12039 size_t ifs_len;
12040 ifs_len = strnlen (ifs_value, MB_CUR_MAX);
12041 ifs_firstc_len = MBLEN (ifs_value, ifs_len);
12042 }
12043 if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
12044 {
12045 ifs_firstc[0] = ifs_value[0];
12046 ifs_firstc[1] = '\0';
12047 ifs_firstc_len = 1;
12048 }
12049 else
12050 memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
12051 }
12052 #else
12053 ifs_firstc = ifs_value ? *ifs_value : 0;
12054 #endif
12055 }
12056
12057 char *
12058 getifs ()
12059 {
12060 return ifs_value;
12061 }
12062
12063 /* This splits a single word into a WORD LIST on $IFS, but only if the word
12064 is not quoted. list_string () performs quote removal for us, even if we
12065 don't do any splitting. */
12066 WORD_LIST *
12067 word_split (w, ifs_chars)
12068 WORD_DESC *w;
12069 char *ifs_chars;
12070 {
12071 WORD_LIST *result;
12072
12073 if (w)
12074 {
12075 char *xifs;
12076
12077 xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
12078 result = list_string (w->word, xifs, w->flags & W_QUOTED);
12079 }
12080 else
12081 result = (WORD_LIST *)NULL;
12082
12083 return (result);
12084 }
12085
12086 /* Perform word splitting on LIST and return the RESULT. It is possible
12087 to return (WORD_LIST *)NULL. */
12088 static WORD_LIST *
12089 word_list_split (list)
12090 WORD_LIST *list;
12091 {
12092 WORD_LIST *result, *t, *tresult, *e;
12093 WORD_DESC *w;
12094
12095 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
12096 {
12097 tresult = word_split (t->word, ifs_value);
12098 /* POSIX 2.6: "If the complete expansion appropriate for a word results
12099 in an empty field, that empty field shall be deleted from the list
12100 of fields that form the completely expanded command, unless the
12101 original word contained single-quote or double-quote characters."
12102 This is where we handle these words that contain quoted null strings
12103 and other characters that expand to nothing after word splitting. */
12104 if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */
12105 {
12106 w = alloc_word_desc ();
12107 w->word = (char *)xmalloc (1);
12108 w->word[0] = '\0';
12109 tresult = make_word_list (w, (WORD_LIST *)NULL);
12110 }
12111 #if defined (ARRAY_VARS)
12112 /* pass W_ARRAYREF through for words that are not split and are
12113 identical to the original word. */
12114 if (tresult && tresult->next == 0 && t->next == 0 && (t->word->flags & W_ARRAYREF) && STREQ (t->word->word, tresult->word->word))
12115 tresult->word->flags |= W_ARRAYREF;
12116 #endif
12117 if (result == 0)
12118 result = e = tresult;
12119 else
12120 {
12121 e->next = tresult;
12122 while (e->next)
12123 e = e->next;
12124 }
12125 }
12126 return (result);
12127 }
12128
12129 /**************************************************
12130 * *
12131 * Functions to expand an entire WORD_LIST *
12132 * *
12133 **************************************************/
12134
12135 /* Do any word-expansion-specific cleanup and jump to top_level */
12136 static void
12137 exp_jump_to_top_level (v)
12138 int v;
12139 {
12140 set_pipestatus_from_exit (last_command_exit_value);
12141
12142 /* Cleanup code goes here. */
12143 expand_no_split_dollar_star = 0; /* XXX */
12144 if (expanding_redir)
12145 undo_partial_redirects ();
12146 expanding_redir = 0;
12147 assigning_in_environment = 0;
12148
12149 if (parse_and_execute_level == 0)
12150 top_level_cleanup (); /* from sig.c */
12151
12152 jump_to_top_level (v);
12153 }
12154
12155 /* Put NLIST (which is a WORD_LIST * of only one element) at the front of
12156 ELIST, and set ELIST to the new list. */
12157 #define PREPEND_LIST(nlist, elist) \
12158 do { nlist->next = elist; elist = nlist; } while (0)
12159
12160 /* Separate out any initial variable assignments from TLIST. If set -k has
12161 been executed, remove all assignment statements from TLIST. Initial
12162 variable assignments and other environment assignments are placed
12163 on SUBST_ASSIGN_VARLIST. */
12164 static WORD_LIST *
12165 separate_out_assignments (tlist)
12166 WORD_LIST *tlist;
12167 {
12168 register WORD_LIST *vp, *lp;
12169
12170 if (tlist == 0)
12171 return ((WORD_LIST *)NULL);
12172
12173 if (subst_assign_varlist)
12174 dispose_words (subst_assign_varlist); /* Clean up after previous error */
12175
12176 subst_assign_varlist = (WORD_LIST *)NULL;
12177 vp = lp = tlist;
12178
12179 /* Separate out variable assignments at the start of the command.
12180 Loop invariant: vp->next == lp
12181 Loop postcondition:
12182 lp = list of words left after assignment statements skipped
12183 tlist = original list of words
12184 */
12185 while (lp && (lp->word->flags & W_ASSIGNMENT))
12186 {
12187 vp = lp;
12188 lp = lp->next;
12189 }
12190
12191 /* If lp != tlist, we have some initial assignment statements.
12192 We make SUBST_ASSIGN_VARLIST point to the list of assignment
12193 words and TLIST point to the remaining words. */
12194 if (lp != tlist)
12195 {
12196 subst_assign_varlist = tlist;
12197 /* ASSERT(vp->next == lp); */
12198 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
12199 tlist = lp; /* remainder of word list */
12200 }
12201
12202 /* vp == end of variable list */
12203 /* tlist == remainder of original word list without variable assignments */
12204 if (!tlist)
12205 /* All the words in tlist were assignment statements */
12206 return ((WORD_LIST *)NULL);
12207
12208 /* ASSERT(tlist != NULL); */
12209 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
12210
12211 /* If the -k option is in effect, we need to go through the remaining
12212 words, separate out the assignment words, and place them on
12213 SUBST_ASSIGN_VARLIST. */
12214 if (place_keywords_in_env)
12215 {
12216 WORD_LIST *tp; /* tp == running pointer into tlist */
12217
12218 tp = tlist;
12219 lp = tlist->next;
12220
12221 /* Loop Invariant: tp->next == lp */
12222 /* Loop postcondition: tlist == word list without assignment statements */
12223 while (lp)
12224 {
12225 if (lp->word->flags & W_ASSIGNMENT)
12226 {
12227 /* Found an assignment statement, add this word to end of
12228 subst_assign_varlist (vp). */
12229 if (!subst_assign_varlist)
12230 subst_assign_varlist = vp = lp;
12231 else
12232 {
12233 vp->next = lp;
12234 vp = lp;
12235 }
12236
12237 /* Remove the word pointed to by LP from TLIST. */
12238 tp->next = lp->next;
12239 /* ASSERT(vp == lp); */
12240 lp->next = (WORD_LIST *)NULL;
12241 lp = tp->next;
12242 }
12243 else
12244 {
12245 tp = lp;
12246 lp = lp->next;
12247 }
12248 }
12249 }
12250 return (tlist);
12251 }
12252
12253 #define WEXP_VARASSIGN 0x001
12254 #define WEXP_BRACEEXP 0x002
12255 #define WEXP_TILDEEXP 0x004
12256 #define WEXP_PARAMEXP 0x008
12257 #define WEXP_PATHEXP 0x010
12258
12259 /* All of the expansions, including variable assignments at the start of
12260 the list. */
12261 #define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
12262
12263 /* All of the expansions except variable assignments at the start of
12264 the list. */
12265 #define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
12266
12267 /* All of the `shell expansions': brace expansion, tilde expansion, parameter
12268 expansion, command substitution, arithmetic expansion, word splitting, and
12269 quote removal. */
12270 #define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
12271
12272 /* Take the list of words in LIST and do the various substitutions. Return
12273 a new list of words which is the expanded list, and without things like
12274 variable assignments. */
12275
12276 WORD_LIST *
12277 expand_words (list)
12278 WORD_LIST *list;
12279 {
12280 return (expand_word_list_internal (list, WEXP_ALL));
12281 }
12282
12283 /* Same as expand_words (), but doesn't hack variable or environment
12284 variables. */
12285 WORD_LIST *
12286 expand_words_no_vars (list)
12287 WORD_LIST *list;
12288 {
12289 return (expand_word_list_internal (list, WEXP_NOVARS));
12290 }
12291
12292 WORD_LIST *
12293 expand_words_shellexp (list)
12294 WORD_LIST *list;
12295 {
12296 return (expand_word_list_internal (list, WEXP_SHELLEXP));
12297 }
12298
12299 static WORD_LIST *
12300 glob_expand_word_list (tlist, eflags)
12301 WORD_LIST *tlist;
12302 int eflags;
12303 {
12304 char **glob_array, *temp_string;
12305 register int glob_index;
12306 WORD_LIST *glob_list, *output_list, *disposables, *next;
12307 WORD_DESC *tword;
12308 int x;
12309
12310 output_list = disposables = (WORD_LIST *)NULL;
12311 glob_array = (char **)NULL;
12312 while (tlist)
12313 {
12314 /* For each word, either globbing is attempted or the word is
12315 added to orig_list. If globbing succeeds, the results are
12316 added to orig_list and the word (tlist) is added to the list
12317 of disposable words. If globbing fails and failed glob
12318 expansions are left unchanged (the shell default), the
12319 original word is added to orig_list. If globbing fails and
12320 failed glob expansions are removed, the original word is
12321 added to the list of disposable words. orig_list ends up
12322 in reverse order and requires a call to REVERSE_LIST to
12323 be set right. After all words are examined, the disposable
12324 words are freed. */
12325 next = tlist->next;
12326
12327 /* If the word isn't an assignment and contains an unquoted
12328 pattern matching character, then glob it. */
12329 if ((tlist->word->flags & W_NOGLOB) == 0 &&
12330 unquoted_glob_pattern_p (tlist->word->word))
12331 {
12332 glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */
12333
12334 /* Handle error cases.
12335 I don't think we should report errors like "No such file
12336 or directory". However, I would like to report errors
12337 like "Read failed". */
12338
12339 if (glob_array == 0 || GLOB_FAILED (glob_array))
12340 {
12341 glob_array = (char **)xmalloc (sizeof (char *));
12342 glob_array[0] = (char *)NULL;
12343 }
12344
12345 /* Dequote the current word in case we have to use it. */
12346 if (glob_array[0] == NULL)
12347 {
12348 temp_string = dequote_string (tlist->word->word);
12349 free (tlist->word->word);
12350 tlist->word->word = temp_string;
12351 }
12352
12353 /* Make the array into a word list. */
12354 glob_list = (WORD_LIST *)NULL;
12355 for (glob_index = 0; glob_array[glob_index]; glob_index++)
12356 {
12357 tword = make_bare_word (glob_array[glob_index]);
12358 glob_list = make_word_list (tword, glob_list);
12359 }
12360
12361 if (glob_list)
12362 {
12363 output_list = (WORD_LIST *)list_append (glob_list, output_list);
12364 PREPEND_LIST (tlist, disposables);
12365 }
12366 else if (fail_glob_expansion != 0)
12367 {
12368 last_command_exit_value = EXECUTION_FAILURE;
12369 report_error (_("no match: %s"), tlist->word->word);
12370 exp_jump_to_top_level (DISCARD);
12371 }
12372 else if (allow_null_glob_expansion == 0)
12373 {
12374 /* Failed glob expressions are left unchanged. */
12375 PREPEND_LIST (tlist, output_list);
12376 }
12377 else
12378 {
12379 /* Failed glob expressions are removed. */
12380 PREPEND_LIST (tlist, disposables);
12381 }
12382 }
12383 else
12384 {
12385 /* Dequote the string. */
12386 temp_string = dequote_string (tlist->word->word);
12387 free (tlist->word->word);
12388 tlist->word->word = temp_string;
12389 PREPEND_LIST (tlist, output_list);
12390 }
12391
12392 strvec_dispose (glob_array);
12393 glob_array = (char **)NULL;
12394
12395 tlist = next;
12396 }
12397
12398 if (disposables)
12399 dispose_words (disposables);
12400
12401 if (output_list)
12402 output_list = REVERSE_LIST (output_list, WORD_LIST *);
12403
12404 return (output_list);
12405 }
12406
12407 #if defined (BRACE_EXPANSION)
12408 static WORD_LIST *
12409 brace_expand_word_list (tlist, eflags)
12410 WORD_LIST *tlist;
12411 int eflags;
12412 {
12413 register char **expansions;
12414 char *temp_string;
12415 WORD_LIST *disposables, *output_list, *next;
12416 WORD_DESC *w;
12417 int eindex;
12418
12419 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
12420 {
12421 next = tlist->next;
12422
12423 if (tlist->word->flags & W_NOBRACE)
12424 {
12425 /*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/
12426 PREPEND_LIST (tlist, output_list);
12427 continue;
12428 }
12429
12430 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
12431 {
12432 /*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
12433 PREPEND_LIST (tlist, output_list);
12434 continue;
12435 }
12436
12437 /* Only do brace expansion if the word has a brace character. If
12438 not, just add the word list element to BRACES and continue. In
12439 the common case, at least when running shell scripts, this will
12440 degenerate to a bunch of calls to `mbschr', and then what is
12441 basically a reversal of TLIST into BRACES, which is corrected
12442 by a call to REVERSE_LIST () on BRACES when the end of TLIST
12443 is reached. */
12444 if (mbschr (tlist->word->word, LBRACE))
12445 {
12446 expansions = brace_expand (tlist->word->word);
12447
12448 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
12449 {
12450 w = alloc_word_desc ();
12451 w->word = temp_string;
12452
12453 /* If brace expansion didn't change the word, preserve
12454 the flags. We may want to preserve the flags
12455 unconditionally someday -- XXX */
12456 if (STREQ (temp_string, tlist->word->word))
12457 w->flags = tlist->word->flags;
12458 else
12459 w = make_word_flags (w, temp_string);
12460
12461 output_list = make_word_list (w, output_list);
12462 }
12463 free (expansions);
12464
12465 /* Add TLIST to the list of words to be freed after brace
12466 expansion has been performed. */
12467 PREPEND_LIST (tlist, disposables);
12468 }
12469 else
12470 PREPEND_LIST (tlist, output_list);
12471 }
12472
12473 if (disposables)
12474 dispose_words (disposables);
12475
12476 if (output_list)
12477 output_list = REVERSE_LIST (output_list, WORD_LIST *);
12478
12479 return (output_list);
12480 }
12481 #endif
12482
12483 #if defined (ARRAY_VARS)
12484 /* Take WORD, a compound array assignment, and internally run (for example),
12485 'declare -A w', where W is the variable name portion of WORD. OPTION is
12486 the list of options to supply to `declare'. CMD is the declaration command
12487 we are expanding right now; it's unused currently. */
12488 static int
12489 make_internal_declare (word, option, cmd)
12490 char *word;
12491 char *option;
12492 char *cmd;
12493 {
12494 int t, r;
12495 WORD_LIST *wl;
12496 WORD_DESC *w;
12497
12498 w = make_word (word);
12499
12500 t = assignment (w->word, 0);
12501 if (w->word[t] == '=')
12502 {
12503 w->word[t] = '\0';
12504 if (w->word[t - 1] == '+') /* cut off any append op */
12505 w->word[t - 1] = '\0';
12506 }
12507
12508 wl = make_word_list (w, (WORD_LIST *)NULL);
12509 wl = make_word_list (make_word (option), wl);
12510
12511 r = declare_builtin (wl);
12512
12513 dispose_words (wl);
12514 return r;
12515 }
12516
12517 /* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME
12518 is an associative array.
12519
12520 If we are processing an indexed array, expand_compound_array_assignment
12521 will expand all the individual words and quote_compound_array_list will
12522 single-quote them. If we are processing an associative array, we use
12523 parse_string_to_word_list to split VALUE into a list of words instead of
12524 faking up a shell variable and calling expand_compound_array_assignment.
12525 expand_and_quote_assoc_word expands and single-quotes each word in VALUE
12526 together so we don't have problems finding the end of the subscript when
12527 quoting it.
12528
12529 Words in VALUE can be individual words, which are expanded and single-quoted,
12530 or words of the form [IND]=VALUE, which end up as explained below, as
12531 ['expanded-ind']='expanded-value'. */
12532
12533 static WORD_LIST *
12534 expand_oneword (value, flags)
12535 char *value;
12536 int flags;
12537 {
12538 WORD_LIST *l, *nl;
12539 char *t;
12540 int kvpair;
12541
12542 if (flags == 0)
12543 {
12544 /* Indexed array */
12545 l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags);
12546 /* Now we quote the results of the expansion above to prevent double
12547 expansion. */
12548 quote_compound_array_list (l, flags);
12549 return l;
12550 }
12551 else
12552 {
12553 /* Associative array */
12554 l = parse_string_to_word_list (value, 1, "array assign");
12555 #if ASSOC_KVPAIR_ASSIGNMENT
12556 kvpair = kvpair_assignment_p (l);
12557 #endif
12558
12559 /* For associative arrays, with their arbitrary subscripts, we have to
12560 expand and quote in one step so we don't have to search for the
12561 closing right bracket more than once. */
12562 for (nl = l; nl; nl = nl->next)
12563 {
12564 #if ASSOC_KVPAIR_ASSIGNMENT
12565 if (kvpair)
12566 /* keys and values undergo the same set of expansions */
12567 t = expand_and_quote_kvpair_word (nl->word->word);
12568 else
12569 #endif
12570 if ((nl->word->flags & W_ASSIGNMENT) == 0)
12571 t = sh_single_quote (nl->word->word ? nl->word->word : "");
12572 else
12573 t = expand_and_quote_assoc_word (nl->word->word, flags);
12574 free (nl->word->word);
12575 nl->word->word = t;
12576 }
12577 return l;
12578 }
12579 }
12580
12581 /* Expand a single compound assignment argument to a declaration builtin.
12582 This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through
12583 unchanged. The VALUE is expanded and each word in the result is single-
12584 quoted. Words of the form [key]=value end up as
12585 ['expanded-key']='expanded-value'. Associative arrays have special
12586 handling, see expand_oneword() above. The return value is
12587 NAME[+]=( expanded-and-quoted-VALUE ). */
12588 static void
12589 expand_compound_assignment_word (tlist, flags)
12590 WORD_LIST *tlist;
12591 int flags;
12592 {
12593 WORD_LIST *l;
12594 int wlen, oind, t;
12595 char *value, *temp;
12596
12597 /*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/
12598 t = assignment (tlist->word->word, 0);
12599
12600 /* value doesn't have the open and close parens */
12601 oind = 1;
12602 value = extract_array_assignment_list (tlist->word->word + t + 1, &oind);
12603 /* This performs one round of expansion on the index/key and value and
12604 single-quotes each word in the result. */
12605 l = expand_oneword (value, flags);
12606 free (value);
12607
12608 value = string_list (l);
12609 dispose_words (l);
12610
12611 wlen = STRLEN (value);
12612
12613 /* Now, let's rebuild the string */
12614 temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */
12615 memcpy (temp, tlist->word->word, ++t);
12616 temp[t++] = '(';
12617 if (value)
12618 memcpy (temp + t, value, wlen);
12619 t += wlen;
12620 temp[t++] = ')';
12621 temp[t] = '\0';
12622 /*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/
12623
12624 free (tlist->word->word);
12625 tlist->word->word = temp;
12626
12627 free (value);
12628 }
12629
12630 /* Expand and process an argument to a declaration command. We have already
12631 set flags in TLIST->word->flags depending on the declaration command
12632 (declare, local, etc.) and the options supplied to it (-a, -A, etc.).
12633 TLIST->word->word is of the form NAME[+]=( VALUE ).
12634
12635 This does several things, all using pieces of other functions to get the
12636 evaluation sequence right. It's called for compound array assignments with
12637 the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs).
12638 It parses out which flags need to be set for declare to create the variable
12639 correctly, then calls declare internally (make_internal_declare) to make
12640 sure the variable exists with the correct attributes. Before the variable
12641 is created, it calls expand_compound_assignment_word to expand VALUE to a
12642 list of words, appropriately quoted for further evaluation. This preserves
12643 the semantics of word-expansion-before-calling-builtins. Finally, it calls
12644 do_word_assignment to perform the expansion and assignment with the same
12645 expansion semantics as a standalone assignment statement (no word splitting,
12646 etc.) even though the word is single-quoted so all that needs to happen is
12647 quote removal. */
12648 static WORD_LIST *
12649 expand_declaration_argument (tlist, wcmd)
12650 WORD_LIST *tlist, *wcmd;
12651 {
12652 char opts[16], omap[128];
12653 int t, opti, oind, skip, inheriting;
12654 WORD_LIST *l;
12655
12656 inheriting = localvar_inherit;
12657 opti = 0;
12658 if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY))
12659 opts[opti++] = '-';
12660
12661 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
12662 {
12663 opts[opti++] = 'g';
12664 opts[opti++] = 'A';
12665 }
12666 else if (tlist->word->flags & W_ASSIGNASSOC)
12667 {
12668 opts[opti++] = 'A';
12669 }
12670 else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
12671 {
12672 opts[opti++] = 'g';
12673 opts[opti++] = 'a';
12674 }
12675 else if (tlist->word->flags & W_ASSIGNARRAY)
12676 {
12677 opts[opti++] = 'a';
12678 }
12679 else if (tlist->word->flags & W_ASSNGLOBAL)
12680 opts[opti++] = 'g';
12681
12682 if (tlist->word->flags & W_CHKLOCAL)
12683 opts[opti++] = 'G';
12684
12685 /* If we have special handling note the integer attribute and others
12686 that transform the value upon assignment. What we do is take all
12687 of the option arguments and scan through them looking for options
12688 that cause such transformations, and add them to the `opts' array. */
12689
12690 memset (omap, '\0', sizeof (omap));
12691 for (l = wcmd->next; l != tlist; l = l->next)
12692 {
12693 int optchar;
12694
12695 if (l->word->word[0] != '-' && l->word->word[0] != '+')
12696 break; /* non-option argument */
12697 if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0)
12698 break; /* -- signals end of options */
12699 optchar = l->word->word[0];
12700 for (oind = 1; l->word->word[oind]; oind++)
12701 switch (l->word->word[oind])
12702 {
12703 case 'I':
12704 inheriting = 1;
12705 case 'i':
12706 case 'l':
12707 case 'u':
12708 case 'c':
12709 omap[l->word->word[oind]] = 1;
12710 if (opti == 0)
12711 opts[opti++] = optchar;
12712 break;
12713 default:
12714 break;
12715 }
12716 }
12717
12718 for (oind = 0; oind < sizeof (omap); oind++)
12719 if (omap[oind])
12720 opts[opti++] = oind;
12721
12722 /* If there are no -a/-A options, but we have a compound assignment,
12723 we have a choice: we can set opts[0]='-', opts[1]='a', since the
12724 default is to create an indexed array, and call
12725 make_internal_declare with that, or we can just skip the -a and let
12726 declare_builtin deal with it. Once we're here, we're better set
12727 up for the latter, since we don't want to deal with looking up
12728 any existing variable here -- better to let declare_builtin do it.
12729 We need the variable created, though, especially if it's local, so
12730 we get the scoping right before we call do_word_assignment.
12731 To ensure that make_local_declare gets called, we add `--' if there
12732 aren't any options. */
12733 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0)
12734 {
12735 if (opti == 0)
12736 {
12737 opts[opti++] = '-';
12738 opts[opti++] = '-';
12739 }
12740 }
12741 opts[opti] = '\0';
12742
12743 /* This isn't perfect, but it's a start. Improvements later. We expand
12744 tlist->word->word and single-quote the results to avoid multiple
12745 expansions by, say, do_assignment_internal(). We have to weigh the
12746 cost of reconstructing the compound assignment string with its single
12747 quoting and letting the declare builtin handle it. The single quotes
12748 will prevent any unwanted additional expansion or word splitting. */
12749 expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0);
12750
12751 skip = 0;
12752 if (opti > 0)
12753 {
12754 t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0);
12755 if (t != EXECUTION_SUCCESS)
12756 {
12757 last_command_exit_value = t;
12758 if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */
12759 skip = 1;
12760 else
12761 exp_jump_to_top_level (DISCARD);
12762 }
12763 }
12764
12765 if (skip == 0)
12766 {
12767 t = do_word_assignment (tlist->word, 0);
12768 if (t == 0)
12769 {
12770 last_command_exit_value = EXECUTION_FAILURE;
12771 exp_jump_to_top_level (DISCARD);
12772 }
12773 }
12774
12775 /* Now transform the word as ksh93 appears to do and go on */
12776 t = assignment (tlist->word->word, 0);
12777 tlist->word->word[t] = '\0';
12778 if (tlist->word->word[t - 1] == '+')
12779 tlist->word->word[t - 1] = '\0'; /* cut off append op */
12780 tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
12781
12782 return (tlist);
12783 }
12784 #endif /* ARRAY_VARS */
12785
12786 static WORD_LIST *
12787 shell_expand_word_list (tlist, eflags)
12788 WORD_LIST *tlist;
12789 int eflags;
12790 {
12791 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd;
12792 int expanded_something, has_dollar_at;
12793
12794 /* We do tilde expansion all the time. This is what 1003.2 says. */
12795 wcmd = new_list = (WORD_LIST *)NULL;
12796
12797 for (orig_list = tlist; tlist; tlist = next)
12798 {
12799 if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN))
12800 wcmd = tlist;
12801
12802 next = tlist->next;
12803
12804 #if defined (ARRAY_VARS)
12805 /* If this is a compound array assignment to a builtin that accepts
12806 such assignments (e.g., `declare'), take the assignment and perform
12807 it separately, handling the semantics of declarations inside shell
12808 functions. This avoids the double-evaluation of such arguments,
12809 because `declare' does some evaluation of compound assignments on
12810 its own. */
12811 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
12812 expand_declaration_argument (tlist, wcmd);
12813 #endif
12814
12815 expanded_something = 0;
12816 expanded = expand_word_internal
12817 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
12818
12819 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
12820 {
12821 /* By convention, each time this error is returned,
12822 tlist->word->word has already been freed. */
12823 tlist->word->word = (char *)NULL;
12824
12825 /* Dispose our copy of the original list. */
12826 dispose_words (orig_list);
12827 /* Dispose the new list we're building. */
12828 dispose_words (new_list);
12829
12830 last_command_exit_value = EXECUTION_FAILURE;
12831 if (expanded == &expand_word_error)
12832 exp_jump_to_top_level (DISCARD);
12833 else
12834 exp_jump_to_top_level (FORCE_EOF);
12835 }
12836
12837 /* Don't split words marked W_NOSPLIT. */
12838 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
12839 {
12840 temp_list = word_list_split (expanded);
12841 dispose_words (expanded);
12842 }
12843 else
12844 {
12845 /* If no parameter expansion, command substitution, process
12846 substitution, or arithmetic substitution took place, then
12847 do not do word splitting. We still have to remove quoted
12848 null characters from the result. */
12849 word_list_remove_quoted_nulls (expanded);
12850 temp_list = expanded;
12851 }
12852
12853 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
12854 new_list = (WORD_LIST *)list_append (expanded, new_list);
12855 }
12856
12857 if (orig_list)
12858 dispose_words (orig_list);
12859
12860 if (new_list)
12861 new_list = REVERSE_LIST (new_list, WORD_LIST *);
12862
12863 return (new_list);
12864 }
12865
12866 /* Perform assignment statements optionally preceding a command name COMMAND.
12867 If COMMAND == NULL, is_nullcmd usually == 1. Follow the POSIX rules for
12868 variable assignment errors. */
12869 static int
12870 do_assignment_statements (varlist, command, is_nullcmd)
12871 WORD_LIST *varlist;
12872 char *command;
12873 int is_nullcmd;
12874 {
12875 WORD_LIST *temp_list;
12876 char *savecmd;
12877 sh_wassign_func_t *assign_func;
12878 int is_special_builtin, is_builtin_or_func, tint;
12879
12880 /* If the remainder of the words expand to nothing, Posix.2 requires
12881 that the variable and environment assignments affect the shell's
12882 environment (do_word_assignment). */
12883 assign_func = is_nullcmd ? do_word_assignment : assign_in_env;
12884 tempenv_assign_error = 0;
12885
12886 is_builtin_or_func = command && (find_shell_builtin (command) || find_function (command));
12887 /* Posix says that special builtins exit if a variable assignment error
12888 occurs in an assignment preceding it. (XXX - this is old -- current Posix
12889 says that any variable assignment error causes a non-interactive shell
12890 to exit. See the STRICT_POSIX checks below. */
12891 is_special_builtin = posixly_correct && command && find_special_builtin (command);
12892
12893 savecmd = this_command_name;
12894 for (temp_list = varlist; temp_list; temp_list = temp_list->next)
12895 {
12896 this_command_name = (char *)NULL;
12897 assigning_in_environment = is_nullcmd == 0;
12898 tint = (*assign_func) (temp_list->word, is_builtin_or_func);
12899 assigning_in_environment = 0;
12900 this_command_name = savecmd;
12901
12902 /* Variable assignment errors in non-interactive shells running
12903 in posix mode cause the shell to exit. */
12904 if (tint == 0)
12905 {
12906 if (is_nullcmd) /* assignment statement */
12907 {
12908 last_command_exit_value = EXECUTION_FAILURE;
12909 #if defined (STRICT_POSIX)
12910 if (posixly_correct && interactive_shell == 0)
12911 #else
12912 if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
12913 #endif
12914 exp_jump_to_top_level (FORCE_EOF);
12915 else
12916 exp_jump_to_top_level (DISCARD);
12917 }
12918 /* In posix mode, assignment errors in the temporary environment
12919 cause a non-interactive shell executing a special builtin to
12920 exit and a non-interactive shell to otherwise jump back to the
12921 top level. This is what POSIX says to do for variable assignment
12922 errors, and POSIX says errors in assigning to the temporary
12923 environment are treated as variable assignment errors.
12924 (XXX - this is not what current POSIX says - look at the
12925 STRICT_POSIX defines. */
12926 else if (posixly_correct)
12927 {
12928 last_command_exit_value = EXECUTION_FAILURE;
12929 #if defined (STRICT_POSIX)
12930 exp_jump_to_top_level ((interactive_shell == 0) ? FORCE_EOF : DISCARD);
12931 #else
12932 if (interactive_shell == 0 && is_special_builtin)
12933 exp_jump_to_top_level (FORCE_EOF);
12934 else if (interactive_shell == 0)
12935 exp_jump_to_top_level (DISCARD); /* XXX - maybe change later */
12936 else
12937 exp_jump_to_top_level (DISCARD);
12938 #endif
12939 }
12940 else
12941 tempenv_assign_error++;
12942 }
12943 }
12944 return (tempenv_assign_error);
12945 }
12946
12947 /* The workhorse for expand_words () and expand_words_no_vars ().
12948 First arg is LIST, a WORD_LIST of words.
12949 Second arg EFLAGS is a flags word controlling which expansions are
12950 performed.
12951
12952 This does all of the substitutions: brace expansion, tilde expansion,
12953 parameter expansion, command substitution, arithmetic expansion,
12954 process substitution, word splitting, and pathname expansion, according
12955 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
12956 set, or for which no expansion is done, do not undergo word splitting.
12957 Words with the W_NOGLOB bit set do not undergo pathname expansion; words
12958 with W_NOBRACE set do not undergo brace expansion (see
12959 brace_expand_word_list above). */
12960 static WORD_LIST *
12961 expand_word_list_internal (list, eflags)
12962 WORD_LIST *list;
12963 int eflags;
12964 {
12965 WORD_LIST *new_list, *temp_list;
12966
12967 tempenv_assign_error = 0;
12968 if (list == 0)
12969 return ((WORD_LIST *)NULL);
12970
12971 garglist = new_list = copy_word_list (list);
12972 if (eflags & WEXP_VARASSIGN)
12973 {
12974 garglist = new_list = separate_out_assignments (new_list);
12975 if (new_list == 0)
12976 {
12977 if (subst_assign_varlist)
12978 do_assignment_statements (subst_assign_varlist, (char *)NULL, 1);
12979
12980 dispose_words (subst_assign_varlist);
12981 subst_assign_varlist = (WORD_LIST *)NULL;
12982
12983 return ((WORD_LIST *)NULL);
12984 }
12985 }
12986
12987 /* Begin expanding the words that remain. The expansions take place on
12988 things that aren't really variable assignments. */
12989
12990 #if defined (BRACE_EXPANSION)
12991 /* Do brace expansion on this word if there are any brace characters
12992 in the string. */
12993 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
12994 new_list = brace_expand_word_list (new_list, eflags);
12995 #endif /* BRACE_EXPANSION */
12996
12997 /* Perform the `normal' shell expansions: tilde expansion, parameter and
12998 variable substitution, command substitution, arithmetic expansion,
12999 and word splitting. */
13000 new_list = shell_expand_word_list (new_list, eflags);
13001
13002 /* Okay, we're almost done. Now let's just do some filename
13003 globbing. */
13004 if (new_list)
13005 {
13006 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
13007 /* Glob expand the word list unless globbing has been disabled. */
13008 new_list = glob_expand_word_list (new_list, eflags);
13009 else
13010 /* Dequote the words, because we're not performing globbing. */
13011 new_list = dequote_list (new_list);
13012 }
13013
13014 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
13015 {
13016 do_assignment_statements (subst_assign_varlist, (new_list && new_list->word) ? new_list->word->word : (char *)NULL, new_list == 0);
13017
13018 dispose_words (subst_assign_varlist);
13019 subst_assign_varlist = (WORD_LIST *)NULL;
13020 }
13021
13022 return (new_list);
13023 }