]> git.ipfire.org Git - thirdparty/bash.git/blob - subst.c
Bash-5.2 patch 1: fix crash with unset arrays in arithmetic contexts
[thirdparty/bash.git] / subst.c
1 /* subst.c -- The part of the shell that does parameter, command, arithmetic,
2 and globbing substitutions. */
3
4 /* ``Have a little faith, there's magic in the night. You ain't a
5 beauty, but, hey, you're alright.'' */
6
7 /* Copyright (C) 1987-2022 Free Software Foundation, Inc.
8
9 This file is part of GNU Bash, the Bourne Again SHell.
10
11 Bash is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 Bash is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with Bash. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "config.h"
26
27 #include "bashtypes.h"
28 #include <stdio.h>
29 #include "chartypes.h"
30 #if defined (HAVE_PWD_H)
31 # include <pwd.h>
32 #endif
33 #include <signal.h>
34 #include <errno.h>
35
36 #if defined (HAVE_UNISTD_H)
37 # include <unistd.h>
38 #endif
39
40 #define NEED_FPURGE_DECL
41
42 #include "bashansi.h"
43 #include "posixstat.h"
44 #include "bashintl.h"
45
46 #include "shell.h"
47 #include "parser.h"
48 #include "redir.h"
49 #include "flags.h"
50 #include "jobs.h"
51 #include "execute_cmd.h"
52 #include "filecntl.h"
53 #include "trap.h"
54 #include "pathexp.h"
55 #include "mailcheck.h"
56
57 #include "shmbutil.h"
58 #if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
59 # include <mbstr.h> /* mbschr */
60 #endif
61 #include "typemax.h"
62
63 #include "builtins/getopt.h"
64 #include "builtins/common.h"
65
66 #include "builtins/builtext.h"
67
68 #include <tilde/tilde.h>
69 #include <glob/strmatch.h>
70
71 #if !defined (errno)
72 extern int errno;
73 #endif /* !errno */
74
75 /* The size that strings change by. */
76 #define DEFAULT_INITIAL_ARRAY_SIZE 112
77 #define DEFAULT_ARRAY_SIZE 128
78
79 /* Variable types. */
80 #define VT_VARIABLE 0
81 #define VT_POSPARMS 1
82 #define VT_ARRAYVAR 2
83 #define VT_ARRAYMEMBER 3
84 #define VT_ASSOCVAR 4
85
86 #define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
87
88 /* Flags for quoted_strchr */
89 #define ST_BACKSL 0x01
90 #define ST_CTLESC 0x02
91 #define ST_SQUOTE 0x04 /* unused yet */
92 #define ST_DQUOTE 0x08 /* unused yet */
93
94 /* These defs make it easier to use the editor. */
95 #define LBRACE '{'
96 #define RBRACE '}'
97 #define LPAREN '('
98 #define RPAREN ')'
99 #define LBRACK '['
100 #define RBRACK ']'
101
102 #if defined (HANDLE_MULTIBYTE)
103 #define WLPAREN L'('
104 #define WRPAREN L')'
105 #endif
106
107 #define DOLLAR_AT_STAR(c) ((c) == '@' || (c) == '*')
108 #define STR_DOLLAR_AT_STAR(s) (DOLLAR_AT_STAR ((s)[0]) && (s)[1] == '\0')
109
110 /* Evaluates to 1 if C is one of the shell's special parameters whose length
111 can be taken, but is also one of the special expansion characters. */
112 #define VALID_SPECIAL_LENGTH_PARAM(c) \
113 ((c) == '-' || (c) == '?' || (c) == '#' || (c) == '@')
114
115 /* Evaluates to 1 if C is one of the shell's special parameters for which an
116 indirect variable reference may be made. */
117 #define VALID_INDIR_PARAM(c) \
118 ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
119
120 /* Evaluates to 1 if C is one of the OP characters that follows the parameter
121 in ${parameter[:]OPword}. */
122 #define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)
123
124 /* Evaluates to 1 if this is one of the shell's special variables. */
125 #define SPECIAL_VAR(name, wi) \
126 (*name && ((DIGIT (*name) && all_digits (name)) || \
127 (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \
128 (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))))
129
130 /* This can be used by all of the *_extract_* functions that have a similar
131 structure. It can't just be wrapped in a do...while(0) loop because of
132 the embedded `break'. The dangling else accommodates a trailing semicolon;
133 we could also put in a do ; while (0) */
134
135 #define CHECK_STRING_OVERRUN(oind, ind, len, ch) \
136 if (ind >= len) \
137 { \
138 oind = len; \
139 ch = 0; \
140 break; \
141 } \
142 else \
143
144 /* An expansion function that takes a string and a quoted flag and returns
145 a WORD_LIST *. Used as the type of the third argument to
146 expand_string_if_necessary(). */
147 typedef WORD_LIST *EXPFUNC PARAMS((char *, int));
148
149 /* Process ID of the last command executed within command substitution. */
150 pid_t last_command_subst_pid = NO_PID;
151 pid_t current_command_subst_pid = NO_PID;
152
153 /* Variables used to keep track of the characters in IFS. */
154 SHELL_VAR *ifs_var;
155 char *ifs_value;
156 unsigned char ifs_cmap[UCHAR_MAX + 1];
157 int ifs_is_set, ifs_is_null;
158
159 #if defined (HANDLE_MULTIBYTE)
160 unsigned char ifs_firstc[MB_LEN_MAX];
161 size_t ifs_firstc_len;
162 #else
163 unsigned char ifs_firstc;
164 #endif
165
166 /* If non-zero, command substitution inherits the value of errexit option */
167 int inherit_errexit = 0;
168
169 /* Sentinel to tell when we are performing variable assignments preceding a
170 command name and putting them into the environment. Used to make sure
171 we use the temporary environment when looking up variable values. */
172 int assigning_in_environment;
173
174 /* Used to hold a list of variable assignments preceding a command. Global
175 so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
176 SIGCHLD trap and so it can be saved and restored by the trap handlers. */
177 WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
178
179 /* Tell the expansion functions to not longjmp back to top_level on fatal
180 errors. Enabled when doing completion and prompt string expansion. */
181 int no_longjmp_on_fatal_error = 0;
182
183 /* Non-zero means to allow unmatched globbed filenames to expand to
184 a null file. */
185 int allow_null_glob_expansion;
186
187 /* Non-zero means to throw an error when globbing fails to match anything. */
188 int fail_glob_expansion;
189
190 /* If non-zero, perform `&' substitution on the replacement string in the
191 pattern substitution word expansion. */
192 int patsub_replacement = 1;
193
194 /* Extern functions and variables from different files. */
195 extern struct fd_bitmap *current_fds_to_close;
196 extern int wordexp_only;
197 extern int singlequote_translations;
198 extern int extended_quote;
199
200 #if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION)
201 extern PROCESS *last_procsub_child;
202 #endif
203
204 #if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)
205 extern wchar_t *wcsdup PARAMS((const wchar_t *));
206 #endif
207
208 #if 0
209 /* Variables to keep track of which words in an expanded word list (the
210 output of expand_word_list_internal) are the result of globbing
211 expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c.
212 (CURRENTLY UNUSED). */
213 char *glob_argv_flags;
214 static int glob_argv_flags_size;
215 #endif
216
217 static WORD_LIST *cached_quoted_dollar_at = 0;
218
219 /* Distinguished error values to return from expansion functions */
220 static WORD_LIST expand_word_error, expand_word_fatal;
221 static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
222 static char expand_param_error, expand_param_fatal, expand_param_unset;
223 static char extract_string_error, extract_string_fatal;
224
225 /* Set by expand_word_unsplit and several of the expand_string_XXX functions;
226 used to inhibit splitting and re-joining $* on $IFS, primarily when doing
227 assignment statements. The idea is that if we're in a context where this
228 is set, we're not going to be performing word splitting, so we use the same
229 rules to expand $* as we would if it appeared within double quotes. */
230 static int expand_no_split_dollar_star = 0;
231
232 /* A WORD_LIST of words to be expanded by expand_word_list_internal,
233 without any leading variable assignments. */
234 static WORD_LIST *garglist = (WORD_LIST *)NULL;
235
236 static char *quoted_substring PARAMS((char *, int, int));
237 static int quoted_strlen PARAMS((char *));
238 static char *quoted_strchr PARAMS((char *, int, int));
239
240 static char *expand_string_if_necessary PARAMS((char *, int, EXPFUNC *));
241 static inline char *expand_string_to_string_internal PARAMS((char *, int, EXPFUNC *));
242 static WORD_LIST *call_expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *));
243 static WORD_LIST *expand_string_internal PARAMS((char *, int));
244 static WORD_LIST *expand_string_leave_quoted PARAMS((char *, int));
245 static WORD_LIST *expand_string_for_rhs PARAMS((char *, int, int, int, int *, int *));
246 static WORD_LIST *expand_string_for_pat PARAMS((char *, int, int *, int *));
247
248 static char *quote_escapes_internal PARAMS((const char *, int));
249
250 static WORD_LIST *list_quote_escapes PARAMS((WORD_LIST *));
251 static WORD_LIST *list_dequote_escapes PARAMS((WORD_LIST *));
252
253 static char *make_quoted_char PARAMS((int));
254 static WORD_LIST *quote_list PARAMS((WORD_LIST *));
255
256 static int unquoted_substring PARAMS((char *, char *));
257 static int unquoted_member PARAMS((int, char *));
258
259 #if defined (ARRAY_VARS)
260 static SHELL_VAR *do_compound_assignment PARAMS((char *, char *, int));
261 #endif
262 static int do_assignment_internal PARAMS((const WORD_DESC *, int));
263
264 static char *string_extract_verbatim PARAMS((char *, size_t, int *, char *, int));
265 static char *string_extract PARAMS((char *, int *, char *, int));
266 static char *string_extract_double_quoted PARAMS((char *, int *, int));
267 static inline char *string_extract_single_quoted PARAMS((char *, int *, int));
268 static inline int skip_single_quoted PARAMS((const char *, size_t, int, int));
269 static int skip_double_quoted PARAMS((char *, size_t, int, int));
270 static char *extract_delimited_string PARAMS((char *, int *, char *, char *, char *, int));
271 static char *extract_heredoc_dolbrace_string PARAMS((char *, int *, int, int));
272 static char *extract_dollar_brace_string PARAMS((char *, int *, int, int));
273 static int skip_matched_pair PARAMS((const char *, int, int, int, int));
274
275 static char *pos_params PARAMS((char *, int, int, int, int));
276
277 static unsigned char *mb_getcharlens PARAMS((char *, int));
278
279 static char *remove_upattern PARAMS((char *, char *, int));
280 #if defined (HANDLE_MULTIBYTE)
281 static wchar_t *remove_wpattern PARAMS((wchar_t *, size_t, wchar_t *, int));
282 #endif
283 static char *remove_pattern PARAMS((char *, char *, int));
284
285 static int match_upattern PARAMS((char *, char *, int, char **, char **));
286 #if defined (HANDLE_MULTIBYTE)
287 static int match_wpattern PARAMS((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
288 #endif
289 static int match_pattern PARAMS((char *, char *, int, char **, char **));
290 static int getpatspec PARAMS((int, char *));
291 static char *getpattern PARAMS((char *, int, int));
292 static char *variable_remove_pattern PARAMS((char *, char *, int, int));
293 static char *list_remove_pattern PARAMS((WORD_LIST *, char *, int, int, int));
294 static char *parameter_list_remove_pattern PARAMS((int, char *, int, int));
295 #ifdef ARRAY_VARS
296 static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int));
297 #endif
298 static char *parameter_brace_remove_pattern PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
299
300 static char *string_var_assignment PARAMS((SHELL_VAR *, char *));
301 #if defined (ARRAY_VARS)
302 static char *array_var_assignment PARAMS((SHELL_VAR *, int, int, int));
303 #endif
304 static char *pos_params_assignment PARAMS((WORD_LIST *, int, int));
305 static char *string_transform PARAMS((int, SHELL_VAR *, char *));
306 static char *list_transform PARAMS((int, SHELL_VAR *, WORD_LIST *, int, int));
307 static char *parameter_list_transform PARAMS((int, int, int));
308 #if defined ARRAY_VARS
309 static char *array_transform PARAMS((int, SHELL_VAR *, int, int));
310 #endif
311 static char *parameter_brace_transform PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int, int));
312 static int valid_parameter_transform PARAMS((char *));
313
314 static char *process_substitute PARAMS((char *, int));
315
316 static char *optimize_cat_file PARAMS((REDIRECT *, int, int, int *));
317 static char *read_comsub PARAMS((int, int, int, int *));
318
319 #ifdef ARRAY_VARS
320 static arrayind_t array_length_reference PARAMS((char *));
321 #endif
322
323 static int valid_brace_expansion_word PARAMS((char *, int));
324 static int chk_atstar PARAMS((char *, int, int, int *, int *));
325 static int chk_arithsub PARAMS((const char *, int));
326
327 static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, array_eltstate_t *));
328 static char *parameter_brace_find_indir PARAMS((char *, int, int, int));
329 static WORD_DESC *parameter_brace_expand_indir PARAMS((char *, int, int, int, int *, int *));
330 static WORD_DESC *parameter_brace_expand_rhs PARAMS((char *, char *, int, int, int, int *, int *));
331 static void parameter_brace_expand_error PARAMS((char *, char *, int));
332
333 static int valid_length_expression PARAMS((char *));
334 static intmax_t parameter_brace_expand_length PARAMS((char *));
335
336 static char *skiparith PARAMS((char *, int));
337 static int verify_substring_values PARAMS((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
338 static int get_var_and_type PARAMS((char *, char *, array_eltstate_t *, int, int, SHELL_VAR **, char **));
339 static char *mb_substring PARAMS((char *, int, int));
340 static char *parameter_brace_substring PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
341
342 static int shouldexp_replacement PARAMS((char *));
343
344 static char *pos_params_pat_subst PARAMS((char *, char *, char *, int));
345
346 static char *expand_string_for_patsub PARAMS((char *, int));
347 static char *parameter_brace_patsub PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
348
349 static char *pos_params_casemod PARAMS((char *, char *, int, int));
350 static char *parameter_brace_casemod PARAMS((char *, char *, array_eltstate_t *, int, char *, int, int, int));
351
352 static WORD_DESC *parameter_brace_expand PARAMS((char *, int *, int, int, int *, int *));
353 static WORD_DESC *param_expand PARAMS((char *, int *, int, int *, int *, int *, int *, int));
354
355 static WORD_LIST *expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *));
356
357 static WORD_LIST *word_list_split PARAMS((WORD_LIST *));
358
359 static void exp_jump_to_top_level PARAMS((int));
360
361 static WORD_LIST *separate_out_assignments PARAMS((WORD_LIST *));
362 static WORD_LIST *glob_expand_word_list PARAMS((WORD_LIST *, int));
363 #ifdef BRACE_EXPANSION
364 static WORD_LIST *brace_expand_word_list PARAMS((WORD_LIST *, int));
365 #endif
366 #if defined (ARRAY_VARS)
367 static int make_internal_declare PARAMS((char *, char *, char *));
368 static void expand_compound_assignment_word PARAMS((WORD_LIST *, int));
369 static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *));
370 #endif
371 static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int));
372 static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int));
373
374 static int do_assignment_statements PARAMS((WORD_LIST *, char *, int));
375
376 /* **************************************************************** */
377 /* */
378 /* Utility Functions */
379 /* */
380 /* **************************************************************** */
381
382 #if defined (DEBUG)
383 void
384 dump_word_flags (flags)
385 int flags;
386 {
387 int f;
388
389 f = flags;
390 fprintf (stderr, "%d -> ", f);
391 if (f & W_ARRAYIND)
392 {
393 f &= ~W_ARRAYIND;
394 fprintf (stderr, "W_ARRAYIND%s", f ? "|" : "");
395 }
396 if (f & W_ASSIGNASSOC)
397 {
398 f &= ~W_ASSIGNASSOC;
399 fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
400 }
401 if (f & W_ASSIGNARRAY)
402 {
403 f &= ~W_ASSIGNARRAY;
404 fprintf (stderr, "W_ASSIGNARRAY%s", f ? "|" : "");
405 }
406 if (f & W_SAWQUOTEDNULL)
407 {
408 f &= ~W_SAWQUOTEDNULL;
409 fprintf (stderr, "W_SAWQUOTEDNULL%s", f ? "|" : "");
410 }
411 if (f & W_NOPROCSUB)
412 {
413 f &= ~W_NOPROCSUB;
414 fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
415 }
416 if (f & W_DQUOTE)
417 {
418 f &= ~W_DQUOTE;
419 fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
420 }
421 if (f & W_HASQUOTEDNULL)
422 {
423 f &= ~W_HASQUOTEDNULL;
424 fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
425 }
426 if (f & W_ASSIGNARG)
427 {
428 f &= ~W_ASSIGNARG;
429 fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
430 }
431 if (f & W_ASSNBLTIN)
432 {
433 f &= ~W_ASSNBLTIN;
434 fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
435 }
436 if (f & W_ASSNGLOBAL)
437 {
438 f &= ~W_ASSNGLOBAL;
439 fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : "");
440 }
441 if (f & W_COMPASSIGN)
442 {
443 f &= ~W_COMPASSIGN;
444 fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
445 }
446 if (f & W_EXPANDRHS)
447 {
448 f &= ~W_EXPANDRHS;
449 fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : "");
450 }
451 if (f & W_NOTILDE)
452 {
453 f &= ~W_NOTILDE;
454 fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
455 }
456 if (f & W_ASSIGNRHS)
457 {
458 f &= ~W_ASSIGNRHS;
459 fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
460 }
461 if (f & W_NOASSNTILDE)
462 {
463 f &= ~W_NOASSNTILDE;
464 fprintf (stderr, "W_NOASSNTILDE%s", f ? "|" : "");
465 }
466 if (f & W_NOCOMSUB)
467 {
468 f &= ~W_NOCOMSUB;
469 fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
470 }
471 if (f & W_ARRAYREF)
472 {
473 f &= ~W_ARRAYREF;
474 fprintf (stderr, "W_ARRAYREF%s", f ? "|" : "");
475 }
476 if (f & W_DOLLARAT)
477 {
478 f &= ~W_DOLLARAT;
479 fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
480 }
481 if (f & W_TILDEEXP)
482 {
483 f &= ~W_TILDEEXP;
484 fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
485 }
486 if (f & W_NOSPLIT2)
487 {
488 f &= ~W_NOSPLIT2;
489 fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
490 }
491 if (f & W_NOSPLIT)
492 {
493 f &= ~W_NOSPLIT;
494 fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
495 }
496 if (f & W_NOBRACE)
497 {
498 f &= ~W_NOBRACE;
499 fprintf (stderr, "W_NOBRACE%s", f ? "|" : "");
500 }
501 if (f & W_NOGLOB)
502 {
503 f &= ~W_NOGLOB;
504 fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
505 }
506 if (f & W_SPLITSPACE)
507 {
508 f &= ~W_SPLITSPACE;
509 fprintf (stderr, "W_SPLITSPACE%s", f ? "|" : "");
510 }
511 if (f & W_ASSIGNMENT)
512 {
513 f &= ~W_ASSIGNMENT;
514 fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
515 }
516 if (f & W_QUOTED)
517 {
518 f &= ~W_QUOTED;
519 fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
520 }
521 if (f & W_HASDOLLAR)
522 {
523 f &= ~W_HASDOLLAR;
524 fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
525 }
526 if (f & W_COMPLETE)
527 {
528 f &= ~W_COMPLETE;
529 fprintf (stderr, "W_COMPLETE%s", f ? "|" : "");
530 }
531 if (f & W_CHKLOCAL)
532 {
533 f &= ~W_CHKLOCAL;
534 fprintf (stderr, "W_CHKLOCAL%s", f ? "|" : "");
535 }
536 if (f & W_FORCELOCAL)
537 {
538 f &= ~W_FORCELOCAL;
539 fprintf (stderr, "W_FORCELOCAL%s", f ? "|" : "");
540 }
541
542 fprintf (stderr, "\n");
543 fflush (stderr);
544 }
545 #endif
546
547 #ifdef INCLUDE_UNUSED
548 static char *
549 quoted_substring (string, start, end)
550 char *string;
551 int start, end;
552 {
553 register int len, l;
554 register char *result, *s, *r;
555
556 len = end - start;
557
558 /* Move to string[start], skipping quoted characters. */
559 for (s = string, l = 0; *s && l < start; )
560 {
561 if (*s == CTLESC)
562 {
563 s++;
564 continue;
565 }
566 l++;
567 if (*s == 0)
568 break;
569 }
570
571 r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */
572
573 /* Copy LEN characters, including quote characters. */
574 s = string + l;
575 for (l = 0; l < len; s++)
576 {
577 if (*s == CTLESC)
578 *r++ = *s++;
579 *r++ = *s;
580 l++;
581 if (*s == 0)
582 break;
583 }
584 *r = '\0';
585 return result;
586 }
587 #endif
588
589 #ifdef INCLUDE_UNUSED
590 /* Return the length of S, skipping over quoted characters */
591 static int
592 quoted_strlen (s)
593 char *s;
594 {
595 register char *p;
596 int i;
597
598 i = 0;
599 for (p = s; *p; p++)
600 {
601 if (*p == CTLESC)
602 {
603 p++;
604 if (*p == 0)
605 return (i + 1);
606 }
607 i++;
608 }
609
610 return i;
611 }
612 #endif
613
614 #ifdef INCLUDE_UNUSED
615 /* Find the first occurrence of character C in string S, obeying shell
616 quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
617 characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters
618 escaped with CTLESC are skipped. */
619 static char *
620 quoted_strchr (s, c, flags)
621 char *s;
622 int c, flags;
623 {
624 register char *p;
625
626 for (p = s; *p; p++)
627 {
628 if (((flags & ST_BACKSL) && *p == '\\')
629 || ((flags & ST_CTLESC) && *p == CTLESC))
630 {
631 p++;
632 if (*p == '\0')
633 return ((char *)NULL);
634 continue;
635 }
636 else if (*p == c)
637 return p;
638 }
639 return ((char *)NULL);
640 }
641
642 /* Return 1 if CHARACTER appears in an unquoted portion of
643 STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */
644 static int
645 unquoted_member (character, string)
646 int character;
647 char *string;
648 {
649 size_t slen;
650 int sindex, c;
651 DECLARE_MBSTATE;
652
653 slen = strlen (string);
654 sindex = 0;
655 while (c = string[sindex])
656 {
657 if (c == character)
658 return (1);
659
660 switch (c)
661 {
662 default:
663 ADVANCE_CHAR (string, slen, sindex);
664 break;
665
666 case '\\':
667 sindex++;
668 if (string[sindex])
669 ADVANCE_CHAR (string, slen, sindex);
670 break;
671
672 case '\'':
673 sindex = skip_single_quoted (string, slen, ++sindex, 0);
674 break;
675
676 case '"':
677 sindex = skip_double_quoted (string, slen, ++sindex, 0);
678 break;
679 }
680 }
681 return (0);
682 }
683
684 /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
685 static int
686 unquoted_substring (substr, string)
687 char *substr, *string;
688 {
689 size_t slen;
690 int sindex, c, sublen;
691 DECLARE_MBSTATE;
692
693 if (substr == 0 || *substr == '\0')
694 return (0);
695
696 slen = strlen (string);
697 sublen = strlen (substr);
698 for (sindex = 0; c = string[sindex]; )
699 {
700 if (STREQN (string + sindex, substr, sublen))
701 return (1);
702
703 switch (c)
704 {
705 case '\\':
706 sindex++;
707 if (string[sindex])
708 ADVANCE_CHAR (string, slen, sindex);
709 break;
710
711 case '\'':
712 sindex = skip_single_quoted (string, slen, ++sindex, 0);
713 break;
714
715 case '"':
716 sindex = skip_double_quoted (string, slen, ++sindex, 0);
717 break;
718
719 default:
720 ADVANCE_CHAR (string, slen, sindex);
721 break;
722 }
723 }
724 return (0);
725 }
726 #endif
727
728 /* Most of the substitutions must be done in parallel. In order
729 to avoid using tons of unclear goto's, I have some functions
730 for manipulating malloc'ed strings. They all take INDX, a
731 pointer to an integer which is the offset into the string
732 where manipulation is taking place. They also take SIZE, a
733 pointer to an integer which is the current length of the
734 character array for this string. */
735
736 /* Append SOURCE to TARGET at INDEX. SIZE is the current amount
737 of space allocated to TARGET. SOURCE can be NULL, in which
738 case nothing happens. Gets rid of SOURCE by freeing it.
739 Returns TARGET in case the location has changed. */
740 INLINE char *
741 sub_append_string (source, target, indx, size)
742 char *source, *target;
743 size_t *indx;
744 size_t *size;
745 {
746 if (source)
747 {
748 size_t n, srclen;
749
750 srclen = STRLEN (source);
751 if (srclen >= (*size - *indx))
752 {
753 n = srclen + *indx;
754 n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
755 target = (char *)xrealloc (target, (*size = n));
756 }
757
758 FASTCOPY (source, target + *indx, srclen);
759 *indx += srclen;
760 target[*indx] = '\0';
761
762 free (source);
763 }
764 return (target);
765 }
766
767 #if 0
768 /* UNUSED */
769 /* Append the textual representation of NUMBER to TARGET.
770 INDX and SIZE are as in SUB_APPEND_STRING. */
771 char *
772 sub_append_number (number, target, indx, size)
773 intmax_t number;
774 char *target;
775 size_t *indx;
776 size_t *size;
777 {
778 char *temp;
779
780 temp = itos (number);
781 return (sub_append_string (temp, target, indx, size));
782 }
783 #endif
784
785 /* Extract a substring from STRING, starting at SINDEX and ending with
786 one of the characters in CHARLIST. Don't make the ending character
787 part of the string. Leave SINDEX pointing at the ending character.
788 Understand about backslashes in the string. If (flags & SX_VARNAME)
789 is non-zero, and array variables have been compiled into the shell,
790 everything between a `[' and a corresponding `]' is skipped over.
791 If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
792 update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must
793 contain a closing character from CHARLIST. */
794 static char *
795 string_extract (string, sindex, charlist, flags)
796 char *string;
797 int *sindex;
798 char *charlist;
799 int flags;
800 {
801 register int c, i;
802 int found;
803 size_t slen;
804 char *temp;
805 DECLARE_MBSTATE;
806
807 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
808 i = *sindex;
809 found = 0;
810 while (c = string[i])
811 {
812 if (c == '\\')
813 {
814 if (string[i + 1])
815 i++;
816 else
817 break;
818 }
819 #if defined (ARRAY_VARS)
820 else if ((flags & SX_VARNAME) && c == LBRACK)
821 {
822 int ni;
823 /* If this is an array subscript, skip over it and continue. */
824 ni = skipsubscript (string, i, 0);
825 if (string[ni] == RBRACK)
826 i = ni;
827 }
828 #endif
829 else if (MEMBER (c, charlist))
830 {
831 found = 1;
832 break;
833 }
834
835 ADVANCE_CHAR (string, slen, i);
836 }
837
838 /* If we had to have a matching delimiter and didn't find one, return an
839 error and let the caller deal with it. */
840 if ((flags & SX_REQMATCH) && found == 0)
841 {
842 *sindex = i;
843 return (&extract_string_error);
844 }
845
846 temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
847 *sindex = i;
848
849 return (temp);
850 }
851
852 /* Extract the contents of STRING as if it is enclosed in double quotes.
853 SINDEX, when passed in, is the offset of the character immediately
854 following the opening double quote; on exit, SINDEX is left pointing after
855 the closing double quote. If STRIPDQ is non-zero, unquoted double
856 quotes are stripped and the string is terminated by a null byte.
857 Backslashes between the embedded double quotes are processed. If STRIPDQ
858 is zero, an unquoted `"' terminates the string. */
859 static char *
860 string_extract_double_quoted (string, sindex, flags)
861 char *string;
862 int *sindex, flags;
863 {
864 size_t slen;
865 char *send;
866 int j, i, t;
867 unsigned char c;
868 char *temp, *ret; /* The new string we return. */
869 int pass_next, backquote, si; /* State variables for the machine. */
870 int dquote;
871 int stripdq;
872 DECLARE_MBSTATE;
873
874 slen = strlen (string + *sindex) + *sindex;
875 send = string + slen;
876
877 stripdq = (flags & SX_STRIPDQ);
878
879 pass_next = backquote = dquote = 0;
880 temp = (char *)xmalloc (1 + slen - *sindex);
881
882 j = 0;
883 i = *sindex;
884 while (c = string[i])
885 {
886 /* Process a character that was quoted by a backslash. */
887 if (pass_next)
888 {
889 /* XXX - take another look at this in light of Interp 221 */
890 /* Posix.2 sez:
891
892 ``The backslash shall retain its special meaning as an escape
893 character only when followed by one of the characters:
894 $ ` " \ <newline>''.
895
896 If STRIPDQ is zero, we handle the double quotes here and let
897 expand_word_internal handle the rest. If STRIPDQ is non-zero,
898 we have already been through one round of backslash stripping,
899 and want to strip these backslashes only if DQUOTE is non-zero,
900 indicating that we are inside an embedded double-quoted string. */
901
902 /* If we are in an embedded quoted string, then don't strip
903 backslashes before characters for which the backslash
904 retains its special meaning, but remove backslashes in
905 front of other characters. If we are not in an
906 embedded quoted string, don't strip backslashes at all.
907 This mess is necessary because the string was already
908 surrounded by double quotes (and sh has some really weird
909 quoting rules).
910 The returned string will be run through expansion as if
911 it were double-quoted. */
912 if ((stripdq == 0 && c != '"') ||
913 (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0)))
914 temp[j++] = '\\';
915 pass_next = 0;
916
917 add_one_character:
918 COPY_CHAR_I (temp, j, string, send, i);
919 continue;
920 }
921
922 /* A backslash protects the next character. The code just above
923 handles preserving the backslash in front of any character but
924 a double quote. */
925 if (c == '\\')
926 {
927 pass_next++;
928 i++;
929 continue;
930 }
931
932 /* Inside backquotes, ``the portion of the quoted string from the
933 initial backquote and the characters up to the next backquote
934 that is not preceded by a backslash, having escape characters
935 removed, defines that command''. */
936 if (backquote)
937 {
938 if (c == '`')
939 backquote = 0;
940 temp[j++] = c; /* COPY_CHAR_I? */
941 i++;
942 continue;
943 }
944
945 if (c == '`')
946 {
947 temp[j++] = c;
948 backquote++;
949 i++;
950 continue;
951 }
952
953 /* Pass everything between `$(' and the matching `)' or a quoted
954 ${ ... } pair through according to the Posix.2 specification. */
955 if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
956 {
957 int free_ret = 1;
958
959 si = i + 2;
960 if (string[i + 1] == LPAREN)
961 ret = extract_command_subst (string, &si, (flags & SX_COMPLETE));
962 else
963 ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0);
964
965 temp[j++] = '$';
966 temp[j++] = string[i + 1];
967
968 /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error
969 is set. */
970 if (ret == 0 && no_longjmp_on_fatal_error)
971 {
972 free_ret = 0;
973 ret = string + i + 2;
974 }
975
976 /* XXX - CHECK_STRING_OVERRUN here? */
977 for (t = 0; ret[t]; t++, j++)
978 temp[j] = ret[t];
979 temp[j] = string[si];
980
981 if (si < i + 2) /* we went back? */
982 i += 2;
983 else if (string[si])
984 {
985 j++;
986 i = si + 1;
987 }
988 else
989 i = si;
990
991 if (free_ret)
992 free (ret);
993 continue;
994 }
995
996 /* Add any character but a double quote to the quoted string we're
997 accumulating. */
998 if (c != '"')
999 goto add_one_character;
1000
1001 /* c == '"' */
1002 if (stripdq)
1003 {
1004 dquote ^= 1;
1005 i++;
1006 continue;
1007 }
1008
1009 break;
1010 }
1011 temp[j] = '\0';
1012
1013 /* Point to after the closing quote. */
1014 if (c)
1015 i++;
1016 *sindex = i;
1017
1018 return (temp);
1019 }
1020
1021 /* This should really be another option to string_extract_double_quoted. */
1022 static int
1023 skip_double_quoted (string, slen, sind, flags)
1024 char *string;
1025 size_t slen;
1026 int sind;
1027 int flags;
1028 {
1029 int c, i;
1030 char *ret;
1031 int pass_next, backquote, si;
1032 DECLARE_MBSTATE;
1033
1034 pass_next = backquote = 0;
1035 i = sind;
1036 while (c = string[i])
1037 {
1038 if (pass_next)
1039 {
1040 pass_next = 0;
1041 ADVANCE_CHAR (string, slen, i);
1042 continue;
1043 }
1044 else if (c == '\\')
1045 {
1046 pass_next++;
1047 i++;
1048 continue;
1049 }
1050 else if (backquote)
1051 {
1052 if (c == '`')
1053 backquote = 0;
1054 ADVANCE_CHAR (string, slen, i);
1055 continue;
1056 }
1057 else if (c == '`')
1058 {
1059 backquote++;
1060 i++;
1061 continue;
1062 }
1063 else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
1064 {
1065 si = i + 2;
1066 if (string[i + 1] == LPAREN)
1067 ret = extract_command_subst (string, &si, SX_NOALLOC|(flags&SX_COMPLETE));
1068 else
1069 ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC);
1070
1071 /* These can consume the entire string if they are unterminated */
1072 CHECK_STRING_OVERRUN (i, si, slen, c);
1073
1074 i = si + 1;
1075 continue;
1076 }
1077 else if (c != '"')
1078 {
1079 ADVANCE_CHAR (string, slen, i);
1080 continue;
1081 }
1082 else
1083 break;
1084 }
1085
1086 if (c)
1087 i++;
1088
1089 return (i);
1090 }
1091
1092 /* Extract the contents of STRING as if it is enclosed in single quotes.
1093 SINDEX, when passed in, is the offset of the character immediately
1094 following the opening single quote; on exit, SINDEX is left pointing after
1095 the closing single quote. ALLOWESC allows the single quote to be quoted by
1096 a backslash; it's not used yet. */
1097 static inline char *
1098 string_extract_single_quoted (string, sindex, allowesc)
1099 char *string;
1100 int *sindex;
1101 int allowesc;
1102 {
1103 register int i;
1104 size_t slen;
1105 char *t;
1106 int pass_next;
1107 DECLARE_MBSTATE;
1108
1109 /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */
1110 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
1111 i = *sindex;
1112 pass_next = 0;
1113 while (string[i])
1114 {
1115 if (pass_next)
1116 {
1117 pass_next = 0;
1118 ADVANCE_CHAR (string, slen, i);
1119 continue;
1120 }
1121 if (allowesc && string[i] == '\\')
1122 pass_next++;
1123 else if (string[i] == '\'')
1124 break;
1125 ADVANCE_CHAR (string, slen, i);
1126 }
1127
1128 t = substring (string, *sindex, i);
1129
1130 if (string[i])
1131 i++;
1132 *sindex = i;
1133
1134 return (t);
1135 }
1136
1137 /* Skip over a single-quoted string. We overload the SX_COMPLETE flag to mean
1138 that we are splitting out words for completion and have encountered a $'...'
1139 string, which allows backslash-escaped single quotes. */
1140 static inline int
1141 skip_single_quoted (string, slen, sind, flags)
1142 const char *string;
1143 size_t slen;
1144 int sind;
1145 int flags;
1146 {
1147 register int c;
1148 DECLARE_MBSTATE;
1149
1150 c = sind;
1151 while (string[c] && string[c] != '\'')
1152 {
1153 if ((flags & SX_COMPLETE) && string[c] == '\\' && string[c+1] == '\'' && string[c+2])
1154 ADVANCE_CHAR (string, slen, c);
1155 ADVANCE_CHAR (string, slen, c);
1156 }
1157
1158 if (string[c])
1159 c++;
1160 return c;
1161 }
1162
1163 /* Just like string_extract, but doesn't hack backslashes or any of
1164 that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */
1165 static char *
1166 string_extract_verbatim (string, slen, sindex, charlist, flags)
1167 char *string;
1168 size_t slen;
1169 int *sindex;
1170 char *charlist;
1171 int flags;
1172 {
1173 register int i;
1174 #if defined (HANDLE_MULTIBYTE)
1175 wchar_t *wcharlist;
1176 #endif
1177 int c;
1178 char *temp;
1179 DECLARE_MBSTATE;
1180
1181 if ((flags & SX_NOCTLESC) && charlist[0] == '\'' && charlist[1] == '\0')
1182 {
1183 temp = string_extract_single_quoted (string, sindex, 0);
1184 --*sindex; /* leave *sindex at separator character */
1185 return temp;
1186 }
1187
1188 /* This can never be called with charlist == NULL. If *charlist == NULL,
1189 we can skip the loop and just return a copy of the string, updating
1190 *sindex */
1191 if (*charlist == 0)
1192 {
1193 temp = string + *sindex;
1194 c = (*sindex == 0) ? slen : STRLEN (temp);
1195 temp = savestring (temp);
1196 *sindex += c;
1197 return temp;
1198 }
1199
1200 i = *sindex;
1201 #if defined (HANDLE_MULTIBYTE)
1202 wcharlist = 0;
1203 #endif
1204 while (c = string[i])
1205 {
1206 #if defined (HANDLE_MULTIBYTE)
1207 size_t mblength;
1208 #endif
1209 if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
1210 {
1211 i += 2;
1212 CHECK_STRING_OVERRUN (i, i, slen, c);
1213 continue;
1214 }
1215 /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
1216 through, to protect the CTLNULs from later calls to
1217 remove_quoted_nulls. */
1218 else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
1219 {
1220 i += 2;
1221 CHECK_STRING_OVERRUN (i, i, slen, c);
1222 continue;
1223 }
1224
1225 #if defined (HANDLE_MULTIBYTE)
1226 if (locale_utf8locale && slen > i && UTF8_SINGLEBYTE (string[i]))
1227 mblength = (string[i] != 0) ? 1 : 0;
1228 else
1229 mblength = MBLEN (string + i, slen - i);
1230 if (mblength > 1)
1231 {
1232 wchar_t wc;
1233 mblength = mbtowc (&wc, string + i, slen - i);
1234 if (MB_INVALIDCH (mblength))
1235 {
1236 if (MEMBER (c, charlist))
1237 break;
1238 }
1239 else
1240 {
1241 if (wcharlist == 0)
1242 {
1243 size_t len;
1244 len = mbstowcs (wcharlist, charlist, 0);
1245 if (len == -1)
1246 len = 0;
1247 wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
1248 mbstowcs (wcharlist, charlist, len + 1);
1249 }
1250
1251 if (wcschr (wcharlist, wc))
1252 break;
1253 }
1254 }
1255 else
1256 #endif
1257 if (MEMBER (c, charlist))
1258 break;
1259
1260 ADVANCE_CHAR (string, slen, i);
1261 }
1262
1263 #if defined (HANDLE_MULTIBYTE)
1264 FREE (wcharlist);
1265 #endif
1266
1267 temp = substring (string, *sindex, i);
1268 *sindex = i;
1269
1270 return (temp);
1271 }
1272
1273 /* Extract the $( construct in STRING, and return a new string.
1274 Start extracting at (SINDEX) as if we had just seen "$(".
1275 Make (SINDEX) get the position of the matching ")". )
1276 XFLAGS is additional flags to pass to other extraction functions. */
1277 char *
1278 extract_command_subst (string, sindex, xflags)
1279 char *string;
1280 int *sindex;
1281 int xflags;
1282 {
1283 char *ret;
1284
1285 if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE))
1286 return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
1287 else
1288 {
1289 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1290 ret = xparse_dolparen (string, string+*sindex, sindex, xflags);
1291 return ret;
1292 }
1293 }
1294
1295 /* Extract the $[ construct in STRING, and return a new string. (])
1296 Start extracting at (SINDEX) as if we had just seen "$[".
1297 Make (SINDEX) get the position of the matching "]". */
1298 char *
1299 extract_arithmetic_subst (string, sindex)
1300 char *string;
1301 int *sindex;
1302 {
1303 return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/
1304 }
1305
1306 #if defined (PROCESS_SUBSTITUTION)
1307 /* Extract the <( or >( construct in STRING, and return a new string.
1308 Start extracting at (SINDEX) as if we had just seen "<(".
1309 Make (SINDEX) get the position of the matching ")". */ /*))*/
1310 char *
1311 extract_process_subst (string, starter, sindex, xflags)
1312 char *string;
1313 char *starter;
1314 int *sindex;
1315 int xflags;
1316 {
1317 #if 0
1318 /* XXX - check xflags&SX_COMPLETE here? */
1319 return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND));
1320 #else
1321 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1322 return (xparse_dolparen (string, string+*sindex, sindex, xflags));
1323 #endif
1324 }
1325 #endif /* PROCESS_SUBSTITUTION */
1326
1327 #if defined (ARRAY_VARS)
1328 /* This can be fooled by unquoted right parens in the passed string. If
1329 each caller verifies that the last character in STRING is a right paren,
1330 we don't even need to call extract_delimited_string. */
1331 char *
1332 extract_array_assignment_list (string, sindex)
1333 char *string;
1334 int *sindex;
1335 {
1336 int slen;
1337 char *ret;
1338
1339 slen = strlen (string);
1340 if (string[slen - 1] == RPAREN)
1341 {
1342 ret = substring (string, *sindex, slen - 1);
1343 *sindex = slen - 1;
1344 return ret;
1345 }
1346 return 0;
1347 }
1348 #endif
1349
1350 /* Extract and create a new string from the contents of STRING, a
1351 character string delimited with OPENER and CLOSER. SINDEX is
1352 the address of an int describing the current offset in STRING;
1353 it should point to just after the first OPENER found. On exit,
1354 SINDEX gets the position of the last character of the matching CLOSER.
1355 If OPENER is more than a single character, ALT_OPENER, if non-null,
1356 contains a character string that can also match CLOSER and thus
1357 needs to be skipped. */
1358 static char *
1359 extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
1360 char *string;
1361 int *sindex;
1362 char *opener, *alt_opener, *closer;
1363 int flags;
1364 {
1365 int i, c, si;
1366 size_t slen;
1367 char *t, *result;
1368 int pass_character, nesting_level, in_comment;
1369 int len_closer, len_opener, len_alt_opener;
1370 DECLARE_MBSTATE;
1371
1372 slen = strlen (string + *sindex) + *sindex;
1373 len_opener = STRLEN (opener);
1374 len_alt_opener = STRLEN (alt_opener);
1375 len_closer = STRLEN (closer);
1376
1377 pass_character = in_comment = 0;
1378
1379 nesting_level = 1;
1380 i = *sindex;
1381
1382 while (nesting_level)
1383 {
1384 c = string[i];
1385
1386 /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond
1387 the end of the string, catch it and cut the loop. */
1388 if (i > slen)
1389 {
1390 i = slen;
1391 c = string[i = slen];
1392 break;
1393 }
1394
1395 if (c == 0)
1396 break;
1397
1398 if (in_comment)
1399 {
1400 if (c == '\n')
1401 in_comment = 0;
1402 ADVANCE_CHAR (string, slen, i);
1403 continue;
1404 }
1405
1406 if (pass_character) /* previous char was backslash */
1407 {
1408 pass_character = 0;
1409 ADVANCE_CHAR (string, slen, i);
1410 continue;
1411 }
1412
1413 /* Not exactly right yet; should handle shell metacharacters and
1414 multibyte characters, too. See COMMENT_BEGIN define in parse.y */
1415 if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
1416 {
1417 in_comment = 1;
1418 ADVANCE_CHAR (string, slen, i);
1419 continue;
1420 }
1421
1422 if (c == CTLESC || c == '\\')
1423 {
1424 pass_character++;
1425 i++;
1426 continue;
1427 }
1428
1429 /* Process a nested command substitution, but only if we're parsing an
1430 arithmetic substitution. */
1431 if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
1432 {
1433 si = i + 2;
1434 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1435 CHECK_STRING_OVERRUN (i, si, slen, c);
1436 i = si + 1;
1437 continue;
1438 }
1439
1440 /* Process a nested OPENER. */
1441 if (STREQN (string + i, opener, len_opener))
1442 {
1443 si = i + len_opener;
1444 t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
1445 CHECK_STRING_OVERRUN (i, si, slen, c);
1446 i = si + 1;
1447 continue;
1448 }
1449
1450 /* Process a nested ALT_OPENER */
1451 if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
1452 {
1453 si = i + len_alt_opener;
1454 t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
1455 CHECK_STRING_OVERRUN (i, si, slen, c);
1456 i = si + 1;
1457 continue;
1458 }
1459
1460 /* If the current substring terminates the delimited string, decrement
1461 the nesting level. */
1462 if (STREQN (string + i, closer, len_closer))
1463 {
1464 i += len_closer - 1; /* move to last byte of the closer */
1465 nesting_level--;
1466 if (nesting_level == 0)
1467 break;
1468 }
1469
1470 /* Pass old-style command substitution through verbatim. */
1471 if (c == '`')
1472 {
1473 si = i + 1;
1474 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1475 CHECK_STRING_OVERRUN (i, si, slen, c);
1476 i = si + 1;
1477 continue;
1478 }
1479
1480 /* Pass single-quoted and double-quoted strings through verbatim. */
1481 if (c == '\'' || c == '"')
1482 {
1483 si = i + 1;
1484 i = (c == '\'') ? skip_single_quoted (string, slen, si, 0)
1485 : skip_double_quoted (string, slen, si, 0);
1486 continue;
1487 }
1488
1489 /* move past this character, which was not special. */
1490 ADVANCE_CHAR (string, slen, i);
1491 }
1492
1493 if (c == 0 && nesting_level)
1494 {
1495 if (no_longjmp_on_fatal_error == 0)
1496 {
1497 last_command_exit_value = EXECUTION_FAILURE;
1498 report_error (_("bad substitution: no closing `%s' in %s"), closer, string);
1499 exp_jump_to_top_level (DISCARD);
1500 }
1501 else
1502 {
1503 *sindex = i;
1504 return (char *)NULL;
1505 }
1506 }
1507
1508 si = i - *sindex - len_closer + 1;
1509 if (flags & SX_NOALLOC)
1510 result = (char *)NULL;
1511 else
1512 {
1513 result = (char *)xmalloc (1 + si);
1514 strncpy (result, string + *sindex, si);
1515 result[si] = '\0';
1516 }
1517 *sindex = i;
1518
1519 return (result);
1520 }
1521
1522 /* A simplified version of extract_dollar_brace_string that exists to handle
1523 $'...' and $"..." quoting in here-documents, since the here-document read
1524 path doesn't. It's separate because we don't want to mess with the fast
1525 common path. We already know we're going to allocate and return a new
1526 string and quoted == Q_HERE_DOCUMENT. We might be able to cut it down
1527 some more, but extracting strings and adding them as we go adds complexity.
1528 This needs to match the logic in parse.y:parse_matched_pair so we get
1529 consistent behavior between here-documents and double-quoted strings. */
1530 static char *
1531 extract_heredoc_dolbrace_string (string, sindex, quoted, flags)
1532 char *string;
1533 int *sindex, quoted, flags;
1534 {
1535 register int i, c;
1536 size_t slen, tlen, result_index, result_size;
1537 int pass_character, nesting_level, si, dolbrace_state;
1538 char *result, *t, *send;
1539 DECLARE_MBSTATE;
1540
1541 pass_character = 0;
1542 nesting_level = 1;
1543 slen = strlen (string + *sindex) + *sindex;
1544 send = string + slen;
1545
1546 result_size = slen;
1547 result_index = 0;
1548 result = xmalloc (result_size + 1);
1549
1550 /* This function isn't called if this condition is not true initially. */
1551 dolbrace_state = DOLBRACE_QUOTE;
1552
1553 i = *sindex;
1554 while (c = string[i])
1555 {
1556 if (pass_character)
1557 {
1558 pass_character = 0;
1559 RESIZE_MALLOCED_BUFFER (result, result_index, locale_mb_cur_max + 1, result_size, 64);
1560 COPY_CHAR_I (result, result_index, string, send, i);
1561 continue;
1562 }
1563
1564 /* CTLESCs and backslashes quote the next character. */
1565 if (c == CTLESC || c == '\\')
1566 {
1567 pass_character++;
1568 RESIZE_MALLOCED_BUFFER (result, result_index, 2, result_size, 64);
1569 result[result_index++] = c;
1570 i++;
1571 continue;
1572 }
1573
1574 /* The entire reason we have this separate function right here. */
1575 if (c == '$' && string[i+1] == '\'')
1576 {
1577 char *ttrans;
1578 int ttranslen;
1579
1580 if ((posixly_correct || extended_quote == 0) && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2)
1581 {
1582 RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, 64);
1583 result[result_index++] = '$';
1584 result[result_index++] = '\'';
1585 i += 2;
1586 continue;
1587 }
1588
1589 si = i + 2;
1590 t = string_extract_single_quoted (string, &si, 1); /* XXX */
1591 CHECK_STRING_OVERRUN (i, si, slen, c);
1592
1593 tlen = si - i - 2; /* -2 since si is one after the close quote */
1594 ttrans = ansiexpand (t, 0, tlen, &ttranslen);
1595 free (t);
1596
1597 /* needed to correctly quote any embedded single quotes. */
1598 if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2)
1599 {
1600 t = sh_single_quote (ttrans);
1601 tlen = strlen (t);
1602 free (ttrans);
1603 }
1604 else if (extended_quote) /* dolbrace_state == DOLBRACE_PARAM */
1605 {
1606 /* This matches what parse.y:parse_matched_pair() does */
1607 t = ttrans;
1608 tlen = strlen (t);
1609 }
1610
1611 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 1, result_size, 64);
1612 strncpy (result + result_index, t, tlen);
1613 result_index += tlen;
1614 free (t);
1615 i = si;
1616 continue;
1617 }
1618
1619 #if defined (TRANSLATABLE_STRINGS)
1620 if (c == '$' && string[i+1] == '"')
1621 {
1622 char *ttrans;
1623 int ttranslen;
1624
1625 si = i + 2;
1626 t = string_extract_double_quoted (string, &si, flags); /* XXX */
1627 CHECK_STRING_OVERRUN (i, si, slen, c);
1628
1629 tlen = si - i - 2; /* -2 since si is one after the close quote */
1630 ttrans = locale_expand (t, 0, tlen, line_number, &ttranslen);
1631 free (t);
1632
1633 t = singlequote_translations ? sh_single_quote (ttrans) : sh_mkdoublequoted (ttrans, ttranslen, 0);
1634 tlen = strlen (t);
1635 free (ttrans);
1636
1637 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 1, result_size, 64);
1638 strncpy (result + result_index, t, tlen);
1639 result_index += tlen;
1640 free (t);
1641 i = si;
1642 continue;
1643 }
1644 #endif /* TRANSLATABLE_STRINGS */
1645
1646 if (c == '$' && string[i+1] == LBRACE)
1647 {
1648 nesting_level++;
1649 RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, 64);
1650 result[result_index++] = c;
1651 result[result_index++] = string[i+1];
1652 i += 2;
1653 if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2 || dolbrace_state == DOLBRACE_WORD)
1654 dolbrace_state = DOLBRACE_PARAM;
1655 continue;
1656 }
1657
1658 if (c == RBRACE)
1659 {
1660 nesting_level--;
1661 if (nesting_level == 0)
1662 break;
1663 RESIZE_MALLOCED_BUFFER (result, result_index, 2, result_size, 64);
1664 result[result_index++] = c;
1665 i++;
1666 continue;
1667 }
1668
1669 /* Pass the contents of old-style command substitutions through
1670 verbatim. */
1671 if (c == '`')
1672 {
1673 si = i + 1;
1674 t = string_extract (string, &si, "`", flags); /* already know (flags & SX_NOALLOC) == 0) */
1675 CHECK_STRING_OVERRUN (i, si, slen, c);
1676
1677 tlen = si - i - 1;
1678 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 3, result_size, 64);
1679 result[result_index++] = c;
1680 strncpy (result + result_index, t, tlen);
1681 result_index += tlen;
1682 result[result_index++] = string[si];
1683 free (t);
1684 i = si + 1;
1685 continue;
1686 }
1687
1688 /* Pass the contents of new-style command substitutions and
1689 arithmetic substitutions through verbatim. */
1690 if (string[i] == '$' && string[i+1] == LPAREN)
1691 {
1692 si = i + 2;
1693 t = extract_command_subst (string, &si, flags);
1694 CHECK_STRING_OVERRUN (i, si, slen, c);
1695
1696 tlen = si - i - 1;
1697 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 4, result_size, 64);
1698 result[result_index++] = c;
1699 result[result_index++] = LPAREN;
1700 strncpy (result + result_index, t, tlen);
1701 result_index += tlen;
1702 result[result_index++] = string[si];
1703 free (t);
1704 i = si + 1;
1705 continue;
1706 }
1707
1708 #if defined (PROCESS_SUBSTITUTION)
1709 /* Technically this should only work at the start of a word */
1710 if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN)
1711 {
1712 si = i + 2;
1713 t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags);
1714 CHECK_STRING_OVERRUN (i, si, slen, c);
1715
1716 tlen = si - i - 1;
1717 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 4, result_size, 64);
1718 result[result_index++] = c;
1719 result[result_index++] = LPAREN;
1720 strncpy (result + result_index, t, tlen);
1721 result_index += tlen;
1722 result[result_index++] = string[si];
1723 free (t);
1724 i = si + 1;
1725 continue;
1726 }
1727 #endif
1728
1729 if (c == '\'' && posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE)
1730 {
1731 COPY_CHAR_I (result, result_index, string, send, i);
1732 continue;
1733 }
1734
1735 /* Pass the contents of single and double-quoted strings through verbatim. */
1736 if (c == '"' || c == '\'')
1737 {
1738 si = i + 1;
1739 if (c == '"')
1740 t = string_extract_double_quoted (string, &si, flags);
1741 else
1742 t = string_extract_single_quoted (string, &si, 0);
1743 CHECK_STRING_OVERRUN (i, si, slen, c);
1744
1745 tlen = si - i - 2; /* -2 since si is one after the close quote */
1746 RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 3, result_size, 64);
1747 result[result_index++] = c;
1748 strncpy (result + result_index, t, tlen);
1749 result_index += tlen;
1750 result[result_index++] = string[si - 1];
1751 free (t);
1752 i = si;
1753 continue;
1754 }
1755
1756 /* copy this character, which was not special. */
1757 COPY_CHAR_I (result, result_index, string, send, i);
1758
1759 /* This logic must agree with parse.y:parse_matched_pair, since they
1760 share the same defines. */
1761 if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
1762 dolbrace_state = DOLBRACE_QUOTE;
1763 else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
1764 dolbrace_state = DOLBRACE_QUOTE;
1765 else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
1766 dolbrace_state = DOLBRACE_QUOTE2; /* XXX */
1767 else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
1768 dolbrace_state = DOLBRACE_QUOTE;
1769 else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
1770 dolbrace_state = DOLBRACE_QUOTE;
1771 /* This is intended to handle all of the [:]op expansions and the substring/
1772 length/pattern removal/pattern substitution expansions. */
1773 else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
1774 dolbrace_state = DOLBRACE_OP;
1775 else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
1776 dolbrace_state = DOLBRACE_WORD;
1777 }
1778
1779 if (c == 0 && nesting_level)
1780 {
1781 free (result);
1782 if (no_longjmp_on_fatal_error == 0)
1783 { /* { */
1784 last_command_exit_value = EXECUTION_FAILURE;
1785 report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
1786 exp_jump_to_top_level (DISCARD);
1787 }
1788 else
1789 {
1790 *sindex = i;
1791 return ((char *)NULL);
1792 }
1793 }
1794
1795 *sindex = i;
1796 result[result_index] = '\0';
1797
1798 return (result);
1799 }
1800
1801 /* Extract a parameter expansion expression within ${ and } from STRING.
1802 Obey the Posix.2 rules for finding the ending `}': count braces while
1803 skipping over enclosed quoted strings and command substitutions.
1804 SINDEX is the address of an int describing the current offset in STRING;
1805 it should point to just after the first `{' found. On exit, SINDEX
1806 gets the position of the matching `}'. QUOTED is non-zero if this
1807 occurs inside double quotes. */
1808 /* XXX -- this is very similar to extract_delimited_string -- XXX */
1809 static char *
1810 extract_dollar_brace_string (string, sindex, quoted, flags)
1811 char *string;
1812 int *sindex, quoted, flags;
1813 {
1814 register int i, c;
1815 size_t slen;
1816 int pass_character, nesting_level, si, dolbrace_state;
1817 char *result, *t;
1818 DECLARE_MBSTATE;
1819
1820 /* The handling of dolbrace_state needs to agree with the code in parse.y:
1821 parse_matched_pair(). The different initial value is to handle the
1822 case where this function is called to parse the word in
1823 ${param op word} (SX_WORD). */
1824 dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM;
1825 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP))
1826 dolbrace_state = DOLBRACE_QUOTE;
1827
1828 if (quoted == Q_HERE_DOCUMENT && dolbrace_state == DOLBRACE_QUOTE && (flags & SX_NOALLOC) == 0)
1829 return (extract_heredoc_dolbrace_string (string, sindex, quoted, flags));
1830
1831 pass_character = 0;
1832 nesting_level = 1;
1833 slen = strlen (string + *sindex) + *sindex;
1834
1835 i = *sindex;
1836 while (c = string[i])
1837 {
1838 if (pass_character)
1839 {
1840 pass_character = 0;
1841 ADVANCE_CHAR (string, slen, i);
1842 continue;
1843 }
1844
1845 /* CTLESCs and backslashes quote the next character. */
1846 if (c == CTLESC || c == '\\')
1847 {
1848 pass_character++;
1849 i++;
1850 continue;
1851 }
1852
1853 if (string[i] == '$' && string[i+1] == LBRACE)
1854 {
1855 nesting_level++;
1856 i += 2;
1857 if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_WORD)
1858 dolbrace_state = DOLBRACE_PARAM;
1859 continue;
1860 }
1861
1862 if (c == RBRACE)
1863 {
1864 nesting_level--;
1865 if (nesting_level == 0)
1866 break;
1867 i++;
1868 continue;
1869 }
1870
1871 /* Pass the contents of old-style command substitutions through
1872 verbatim. */
1873 if (c == '`')
1874 {
1875 si = i + 1;
1876 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1877
1878 CHECK_STRING_OVERRUN (i, si, slen, c);
1879
1880 i = si + 1;
1881 continue;
1882 }
1883
1884 /* Pass the contents of new-style command substitutions and
1885 arithmetic substitutions through verbatim. */
1886 if (string[i] == '$' && string[i+1] == LPAREN)
1887 {
1888 si = i + 2;
1889 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1890
1891 CHECK_STRING_OVERRUN (i, si, slen, c);
1892
1893 i = si + 1;
1894 continue;
1895 }
1896
1897 #if defined (PROCESS_SUBSTITUTION)
1898 /* Technically this should only work at the start of a word */
1899 if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN)
1900 {
1901 si = i + 2;
1902 t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags|SX_NOALLOC);
1903
1904 CHECK_STRING_OVERRUN (i, si, slen, c);
1905
1906 i = si + 1;
1907 continue;
1908 }
1909 #endif
1910
1911 /* Pass the contents of double-quoted strings through verbatim. */
1912 if (c == '"')
1913 {
1914 si = i + 1;
1915 i = skip_double_quoted (string, slen, si, 0);
1916 /* skip_XXX_quoted leaves index one past close quote */
1917 continue;
1918 }
1919
1920 if (c == '\'')
1921 {
1922 /*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
1923 if (posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1924 ADVANCE_CHAR (string, slen, i);
1925 else
1926 {
1927 si = i + 1;
1928 i = skip_single_quoted (string, slen, si, 0);
1929 }
1930
1931 continue;
1932 }
1933
1934 #if defined (ARRAY_VARS)
1935 if (c == LBRACK && dolbrace_state == DOLBRACE_PARAM)
1936 {
1937 si = skipsubscript (string, i, 0);
1938 CHECK_STRING_OVERRUN (i, si, slen, c);
1939 if (string[si] == RBRACK)
1940 c = string[i = si];
1941 }
1942 #endif
1943
1944 /* move past this character, which was not special. */
1945 ADVANCE_CHAR (string, slen, i);
1946
1947 /* This logic must agree with parse.y:parse_matched_pair, since they
1948 share the same defines. */
1949 if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
1950 dolbrace_state = DOLBRACE_QUOTE;
1951 else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
1952 dolbrace_state = DOLBRACE_QUOTE;
1953 else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
1954 dolbrace_state = DOLBRACE_QUOTE2; /* XXX */
1955 else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
1956 dolbrace_state = DOLBRACE_QUOTE;
1957 else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
1958 dolbrace_state = DOLBRACE_QUOTE;
1959 /* This is intended to handle all of the [:]op expansions and the substring/
1960 length/pattern removal/pattern substitution expansions. */
1961 else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
1962 dolbrace_state = DOLBRACE_OP;
1963 else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
1964 dolbrace_state = DOLBRACE_WORD;
1965 }
1966
1967 if (c == 0 && nesting_level)
1968 {
1969 if (no_longjmp_on_fatal_error == 0)
1970 { /* { */
1971 last_command_exit_value = EXECUTION_FAILURE;
1972 report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
1973 exp_jump_to_top_level (DISCARD);
1974 }
1975 else
1976 {
1977 *sindex = i;
1978 return ((char *)NULL);
1979 }
1980 }
1981
1982 result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
1983 *sindex = i;
1984
1985 return (result);
1986 }
1987
1988 /* Remove backslashes which are quoting backquotes from STRING. Modifies
1989 STRING, and returns a pointer to it. */
1990 char *
1991 de_backslash (string)
1992 char *string;
1993 {
1994 register size_t slen;
1995 register int i, j, prev_i;
1996 DECLARE_MBSTATE;
1997
1998 slen = strlen (string);
1999 i = j = 0;
2000
2001 /* Loop copying string[i] to string[j], i >= j. */
2002 while (i < slen)
2003 {
2004 if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
2005 string[i + 1] == '$'))
2006 i++;
2007 prev_i = i;
2008 ADVANCE_CHAR (string, slen, i);
2009 if (j < prev_i)
2010 do string[j++] = string[prev_i++]; while (prev_i < i);
2011 else
2012 j = i;
2013 }
2014 string[j] = '\0';
2015
2016 return (string);
2017 }
2018
2019 #if 0
2020 /*UNUSED*/
2021 /* Replace instances of \! in a string with !. */
2022 void
2023 unquote_bang (string)
2024 char *string;
2025 {
2026 register int i, j;
2027 register char *temp;
2028
2029 temp = (char *)xmalloc (1 + strlen (string));
2030
2031 for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
2032 {
2033 if (string[i] == '\\' && string[i + 1] == '!')
2034 {
2035 temp[j] = '!';
2036 i++;
2037 }
2038 }
2039 strcpy (string, temp);
2040 free (temp);
2041 }
2042 #endif
2043
2044 #define CQ_RETURN(x) do { no_longjmp_on_fatal_error = oldjmp; return (x); } while (0)
2045
2046 /* When FLAGS & 2 == 0, this function assumes STRING[I] == OPEN; when
2047 FLAGS & 2 != 0, it assumes STRING[I] points to one character past OPEN;
2048 returns with STRING[RET] == close; used to parse array subscripts.
2049 FLAGS & 1 means not to attempt to skip over matched pairs of quotes or
2050 backquotes, or skip word expansions; it is intended to be used after
2051 expansion has been performed and during final assignment parsing (see
2052 arrayfunc.c:assign_compound_array_list()) or during execution by a builtin
2053 which has already undergone word expansion. */
2054 static int
2055 skip_matched_pair (string, start, open, close, flags)
2056 const char *string;
2057 int start, open, close, flags;
2058 {
2059 int i, pass_next, backq, si, c, count, oldjmp;
2060 size_t slen;
2061 char *temp, *ss;
2062 DECLARE_MBSTATE;
2063
2064 slen = strlen (string + start) + start;
2065 oldjmp = no_longjmp_on_fatal_error;
2066 no_longjmp_on_fatal_error = 1;
2067
2068 /* Move to the first character after a leading OPEN. If FLAGS&2, we assume
2069 that START already points to that character. If not, we need to skip over
2070 it here. */
2071 i = (flags & 2) ? start : start + 1;
2072 count = 1;
2073 pass_next = backq = 0;
2074 ss = (char *)string;
2075 while (c = string[i])
2076 {
2077 if (pass_next)
2078 {
2079 pass_next = 0;
2080 if (c == 0)
2081 CQ_RETURN(i);
2082 ADVANCE_CHAR (string, slen, i);
2083 continue;
2084 }
2085 else if ((flags & 1) == 0 && c == '\\')
2086 {
2087 pass_next = 1;
2088 i++;
2089 continue;
2090 }
2091 else if (backq)
2092 {
2093 if (c == '`')
2094 backq = 0;
2095 ADVANCE_CHAR (string, slen, i);
2096 continue;
2097 }
2098 else if ((flags & 1) == 0 && c == '`')
2099 {
2100 backq = 1;
2101 i++;
2102 continue;
2103 }
2104 else if ((flags & 1) == 0 && c == open)
2105 {
2106 count++;
2107 i++;
2108 continue;
2109 }
2110 else if (c == close)
2111 {
2112 count--;
2113 if (count == 0)
2114 break;
2115 i++;
2116 continue;
2117 }
2118 else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
2119 {
2120 i = (c == '\'') ? skip_single_quoted (ss, slen, ++i, 0)
2121 : skip_double_quoted (ss, slen, ++i, 0);
2122 /* no increment, the skip functions increment past the closing quote. */
2123 }
2124 else if ((flags & 1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
2125 {
2126 si = i + 2;
2127 if (string[si] == '\0')
2128 CQ_RETURN(si);
2129
2130 /* XXX - extract_command_subst here? */
2131 if (string[i+1] == LPAREN)
2132 temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
2133 else
2134 temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
2135
2136 CHECK_STRING_OVERRUN (i, si, slen, c);
2137
2138 i = si;
2139 if (string[i] == '\0') /* don't increment i past EOS in loop */
2140 break;
2141 i++;
2142 continue;
2143 }
2144 else
2145 ADVANCE_CHAR (string, slen, i);
2146 }
2147
2148 CQ_RETURN(i);
2149 }
2150
2151 #if defined (ARRAY_VARS)
2152 /* FLAGS has 1 as a reserved value, since skip_matched_pair uses it for
2153 skipping over quoted strings and taking the first instance of the
2154 closing character. FLAGS & 2 means that STRING[START] points one
2155 character past the open bracket; FLAGS & 2 == 0 means that STRING[START]
2156 points to the open bracket. skip_matched_pair knows how to deal with this. */
2157 int
2158 skipsubscript (string, start, flags)
2159 const char *string;
2160 int start, flags;
2161 {
2162 return (skip_matched_pair (string, start, '[', ']', flags));
2163 }
2164 #endif
2165
2166 /* Skip characters in STRING until we find a character in DELIMS, and return
2167 the index of that character. START is the index into string at which we
2168 begin. This is similar in spirit to strpbrk, but it returns an index into
2169 STRING and takes a starting index. This little piece of code knows quite
2170 a lot of shell syntax. It's very similar to skip_double_quoted and other
2171 functions of that ilk. */
2172 int
2173 skip_to_delim (string, start, delims, flags)
2174 char *string;
2175 int start;
2176 char *delims;
2177 int flags;
2178 {
2179 int i, pass_next, backq, dquote, si, c, oldjmp;
2180 int invert, skipquote, skipcmd, noprocsub, completeflag;
2181 int arithexp, skipcol;
2182 size_t slen;
2183 char *temp, open[3];
2184 DECLARE_MBSTATE;
2185
2186 slen = strlen (string + start) + start;
2187 oldjmp = no_longjmp_on_fatal_error;
2188 if (flags & SD_NOJMP)
2189 no_longjmp_on_fatal_error = 1;
2190 invert = (flags & SD_INVERT);
2191 skipcmd = (flags & SD_NOSKIPCMD) == 0;
2192 noprocsub = (flags & SD_NOPROCSUB);
2193 completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0;
2194
2195 arithexp = (flags & SD_ARITHEXP);
2196 skipcol = 0;
2197
2198 i = start;
2199 pass_next = backq = dquote = 0;
2200 while (c = string[i])
2201 {
2202 /* If this is non-zero, we should not let quote characters be delimiters
2203 and the current character is a single or double quote. We should not
2204 test whether or not it's a delimiter until after we skip single- or
2205 double-quoted strings. */
2206 skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
2207 if (pass_next)
2208 {
2209 pass_next = 0;
2210 if (c == 0)
2211 CQ_RETURN(i);
2212 ADVANCE_CHAR (string, slen, i);
2213 continue;
2214 }
2215 else if (c == '\\')
2216 {
2217 pass_next = 1;
2218 i++;
2219 continue;
2220 }
2221 else if (backq)
2222 {
2223 if (c == '`')
2224 backq = 0;
2225 ADVANCE_CHAR (string, slen, i);
2226 continue;
2227 }
2228 else if (c == '`')
2229 {
2230 backq = 1;
2231 i++;
2232 continue;
2233 }
2234 else if (arithexp && skipcol && c == ':')
2235 {
2236 skipcol--;
2237 i++;
2238 continue;
2239 }
2240 else if (arithexp && c == '?')
2241 {
2242 skipcol++;
2243 i++;
2244 continue;
2245 }
2246 else if (skipquote == 0 && invert == 0 && member (c, delims))
2247 break;
2248 /* the usual case is to use skip_xxx_quoted, but we don't skip over double
2249 quoted strings when looking for the history expansion character as a
2250 delimiter. */
2251 /* special case for programmable completion which takes place before
2252 parser converts backslash-escaped single quotes between $'...' to
2253 `regular' single-quoted strings. */
2254 else if (completeflag && i > 0 && string[i-1] == '$' && c == '\'')
2255 i = skip_single_quoted (string, slen, ++i, SX_COMPLETE);
2256 else if (c == '\'')
2257 i = skip_single_quoted (string, slen, ++i, 0);
2258 else if (c == '"')
2259 i = skip_double_quoted (string, slen, ++i, completeflag);
2260 else if (c == LPAREN && arithexp)
2261 {
2262 si = i + 1;
2263 if (string[si] == '\0')
2264 CQ_RETURN(si);
2265
2266 temp = extract_delimited_string (string, &si, "(", "(", ")", SX_NOALLOC); /* ) */
2267 i = si;
2268 if (string[i] == '\0') /* don't increment i past EOS in loop */
2269 break;
2270 i++;
2271 continue;
2272 }
2273 else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
2274 {
2275 si = i + 2;
2276 if (string[si] == '\0')
2277 CQ_RETURN(si);
2278
2279 if (string[i+1] == LPAREN)
2280 temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND|completeflag); /* ) */
2281 else
2282 temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
2283 CHECK_STRING_OVERRUN (i, si, slen, c);
2284 i = si;
2285 if (string[i] == '\0') /* don't increment i past EOS in loop */
2286 break;
2287 i++;
2288 continue;
2289 }
2290 #if defined (PROCESS_SUBSTITUTION)
2291 else if (skipcmd && noprocsub == 0 && (c == '<' || c == '>') && string[i+1] == LPAREN)
2292 {
2293 si = i + 2;
2294 if (string[si] == '\0')
2295 CQ_RETURN(si);
2296
2297 temp = extract_delimited_string (string, &si, (c == '<') ? "<(" : ">(", "(", ")", SX_COMMAND|SX_NOALLOC); /* )) */
2298 CHECK_STRING_OVERRUN (i, si, slen, c);
2299 i = si;
2300 if (string[i] == '\0')
2301 break;
2302 i++;
2303 continue;
2304 }
2305 #endif /* PROCESS_SUBSTITUTION */
2306 #if defined (EXTENDED_GLOB)
2307 else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@"))
2308 {
2309 si = i + 2;
2310 if (string[si] == '\0')
2311 CQ_RETURN(si);
2312
2313 open[0] = c;
2314 open[1] = LPAREN;
2315 open[2] = '\0';
2316 temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */
2317
2318 CHECK_STRING_OVERRUN (i, si, slen, c);
2319 i = si;
2320 if (string[i] == '\0') /* don't increment i past EOS in loop */
2321 break;
2322 i++;
2323 continue;
2324 }
2325 #endif
2326 else if ((flags & SD_GLOB) && c == LBRACK)
2327 {
2328 si = i + 1;
2329 if (string[si] == '\0')
2330 CQ_RETURN(si);
2331
2332 temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */
2333
2334 i = si;
2335 if (string[i] == '\0') /* don't increment i past EOS in loop */
2336 break;
2337 i++;
2338 continue;
2339 }
2340 else if ((skipquote || invert) && (member (c, delims) == 0))
2341 break;
2342 else
2343 ADVANCE_CHAR (string, slen, i);
2344 }
2345
2346 CQ_RETURN(i);
2347 }
2348
2349 #if defined (BANG_HISTORY)
2350 /* Skip to the history expansion character (delims[0]), paying attention to
2351 quoted strings and command and process substitution. This is a stripped-
2352 down version of skip_to_delims. The essential difference is that this
2353 resets the quoting state when starting a command substitution */
2354 int
2355 skip_to_histexp (string, start, delims, flags)
2356 char *string;
2357 int start;
2358 char *delims;
2359 int flags;
2360 {
2361 int i, pass_next, backq, dquote, c, oldjmp;
2362 int histexp_comsub, histexp_backq, old_dquote;
2363 size_t slen;
2364 DECLARE_MBSTATE;
2365
2366 slen = strlen (string + start) + start;
2367 oldjmp = no_longjmp_on_fatal_error;
2368 if (flags & SD_NOJMP)
2369 no_longjmp_on_fatal_error = 1;
2370
2371 histexp_comsub = histexp_backq = old_dquote = 0;
2372
2373 i = start;
2374 pass_next = backq = dquote = 0;
2375 while (c = string[i])
2376 {
2377 if (pass_next)
2378 {
2379 pass_next = 0;
2380 if (c == 0)
2381 CQ_RETURN(i);
2382 ADVANCE_CHAR (string, slen, i);
2383 continue;
2384 }
2385 else if (c == '\\')
2386 {
2387 pass_next = 1;
2388 i++;
2389 continue;
2390 }
2391 else if (backq && c == '`')
2392 {
2393 backq = 0;
2394 histexp_backq--;
2395 dquote = old_dquote;
2396 i++;
2397 continue;
2398 }
2399 else if (c == '`')
2400 {
2401 backq = 1;
2402 histexp_backq++;
2403 old_dquote = dquote; /* simple - one level for now */
2404 dquote = 0;
2405 i++;
2406 continue;
2407 }
2408 /* When in double quotes, act as if the double quote is a member of
2409 history_no_expand_chars, like the history library does */
2410 else if (dquote && c == delims[0] && string[i+1] == '"')
2411 {
2412 i++;
2413 continue;
2414 }
2415 else if (c == delims[0])
2416 break;
2417 /* the usual case is to use skip_xxx_quoted, but we don't skip over double
2418 quoted strings when looking for the history expansion character as a
2419 delimiter. */
2420 else if (dquote && c == '\'')
2421 {
2422 i++;
2423 continue;
2424 }
2425 else if (c == '\'')
2426 i = skip_single_quoted (string, slen, ++i, 0);
2427 /* The posixly_correct test makes posix-mode shells allow double quotes
2428 to quote the history expansion character */
2429 else if (posixly_correct == 0 && c == '"')
2430 {
2431 dquote = 1 - dquote;
2432 i++;
2433 continue;
2434 }
2435 else if (c == '"')
2436 i = skip_double_quoted (string, slen, ++i, 0);
2437 #if defined (PROCESS_SUBSTITUTION)
2438 else if ((c == '$' || c == '<' || c == '>') && string[i+1] == LPAREN && string[i+2] != LPAREN)
2439 #else
2440 else if (c == '$' && string[i+1] == LPAREN && string[i+2] != LPAREN)
2441 #endif
2442 {
2443 if (string[i+2] == '\0')
2444 CQ_RETURN(i+2);
2445 i += 2;
2446 histexp_comsub++;
2447 old_dquote = dquote;
2448 dquote = 0;
2449 }
2450 else if (histexp_comsub && c == RPAREN)
2451 {
2452 histexp_comsub--;
2453 dquote = old_dquote;
2454 i++;
2455 continue;
2456 }
2457 else if (backq) /* placeholder */
2458 {
2459 ADVANCE_CHAR (string, slen, i);
2460 continue;
2461 }
2462 else
2463 ADVANCE_CHAR (string, slen, i);
2464 }
2465
2466 CQ_RETURN(i);
2467 }
2468 #endif /* BANG_HISTORY */
2469
2470 #if defined (READLINE)
2471 /* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
2472 an unclosed quoted string), or if the character at EINDEX is quoted
2473 by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various
2474 single and double-quoted string parsing functions should not return an
2475 error if there are unclosed quotes or braces. The characters that this
2476 recognizes need to be the same as the contents of
2477 rl_completer_quote_characters. */
2478
2479 int
2480 char_is_quoted (string, eindex)
2481 char *string;
2482 int eindex;
2483 {
2484 int i, pass_next, c, oldjmp;
2485 size_t slen;
2486 DECLARE_MBSTATE;
2487
2488 slen = strlen (string);
2489 oldjmp = no_longjmp_on_fatal_error;
2490 no_longjmp_on_fatal_error = 1;
2491 i = pass_next = 0;
2492
2493 /* If we have an open quoted string from a previous line, see if it's
2494 closed before string[eindex], so we don't interpret that close quote
2495 as starting a new quoted string. */
2496 if (current_command_line_count > 0 && dstack.delimiter_depth > 0)
2497 {
2498 c = dstack.delimiters[dstack.delimiter_depth - 1];
2499 if (c == '\'')
2500 i = skip_single_quoted (string, slen, 0, 0);
2501 else if (c == '"')
2502 i = skip_double_quoted (string, slen, 0, SX_COMPLETE);
2503 if (i > eindex)
2504 CQ_RETURN (1);
2505 }
2506
2507 while (i <= eindex)
2508 {
2509 c = string[i];
2510
2511 if (pass_next)
2512 {
2513 pass_next = 0;
2514 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
2515 CQ_RETURN(1);
2516 ADVANCE_CHAR (string, slen, i);
2517 continue;
2518 }
2519 else if (c == '\\')
2520 {
2521 pass_next = 1;
2522 i++;
2523 continue;
2524 }
2525 else if (c == '$' && string[i+1] == '\'' && string[i+2])
2526 {
2527 i += 2;
2528 i = skip_single_quoted (string, slen, i, SX_COMPLETE);
2529 if (i > eindex)
2530 CQ_RETURN (i);
2531 }
2532 else if (c == '\'' || c == '"')
2533 {
2534 i = (c == '\'') ? skip_single_quoted (string, slen, ++i, 0)
2535 : skip_double_quoted (string, slen, ++i, SX_COMPLETE);
2536 if (i > eindex)
2537 CQ_RETURN(1);
2538 /* no increment, the skip_xxx functions go one past end */
2539 }
2540 else
2541 ADVANCE_CHAR (string, slen, i);
2542 }
2543
2544 CQ_RETURN(0);
2545 }
2546
2547 int
2548 unclosed_pair (string, eindex, openstr)
2549 char *string;
2550 int eindex;
2551 char *openstr;
2552 {
2553 int i, pass_next, openc, olen;
2554 size_t slen;
2555 DECLARE_MBSTATE;
2556
2557 slen = strlen (string);
2558 olen = strlen (openstr);
2559 i = pass_next = openc = 0;
2560 while (i <= eindex)
2561 {
2562 if (pass_next)
2563 {
2564 pass_next = 0;
2565 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
2566 return 0;
2567 ADVANCE_CHAR (string, slen, i);
2568 continue;
2569 }
2570 else if (string[i] == '\\')
2571 {
2572 pass_next = 1;
2573 i++;
2574 continue;
2575 }
2576 else if (STREQN (string + i, openstr, olen))
2577 {
2578 openc = 1 - openc;
2579 i += olen;
2580 }
2581 /* XXX - may want to handle $'...' specially here */
2582 else if (string[i] == '\'' || string[i] == '"')
2583 {
2584 i = (string[i] == '\'') ? skip_single_quoted (string, slen, i, 0)
2585 : skip_double_quoted (string, slen, i, SX_COMPLETE);
2586 if (i > eindex)
2587 return 0;
2588 }
2589 else
2590 ADVANCE_CHAR (string, slen, i);
2591 }
2592 return (openc);
2593 }
2594
2595 /* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
2596 individual words. If DELIMS is NULL, the current value of $IFS is used
2597 to split the string, and the function follows the shell field splitting
2598 rules. SENTINEL is an index to look for. NWP, if non-NULL,
2599 gets the number of words in the returned list. CWP, if non-NULL, gets
2600 the index of the word containing SENTINEL. Non-whitespace chars in
2601 DELIMS delimit separate fields. This is used by programmable completion. */
2602 WORD_LIST *
2603 split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
2604 char *string;
2605 int slen;
2606 const char *delims;
2607 int sentinel, flags;
2608 int *nwp, *cwp;
2609 {
2610 int ts, te, i, nw, cw, ifs_split, dflags;
2611 char *token, *d, *d2;
2612 WORD_LIST *ret, *tl;
2613
2614 if (string == 0 || *string == '\0')
2615 {
2616 if (nwp)
2617 *nwp = 0;
2618 if (cwp)
2619 *cwp = 0;
2620 return ((WORD_LIST *)NULL);
2621 }
2622
2623 d = (delims == 0) ? ifs_value : (char *)delims;
2624 ifs_split = delims == 0;
2625
2626 /* Make d2 the non-whitespace characters in delims */
2627 d2 = 0;
2628 if (delims)
2629 {
2630 size_t slength;
2631 #if defined (HANDLE_MULTIBYTE)
2632 size_t mblength = 1;
2633 #endif
2634 DECLARE_MBSTATE;
2635
2636 slength = strlen (delims);
2637 d2 = (char *)xmalloc (slength + 1);
2638 i = ts = 0;
2639 while (delims[i])
2640 {
2641 #if defined (HANDLE_MULTIBYTE)
2642 mbstate_t state_bak;
2643 state_bak = state;
2644 mblength = MBRLEN (delims + i, slength, &state);
2645 if (MB_INVALIDCH (mblength))
2646 state = state_bak;
2647 else if (mblength > 1)
2648 {
2649 memcpy (d2 + ts, delims + i, mblength);
2650 ts += mblength;
2651 i += mblength;
2652 slength -= mblength;
2653 continue;
2654 }
2655 #endif
2656 if (whitespace (delims[i]) == 0)
2657 d2[ts++] = delims[i];
2658
2659 i++;
2660 slength--;
2661 }
2662 d2[ts] = '\0';
2663 }
2664
2665 ret = (WORD_LIST *)NULL;
2666
2667 /* Remove sequences of whitespace characters at the start of the string, as
2668 long as those characters are delimiters. */
2669 for (i = 0; member (string[i], d) && spctabnl (string[i]); i++)
2670 ;
2671 if (string[i] == '\0')
2672 {
2673 FREE (d2);
2674 return (ret);
2675 }
2676
2677 ts = i;
2678 nw = 0;
2679 cw = -1;
2680 dflags = flags|SD_NOJMP;
2681 while (1)
2682 {
2683 te = skip_to_delim (string, ts, d, dflags);
2684
2685 /* If we have a non-whitespace delimiter character, use it to make a
2686 separate field. This is just about what $IFS splitting does and
2687 is closer to the behavior of the shell parser. */
2688 if (ts == te && d2 && member (string[ts], d2))
2689 {
2690 te = ts + 1;
2691 /* If we're using IFS splitting, the non-whitespace delimiter char
2692 and any additional IFS whitespace delimits a field. */
2693 if (ifs_split)
2694 while (member (string[te], d) && spctabnl (string[te]) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2695 te++;
2696 else
2697 while (member (string[te], d2) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2698 te++;
2699 }
2700
2701 token = substring (string, ts, te);
2702
2703 ret = add_string_to_list (token, ret); /* XXX */
2704 free (token);
2705 nw++;
2706
2707 if (sentinel >= ts && sentinel <= te)
2708 cw = nw;
2709
2710 /* If the cursor is at whitespace just before word start, set the
2711 sentinel word to the current word. */
2712 if (cwp && cw == -1 && sentinel == ts-1)
2713 cw = nw;
2714
2715 /* If the cursor is at whitespace between two words, make a new, empty
2716 word, add it before (well, after, since the list is in reverse order)
2717 the word we just added, and set the current word to that one. */
2718 if (cwp && cw == -1 && sentinel < ts)
2719 {
2720 tl = make_word_list (make_word (""), ret->next);
2721 ret->next = tl;
2722 cw = nw;
2723 nw++;
2724 }
2725
2726 if (string[te] == 0)
2727 break;
2728
2729 i = te;
2730 /* XXX - honor SD_NOQUOTEDELIM here */
2731 while (member (string[i], d) && (ifs_split || spctabnl(string[i])) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2732 i++;
2733
2734 if (string[i])
2735 ts = i;
2736 else
2737 break;
2738 }
2739
2740 /* Special case for SENTINEL at the end of STRING. If we haven't found
2741 the word containing SENTINEL yet, and the index we're looking for is at
2742 the end of STRING (or past the end of the previously-found token,
2743 possible if the end of the line is composed solely of IFS whitespace)
2744 add an additional null argument and set the current word pointer to that. */
2745 if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
2746 {
2747 if (whitespace (string[sentinel - 1]))
2748 {
2749 token = "";
2750 ret = add_string_to_list (token, ret);
2751 nw++;
2752 }
2753 cw = nw;
2754 }
2755
2756 if (nwp)
2757 *nwp = nw;
2758 if (cwp)
2759 *cwp = cw;
2760
2761 FREE (d2);
2762
2763 return (REVERSE_LIST (ret, WORD_LIST *));
2764 }
2765 #endif /* READLINE */
2766
2767 #if 0
2768 /* UNUSED */
2769 /* Extract the name of the variable to bind to from the assignment string. */
2770 char *
2771 assignment_name (string)
2772 char *string;
2773 {
2774 int offset;
2775 char *temp;
2776
2777 offset = assignment (string, 0);
2778 if (offset == 0)
2779 return (char *)NULL;
2780 temp = substring (string, 0, offset);
2781 return (temp);
2782 }
2783 #endif
2784
2785 /* **************************************************************** */
2786 /* */
2787 /* Functions to convert strings to WORD_LISTs and vice versa */
2788 /* */
2789 /* **************************************************************** */
2790
2791 /* Return a single string of all the words in LIST. SEP is the separator
2792 to put between individual elements of LIST in the output string. */
2793 char *
2794 string_list_internal (list, sep)
2795 WORD_LIST *list;
2796 char *sep;
2797 {
2798 register WORD_LIST *t;
2799 char *result, *r;
2800 size_t word_len, sep_len, result_size;
2801
2802 if (list == 0)
2803 return ((char *)NULL);
2804
2805 /* Short-circuit quickly if we don't need to separate anything. */
2806 if (list->next == 0)
2807 return (savestring (list->word->word));
2808
2809 /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
2810 sep_len = STRLEN (sep);
2811 result_size = 0;
2812
2813 for (t = list; t; t = t->next)
2814 {
2815 if (t != list)
2816 result_size += sep_len;
2817 result_size += strlen (t->word->word);
2818 }
2819
2820 r = result = (char *)xmalloc (result_size + 1);
2821
2822 for (t = list; t; t = t->next)
2823 {
2824 if (t != list && sep_len)
2825 {
2826 if (sep_len > 1)
2827 {
2828 FASTCOPY (sep, r, sep_len);
2829 r += sep_len;
2830 }
2831 else
2832 *r++ = sep[0];
2833 }
2834
2835 word_len = strlen (t->word->word);
2836 FASTCOPY (t->word->word, r, word_len);
2837 r += word_len;
2838 }
2839
2840 *r = '\0';
2841 return (result);
2842 }
2843
2844 /* Return a single string of all the words present in LIST, separating
2845 each word with a space. */
2846 char *
2847 string_list (list)
2848 WORD_LIST *list;
2849 {
2850 return (string_list_internal (list, " "));
2851 }
2852
2853 /* An external interface that can be used by the rest of the shell to
2854 obtain a string containing the first character in $IFS. Handles all
2855 the multibyte complications. If LENP is non-null, it is set to the
2856 length of the returned string. */
2857 char *
2858 ifs_firstchar (lenp)
2859 int *lenp;
2860 {
2861 char *ret;
2862 int len;
2863
2864 ret = xmalloc (MB_LEN_MAX + 1);
2865 #if defined (HANDLE_MULTIBYTE)
2866 if (ifs_firstc_len == 1)
2867 {
2868 ret[0] = ifs_firstc[0];
2869 ret[1] = '\0';
2870 len = ret[0] ? 1 : 0;
2871 }
2872 else
2873 {
2874 memcpy (ret, ifs_firstc, ifs_firstc_len);
2875 ret[len = ifs_firstc_len] = '\0';
2876 }
2877 #else
2878 ret[0] = ifs_firstc;
2879 ret[1] = '\0';
2880 len = ret[0] ? 0 : 1;
2881 #endif
2882
2883 if (lenp)
2884 *lenp = len;
2885
2886 return ret;
2887 }
2888
2889 /* Return a single string of all the words present in LIST, obeying the
2890 quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
2891 expansion [of $*] appears within a double quoted string, it expands
2892 to a single field with the value of each parameter separated by the
2893 first character of the IFS variable, or by a <space> if IFS is unset." */
2894 /* Posix interpretation 888 changes this when IFS is null by specifying
2895 that when unquoted, this expands to separate arguments */
2896 char *
2897 string_list_dollar_star (list, quoted, flags)
2898 WORD_LIST *list;
2899 int quoted, flags;
2900 {
2901 char *ret;
2902 #if defined (HANDLE_MULTIBYTE)
2903 # if defined (__GNUC__)
2904 char sep[MB_CUR_MAX + 1];
2905 # else
2906 char *sep = 0;
2907 # endif
2908 #else
2909 char sep[2];
2910 #endif
2911
2912 #if defined (HANDLE_MULTIBYTE)
2913 # if !defined (__GNUC__)
2914 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2915 # endif /* !__GNUC__ */
2916 if (ifs_firstc_len == 1)
2917 {
2918 sep[0] = ifs_firstc[0];
2919 sep[1] = '\0';
2920 }
2921 else
2922 {
2923 memcpy (sep, ifs_firstc, ifs_firstc_len);
2924 sep[ifs_firstc_len] = '\0';
2925 }
2926 #else
2927 sep[0] = ifs_firstc;
2928 sep[1] = '\0';
2929 #endif
2930
2931 ret = string_list_internal (list, sep);
2932 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2933 free (sep);
2934 #endif
2935 return ret;
2936 }
2937
2938 /* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
2939 is non-zero, the $@ appears within double quotes, and we should quote
2940 the list before converting it into a string. If IFS is unset, and the
2941 word is not quoted, we just need to quote CTLESC and CTLNUL characters
2942 in the words in the list, because the default value of $IFS is
2943 <space><tab><newline>, IFS characters in the words in the list should
2944 also be split. If IFS is null, and the word is not quoted, we need
2945 to quote the words in the list to preserve the positional parameters
2946 exactly.
2947 Valid values for the FLAGS argument are the PF_ flags in command.h,
2948 the only one we care about is PF_ASSIGNRHS. $@ is supposed to expand
2949 to the positional parameters separated by spaces no matter what IFS is
2950 set to if in a context where word splitting is not performed. The only
2951 one that we didn't handle before is assignment statement arguments to
2952 declaration builtins like `declare'. */
2953 char *
2954 string_list_dollar_at (list, quoted, flags)
2955 WORD_LIST *list;
2956 int quoted;
2957 int flags;
2958 {
2959 char *ifs, *ret;
2960 #if defined (HANDLE_MULTIBYTE)
2961 # if defined (__GNUC__)
2962 char sep[MB_CUR_MAX + 1];
2963 # else
2964 char *sep = 0;
2965 # endif /* !__GNUC__ */
2966 #else
2967 char sep[2];
2968 #endif
2969 WORD_LIST *tlist;
2970
2971 /* XXX this could just be ifs = ifs_value; */
2972 ifs = ifs_var ? value_cell (ifs_var) : (char *)0;
2973
2974 #if defined (HANDLE_MULTIBYTE)
2975 # if !defined (__GNUC__)
2976 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2977 # endif /* !__GNUC__ */
2978 /* XXX - testing PF_ASSIGNRHS to make sure positional parameters are
2979 separated with a space even when word splitting will not occur. */
2980 if (flags & PF_ASSIGNRHS)
2981 {
2982 sep[0] = ' ';
2983 sep[1] = '\0';
2984 }
2985 else if (ifs && *ifs)
2986 {
2987 if (ifs_firstc_len == 1)
2988 {
2989 sep[0] = ifs_firstc[0];
2990 sep[1] = '\0';
2991 }
2992 else
2993 {
2994 memcpy (sep, ifs_firstc, ifs_firstc_len);
2995 sep[ifs_firstc_len] = '\0';
2996 }
2997 }
2998 else
2999 {
3000 sep[0] = ' ';
3001 sep[1] = '\0';
3002 }
3003 #else /* !HANDLE_MULTIBYTE */
3004 /* XXX - PF_ASSIGNRHS means no word splitting, so we want positional
3005 parameters separated by a space. */
3006 sep[0] = ((flags & PF_ASSIGNRHS) || ifs == 0 || *ifs == 0) ? ' ' : *ifs;
3007 sep[1] = '\0';
3008 #endif /* !HANDLE_MULTIBYTE */
3009
3010 /* XXX -- why call quote_list if ifs == 0? we can get away without doing
3011 it now that quote_escapes quotes spaces */
3012 tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
3013 ? quote_list (list)
3014 : list_quote_escapes (list);
3015
3016 ret = string_list_internal (tlist, sep);
3017 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
3018 free (sep);
3019 #endif
3020 return ret;
3021 }
3022
3023 /* Turn the positional parameters into a string, understanding quoting and
3024 the various subtleties of using the first character of $IFS as the
3025 separator. Calls string_list_dollar_at, string_list_dollar_star, and
3026 string_list as appropriate. */
3027 /* This needs to fully understand the additional contexts where word
3028 splitting does not occur (W_ASSIGNRHS, etc.) */
3029 char *
3030 string_list_pos_params (pchar, list, quoted, pflags)
3031 int pchar;
3032 WORD_LIST *list;
3033 int quoted, pflags;
3034 {
3035 char *ret;
3036 WORD_LIST *tlist;
3037
3038 if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
3039 {
3040 tlist = quote_list (list);
3041 word_list_remove_quoted_nulls (tlist);
3042 ret = string_list_dollar_star (tlist, 0, 0);
3043 }
3044 else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
3045 {
3046 tlist = quote_list (list);
3047 word_list_remove_quoted_nulls (tlist);
3048 ret = string_list (tlist);
3049 }
3050 else if (pchar == '*' && quoted == 0 && ifs_is_null) /* XXX */
3051 ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
3052 else if (pchar == '*' && quoted == 0 && (pflags & PF_ASSIGNRHS)) /* XXX */
3053 ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
3054 else if (pchar == '*')
3055 {
3056 /* Even when unquoted, string_list_dollar_star does the right thing
3057 making sure that the first character of $IFS is used as the
3058 separator. */
3059 ret = string_list_dollar_star (list, quoted, 0);
3060 }
3061 else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
3062 /* We use string_list_dollar_at, but only if the string is quoted, since
3063 that quotes the escapes if it's not, which we don't want. We could
3064 use string_list (the old code did), but that doesn't do the right
3065 thing if the first character of $IFS is not a space. We use
3066 string_list_dollar_star if the string is unquoted so we make sure that
3067 the elements of $@ are separated by the first character of $IFS for
3068 later splitting. */
3069 ret = string_list_dollar_at (list, quoted, 0);
3070 else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */
3071 ret = string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
3072 else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS))
3073 ret = string_list_dollar_at (list, quoted, pflags); /* Posix interp 888 */
3074 else if (pchar == '@')
3075 ret = string_list_dollar_star (list, quoted, 0);
3076 else
3077 ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
3078
3079 return ret;
3080 }
3081
3082 /* Return the list of words present in STRING. Separate the string into
3083 words at any of the characters found in SEPARATORS. If QUOTED is
3084 non-zero then word in the list will have its quoted flag set, otherwise
3085 the quoted flag is left as make_word () deemed fit.
3086
3087 This obeys the P1003.2 word splitting semantics. If `separators' is
3088 exactly <space><tab><newline>, then the splitting algorithm is that of
3089 the Bourne shell, which treats any sequence of characters from `separators'
3090 as a delimiter. If IFS is unset, which results in `separators' being set
3091 to "", no splitting occurs. If separators has some other value, the
3092 following rules are applied (`IFS white space' means zero or more
3093 occurrences of <space>, <tab>, or <newline>, as long as those characters
3094 are in `separators'):
3095
3096 1) IFS white space is ignored at the start and the end of the
3097 string.
3098 2) Each occurrence of a character in `separators' that is not
3099 IFS white space, along with any adjacent occurrences of
3100 IFS white space delimits a field.
3101 3) Any nonzero-length sequence of IFS white space delimits a field.
3102 */
3103
3104 /* BEWARE! list_string strips null arguments. Don't call it twice and
3105 expect to have "" preserved! */
3106
3107 /* This performs word splitting and quoted null character removal on
3108 STRING. */
3109 #define issep(c) \
3110 (((separators)[0]) ? ((separators)[1] ? isifs(c) \
3111 : (c) == (separators)[0]) \
3112 : 0)
3113
3114 /* member of the space character class in the current locale */
3115 #define ifs_whitespace(c) ISSPACE(c)
3116
3117 /* "adjacent IFS white space" */
3118 #define ifs_whitesep(c) ((sh_style_split || separators == 0) ? spctabnl (c) \
3119 : ifs_whitespace (c))
3120
3121 WORD_LIST *
3122 list_string (string, separators, quoted)
3123 register char *string, *separators;
3124 int quoted;
3125 {
3126 WORD_LIST *result;
3127 WORD_DESC *t;
3128 char *current_word, *s;
3129 int sindex, sh_style_split, whitesep, xflags, free_word;
3130 size_t slen;
3131
3132 if (!string || !*string)
3133 return ((WORD_LIST *)NULL);
3134
3135 sh_style_split = separators && separators[0] == ' ' &&
3136 separators[1] == '\t' &&
3137 separators[2] == '\n' &&
3138 separators[3] == '\0';
3139 for (xflags = 0, s = ifs_value; s && *s; s++)
3140 {
3141 if (*s == CTLESC) xflags |= SX_NOCTLESC;
3142 else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
3143 }
3144
3145 slen = 0;
3146 /* Remove sequences of whitespace at the beginning of STRING, as
3147 long as those characters appear in IFS. Do not do this if
3148 STRING is quoted or if there are no separator characters. We use the
3149 Posix definition of whitespace as a member of the space character
3150 class in the current locale. */
3151 #if 0
3152 if (!quoted || !separators || !*separators)
3153 #else
3154 /* issep() requires that separators be non-null, and always returns 0 if
3155 separator is the empty string, so don't bother if we get an empty string
3156 for separators. We already returned NULL above if STRING is empty. */
3157 if (!quoted && separators && *separators)
3158 #endif
3159 {
3160 for (s = string; *s && issep (*s) && ifs_whitespace (*s); s++);
3161
3162 if (!*s)
3163 return ((WORD_LIST *)NULL);
3164
3165 string = s;
3166 }
3167
3168 /* OK, now STRING points to a word that does not begin with white space.
3169 The splitting algorithm is:
3170 extract a word, stopping at a separator
3171 skip sequences of whitespace characters as long as they are separators
3172 This obeys the field splitting rules in Posix.2. */
3173 slen = STRLEN (string);
3174 for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
3175 {
3176 /* Don't need string length in ADVANCE_CHAR unless multibyte chars are
3177 possible, but need it in string_extract_verbatim for bounds checking */
3178 current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
3179 if (current_word == 0)
3180 break;
3181
3182 free_word = 1; /* If non-zero, we free current_word */
3183
3184 /* If we have a quoted empty string, add a quoted null argument. We
3185 want to preserve the quoted null character iff this is a quoted
3186 empty string; otherwise the quoted null characters are removed
3187 below. */
3188 if (QUOTED_NULL (current_word))
3189 {
3190 t = alloc_word_desc ();
3191 t->word = make_quoted_char ('\0');
3192 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
3193 result = make_word_list (t, result);
3194 }
3195 else if (current_word[0] != '\0')
3196 {
3197 /* If we have something, then add it regardless. However,
3198 perform quoted null character removal on the current word. */
3199 remove_quoted_nulls (current_word);
3200
3201 /* We don't want to set the word flags based on the string contents
3202 here -- that's mostly for the parser -- so we just allocate a
3203 WORD_DESC *, assign current_word (noting that we don't want to
3204 free it), and skip all of make_word. */
3205 t = alloc_word_desc ();
3206 t->word = current_word;
3207 result = make_word_list (t, result);
3208 free_word = 0;
3209 result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */
3210 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
3211 result->word->flags |= W_QUOTED;
3212 /* If removing quoted null characters leaves an empty word, note
3213 that we saw this for the caller to act on. */
3214 if (current_word == 0 || current_word[0] == '\0')
3215 result->word->flags |= W_SAWQUOTEDNULL;
3216 }
3217
3218 /* If we're not doing sequences of separators in the traditional
3219 Bourne shell style, then add a quoted null argument. */
3220 else if (!sh_style_split && !ifs_whitespace (string[sindex]))
3221 {
3222 t = alloc_word_desc ();
3223 t->word = make_quoted_char ('\0');
3224 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
3225 result = make_word_list (t, result);
3226 }
3227
3228 if (free_word)
3229 free (current_word);
3230
3231 /* Note whether or not the separator is IFS whitespace, used later. */
3232 whitesep = string[sindex] && ifs_whitesep (string[sindex]);
3233
3234 /* Move past the current separator character. */
3235 if (string[sindex])
3236 {
3237 DECLARE_MBSTATE;
3238 ADVANCE_CHAR (string, slen, sindex);
3239 }
3240
3241 /* Now skip sequences of whitespace characters if they are
3242 in the list of separators. */
3243 while (string[sindex] && ifs_whitesep (string[sindex]) && issep (string[sindex]))
3244 sindex++;
3245
3246 /* If the first separator was IFS whitespace and the current character
3247 is a non-whitespace IFS character, it should be part of the current
3248 field delimiter, not a separate delimiter that would result in an
3249 empty field. Look at POSIX.2, 3.6.5, (3)(b). */
3250 if (string[sindex] && whitesep && issep (string[sindex]) && !ifs_whitesep (string[sindex]))
3251 {
3252 sindex++;
3253 /* An IFS character that is not IFS white space, along with any
3254 adjacent IFS white space, shall delimit a field. (SUSv3) */
3255 while (string[sindex] && ifs_whitesep (string[sindex]) && isifs (string[sindex]))
3256 sindex++;
3257 }
3258 }
3259 return (REVERSE_LIST (result, WORD_LIST *));
3260 }
3261
3262 /* Parse a single word from STRING, using SEPARATORS to separate fields.
3263 ENDPTR is set to the first character after the word. This is used by
3264 the `read' builtin.
3265
3266 This is never called with SEPARATORS != $IFS, and takes advantage of that.
3267
3268 XXX - this function is very similar to list_string; they should be
3269 combined - XXX */
3270
3271 /* character is in $IFS */
3272 #define islocalsep(c) (local_cmap[(unsigned char)(c)] != 0)
3273
3274 char *
3275 get_word_from_string (stringp, separators, endptr)
3276 char **stringp, *separators, **endptr;
3277 {
3278 register char *s;
3279 char *current_word;
3280 int sindex, sh_style_split, whitesep, xflags;
3281 unsigned char local_cmap[UCHAR_MAX+1]; /* really only need single-byte chars here */
3282 size_t slen;
3283
3284 if (!stringp || !*stringp || !**stringp)
3285 return ((char *)NULL);
3286
3287 sh_style_split = separators && separators[0] == ' ' &&
3288 separators[1] == '\t' &&
3289 separators[2] == '\n' &&
3290 separators[3] == '\0';
3291 memset (local_cmap, '\0', sizeof (local_cmap));
3292 for (xflags = 0, s = separators; s && *s; s++)
3293 {
3294 if (*s == CTLESC) xflags |= SX_NOCTLESC;
3295 if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
3296 local_cmap[(unsigned char)*s] = 1; /* local charmap of separators */
3297 }
3298
3299 s = *stringp;
3300 slen = 0;
3301
3302 /* Remove sequences of whitespace at the beginning of STRING, as
3303 long as those characters appear in SEPARATORS. This happens if
3304 SEPARATORS == $' \t\n' or if IFS is unset. */
3305 if (sh_style_split || separators == 0)
3306 for (; *s && spctabnl (*s) && islocalsep (*s); s++);
3307 else
3308 for (; *s && ifs_whitespace (*s) && islocalsep (*s); s++);
3309
3310 /* If the string is nothing but whitespace, update it and return. */
3311 if (!*s)
3312 {
3313 *stringp = s;
3314 if (endptr)
3315 *endptr = s;
3316 return ((char *)NULL);
3317 }
3318
3319 /* OK, S points to a word that does not begin with white space.
3320 Now extract a word, stopping at a separator, save a pointer to
3321 the first character after the word, then skip sequences of spc,
3322 tab, or nl as long as they are separators.
3323
3324 This obeys the field splitting rules in Posix.2. */
3325 sindex = 0;
3326 /* Don't need string length in ADVANCE_CHAR unless multibyte chars are
3327 possible, but need it in string_extract_verbatim for bounds checking */
3328 slen = STRLEN (s);
3329 current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
3330
3331 /* Set ENDPTR to the first character after the end of the word. */
3332 if (endptr)
3333 *endptr = s + sindex;
3334
3335 /* Note whether or not the separator is IFS whitespace, used later. */
3336 whitesep = s[sindex] && ifs_whitesep (s[sindex]);
3337
3338 /* Move past the current separator character. */
3339 if (s[sindex])
3340 {
3341 DECLARE_MBSTATE;
3342 ADVANCE_CHAR (s, slen, sindex);
3343 }
3344
3345 /* Now skip sequences of space, tab, or newline characters if they are
3346 in the list of separators. */
3347 while (s[sindex] && spctabnl (s[sindex]) && islocalsep (s[sindex]))
3348 sindex++;
3349
3350 /* If the first separator was IFS whitespace and the current character is
3351 a non-whitespace IFS character, it should be part of the current field
3352 delimiter, not a separate delimiter that would result in an empty field.
3353 Look at POSIX.2, 3.6.5, (3)(b). */
3354 if (s[sindex] && whitesep && islocalsep (s[sindex]) && !ifs_whitesep (s[sindex]))
3355 {
3356 sindex++;
3357 /* An IFS character that is not IFS white space, along with any adjacent
3358 IFS white space, shall delimit a field. */
3359 while (s[sindex] && ifs_whitesep (s[sindex]) && islocalsep(s[sindex]))
3360 sindex++;
3361 }
3362
3363 /* Update STRING to point to the next field. */
3364 *stringp = s + sindex;
3365 return (current_word);
3366 }
3367
3368 /* Remove IFS white space at the end of STRING. Start at the end
3369 of the string and walk backwards until the beginning of the string
3370 or we find a character that's not IFS white space and not CTLESC.
3371 Only let CTLESC escape a white space character if SAW_ESCAPE is
3372 non-zero. */
3373 char *
3374 strip_trailing_ifs_whitespace (string, separators, saw_escape)
3375 char *string, *separators;
3376 int saw_escape;
3377 {
3378 char *s;
3379
3380 s = string + STRLEN (string) - 1;
3381 while (s > string && ((spctabnl (*s) && isifs (*s)) ||
3382 (saw_escape && *s == CTLESC && spctabnl (s[1]))))
3383 s--;
3384 *++s = '\0';
3385 return string;
3386 }
3387
3388 #if 0
3389 /* UNUSED */
3390 /* Split STRING into words at whitespace. Obeys shell-style quoting with
3391 backslashes, single and double quotes. */
3392 WORD_LIST *
3393 list_string_with_quotes (string)
3394 char *string;
3395 {
3396 WORD_LIST *list;
3397 char *token, *s;
3398 size_t s_len;
3399 int c, i, tokstart, len;
3400
3401 for (s = string; s && *s && spctabnl (*s); s++)
3402 ;
3403 if (s == 0 || *s == 0)
3404 return ((WORD_LIST *)NULL);
3405
3406 s_len = strlen (s);
3407 tokstart = i = 0;
3408 list = (WORD_LIST *)NULL;
3409 while (1)
3410 {
3411 c = s[i];
3412 if (c == '\\')
3413 {
3414 i++;
3415 if (s[i])
3416 i++;
3417 }
3418 else if (c == '\'')
3419 i = skip_single_quoted (s, s_len, ++i, 0);
3420 else if (c == '"')
3421 i = skip_double_quoted (s, s_len, ++i, 0);
3422 else if (c == 0 || spctabnl (c))
3423 {
3424 /* We have found the end of a token. Make a word out of it and
3425 add it to the word list. */
3426 token = substring (s, tokstart, i);
3427 list = add_string_to_list (token, list);
3428 free (token);
3429 while (spctabnl (s[i]))
3430 i++;
3431 if (s[i])
3432 tokstart = i;
3433 else
3434 break;
3435 }
3436 else
3437 i++; /* normal character */
3438 }
3439 return (REVERSE_LIST (list, WORD_LIST *));
3440 }
3441 #endif
3442
3443 /********************************************************/
3444 /* */
3445 /* Functions to perform assignment statements */
3446 /* */
3447 /********************************************************/
3448
3449 #if defined (ARRAY_VARS)
3450 static SHELL_VAR *
3451 do_compound_assignment (name, value, flags)
3452 char *name, *value;
3453 int flags;
3454 {
3455 SHELL_VAR *v;
3456 int mklocal, mkassoc, mkglobal, chklocal;
3457 WORD_LIST *list;
3458 char *newname; /* used for local nameref references */
3459
3460 mklocal = flags & ASS_MKLOCAL;
3461 mkassoc = flags & ASS_MKASSOC;
3462 mkglobal = flags & ASS_MKGLOBAL;
3463 chklocal = flags & ASS_CHKLOCAL;
3464
3465 if (mklocal && variable_context)
3466 {
3467 v = find_variable (name); /* follows namerefs */
3468 newname = (v == 0) ? nameref_transform_name (name, flags) : v->name;
3469 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3470 {
3471 if (readonly_p (v))
3472 err_readonly (name);
3473 return (v); /* XXX */
3474 }
3475 list = expand_compound_array_assignment (v, value, flags);
3476 if (mkassoc)
3477 v = make_local_assoc_variable (newname, 0);
3478 else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context)
3479 v = make_local_array_variable (newname, 0);
3480 if (v)
3481 assign_compound_array_list (v, list, flags);
3482 if (list)
3483 dispose_words (list);
3484 }
3485 /* In a function but forcing assignment in global context. CHKLOCAL means to
3486 check for an existing local variable first. */
3487 else if (mkglobal && variable_context)
3488 {
3489 v = chklocal ? find_variable (name) : 0;
3490 if (v && (local_p (v) == 0 || v->context != variable_context))
3491 v = 0;
3492 if (v == 0)
3493 v = find_global_variable (name);
3494 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3495 {
3496 if (readonly_p (v))
3497 err_readonly (name);
3498 return (v); /* XXX */
3499 }
3500 /* sanity check */
3501 newname = (v == 0) ? nameref_transform_name (name, flags) : name;
3502 list = expand_compound_array_assignment (v, value, flags);
3503 if (v == 0 && mkassoc)
3504 v = make_new_assoc_variable (newname);
3505 else if (v && mkassoc && assoc_p (v) == 0)
3506 v = convert_var_to_assoc (v);
3507 else if (v == 0)
3508 v = make_new_array_variable (newname);
3509 else if (v && mkassoc == 0 && array_p (v) == 0)
3510 v = convert_var_to_array (v);
3511 if (v)
3512 assign_compound_array_list (v, list, flags);
3513 if (list)
3514 dispose_words (list);
3515 }
3516 else
3517 {
3518 v = assign_array_from_string (name, value, flags);
3519 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3520 {
3521 if (readonly_p (v))
3522 err_readonly (name);
3523 return (v); /* XXX */
3524 }
3525 }
3526
3527 return (v);
3528 }
3529 #endif
3530
3531 /* Given STRING, an assignment string, get the value of the right side
3532 of the `=', and bind it to the left side. If EXPAND is true, then
3533 perform parameter expansion, command substitution, and arithmetic
3534 expansion on the right-hand side. Perform tilde expansion in any
3535 case. Do not perform word splitting on the result of expansion. */
3536 static int
3537 do_assignment_internal (word, expand)
3538 const WORD_DESC *word;
3539 int expand;
3540 {
3541 int offset, appendop, assign_list, aflags, retval;
3542 char *name, *value, *temp;
3543 SHELL_VAR *entry;
3544 #if defined (ARRAY_VARS)
3545 char *t;
3546 int ni;
3547 #endif
3548 const char *string;
3549
3550 if (word == 0 || word->word == 0)
3551 return 0;
3552
3553 appendop = assign_list = aflags = 0;
3554 string = word->word;
3555 offset = assignment (string, 0);
3556 name = savestring (string);
3557 value = (char *)NULL;
3558
3559 if (name[offset] == '=')
3560 {
3561 if (name[offset - 1] == '+')
3562 {
3563 appendop = 1;
3564 name[offset - 1] = '\0';
3565 }
3566
3567 name[offset] = 0; /* might need this set later */
3568 temp = name + offset + 1;
3569
3570 #if defined (ARRAY_VARS)
3571 if (expand && (word->flags & W_COMPASSIGN))
3572 {
3573 assign_list = ni = 1;
3574 value = extract_array_assignment_list (temp, &ni);
3575 }
3576 else
3577 #endif
3578 if (expand && temp[0])
3579 value = expand_string_if_necessary (temp, 0, expand_string_assignment);
3580 else
3581 value = savestring (temp);
3582 }
3583
3584 if (value == 0)
3585 {
3586 value = (char *)xmalloc (1);
3587 value[0] = '\0';
3588 }
3589
3590 if (echo_command_at_execute)
3591 {
3592 if (appendop)
3593 name[offset - 1] = '+';
3594 xtrace_print_assignment (name, value, assign_list, 1);
3595 if (appendop)
3596 name[offset - 1] = '\0';
3597 }
3598
3599 #define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
3600
3601 if (appendop)
3602 aflags |= ASS_APPEND;
3603
3604 #if defined (ARRAY_VARS)
3605 if (t = mbschr (name, LBRACK))
3606 {
3607 if (assign_list)
3608 {
3609 report_error (_("%s: cannot assign list to array member"), name);
3610 ASSIGN_RETURN (0);
3611 }
3612 aflags |= ASS_ALLOWALLSUB; /* allow a[@]=value for existing associative arrays */
3613 entry = assign_array_element (name, value, aflags, (array_eltstate_t *)0);
3614 if (entry == 0)
3615 ASSIGN_RETURN (0);
3616 }
3617 else if (assign_list)
3618 {
3619 if ((word->flags & W_ASSIGNARG) && (word->flags & W_CHKLOCAL))
3620 aflags |= ASS_CHKLOCAL;
3621 if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0)
3622 aflags |= ASS_MKLOCAL;
3623 if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL))
3624 aflags |= ASS_MKGLOBAL;
3625 if (word->flags & W_ASSIGNASSOC)
3626 aflags |= ASS_MKASSOC;
3627 entry = do_compound_assignment (name, value, aflags);
3628 }
3629 else
3630 #endif /* ARRAY_VARS */
3631 entry = bind_variable (name, value, aflags);
3632
3633 if (entry)
3634 stupidly_hack_special_variables (entry->name); /* might be a nameref */
3635 else
3636 stupidly_hack_special_variables (name);
3637
3638 /* Return 1 if the assignment seems to have been performed correctly. */
3639 if (entry == 0 || readonly_p (entry))
3640 retval = 0; /* assignment failure */
3641 else if (noassign_p (entry))
3642 {
3643 set_exit_status (EXECUTION_FAILURE);
3644 retval = 1; /* error status, but not assignment failure */
3645 }
3646 else
3647 retval = 1;
3648
3649 if (entry && retval != 0 && noassign_p (entry) == 0)
3650 VUNSETATTR (entry, att_invisible);
3651
3652 ASSIGN_RETURN (retval);
3653 }
3654
3655 /* Perform the assignment statement in STRING, and expand the
3656 right side by doing tilde, command and parameter expansion. */
3657 int
3658 do_assignment (string)
3659 char *string;
3660 {
3661 WORD_DESC td;
3662
3663 td.flags = W_ASSIGNMENT;
3664 td.word = string;
3665
3666 return do_assignment_internal (&td, 1);
3667 }
3668
3669 int
3670 do_word_assignment (word, flags)
3671 WORD_DESC *word;
3672 int flags;
3673 {
3674 return do_assignment_internal (word, 1);
3675 }
3676
3677 /* Given STRING, an assignment string, get the value of the right side
3678 of the `=', and bind it to the left side. Do not perform any word
3679 expansions on the right hand side. */
3680 int
3681 do_assignment_no_expand (string)
3682 char *string;
3683 {
3684 WORD_DESC td;
3685
3686 td.flags = W_ASSIGNMENT;
3687 td.word = string;
3688
3689 return (do_assignment_internal (&td, 0));
3690 }
3691
3692 /***************************************************
3693 * *
3694 * Functions to manage the positional parameters *
3695 * *
3696 ***************************************************/
3697
3698 /* Return the word list that corresponds to `$*'. */
3699 WORD_LIST *
3700 list_rest_of_args ()
3701 {
3702 register WORD_LIST *list, *args;
3703 int i;
3704
3705 /* Break out of the loop as soon as one of the dollar variables is null. */
3706 for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
3707 list = make_word_list (make_bare_word (dollar_vars[i]), list);
3708
3709 for (args = rest_of_args; args; args = args->next)
3710 list = make_word_list (make_bare_word (args->word->word), list);
3711
3712 return (REVERSE_LIST (list, WORD_LIST *));
3713 }
3714
3715 /* Return the value of a positional parameter. This handles values > 10. */
3716 char *
3717 get_dollar_var_value (ind)
3718 intmax_t ind;
3719 {
3720 char *temp;
3721 WORD_LIST *p;
3722
3723 if (ind < 10)
3724 temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
3725 else /* We want something like ${11} */
3726 {
3727 ind -= 10;
3728 for (p = rest_of_args; p && ind--; p = p->next)
3729 ;
3730 temp = p ? savestring (p->word->word) : (char *)NULL;
3731 }
3732 return (temp);
3733 }
3734
3735 /* Make a single large string out of the dollar digit variables,
3736 and the rest_of_args. If DOLLAR_STAR is 1, then obey the special
3737 case of "$*" with respect to IFS. */
3738 char *
3739 string_rest_of_args (dollar_star)
3740 int dollar_star;
3741 {
3742 register WORD_LIST *list;
3743 char *string;
3744
3745 list = list_rest_of_args ();
3746 string = dollar_star ? string_list_dollar_star (list, 0, 0) : string_list (list);
3747 dispose_words (list);
3748 return (string);
3749 }
3750
3751 /* Return a string containing the positional parameters from START to
3752 END, inclusive. If STRING[0] == '*', we obey the rules for $*,
3753 which only makes a difference if QUOTED is non-zero. If QUOTED includes
3754 Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise
3755 no quoting chars are added. */
3756 static char *
3757 pos_params (string, start, end, quoted, pflags)
3758 char *string;
3759 int start, end, quoted, pflags;
3760 {
3761 WORD_LIST *save, *params, *h, *t;
3762 char *ret;
3763 int i;
3764
3765 /* see if we can short-circuit. if start == end, we want 0 parameters. */
3766 if (start == end)
3767 return ((char *)NULL);
3768
3769 save = params = list_rest_of_args ();
3770 if (save == 0 && start > 0)
3771 return ((char *)NULL);
3772
3773 if (start == 0) /* handle ${@:0[:x]} specially */
3774 {
3775 t = make_word_list (make_word (dollar_vars[0]), params);
3776 save = params = t;
3777 }
3778
3779 for (i = start ? 1 : 0; params && i < start; i++)
3780 params = params->next;
3781 if (params == 0)
3782 {
3783 dispose_words (save);
3784 return ((char *)NULL);
3785 }
3786 for (h = t = params; params && i < end; i++)
3787 {
3788 t = params;
3789 params = params->next;
3790 }
3791 t->next = (WORD_LIST *)NULL;
3792
3793 ret = string_list_pos_params (string[0], h, quoted, pflags);
3794
3795 if (t != params)
3796 t->next = params;
3797
3798 dispose_words (save);
3799 return (ret);
3800 }
3801
3802 /******************************************************************/
3803 /* */
3804 /* Functions to expand strings to strings or WORD_LISTs */
3805 /* */
3806 /******************************************************************/
3807
3808 #if defined (PROCESS_SUBSTITUTION)
3809 #define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~')
3810 #else
3811 #define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
3812 #endif
3813
3814 /* If there are any characters in STRING that require full expansion,
3815 then call FUNC to expand STRING; otherwise just perform quote
3816 removal if necessary. This returns a new string. */
3817 static char *
3818 expand_string_if_necessary (string, quoted, func)
3819 char *string;
3820 int quoted;
3821 EXPFUNC *func;
3822 {
3823 WORD_LIST *list;
3824 size_t slen;
3825 int i, saw_quote;
3826 char *ret;
3827 DECLARE_MBSTATE;
3828
3829 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3830 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
3831 i = saw_quote = 0;
3832 while (string[i])
3833 {
3834 if (EXP_CHAR (string[i]))
3835 break;
3836 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3837 saw_quote = 1;
3838 ADVANCE_CHAR (string, slen, i);
3839 }
3840
3841 if (string[i])
3842 {
3843 list = (*func) (string, quoted);
3844 if (list)
3845 {
3846 ret = string_list (list);
3847 dispose_words (list);
3848 }
3849 else
3850 ret = (char *)NULL;
3851 }
3852 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3853 ret = string_quote_removal (string, quoted);
3854 else
3855 ret = savestring (string);
3856
3857 return ret;
3858 }
3859
3860 static inline char *
3861 expand_string_to_string_internal (string, quoted, func)
3862 char *string;
3863 int quoted;
3864 EXPFUNC *func;
3865 {
3866 WORD_LIST *list;
3867 char *ret;
3868
3869 if (string == 0 || *string == '\0')
3870 return ((char *)NULL);
3871
3872 list = (*func) (string, quoted);
3873 if (list)
3874 {
3875 ret = string_list (list);
3876 dispose_words (list);
3877 }
3878 else
3879 ret = (char *)NULL;
3880
3881 return (ret);
3882 }
3883
3884 char *
3885 expand_string_to_string (string, quoted)
3886 char *string;
3887 int quoted;
3888 {
3889 return (expand_string_to_string_internal (string, quoted, expand_string));
3890 }
3891
3892 char *
3893 expand_string_unsplit_to_string (string, quoted)
3894 char *string;
3895 int quoted;
3896 {
3897 return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
3898 }
3899
3900 char *
3901 expand_assignment_string_to_string (string, quoted)
3902 char *string;
3903 int quoted;
3904 {
3905 return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
3906 }
3907
3908 /* Kind of like a combination of dequote_string and quote_string_for_globbing;
3909 try to remove CTLESC quoting characters and convert CTLESC escaping a `&'
3910 or a backslash into a backslash. The output of this function must eventually
3911 be processed by strcreplace(). */
3912 static char *
3913 quote_string_for_repl (string, flags)
3914 char *string;
3915 int flags;
3916 {
3917 size_t slen;
3918 char *result, *t;
3919 const char *s, *send;
3920 DECLARE_MBSTATE;
3921
3922 slen = strlen (string);
3923 send = string + slen;
3924
3925 result = (char *)xmalloc (slen * 2 + 1);
3926
3927 if (string[0] == CTLESC && string[1] == 0)
3928 {
3929 result[0] = CTLESC;
3930 result[1] = '\0';
3931 return (result);
3932 }
3933
3934 /* This is awkward. We want to translate CTLESC-\ to \\ if we will
3935 eventually send this string through strcreplace(), which we will do
3936 only if shouldexp_replacement() determines that there is something
3937 to replace. We can either make sure to escape backslashes here and
3938 have shouldexp_replacement() signal that we should send the string to
3939 strcreplace() if it sees an escaped backslash, or we can scan the
3940 string before copying it and turn CTLESC-\ into \\ only if we encounter
3941 a CTLESC-& or a &. This does the former and changes shouldexp_replacement().
3942 If we double the backslashes here, we'll get doubled backslashes in any
3943 result that doesn't get passed to strcreplace(). */
3944
3945 for (s = string, t = result; *s; )
3946 {
3947 /* This function's result has to be processed by strcreplace() */
3948 if (*s == CTLESC && (s[1] == '&' || s[1] == '\\'))
3949 {
3950 *t++ = '\\';
3951 s++;
3952 *t++ = *s++;
3953 continue;
3954 }
3955 /* Dequote it */
3956 if (*s == CTLESC)
3957 {
3958 s++;
3959 if (*s == '\0')
3960 break;
3961 }
3962 COPY_CHAR_P (t, s, send);
3963 }
3964
3965 *t = '\0';
3966 return (result);
3967 }
3968
3969 /* This does not perform word splitting on the WORD_LIST it returns and
3970 it treats $* as if it were quoted. It dequotes the WORD_LIST, adds
3971 backslash escapes before CTLESC-quoted backslash and `& if
3972 patsub_replacement is enabled. */
3973 static char *
3974 expand_string_for_patsub (string, quoted)
3975 char *string;
3976 int quoted;
3977 {
3978 WORD_LIST *value;
3979 char *ret, *t;
3980
3981 if (string == 0 || *string == '\0')
3982 return (char *)NULL;
3983
3984 value = expand_string_for_pat (string, quoted, (int *)0, (int *)0);
3985
3986 if (value && value->word)
3987 {
3988 remove_quoted_nulls (value->word->word); /* XXX */
3989 value->word->flags &= ~W_HASQUOTEDNULL;
3990 }
3991
3992 if (value)
3993 {
3994 t = (value->next) ? string_list (value) : value->word->word;
3995 ret = quote_string_for_repl (t, quoted);
3996 if (t != value->word->word)
3997 free (t);
3998 dispose_words (value);
3999 }
4000 else
4001 ret = (char *)NULL;
4002
4003 return (ret);
4004 }
4005
4006 char *
4007 expand_arith_string (string, quoted)
4008 char *string;
4009 int quoted;
4010 {
4011 WORD_DESC td;
4012 WORD_LIST *list, *tlist;
4013 size_t slen;
4014 int i, saw_quote;
4015 char *ret;
4016 DECLARE_MBSTATE;
4017
4018 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
4019 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
4020 i = saw_quote = 0;
4021 while (string[i])
4022 {
4023 if (EXP_CHAR (string[i]))
4024 break;
4025 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
4026 saw_quote = string[i];
4027 ADVANCE_CHAR (string, slen, i);
4028 }
4029
4030 if (string[i])
4031 {
4032 /* This is expanded version of expand_string_internal as it's called by
4033 expand_string_leave_quoted */
4034 td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */
4035 #if 0 /* TAG: bash-5.2 */
4036 if (quoted & Q_ARRAYSUB)
4037 td.flags |= W_NOCOMSUB;
4038 #endif
4039 td.word = savestring (string);
4040 list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4041 /* This takes care of the calls from expand_string_leave_quoted and
4042 expand_string */
4043 if (list)
4044 {
4045 tlist = word_list_split (list);
4046 dispose_words (list);
4047 list = tlist;
4048 if (list)
4049 dequote_list (list);
4050 }
4051 /* This comes from expand_string_if_necessary */
4052 if (list)
4053 {
4054 ret = string_list (list);
4055 dispose_words (list);
4056 }
4057 else
4058 ret = (char *)NULL;
4059 FREE (td.word);
4060 }
4061 else if (saw_quote && (quoted & Q_ARITH))
4062 ret = string_quote_removal (string, quoted);
4063 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
4064 ret = string_quote_removal (string, quoted);
4065 else
4066 ret = savestring (string);
4067
4068 return ret;
4069 }
4070
4071 #if defined (COND_COMMAND)
4072 /* Just remove backslashes in STRING. Returns a new string. */
4073 char *
4074 remove_backslashes (string)
4075 char *string;
4076 {
4077 char *r, *ret, *s;
4078
4079 r = ret = (char *)xmalloc (strlen (string) + 1);
4080 for (s = string; s && *s; )
4081 {
4082 if (*s == '\\')
4083 s++;
4084 if (*s == 0)
4085 break;
4086 *r++ = *s++;
4087 }
4088 *r = '\0';
4089 return ret;
4090 }
4091
4092 /* This needs better error handling. */
4093 /* Expand W for use as an argument to a unary or binary operator in a
4094 [[...]] expression. If SPECIAL is 1, this is the rhs argument
4095 to the != or == operator, and should be treated as a pattern. In
4096 this case, we quote the string specially for the globbing code. If
4097 SPECIAL is 2, this is an rhs argument for the =~ operator, and should
4098 be quoted appropriately for regcomp/regexec. If SPECIAL is 3, this is
4099 an array subscript and should be quoted after expansion so it's only
4100 expanded once (Q_ARITH). The caller is responsible
4101 for removing the backslashes if the unquoted word is needed later. In
4102 any case, since we don't perform word splitting, we need to do quoted
4103 null character removal. */
4104 char *
4105 cond_expand_word (w, special)
4106 WORD_DESC *w;
4107 int special;
4108 {
4109 char *r, *p;
4110 WORD_LIST *l;
4111 int qflags;
4112
4113 if (w->word == 0 || w->word[0] == '\0')
4114 return ((char *)NULL);
4115
4116 expand_no_split_dollar_star = 1;
4117 w->flags |= W_NOSPLIT2;
4118 qflags = (special == 3) ? Q_ARITH : 0;
4119 l = call_expand_word_internal (w, qflags, 0, (int *)0, (int *)0);
4120 expand_no_split_dollar_star = 0;
4121 if (l)
4122 {
4123 if (special == 0) /* LHS */
4124 {
4125 if (l->word)
4126 word_list_remove_quoted_nulls (l);
4127 dequote_list (l);
4128 r = string_list (l);
4129 }
4130 else if (special == 3) /* arithmetic expression, Q_ARITH */
4131 {
4132 if (l->word)
4133 word_list_remove_quoted_nulls (l); /* for now */
4134 dequote_list (l);
4135 r = string_list (l);
4136 }
4137 else
4138 {
4139 /* Need to figure out whether or not we should call dequote_escapes
4140 or a new dequote_ctlnul function here, and under what
4141 circumstances. */
4142 qflags = QGLOB_CVTNULL|QGLOB_CTLESC;
4143 if (special == 2)
4144 qflags |= QGLOB_REGEXP;
4145 word_list_remove_quoted_nulls (l);
4146 p = string_list (l);
4147 r = quote_string_for_globbing (p, qflags);
4148 free (p);
4149 }
4150 dispose_words (l);
4151 }
4152 else
4153 r = (char *)NULL;
4154
4155 return r;
4156 }
4157 #endif
4158
4159 /* Expand $'...' and $"..." in a string for code paths that don't do it. The
4160 FLAGS argument is 1 if this function should treat CTLESC as a quote
4161 character (e.g., for here-documents) or not (e.g., for shell_expand_line). */
4162 char *
4163 expand_string_dollar_quote (string, flags)
4164 char *string;
4165 int flags;
4166 {
4167 size_t slen, retind, retsize;
4168 int sindex, c, translen, peekc, news;
4169 char *ret, *trans, *send, *t;
4170 DECLARE_MBSTATE;
4171
4172 slen = strlen (string);
4173 send = string + slen;
4174 sindex = 0;
4175
4176 retsize = slen + 1;
4177 ret = xmalloc (retsize);
4178 retind = 0;
4179
4180 while (c = string[sindex])
4181 {
4182 switch (c)
4183 {
4184 default:
4185 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 1, retsize, 64);
4186 COPY_CHAR_I (ret, retind, string, send, sindex);
4187 break;
4188
4189 case '\\':
4190 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 2, retsize, 64);
4191 ret[retind++] = string[sindex++];
4192
4193 if (string[sindex])
4194 COPY_CHAR_I (ret, retind, string, send, sindex);
4195 break;
4196
4197 case '\'':
4198 case '"':
4199 if (c == '\'')
4200 news = skip_single_quoted (string, slen, ++sindex, SX_COMPLETE);
4201 else
4202 news = skip_double_quoted (string, slen, ++sindex, SX_COMPLETE);
4203 translen = news - sindex - 1;
4204 RESIZE_MALLOCED_BUFFER (ret, retind, translen + 3, retsize, 64);
4205 ret[retind++] = c;
4206 if (translen > 0)
4207 {
4208 strncpy (ret + retind, string + sindex, translen);
4209 retind += translen;
4210 }
4211 if (news > sindex && string[news - 1] == c)
4212 ret[retind++] = c;
4213 sindex = news;
4214 break;
4215
4216 case CTLESC:
4217 RESIZE_MALLOCED_BUFFER (ret, retind, locale_mb_cur_max + 2, retsize, 64);
4218 if (flags)
4219 ret[retind++] = string[sindex++];
4220 if (string[sindex])
4221 COPY_CHAR_I (ret, retind, string, send, sindex);
4222 break;
4223
4224 case '$':
4225 peekc = string[++sindex];
4226 #if defined (TRANSLATABLE_STRINGS)
4227 if (peekc != '\'' && peekc != '"')
4228 #else
4229 if (peekc != '\'')
4230 #endif
4231 {
4232 RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 16);
4233 ret[retind++] = c;
4234 break;
4235 }
4236 if (string[sindex + 1] == '\0') /* don't bother */
4237 {
4238 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4239 ret[retind++] = c;
4240 ret[retind++] = peekc;
4241 sindex++;
4242 break;
4243 }
4244 if (peekc == '\'')
4245 {
4246 /* SX_COMPLETE is the equivalent of ALLOWESC here */
4247 /* We overload SX_COMPLETE below */
4248 news = skip_single_quoted (string, slen, ++sindex, SX_COMPLETE);
4249 /* Check for unclosed string and don't bother if so */
4250 if (news > sindex && string[news] == '\0' && string[news-1] != peekc)
4251 {
4252 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4253 ret[retind++] = c;
4254 ret[retind++] = peekc;
4255 continue;
4256 }
4257 t = substring (string, sindex, news - 1);
4258 trans = ansiexpand (t, 0, news-sindex-1, &translen);
4259 free (t);
4260 t = sh_single_quote (trans);
4261 sindex = news;
4262 }
4263 #if defined (TRANSLATABLE_STRINGS)
4264 else
4265 {
4266 news = ++sindex;
4267 t = string_extract_double_quoted (string, &news, SX_COMPLETE);
4268 /* Check for unclosed string and don't bother if so */
4269 if (news > sindex && string[news] == '\0' && string[news-1] != peekc)
4270 {
4271 RESIZE_MALLOCED_BUFFER (ret, retind, 3, retsize, 16);
4272 ret[retind++] = c;
4273 ret[retind++] = peekc;
4274 free (t);
4275 continue;
4276 }
4277 trans = locale_expand (t, 0, news-sindex, 0, &translen);
4278 free (t);
4279 if (singlequote_translations &&
4280 ((news-sindex-1) != translen || STREQN (t, trans, translen) == 0))
4281 t = sh_single_quote (trans);
4282 else
4283 t = sh_mkdoublequoted (trans, translen, 0);
4284 sindex = news;
4285 }
4286 #endif /* TRANSLATABLE_STRINGS */
4287 free (trans);
4288 trans = t;
4289 translen = strlen (trans);
4290
4291 RESIZE_MALLOCED_BUFFER (ret, retind, translen + 1, retsize, 128);
4292 strcpy (ret + retind, trans);
4293 retind += translen;
4294 FREE (trans);
4295 break;
4296 }
4297 }
4298
4299 ret[retind] = 0;
4300 return ret;
4301 }
4302
4303 /* Call expand_word_internal to expand W and handle error returns.
4304 A convenience function for functions that don't want to handle
4305 any errors or free any memory before aborting. */
4306 static WORD_LIST *
4307 call_expand_word_internal (w, q, i, c, e)
4308 WORD_DESC *w;
4309 int q, i, *c, *e;
4310 {
4311 WORD_LIST *result;
4312
4313 result = expand_word_internal (w, q, i, c, e);
4314 if (result == &expand_word_error || result == &expand_word_fatal)
4315 {
4316 /* By convention, each time this error is returned, w->word has
4317 already been freed (it sometimes may not be in the fatal case,
4318 but that doesn't result in a memory leak because we're going
4319 to exit in most cases). */
4320 w->word = (char *)NULL;
4321 last_command_exit_value = EXECUTION_FAILURE;
4322 exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
4323 /* NOTREACHED */
4324 return (NULL);
4325 }
4326 else
4327 return (result);
4328 }
4329
4330 /* Perform parameter expansion, command substitution, and arithmetic
4331 expansion on STRING, as if it were a word. Leave the result quoted.
4332 Since this does not perform word splitting, it leaves quoted nulls
4333 in the result. */
4334 static WORD_LIST *
4335 expand_string_internal (string, quoted)
4336 char *string;
4337 int quoted;
4338 {
4339 WORD_DESC td;
4340 WORD_LIST *tresult;
4341
4342 if (string == 0 || *string == 0)
4343 return ((WORD_LIST *)NULL);
4344
4345 td.flags = 0;
4346 td.word = savestring (string);
4347
4348 tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4349
4350 FREE (td.word);
4351 return (tresult);
4352 }
4353
4354 /* Expand STRING by performing parameter expansion, command substitution,
4355 and arithmetic expansion. Dequote the resulting WORD_LIST before
4356 returning it, but do not perform word splitting. The call to
4357 remove_quoted_nulls () is in here because word splitting normally
4358 takes care of quote removal. */
4359 WORD_LIST *
4360 expand_string_unsplit (string, quoted)
4361 char *string;
4362 int quoted;
4363 {
4364 WORD_LIST *value;
4365
4366 if (string == 0 || *string == '\0')
4367 return ((WORD_LIST *)NULL);
4368
4369 expand_no_split_dollar_star = 1;
4370 value = expand_string_internal (string, quoted);
4371 expand_no_split_dollar_star = 0;
4372
4373 if (value)
4374 {
4375 if (value->word)
4376 {
4377 remove_quoted_nulls (value->word->word); /* XXX */
4378 value->word->flags &= ~W_HASQUOTEDNULL;
4379 }
4380 dequote_list (value);
4381 }
4382 return (value);
4383 }
4384
4385 /* Expand the rhs of an assignment statement */
4386 WORD_LIST *
4387 expand_string_assignment (string, quoted)
4388 char *string;
4389 int quoted;
4390 {
4391 WORD_DESC td;
4392 WORD_LIST *value;
4393
4394 if (string == 0 || *string == '\0')
4395 return ((WORD_LIST *)NULL);
4396
4397 expand_no_split_dollar_star = 1;
4398
4399 #if 0
4400 /* Other shells (ksh93) do it this way, which affects how $@ is expanded
4401 in constructs like bar=${@#0} (preserves the spaces resulting from the
4402 expansion of $@ in a context where you don't do word splitting); Posix
4403 interp 888 makes the expansion of $@ in contexts where word splitting
4404 is not performed unspecified. */
4405 td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */
4406 #else
4407 td.flags = W_ASSIGNRHS;
4408 #endif
4409 td.flags |= (W_NOGLOB|W_TILDEEXP);
4410 td.word = savestring (string);
4411 value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4412 FREE (td.word);
4413
4414 expand_no_split_dollar_star = 0;
4415
4416 if (value)
4417 {
4418 if (value->word)
4419 {
4420 remove_quoted_nulls (value->word->word); /* XXX */
4421 value->word->flags &= ~W_HASQUOTEDNULL;
4422 }
4423 dequote_list (value);
4424 }
4425 return (value);
4426 }
4427
4428 /* Expand one of the PS? prompt strings. This is a sort of combination of
4429 expand_string_unsplit and expand_string_internal, but returns the
4430 passed string when an error occurs. Might want to trap other calls
4431 to jump_to_top_level here so we don't endlessly loop. */
4432 WORD_LIST *
4433 expand_prompt_string (string, quoted, wflags)
4434 char *string;
4435 int quoted;
4436 int wflags;
4437 {
4438 WORD_LIST *value;
4439 WORD_DESC td;
4440
4441 if (string == 0 || *string == 0)
4442 return ((WORD_LIST *)NULL);
4443
4444 td.flags = wflags;
4445 td.word = savestring (string);
4446
4447 no_longjmp_on_fatal_error = 1;
4448 value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
4449 no_longjmp_on_fatal_error = 0;
4450
4451 if (value == &expand_word_error || value == &expand_word_fatal)
4452 {
4453 value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
4454 return value;
4455 }
4456 FREE (td.word);
4457 if (value)
4458 {
4459 if (value->word)
4460 {
4461 remove_quoted_nulls (value->word->word); /* XXX */
4462 value->word->flags &= ~W_HASQUOTEDNULL;
4463 }
4464 dequote_list (value);
4465 }
4466 return (value);
4467 }
4468
4469 /* Expand STRING just as if you were expanding a word, but do not dequote
4470 the resultant WORD_LIST. This is called only from within this file,
4471 and is used to correctly preserve quoted characters when expanding
4472 things like ${1+"$@"}. This does parameter expansion, command
4473 substitution, arithmetic expansion, and word splitting. */
4474 static WORD_LIST *
4475 expand_string_leave_quoted (string, quoted)
4476 char *string;
4477 int quoted;
4478 {
4479 WORD_LIST *tlist;
4480 WORD_LIST *tresult;
4481
4482 if (string == 0 || *string == '\0')
4483 return ((WORD_LIST *)NULL);
4484
4485 tlist = expand_string_internal (string, quoted);
4486
4487 if (tlist)
4488 {
4489 tresult = word_list_split (tlist);
4490 dispose_words (tlist);
4491 return (tresult);
4492 }
4493 return ((WORD_LIST *)NULL);
4494 }
4495
4496 /* This does not perform word splitting or dequote the WORD_LIST
4497 it returns. */
4498 static WORD_LIST *
4499 expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p)
4500 char *string;
4501 int quoted, op, pflags;
4502 int *dollar_at_p, *expanded_p;
4503 {
4504 WORD_DESC td;
4505 WORD_LIST *tresult;
4506 int old_nosplit;
4507
4508 if (string == 0 || *string == '\0')
4509 return (WORD_LIST *)NULL;
4510
4511 /* We want field splitting to be determined by what is going to be done with
4512 the entire ${parameterOPword} expansion, so we don't want to split the RHS
4513 we expand here. However, the expansion of $* is determined by whether we
4514 are going to eventually perform word splitting, so we want to set this
4515 depending on whether or not are are going to be splitting: if the expansion
4516 is quoted, if the OP is `=', or if IFS is set to the empty string, we
4517 are not going to be splitting, so we set expand_no_split_dollar_star to
4518 note this to callees.
4519 We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an
4520 assignment statement. */
4521 /* The updated treatment of $* is the result of Posix interp 888 */
4522 /* This was further clarified on the austin-group list in March, 2017 and
4523 in Posix bug 1129 */
4524 old_nosplit = expand_no_split_dollar_star;
4525 expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */
4526 td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */
4527 td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */
4528 if (pflags & PF_ASSIGNRHS) /* pass through */
4529 td.flags |= W_ASSIGNRHS;
4530 if (op == '=')
4531 #if 0
4532 td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */
4533 #else
4534 td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */
4535 #endif
4536 td.word = savestring (string);
4537 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
4538 expand_no_split_dollar_star = old_nosplit;
4539 free (td.word);
4540
4541 return (tresult);
4542 }
4543
4544 /* This does not perform word splitting or dequote the WORD_LIST
4545 it returns and it treats $* as if it were quoted. */
4546 static WORD_LIST *
4547 expand_string_for_pat (string, quoted, dollar_at_p, expanded_p)
4548 char *string;
4549 int quoted, *dollar_at_p, *expanded_p;
4550 {
4551 WORD_DESC td;
4552 WORD_LIST *tresult;
4553 int oexp;
4554
4555 if (string == 0 || *string == '\0')
4556 return (WORD_LIST *)NULL;
4557
4558 oexp = expand_no_split_dollar_star;
4559 expand_no_split_dollar_star = 1;
4560 td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */
4561 td.word = savestring (string);
4562 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
4563 expand_no_split_dollar_star = oexp;
4564 free (td.word);
4565
4566 return (tresult);
4567 }
4568
4569 /* Expand STRING just as if you were expanding a word. This also returns
4570 a list of words. Note that filename globbing is *NOT* done for word
4571 or string expansion, just when the shell is expanding a command. This
4572 does parameter expansion, command substitution, arithmetic expansion,
4573 and word splitting. Dequote the resultant WORD_LIST before returning. */
4574 WORD_LIST *
4575 expand_string (string, quoted)
4576 char *string;
4577 int quoted;
4578 {
4579 WORD_LIST *result;
4580
4581 if (string == 0 || *string == '\0')
4582 return ((WORD_LIST *)NULL);
4583
4584 result = expand_string_leave_quoted (string, quoted);
4585 return (result ? dequote_list (result) : result);
4586 }
4587
4588 /*******************************************
4589 * *
4590 * Functions to expand WORD_DESCs *
4591 * *
4592 *******************************************/
4593
4594 /* Expand WORD, performing word splitting on the result. This does
4595 parameter expansion, command substitution, arithmetic expansion,
4596 word splitting, and quote removal. */
4597
4598 WORD_LIST *
4599 expand_word (word, quoted)
4600 WORD_DESC *word;
4601 int quoted;
4602 {
4603 WORD_LIST *result, *tresult;
4604
4605 tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4606 result = word_list_split (tresult);
4607 dispose_words (tresult);
4608 return (result ? dequote_list (result) : result);
4609 }
4610
4611 /* Expand WORD, but do not perform word splitting on the result. This
4612 does parameter expansion, command substitution, arithmetic expansion,
4613 and quote removal. */
4614 WORD_LIST *
4615 expand_word_unsplit (word, quoted)
4616 WORD_DESC *word;
4617 int quoted;
4618 {
4619 WORD_LIST *result;
4620
4621 result = expand_word_leave_quoted (word, quoted);
4622 return (result ? dequote_list (result) : result);
4623 }
4624
4625 /* Perform shell expansions on WORD, but do not perform word splitting or
4626 quote removal on the result. Virtually identical to expand_word_unsplit;
4627 could be combined if implementations don't diverge. */
4628 WORD_LIST *
4629 expand_word_leave_quoted (word, quoted)
4630 WORD_DESC *word;
4631 int quoted;
4632 {
4633 WORD_LIST *result;
4634
4635 expand_no_split_dollar_star = 1;
4636 if (ifs_is_null)
4637 word->flags |= W_NOSPLIT;
4638 word->flags |= W_NOSPLIT2;
4639 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4640 expand_no_split_dollar_star = 0;
4641
4642 return result;
4643 }
4644
4645 /***************************************************
4646 * *
4647 * Functions to handle quoting chars *
4648 * *
4649 ***************************************************/
4650
4651 /* Conventions:
4652
4653 A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
4654 The parser passes CTLNUL as CTLESC CTLNUL. */
4655
4656 /* Quote escape characters in string s, but no other characters. This is
4657 used to protect CTLESC and CTLNUL in variable values from the rest of
4658 the word expansion process after the variable is expanded (word splitting
4659 and filename generation). If IFS is null, we quote spaces as well, just
4660 in case we split on spaces later (in the case of unquoted $@, we will
4661 eventually attempt to split the entire word on spaces). Corresponding
4662 code exists in dequote_escapes. Even if we don't end up splitting on
4663 spaces, quoting spaces is not a problem. This should never be called on
4664 a string that is quoted with single or double quotes or part of a here
4665 document (effectively double-quoted).
4666 FLAGS says whether or not we are going to split the result. If we are not,
4667 and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL,
4668 respectively, to prevent them from being removed as part of dequoting. */
4669 static char *
4670 quote_escapes_internal (string, flags)
4671 const char *string;
4672 int flags;
4673 {
4674 const char *s, *send;
4675 char *t, *result;
4676 size_t slen;
4677 int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit;
4678 DECLARE_MBSTATE;
4679
4680 slen = strlen (string);
4681 send = string + slen;
4682
4683 quote_spaces = (ifs_value && *ifs_value == 0);
4684 nosplit = (flags & PF_NOSPLIT2);
4685
4686 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
4687 {
4688 skip_ctlesc |= (nosplit == 0 && *s == CTLESC);
4689 skip_ctlnul |= (nosplit == 0 && *s == CTLNUL);
4690 }
4691
4692 t = result = (char *)xmalloc ((slen * 2) + 1);
4693 s = string;
4694
4695 while (*s)
4696 {
4697 if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
4698 *t++ = CTLESC;
4699 COPY_CHAR_P (t, s, send);
4700 }
4701 *t = '\0';
4702
4703 return (result);
4704 }
4705
4706 char *
4707 quote_escapes (string)
4708 const char *string;
4709 {
4710 return (quote_escapes_internal (string, 0));
4711 }
4712
4713 char *
4714 quote_rhs (string)
4715 const char *string;
4716 {
4717 return (quote_escapes_internal (string, PF_NOSPLIT2));
4718 }
4719
4720 static WORD_LIST *
4721 list_quote_escapes (list)
4722 WORD_LIST *list;
4723 {
4724 register WORD_LIST *w;
4725 char *t;
4726
4727 for (w = list; w; w = w->next)
4728 {
4729 t = w->word->word;
4730 w->word->word = quote_escapes (t);
4731 free (t);
4732 }
4733 return list;
4734 }
4735
4736 /* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
4737
4738 The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
4739 This is necessary to make unquoted CTLESC and CTLNUL characters in the
4740 data stream pass through properly.
4741
4742 We need to remove doubled CTLESC characters inside quoted strings before
4743 quoting the entire string, so we do not double the number of CTLESC
4744 characters.
4745
4746 Also used by parts of the pattern substitution code. */
4747 char *
4748 dequote_escapes (string)
4749 const char *string;
4750 {
4751 const char *s, *send;
4752 char *t, *result;
4753 size_t slen;
4754 int quote_spaces;
4755 DECLARE_MBSTATE;
4756
4757 if (string == 0)
4758 return (char *)0;
4759
4760 slen = strlen (string);
4761 send = string + slen;
4762
4763 t = result = (char *)xmalloc (slen + 1);
4764
4765 if (strchr (string, CTLESC) == 0)
4766 return (strcpy (result, string));
4767
4768 quote_spaces = (ifs_value && *ifs_value == 0);
4769
4770 s = string;
4771 while (*s)
4772 {
4773 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
4774 {
4775 s++;
4776 if (*s == '\0')
4777 break;
4778 }
4779 COPY_CHAR_P (t, s, send);
4780 }
4781 *t = '\0';
4782
4783 return result;
4784 }
4785
4786 #if defined (INCLUDE_UNUSED)
4787 static WORD_LIST *
4788 list_dequote_escapes (list)
4789 WORD_LIST *list;
4790 {
4791 register WORD_LIST *w;
4792 char *t;
4793
4794 for (w = list; w; w = w->next)
4795 {
4796 t = w->word->word;
4797 w->word->word = dequote_escapes (t);
4798 free (t);
4799 }
4800 return list;
4801 }
4802 #endif
4803
4804 /* Return a new string with the quoted representation of character C.
4805 This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
4806 set in any resultant WORD_DESC where this value is the word. */
4807 static char *
4808 make_quoted_char (c)
4809 int c;
4810 {
4811 char *temp;
4812
4813 temp = (char *)xmalloc (3);
4814 if (c == 0)
4815 {
4816 temp[0] = CTLNUL;
4817 temp[1] = '\0';
4818 }
4819 else
4820 {
4821 temp[0] = CTLESC;
4822 temp[1] = c;
4823 temp[2] = '\0';
4824 }
4825 return (temp);
4826 }
4827
4828 /* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so
4829 the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
4830 this value is the word. */
4831 char *
4832 quote_string (string)
4833 char *string;
4834 {
4835 register char *t;
4836 size_t slen;
4837 char *result, *send;
4838
4839 if (*string == 0)
4840 {
4841 result = (char *)xmalloc (2);
4842 result[0] = CTLNUL;
4843 result[1] = '\0';
4844 }
4845 else
4846 {
4847 DECLARE_MBSTATE;
4848
4849 slen = strlen (string);
4850 send = string + slen;
4851
4852 result = (char *)xmalloc ((slen * 2) + 1);
4853
4854 for (t = result; string < send; )
4855 {
4856 *t++ = CTLESC;
4857 COPY_CHAR_P (t, string, send);
4858 }
4859 *t = '\0';
4860 }
4861 return (result);
4862 }
4863
4864 /* De-quote quoted characters in STRING. */
4865 char *
4866 dequote_string (string)
4867 char *string;
4868 {
4869 register char *s, *t;
4870 size_t slen;
4871 char *result, *send;
4872 DECLARE_MBSTATE;
4873
4874 if (string[0] == CTLESC && string[1] == 0)
4875 internal_debug ("dequote_string: string with bare CTLESC");
4876
4877 slen = STRLEN (string);
4878
4879 t = result = (char *)xmalloc (slen + 1);
4880
4881 if (QUOTED_NULL (string))
4882 {
4883 result[0] = '\0';
4884 return (result);
4885 }
4886
4887 /* A string consisting of only a single CTLESC should pass through unchanged */
4888 if (string[0] == CTLESC && string[1] == 0)
4889 {
4890 result[0] = CTLESC;
4891 result[1] = '\0';
4892 return (result);
4893 }
4894
4895 /* If no character in the string can be quoted, don't bother examining
4896 each character. Just return a copy of the string passed to us. */
4897 if (strchr (string, CTLESC) == NULL)
4898 return (strcpy (result, string));
4899
4900 send = string + slen;
4901 s = string;
4902 while (*s)
4903 {
4904 if (*s == CTLESC)
4905 {
4906 s++;
4907 if (*s == '\0')
4908 break;
4909 }
4910 COPY_CHAR_P (t, s, send);
4911 }
4912
4913 *t = '\0';
4914 return (result);
4915 }
4916
4917 /* Quote the entire WORD_LIST list. */
4918 static WORD_LIST *
4919 quote_list (list)
4920 WORD_LIST *list;
4921 {
4922 register WORD_LIST *w;
4923 char *t;
4924
4925 for (w = list; w; w = w->next)
4926 {
4927 t = w->word->word;
4928 w->word->word = quote_string (t);
4929 if (*t == 0)
4930 w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
4931 w->word->flags |= W_QUOTED;
4932 free (t);
4933 }
4934 return list;
4935 }
4936
4937 WORD_DESC *
4938 dequote_word (word)
4939 WORD_DESC *word;
4940 {
4941 register char *s;
4942
4943 s = dequote_string (word->word);
4944 if (QUOTED_NULL (word->word))
4945 word->flags &= ~W_HASQUOTEDNULL;
4946 free (word->word);
4947 word->word = s;
4948
4949 return word;
4950 }
4951
4952 /* De-quote quoted characters in each word in LIST. */
4953 WORD_LIST *
4954 dequote_list (list)
4955 WORD_LIST *list;
4956 {
4957 register char *s;
4958 register WORD_LIST *tlist;
4959
4960 for (tlist = list; tlist; tlist = tlist->next)
4961 {
4962 s = dequote_string (tlist->word->word);
4963 if (QUOTED_NULL (tlist->word->word))
4964 tlist->word->flags &= ~W_HASQUOTEDNULL;
4965 free (tlist->word->word);
4966 tlist->word->word = s;
4967 }
4968 return list;
4969 }
4970
4971 /* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
4972 string. */
4973 char *
4974 remove_quoted_escapes (string)
4975 char *string;
4976 {
4977 char *t;
4978
4979 if (string)
4980 {
4981 t = dequote_escapes (string);
4982 strcpy (string, t);
4983 free (t);
4984 }
4985
4986 return (string);
4987 }
4988
4989 /* Remove quoted $IFS characters from STRING. Quoted IFS characters are
4990 added to protect them from word splitting, but we need to remove them
4991 if no word splitting takes place. This returns newly-allocated memory,
4992 so callers can use it to replace savestring(). */
4993 char *
4994 remove_quoted_ifs (string)
4995 char *string;
4996 {
4997 register size_t slen;
4998 register int i, j;
4999 char *ret, *send;
5000 DECLARE_MBSTATE;
5001
5002 slen = strlen (string);
5003 send = string + slen;
5004
5005 i = j = 0;
5006 ret = (char *)xmalloc (slen + 1);
5007
5008 while (i < slen)
5009 {
5010 if (string[i] == CTLESC)
5011 {
5012 i++;
5013 if (string[i] == 0 || isifs (string[i]) == 0)
5014 ret[j++] = CTLESC;
5015 if (i == slen)
5016 break;
5017 }
5018
5019 COPY_CHAR_I (ret, j, string, send, i);
5020 }
5021 ret[j] = '\0';
5022
5023 return (ret);
5024 }
5025
5026 char *
5027 remove_quoted_nulls (string)
5028 char *string;
5029 {
5030 register size_t slen;
5031 register int i, j, prev_i;
5032 DECLARE_MBSTATE;
5033
5034 if (strchr (string, CTLNUL) == 0) /* XXX */
5035 return string; /* XXX */
5036
5037 slen = strlen (string);
5038 i = j = 0;
5039
5040 while (i < slen)
5041 {
5042 if (string[i] == CTLESC)
5043 {
5044 /* Old code had j++, but we cannot assume that i == j at this
5045 point -- what if a CTLNUL has already been removed from the
5046 string? We don't want to drop the CTLESC or recopy characters
5047 that we've already copied down. */
5048 i++;
5049 string[j++] = CTLESC;
5050 if (i == slen)
5051 break;
5052 }
5053 else if (string[i] == CTLNUL)
5054 {
5055 i++;
5056 continue;
5057 }
5058
5059 prev_i = i;
5060 ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */
5061 if (j < prev_i)
5062 {
5063 do string[j++] = string[prev_i++]; while (prev_i < i);
5064 }
5065 else
5066 j = i;
5067 }
5068 string[j] = '\0';
5069
5070 return (string);
5071 }
5072
5073 /* Perform quoted null character removal on each element of LIST.
5074 This modifies LIST. */
5075 void
5076 word_list_remove_quoted_nulls (list)
5077 WORD_LIST *list;
5078 {
5079 register WORD_LIST *t;
5080
5081 for (t = list; t; t = t->next)
5082 {
5083 remove_quoted_nulls (t->word->word);
5084 t->word->flags &= ~W_HASQUOTEDNULL;
5085 }
5086 }
5087
5088 /* **************************************************************** */
5089 /* */
5090 /* Functions for Matching and Removing Patterns */
5091 /* */
5092 /* **************************************************************** */
5093
5094 #if defined (HANDLE_MULTIBYTE)
5095 # ifdef INCLUDE_UNUSED
5096 static unsigned char *
5097 mb_getcharlens (string, len)
5098 char *string;
5099 int len;
5100 {
5101 int i, offset, last;
5102 unsigned char *ret;
5103 char *p;
5104 DECLARE_MBSTATE;
5105
5106 i = offset = 0;
5107 last = 0;
5108 ret = (unsigned char *)xmalloc (len);
5109 memset (ret, 0, len);
5110 while (string[last])
5111 {
5112 ADVANCE_CHAR (string, len, offset);
5113 ret[last] = offset - last;
5114 last = offset;
5115 }
5116 return ret;
5117 }
5118 # endif
5119 #endif
5120
5121 /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
5122 can have one of 4 values:
5123 RP_LONG_LEFT remove longest matching portion at start of PARAM
5124 RP_SHORT_LEFT remove shortest matching portion at start of PARAM
5125 RP_LONG_RIGHT remove longest matching portion at end of PARAM
5126 RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
5127 */
5128
5129 #define RP_LONG_LEFT 1
5130 #define RP_SHORT_LEFT 2
5131 #define RP_LONG_RIGHT 3
5132 #define RP_SHORT_RIGHT 4
5133
5134 /* Returns its first argument if nothing matched; new memory otherwise */
5135 static char *
5136 remove_upattern (param, pattern, op)
5137 char *param, *pattern;
5138 int op;
5139 {
5140 register size_t len;
5141 register char *end;
5142 register char *p, *ret, c;
5143
5144 len = STRLEN (param);
5145 end = param + len;
5146
5147 switch (op)
5148 {
5149 case RP_LONG_LEFT: /* remove longest match at start */
5150 for (p = end; p >= param; p--)
5151 {
5152 c = *p; *p = '\0';
5153 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5154 {
5155 *p = c;
5156 return (savestring (p));
5157 }
5158 *p = c;
5159
5160 }
5161 break;
5162
5163 case RP_SHORT_LEFT: /* remove shortest match at start */
5164 for (p = param; p <= end; p++)
5165 {
5166 c = *p; *p = '\0';
5167 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5168 {
5169 *p = c;
5170 return (savestring (p));
5171 }
5172 *p = c;
5173 }
5174 break;
5175
5176 case RP_LONG_RIGHT: /* remove longest match at end */
5177 for (p = param; p <= end; p++)
5178 {
5179 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5180 {
5181 c = *p; *p = '\0';
5182 ret = savestring (param);
5183 *p = c;
5184 return (ret);
5185 }
5186 }
5187 break;
5188
5189 case RP_SHORT_RIGHT: /* remove shortest match at end */
5190 for (p = end; p >= param; p--)
5191 {
5192 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5193 {
5194 c = *p; *p = '\0';
5195 ret = savestring (param);
5196 *p = c;
5197 return (ret);
5198 }
5199 }
5200 break;
5201 }
5202
5203 return (param); /* no match, return original string */
5204 }
5205
5206 #if defined (HANDLE_MULTIBYTE)
5207 /* Returns its first argument if nothing matched; new memory otherwise */
5208 static wchar_t *
5209 remove_wpattern (wparam, wstrlen, wpattern, op)
5210 wchar_t *wparam;
5211 size_t wstrlen;
5212 wchar_t *wpattern;
5213 int op;
5214 {
5215 wchar_t wc, *ret;
5216 int n;
5217
5218 switch (op)
5219 {
5220 case RP_LONG_LEFT: /* remove longest match at start */
5221 for (n = wstrlen; n >= 0; n--)
5222 {
5223 wc = wparam[n]; wparam[n] = L'\0';
5224 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5225 {
5226 wparam[n] = wc;
5227 return (wcsdup (wparam + n));
5228 }
5229 wparam[n] = wc;
5230 }
5231 break;
5232
5233 case RP_SHORT_LEFT: /* remove shortest match at start */
5234 for (n = 0; n <= wstrlen; n++)
5235 {
5236 wc = wparam[n]; wparam[n] = L'\0';
5237 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5238 {
5239 wparam[n] = wc;
5240 return (wcsdup (wparam + n));
5241 }
5242 wparam[n] = wc;
5243 }
5244 break;
5245
5246 case RP_LONG_RIGHT: /* remove longest match at end */
5247 for (n = 0; n <= wstrlen; n++)
5248 {
5249 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5250 {
5251 wc = wparam[n]; wparam[n] = L'\0';
5252 ret = wcsdup (wparam);
5253 wparam[n] = wc;
5254 return (ret);
5255 }
5256 }
5257 break;
5258
5259 case RP_SHORT_RIGHT: /* remove shortest match at end */
5260 for (n = wstrlen; n >= 0; n--)
5261 {
5262 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
5263 {
5264 wc = wparam[n]; wparam[n] = L'\0';
5265 ret = wcsdup (wparam);
5266 wparam[n] = wc;
5267 return (ret);
5268 }
5269 }
5270 break;
5271 }
5272
5273 return (wparam); /* no match, return original string */
5274 }
5275 #endif /* HANDLE_MULTIBYTE */
5276
5277 static char *
5278 remove_pattern (param, pattern, op)
5279 char *param, *pattern;
5280 int op;
5281 {
5282 char *xret;
5283
5284 if (param == NULL)
5285 return (param);
5286 if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
5287 return (savestring (param));
5288
5289 #if defined (HANDLE_MULTIBYTE)
5290 if (MB_CUR_MAX > 1)
5291 {
5292 wchar_t *ret, *oret;
5293 size_t n;
5294 wchar_t *wparam, *wpattern;
5295 mbstate_t ps;
5296
5297 /* XXX - could optimize here by checking param and pattern for multibyte
5298 chars with mbsmbchar and calling remove_upattern. */
5299
5300 n = xdupmbstowcs (&wpattern, NULL, pattern);
5301 if (n == (size_t)-1)
5302 {
5303 xret = remove_upattern (param, pattern, op);
5304 return ((xret == param) ? savestring (param) : xret);
5305 }
5306 n = xdupmbstowcs (&wparam, NULL, param);
5307
5308 if (n == (size_t)-1)
5309 {
5310 free (wpattern);
5311 xret = remove_upattern (param, pattern, op);
5312 return ((xret == param) ? savestring (param) : xret);
5313 }
5314 oret = ret = remove_wpattern (wparam, n, wpattern, op);
5315 /* Don't bother to convert wparam back to multibyte string if nothing
5316 matched; just return copy of original string */
5317 if (ret == wparam)
5318 {
5319 free (wparam);
5320 free (wpattern);
5321 return (savestring (param));
5322 }
5323
5324 free (wparam);
5325 free (wpattern);
5326
5327 n = strlen (param);
5328 xret = (char *)xmalloc (n + 1);
5329 memset (&ps, '\0', sizeof (mbstate_t));
5330 n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
5331 xret[n] = '\0'; /* just to make sure */
5332 free (oret);
5333 return xret;
5334 }
5335 else
5336 #endif
5337 {
5338 xret = remove_upattern (param, pattern, op);
5339 return ((xret == param) ? savestring (param) : xret);
5340 }
5341 }
5342
5343 /* Match PAT anywhere in STRING and return the match boundaries.
5344 This returns 1 in case of a successful match, 0 otherwise. SP
5345 and EP are pointers into the string where the match begins and
5346 ends, respectively. MTYPE controls what kind of match is attempted.
5347 MATCH_BEG and MATCH_END anchor the match at the beginning and end
5348 of the string, respectively. The longest match is returned. */
5349 static int
5350 match_upattern (string, pat, mtype, sp, ep)
5351 char *string, *pat;
5352 int mtype;
5353 char **sp, **ep;
5354 {
5355 int c, mlen;
5356 size_t len;
5357 register char *p, *p1, *npat;
5358 char *end;
5359
5360 /* If the pattern doesn't match anywhere in the string, go ahead and
5361 short-circuit right away. A minor optimization, saves a bunch of
5362 unnecessary calls to strmatch (up to N calls for a string of N
5363 characters) if the match is unsuccessful. To preserve the semantics
5364 of the substring matches below, we make sure that the pattern has
5365 `*' as first and last character, making a new pattern if necessary. */
5366 /* XXX - check this later if I ever implement `**' with special meaning,
5367 since this will potentially result in `**' at the beginning or end */
5368 len = STRLEN (pat);
5369 if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
5370 {
5371 int unescaped_backslash;
5372 char *pp;
5373
5374 p = npat = (char *)xmalloc (len + 3);
5375 p1 = pat;
5376 if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob)))
5377 *p++ = '*';
5378 while (*p1)
5379 *p++ = *p1++;
5380 #if 1
5381 /* Need to also handle a pattern that ends with an unescaped backslash.
5382 For right now, we ignore it because the pattern matching code will
5383 fail the match anyway */
5384 /* If the pattern ends with a `*' we leave it alone if it's preceded by
5385 an even number of backslashes, but if it's escaped by a backslash
5386 we need to add another `*'. */
5387 if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\')))
5388 {
5389 pp = p1 - 3;
5390 while (pp >= pat && *pp-- == '\\')
5391 unescaped_backslash = 1 - unescaped_backslash;
5392 if (unescaped_backslash)
5393 *p++ = '*';
5394 }
5395 else if (mtype != MATCH_END && p1[-1] != '*')
5396 *p++ = '*';
5397 #else
5398 if (p1[-1] != '*' || p1[-2] == '\\')
5399 *p++ = '*';
5400 #endif
5401 *p = '\0';
5402 }
5403 else
5404 npat = pat;
5405 c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
5406 if (npat != pat)
5407 free (npat);
5408 if (c == FNM_NOMATCH)
5409 return (0);
5410
5411 len = STRLEN (string);
5412 end = string + len;
5413
5414 mlen = umatchlen (pat, len);
5415 if (mlen > (int)len)
5416 return (0);
5417
5418 switch (mtype)
5419 {
5420 case MATCH_ANY:
5421 for (p = string; p <= end; p++)
5422 {
5423 if (match_pattern_char (pat, p, FNMATCH_IGNCASE))
5424 {
5425 p1 = (mlen == -1) ? end : p + mlen;
5426 /* p1 - p = length of portion of string to be considered
5427 p = current position in string
5428 mlen = number of characters consumed by match (-1 for entire string)
5429 end = end of string
5430 we want to break immediately if the potential match len
5431 is greater than the number of characters remaining in the
5432 string
5433 */
5434 if (p1 > end)
5435 break;
5436 for ( ; p1 >= p; p1--)
5437 {
5438 c = *p1; *p1 = '\0';
5439 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5440 {
5441 *p1 = c;
5442 *sp = p;
5443 *ep = p1;
5444 return 1;
5445 }
5446 *p1 = c;
5447 #if 1
5448 /* If MLEN != -1, we have a fixed length pattern. */
5449 if (mlen != -1)
5450 break;
5451 #endif
5452 }
5453 }
5454 }
5455
5456 return (0);
5457
5458 case MATCH_BEG:
5459 if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0)
5460 return (0);
5461
5462 for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
5463 {
5464 c = *p; *p = '\0';
5465 if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5466 {
5467 *p = c;
5468 *sp = string;
5469 *ep = p;
5470 return 1;
5471 }
5472 *p = c;
5473 /* If MLEN != -1, we have a fixed length pattern. */
5474 if (mlen != -1)
5475 break;
5476 }
5477
5478 return (0);
5479
5480 case MATCH_END:
5481 for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
5482 {
5483 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5484 {
5485 *sp = p;
5486 *ep = end;
5487 return 1;
5488 }
5489 /* If MLEN != -1, we have a fixed length pattern. */
5490 if (mlen != -1)
5491 break;
5492 }
5493
5494 return (0);
5495 }
5496
5497 return (0);
5498 }
5499
5500 #if defined (HANDLE_MULTIBYTE)
5501
5502 #define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c))
5503
5504 /* Match WPAT anywhere in WSTRING and return the match boundaries.
5505 This returns 1 in case of a successful match, 0 otherwise. Wide
5506 character version. */
5507 static int
5508 match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
5509 wchar_t *wstring;
5510 char **indices;
5511 size_t wstrlen;
5512 wchar_t *wpat;
5513 int mtype;
5514 char **sp, **ep;
5515 {
5516 wchar_t wc, *wp, *nwpat, *wp1;
5517 size_t len;
5518 int mlen;
5519 int n, n1, n2, simple;
5520
5521 simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
5522 #if defined (EXTENDED_GLOB)
5523 if (extended_glob)
5524 simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
5525 #endif
5526
5527 /* If the pattern doesn't match anywhere in the string, go ahead and
5528 short-circuit right away. A minor optimization, saves a bunch of
5529 unnecessary calls to strmatch (up to N calls for a string of N
5530 characters) if the match is unsuccessful. To preserve the semantics
5531 of the substring matches below, we make sure that the pattern has
5532 `*' as first and last character, making a new pattern if necessary. */
5533 len = wcslen (wpat);
5534 if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
5535 {
5536 int unescaped_backslash;
5537 wchar_t *wpp;
5538
5539 wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
5540 wp1 = wpat;
5541 if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
5542 *wp++ = L'*';
5543 while (*wp1 != L'\0')
5544 *wp++ = *wp1++;
5545 #if 1
5546 /* See comments above in match_upattern. */
5547 if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\'))
5548 {
5549 wpp = wp1 - 3;
5550 while (wpp >= wpat && *wpp-- == L'\\')
5551 unescaped_backslash = 1 - unescaped_backslash;
5552 if (unescaped_backslash)
5553 *wp++ = L'*';
5554 }
5555 else if (wp1[-1] != L'*')
5556 *wp++ = L'*';
5557 #else
5558 if (wp1[-1] != L'*' || wp1[-2] == L'\\')
5559 *wp++ = L'*';
5560 #endif
5561 *wp = '\0';
5562 }
5563 else
5564 nwpat = wpat;
5565 len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
5566 if (nwpat != wpat)
5567 free (nwpat);
5568 if (len == FNM_NOMATCH)
5569 return (0);
5570
5571 mlen = wmatchlen (wpat, wstrlen);
5572 if (mlen > (int)wstrlen)
5573 return (0);
5574
5575 /* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
5576 switch (mtype)
5577 {
5578 case MATCH_ANY:
5579 for (n = 0; n <= wstrlen; n++)
5580 {
5581 n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE);
5582 if (n2)
5583 {
5584 n1 = (mlen == -1) ? wstrlen : n + mlen;
5585 if (n1 > wstrlen)
5586 break;
5587
5588 for ( ; n1 >= n; n1--)
5589 {
5590 wc = wstring[n1]; wstring[n1] = L'\0';
5591 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5592 {
5593 wstring[n1] = wc;
5594 *sp = indices[n];
5595 *ep = indices[n1];
5596 return 1;
5597 }
5598 wstring[n1] = wc;
5599 /* If MLEN != -1, we have a fixed length pattern. */
5600 if (mlen != -1)
5601 break;
5602 }
5603 }
5604 }
5605
5606 return (0);
5607
5608 case MATCH_BEG:
5609 if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0)
5610 return (0);
5611
5612 for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
5613 {
5614 wc = wstring[n]; wstring[n] = L'\0';
5615 if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5616 {
5617 wstring[n] = wc;
5618 *sp = indices[0];
5619 *ep = indices[n];
5620 return 1;
5621 }
5622 wstring[n] = wc;
5623 /* If MLEN != -1, we have a fixed length pattern. */
5624 if (mlen != -1)
5625 break;
5626 }
5627
5628 return (0);
5629
5630 case MATCH_END:
5631 for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
5632 {
5633 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5634 {
5635 *sp = indices[n];
5636 *ep = indices[wstrlen];
5637 return 1;
5638 }
5639 /* If MLEN != -1, we have a fixed length pattern. */
5640 if (mlen != -1)
5641 break;
5642 }
5643
5644 return (0);
5645 }
5646
5647 return (0);
5648 }
5649 #undef WFOLD
5650 #endif /* HANDLE_MULTIBYTE */
5651
5652 static int
5653 match_pattern (string, pat, mtype, sp, ep)
5654 char *string, *pat;
5655 int mtype;
5656 char **sp, **ep;
5657 {
5658 #if defined (HANDLE_MULTIBYTE)
5659 int ret;
5660 size_t n;
5661 wchar_t *wstring, *wpat;
5662 char **indices;
5663 #endif
5664
5665 if (string == 0 || pat == 0 || *pat == 0)
5666 return (0);
5667
5668 #if defined (HANDLE_MULTIBYTE)
5669 if (MB_CUR_MAX > 1)
5670 {
5671 if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
5672 return (match_upattern (string, pat, mtype, sp, ep));
5673
5674 n = xdupmbstowcs (&wpat, NULL, pat);
5675 if (n == (size_t)-1)
5676 return (match_upattern (string, pat, mtype, sp, ep));
5677 n = xdupmbstowcs (&wstring, &indices, string);
5678 if (n == (size_t)-1)
5679 {
5680 free (wpat);
5681 return (match_upattern (string, pat, mtype, sp, ep));
5682 }
5683 ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
5684
5685 free (wpat);
5686 free (wstring);
5687 free (indices);
5688
5689 return (ret);
5690 }
5691 else
5692 #endif
5693 return (match_upattern (string, pat, mtype, sp, ep));
5694 }
5695
5696 static int
5697 getpatspec (c, value)
5698 int c;
5699 char *value;
5700 {
5701 if (c == '#')
5702 return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
5703 else /* c == '%' */
5704 return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
5705 }
5706
5707 /* Posix.2 says that the WORD should be run through tilde expansion,
5708 parameter expansion, command substitution and arithmetic expansion.
5709 This leaves the result quoted, so quote_string_for_globbing () has
5710 to be called to fix it up for strmatch (). If QUOTED is non-zero,
5711 it means that the entire expression was enclosed in double quotes.
5712 This means that quoting characters in the pattern do not make any
5713 special pattern characters quoted. For example, the `*' in the
5714 following retains its special meaning: "${foo#'*'}". */
5715 static char *
5716 getpattern (value, quoted, expandpat)
5717 char *value;
5718 int quoted, expandpat;
5719 {
5720 char *pat, *tword;
5721 WORD_LIST *l;
5722 #if 0
5723 int i;
5724 #endif
5725 /* There is a problem here: how to handle single or double quotes in the
5726 pattern string when the whole expression is between double quotes?
5727 POSIX.2 says that enclosing double quotes do not cause the pattern to
5728 be quoted, but does that leave us a problem with @ and array[@] and their
5729 expansions inside a pattern? */
5730 #if 0
5731 if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
5732 {
5733 i = 0;
5734 pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ);
5735 free (tword);
5736 tword = pat;
5737 }
5738 #endif
5739
5740 /* expand_string_for_pat () leaves WORD quoted and does not perform
5741 word splitting. */
5742 l = *value ? expand_string_for_pat (value,
5743 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
5744 (int *)NULL, (int *)NULL)
5745 : (WORD_LIST *)0;
5746 if (l)
5747 word_list_remove_quoted_nulls (l);
5748 pat = string_list (l);
5749 dispose_words (l);
5750 if (pat)
5751 {
5752 tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
5753 free (pat);
5754 pat = tword;
5755 }
5756 return (pat);
5757 }
5758
5759 #if 0
5760 /* Handle removing a pattern from a string as a result of ${name%[%]value}
5761 or ${name#[#]value}. */
5762 static char *
5763 variable_remove_pattern (value, pattern, patspec, quoted)
5764 char *value, *pattern;
5765 int patspec, quoted;
5766 {
5767 char *tword;
5768
5769 tword = remove_pattern (value, pattern, patspec);
5770
5771 return (tword);
5772 }
5773 #endif
5774
5775 static char *
5776 list_remove_pattern (list, pattern, patspec, itype, quoted)
5777 WORD_LIST *list;
5778 char *pattern;
5779 int patspec, itype, quoted;
5780 {
5781 WORD_LIST *new, *l;
5782 WORD_DESC *w;
5783 char *tword;
5784
5785 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
5786 {
5787 tword = remove_pattern (l->word->word, pattern, patspec);
5788 w = alloc_word_desc ();
5789 w->word = tword ? tword : savestring ("");
5790 new = make_word_list (w, new);
5791 }
5792
5793 l = REVERSE_LIST (new, WORD_LIST *);
5794 tword = string_list_pos_params (itype, l, quoted, 0);
5795 dispose_words (l);
5796
5797 return (tword);
5798 }
5799
5800 static char *
5801 parameter_list_remove_pattern (itype, pattern, patspec, quoted)
5802 int itype;
5803 char *pattern;
5804 int patspec, quoted;
5805 {
5806 char *ret;
5807 WORD_LIST *list;
5808
5809 list = list_rest_of_args ();
5810 if (list == 0)
5811 return ((char *)NULL);
5812 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5813 dispose_words (list);
5814 return (ret);
5815 }
5816
5817 #if defined (ARRAY_VARS)
5818 static char *
5819 array_remove_pattern (var, pattern, patspec, starsub, quoted)
5820 SHELL_VAR *var;
5821 char *pattern;
5822 int patspec;
5823 int starsub; /* so we can figure out how it's indexed */
5824 int quoted;
5825 {
5826 ARRAY *a;
5827 HASH_TABLE *h;
5828 int itype;
5829 char *ret;
5830 WORD_LIST *list;
5831 SHELL_VAR *v;
5832
5833 v = var; /* XXX - for now */
5834
5835 itype = starsub ? '*' : '@';
5836
5837 a = (v && array_p (v)) ? array_cell (v) : 0;
5838 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
5839
5840 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
5841 if (list == 0)
5842 return ((char *)NULL);
5843 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5844 dispose_words (list);
5845
5846 return ret;
5847 }
5848 #endif /* ARRAY_VARS */
5849
5850 static char *
5851 parameter_brace_remove_pattern (varname, value, estatep, patstr, rtype, quoted, flags)
5852 char *varname, *value;
5853 array_eltstate_t *estatep;
5854 char *patstr;
5855 int rtype, quoted, flags;
5856 {
5857 int vtype, patspec, starsub;
5858 char *temp1, *val, *pattern, *oname;
5859 SHELL_VAR *v;
5860
5861 if (value == 0)
5862 return ((char *)NULL);
5863
5864 oname = this_command_name;
5865 this_command_name = varname;
5866
5867 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
5868 if (vtype == -1)
5869 {
5870 this_command_name = oname;
5871 return ((char *)NULL);
5872 }
5873
5874 starsub = vtype & VT_STARSUB;
5875 vtype &= ~VT_STARSUB;
5876
5877 patspec = getpatspec (rtype, patstr);
5878 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
5879 patstr++;
5880
5881 /* Need to pass getpattern newly-allocated memory in case of expansion --
5882 the expansion code will free the passed string on an error. */
5883 temp1 = savestring (patstr);
5884 pattern = getpattern (temp1, quoted, 1);
5885 free (temp1);
5886
5887 temp1 = (char *)NULL; /* shut up gcc */
5888 switch (vtype)
5889 {
5890 case VT_VARIABLE:
5891 case VT_ARRAYMEMBER:
5892 temp1 = remove_pattern (val, pattern, patspec);
5893 if (vtype == VT_VARIABLE)
5894 FREE (val);
5895 if (temp1)
5896 {
5897 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5898 ? quote_string (temp1)
5899 : quote_escapes (temp1);
5900 free (temp1);
5901 temp1 = val;
5902 }
5903 break;
5904 #if defined (ARRAY_VARS)
5905 case VT_ARRAYVAR:
5906 temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted);
5907 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5908 {
5909 val = quote_escapes (temp1);
5910 free (temp1);
5911 temp1 = val;
5912 }
5913 break;
5914 #endif
5915 case VT_POSPARMS:
5916 temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
5917 if (temp1 && quoted == 0 && ifs_is_null)
5918 {
5919 /* Posix interp 888 */
5920 }
5921 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5922 {
5923 val = quote_escapes (temp1);
5924 free (temp1);
5925 temp1 = val;
5926 }
5927 break;
5928 }
5929
5930 this_command_name = oname;
5931
5932 FREE (pattern);
5933 return temp1;
5934 }
5935
5936 #if defined (PROCESS_SUBSTITUTION)
5937
5938 static void reap_some_procsubs PARAMS((int));
5939
5940 /*****************************************************************/
5941 /* */
5942 /* Hacking Process Substitution */
5943 /* */
5944 /*****************************************************************/
5945
5946 #if !defined (HAVE_DEV_FD)
5947 /* Named pipes must be removed explicitly with `unlink'. This keeps a list
5948 of FIFOs the shell has open. unlink_fifo_list will walk the list and
5949 unlink the ones that don't have a living process on the other end.
5950 unlink_all_fifos will walk the list and unconditionally unlink them, trying
5951 to open and close the FIFO first to release any child processes sleeping on
5952 the FIFO. add_fifo_list adds the name of an open FIFO to the list.
5953 NFIFO is a count of the number of FIFOs in the list. */
5954 #define FIFO_INCR 20
5955
5956 /* PROC value of -1 means the process has been reaped and the FIFO needs to
5957 be removed. PROC value of 0 means the slot is unused. */
5958 struct temp_fifo {
5959 char *file;
5960 pid_t proc;
5961 };
5962
5963 static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
5964 static int nfifo;
5965 static int fifo_list_size;
5966
5967 void
5968 clear_fifo_list ()
5969 {
5970 int i;
5971
5972 for (i = 0; i < fifo_list_size; i++)
5973 {
5974 if (fifo_list[i].file)
5975 free (fifo_list[i].file);
5976 fifo_list[i].file = NULL;
5977 fifo_list[i].proc = 0;
5978 }
5979 nfifo = 0;
5980 }
5981
5982 void *
5983 copy_fifo_list (sizep)
5984 int *sizep;
5985 {
5986 if (sizep)
5987 *sizep = 0;
5988 return (void *)NULL;
5989 }
5990
5991 static void
5992 add_fifo_list (pathname)
5993 char *pathname;
5994 {
5995 int osize, i;
5996
5997 if (nfifo >= fifo_list_size - 1)
5998 {
5999 osize = fifo_list_size;
6000 fifo_list_size += FIFO_INCR;
6001 fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
6002 fifo_list_size * sizeof (struct temp_fifo));
6003 for (i = osize; i < fifo_list_size; i++)
6004 {
6005 fifo_list[i].file = (char *)NULL;
6006 fifo_list[i].proc = 0; /* unused */
6007 }
6008 }
6009
6010 fifo_list[nfifo].file = savestring (pathname);
6011 nfifo++;
6012 }
6013
6014 void
6015 unlink_fifo (i)
6016 int i;
6017 {
6018 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
6019 {
6020 unlink (fifo_list[i].file);
6021 free (fifo_list[i].file);
6022 fifo_list[i].file = (char *)NULL;
6023 fifo_list[i].proc = 0;
6024 }
6025 }
6026
6027 void
6028 unlink_fifo_list ()
6029 {
6030 int saved, i, j;
6031
6032 if (nfifo == 0)
6033 return;
6034
6035 for (i = saved = 0; i < nfifo; i++)
6036 {
6037 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
6038 {
6039 unlink (fifo_list[i].file);
6040 free (fifo_list[i].file);
6041 fifo_list[i].file = (char *)NULL;
6042 fifo_list[i].proc = 0;
6043 }
6044 else
6045 saved++;
6046 }
6047
6048 /* If we didn't remove some of the FIFOs, compact the list. */
6049 if (saved)
6050 {
6051 for (i = j = 0; i < nfifo; i++)
6052 if (fifo_list[i].file)
6053 {
6054 if (i != j)
6055 {
6056 fifo_list[j].file = fifo_list[i].file;
6057 fifo_list[j].proc = fifo_list[i].proc;
6058 fifo_list[i].file = (char *)NULL;
6059 fifo_list[i].proc = 0;
6060 }
6061 j++;
6062 }
6063 nfifo = j;
6064 }
6065 else
6066 nfifo = 0;
6067 }
6068
6069 void
6070 unlink_all_fifos ()
6071 {
6072 int i, fd;
6073
6074 if (nfifo == 0)
6075 return;
6076
6077 for (i = 0; i < nfifo; i++)
6078 {
6079 fifo_list[i].proc = (pid_t)-1;
6080 #if defined (O_NONBLOCK)
6081 fd = open (fifo_list[i].file, O_RDWR|O_NONBLOCK);
6082 #else
6083 fd = -1;
6084 #endif
6085 unlink_fifo (i);
6086 if (fd >= 0)
6087 close (fd);
6088 }
6089
6090 nfifo = 0;
6091 }
6092
6093 /* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
6094 from some point in the past, and close all open FIFOs in fifo_list
6095 that are not marked as active in LIST. If LIST is NULL, close
6096 everything in fifo_list. LSIZE is the number of elements in LIST, in
6097 case it's larger than fifo_list_size (size of fifo_list). */
6098 void
6099 close_new_fifos (list, lsize)
6100 void *list;
6101 int lsize;
6102 {
6103 int i;
6104 char *plist;
6105
6106 if (list == 0)
6107 {
6108 unlink_fifo_list ();
6109 return;
6110 }
6111
6112 for (plist = (char *)list, i = 0; i < lsize; i++)
6113 if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
6114 unlink_fifo (i);
6115
6116 for (i = lsize; i < fifo_list_size; i++)
6117 unlink_fifo (i);
6118 }
6119
6120 int
6121 find_procsub_child (pid)
6122 pid_t pid;
6123 {
6124 int i;
6125
6126 for (i = 0; i < nfifo; i++)
6127 if (fifo_list[i].proc == pid)
6128 return i;
6129 return -1;
6130 }
6131
6132 void
6133 set_procsub_status (ind, pid, status)
6134 int ind;
6135 pid_t pid;
6136 int status;
6137 {
6138 if (ind >= 0 && ind < nfifo)
6139 fifo_list[ind].proc = (pid_t)-1; /* sentinel */
6140 }
6141
6142 /* If we've marked the process for this procsub as dead, close the
6143 associated file descriptor and delete the FIFO. */
6144 static void
6145 reap_some_procsubs (max)
6146 int max;
6147 {
6148 int i;
6149
6150 for (i = 0; i < max; i++)
6151 if (fifo_list[i].proc == (pid_t)-1) /* reaped */
6152 unlink_fifo (i);
6153 }
6154
6155 void
6156 reap_procsubs ()
6157 {
6158 reap_some_procsubs (nfifo);
6159 }
6160
6161 #if 0
6162 /* UNUSED */
6163 void
6164 wait_procsubs ()
6165 {
6166 int i, r;
6167
6168 for (i = 0; i < nfifo; i++)
6169 {
6170 if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0)
6171 {
6172 r = wait_for (fifo_list[i].proc, 0);
6173 save_proc_status (fifo_list[i].proc, r);
6174 fifo_list[i].proc = (pid_t)-1;
6175 }
6176 }
6177 }
6178 #endif
6179
6180 int
6181 fifos_pending ()
6182 {
6183 return nfifo;
6184 }
6185
6186 int
6187 num_fifos ()
6188 {
6189 return nfifo;
6190 }
6191
6192 static char *
6193 make_named_pipe ()
6194 {
6195 char *tname;
6196
6197 tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
6198 if (mkfifo (tname, 0600) < 0)
6199 {
6200 free (tname);
6201 return ((char *)NULL);
6202 }
6203
6204 add_fifo_list (tname);
6205 return (tname);
6206 }
6207
6208 #else /* HAVE_DEV_FD */
6209
6210 /* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
6211 has open to children. NFDS is a count of the number of bits currently
6212 set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
6213 of open files. */
6214 /* dev_fd_list[I] value of -1 means the process has been reaped and file
6215 descriptor I needs to be closed. Value of 0 means the slot is unused. */
6216
6217 static pid_t *dev_fd_list = (pid_t *)NULL;
6218 static int nfds;
6219 static int totfds; /* The highest possible number of open files. */
6220
6221 void
6222 clear_fifo (i)
6223 int i;
6224 {
6225 if (dev_fd_list[i])
6226 {
6227 dev_fd_list[i] = 0;
6228 nfds--;
6229 }
6230 }
6231
6232 void
6233 clear_fifo_list ()
6234 {
6235 register int i;
6236
6237 if (nfds == 0)
6238 return;
6239
6240 for (i = 0; nfds && i < totfds; i++)
6241 clear_fifo (i);
6242
6243 nfds = 0;
6244 }
6245
6246 void *
6247 copy_fifo_list (sizep)
6248 int *sizep;
6249 {
6250 void *ret;
6251
6252 if (nfds == 0 || totfds == 0)
6253 {
6254 if (sizep)
6255 *sizep = 0;
6256 return (void *)NULL;
6257 }
6258
6259 if (sizep)
6260 *sizep = totfds;
6261 ret = xmalloc (totfds * sizeof (pid_t));
6262 return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t)));
6263 }
6264
6265 static void
6266 add_fifo_list (fd)
6267 int fd;
6268 {
6269 if (dev_fd_list == 0 || fd >= totfds)
6270 {
6271 int ofds;
6272
6273 ofds = totfds;
6274 totfds = getdtablesize ();
6275 if (totfds < 0 || totfds > 256)
6276 totfds = 256;
6277 if (fd >= totfds)
6278 totfds = fd + 2;
6279
6280 dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0]));
6281 /* XXX - might need a loop for this */
6282 memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t));
6283 }
6284
6285 dev_fd_list[fd] = 1; /* marker; updated later */
6286 nfds++;
6287 }
6288
6289 int
6290 fifos_pending ()
6291 {
6292 return 0; /* used for cleanup; not needed with /dev/fd */
6293 }
6294
6295 int
6296 num_fifos ()
6297 {
6298 return nfds;
6299 }
6300
6301 void
6302 unlink_fifo (fd)
6303 int fd;
6304 {
6305 if (dev_fd_list[fd])
6306 {
6307 close (fd);
6308 dev_fd_list[fd] = 0;
6309 nfds--;
6310 }
6311 }
6312
6313 void
6314 unlink_fifo_list ()
6315 {
6316 register int i;
6317
6318 if (nfds == 0)
6319 return;
6320
6321 for (i = totfds-1; nfds && i >= 0; i--)
6322 unlink_fifo (i);
6323
6324 nfds = 0;
6325 }
6326
6327 void
6328 unlink_all_fifos ()
6329 {
6330 unlink_fifo_list ();
6331 }
6332
6333 /* Take LIST, which is a snapshot copy of dev_fd_list from some point in
6334 the past, and close all open fds in dev_fd_list that are not marked
6335 as open in LIST. If LIST is NULL, close everything in dev_fd_list.
6336 LSIZE is the number of elements in LIST, in case it's larger than
6337 totfds (size of dev_fd_list). */
6338 void
6339 close_new_fifos (list, lsize)
6340 void *list;
6341 int lsize;
6342 {
6343 int i;
6344 pid_t *plist;
6345
6346 if (list == 0)
6347 {
6348 unlink_fifo_list ();
6349 return;
6350 }
6351
6352 for (plist = (pid_t *)list, i = 0; i < lsize; i++)
6353 if (plist[i] == 0 && i < totfds && dev_fd_list[i])
6354 unlink_fifo (i);
6355
6356 for (i = lsize; i < totfds; i++)
6357 unlink_fifo (i);
6358 }
6359
6360 int
6361 find_procsub_child (pid)
6362 pid_t pid;
6363 {
6364 int i;
6365
6366 if (nfds == 0)
6367 return -1;
6368
6369 for (i = 0; i < totfds; i++)
6370 if (dev_fd_list[i] == pid)
6371 return i;
6372
6373 return -1;
6374 }
6375
6376 void
6377 set_procsub_status (ind, pid, status)
6378 int ind;
6379 pid_t pid;
6380 int status;
6381 {
6382 if (ind >= 0 && ind < totfds)
6383 dev_fd_list[ind] = (pid_t)-1; /* sentinel */
6384 }
6385
6386 /* If we've marked the process for this procsub as dead, close the
6387 associated file descriptor. */
6388 static void
6389 reap_some_procsubs (max)
6390 int max;
6391 {
6392 int i;
6393
6394 for (i = 0; nfds > 0 && i < max; i++)
6395 if (dev_fd_list[i] == (pid_t)-1)
6396 unlink_fifo (i);
6397 }
6398
6399 void
6400 reap_procsubs ()
6401 {
6402 reap_some_procsubs (totfds);
6403 }
6404
6405 #if 0
6406 /* UNUSED */
6407 void
6408 wait_procsubs ()
6409 {
6410 int i, r;
6411
6412 for (i = 0; nfds > 0 && i < totfds; i++)
6413 {
6414 if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0)
6415 {
6416 r = wait_for (dev_fd_list[i], 0);
6417 save_proc_status (dev_fd_list[i], r);
6418 dev_fd_list[i] = (pid_t)-1;
6419 }
6420 }
6421 }
6422 #endif
6423
6424 #if defined (NOTDEF)
6425 print_dev_fd_list ()
6426 {
6427 register int i;
6428
6429 fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
6430 fflush (stderr);
6431
6432 for (i = 0; i < totfds; i++)
6433 {
6434 if (dev_fd_list[i])
6435 fprintf (stderr, " %d", i);
6436 }
6437 fprintf (stderr, "\n");
6438 }
6439 #endif /* NOTDEF */
6440
6441 static char *
6442 make_dev_fd_filename (fd)
6443 int fd;
6444 {
6445 char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
6446
6447 ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
6448
6449 strcpy (ret, DEV_FD_PREFIX);
6450 p = inttostr (fd, intbuf, sizeof (intbuf));
6451 strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
6452
6453 add_fifo_list (fd);
6454 return (ret);
6455 }
6456
6457 #endif /* HAVE_DEV_FD */
6458
6459 /* Return a filename that will open a connection to the process defined by
6460 executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
6461 a filename in /dev/fd corresponding to a descriptor that is one of the
6462 ends of the pipe. If not defined, we use named pipes on systems that have
6463 them. Systems without /dev/fd and named pipes are out of luck.
6464
6465 OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
6466 use the read end of the pipe and dup that file descriptor to fd 0 in
6467 the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
6468 writing or use the write end of the pipe in the child, and dup that
6469 file descriptor to fd 1 in the child. The parent does the opposite. */
6470
6471 static char *
6472 process_substitute (string, open_for_read_in_child)
6473 char *string;
6474 int open_for_read_in_child;
6475 {
6476 char *pathname;
6477 int fd, result, rc, function_value;
6478 pid_t old_pid, pid;
6479 #if defined (HAVE_DEV_FD)
6480 int parent_pipe_fd, child_pipe_fd;
6481 int fildes[2];
6482 #endif /* HAVE_DEV_FD */
6483 #if defined (JOB_CONTROL)
6484 pid_t old_pipeline_pgrp;
6485 #endif
6486
6487 if (!string || !*string || wordexp_only)
6488 return ((char *)NULL);
6489
6490 #if !defined (HAVE_DEV_FD)
6491 pathname = make_named_pipe ();
6492 #else /* HAVE_DEV_FD */
6493 if (pipe (fildes) < 0)
6494 {
6495 sys_error ("%s", _("cannot make pipe for process substitution"));
6496 return ((char *)NULL);
6497 }
6498 /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
6499 the pipe in the parent, otherwise the read end. */
6500 parent_pipe_fd = fildes[open_for_read_in_child];
6501 child_pipe_fd = fildes[1 - open_for_read_in_child];
6502 /* Move the parent end of the pipe to some high file descriptor, to
6503 avoid clashes with FDs used by the script. */
6504 parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
6505
6506 pathname = make_dev_fd_filename (parent_pipe_fd);
6507 #endif /* HAVE_DEV_FD */
6508
6509 if (pathname == 0)
6510 {
6511 sys_error ("%s", _("cannot make pipe for process substitution"));
6512 return ((char *)NULL);
6513 }
6514
6515 old_pid = last_made_pid;
6516
6517 #if defined (JOB_CONTROL)
6518 old_pipeline_pgrp = pipeline_pgrp;
6519 if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0)
6520 pipeline_pgrp = shell_pgrp;
6521 save_pipeline (1);
6522 #endif /* JOB_CONTROL */
6523
6524 pid = make_child ((char *)NULL, FORK_ASYNC);
6525 if (pid == 0)
6526 {
6527 #if 0
6528 int old_interactive;
6529
6530 old_interactive = interactive;
6531 #endif
6532 /* The currently-executing shell is not interactive */
6533 interactive = 0;
6534
6535 reset_terminating_signals (); /* XXX */
6536 free_pushed_string_input ();
6537 /* Cancel traps, in trap.c. */
6538 restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */
6539 subshell_environment &= ~SUBSHELL_IGNTRAP;
6540 QUIT; /* catch any interrupts we got post-fork */
6541 setup_async_signals ();
6542 #if 0
6543 if (open_for_read_in_child == 0 && old_interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))
6544 async_redirect_stdin ();
6545 #endif
6546
6547 subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB|SUBSHELL_ASYNC;
6548
6549 /* We don't inherit the verbose option for command substitutions now, so
6550 let's try it for process substitutions. */
6551 change_flag ('v', FLAG_OFF);
6552
6553 /* if we're expanding a redirection, we shouldn't have access to the
6554 temporary environment, but commands in the subshell should have
6555 access to their own temporary environment. */
6556 if (expanding_redir)
6557 flush_temporary_env ();
6558 }
6559
6560 #if defined (JOB_CONTROL)
6561 set_sigchld_handler ();
6562 stop_making_children ();
6563 /* XXX - should we only do this in the parent? (as in command subst) */
6564 pipeline_pgrp = old_pipeline_pgrp;
6565 #else
6566 stop_making_children ();
6567 #endif /* JOB_CONTROL */
6568
6569 if (pid < 0)
6570 {
6571 sys_error ("%s", _("cannot make child for process substitution"));
6572 free (pathname);
6573 #if defined (HAVE_DEV_FD)
6574 close (parent_pipe_fd);
6575 close (child_pipe_fd);
6576 #endif /* HAVE_DEV_FD */
6577 #if defined (JOB_CONTROL)
6578 restore_pipeline (1);
6579 #endif
6580 return ((char *)NULL);
6581 }
6582
6583 if (pid > 0)
6584 {
6585 #if defined (JOB_CONTROL)
6586 last_procsub_child = restore_pipeline (0);
6587 /* We assume that last_procsub_child->next == last_procsub_child because
6588 of how jobs.c:add_process() works. */
6589 last_procsub_child->next = 0;
6590 procsub_add (last_procsub_child);
6591 #endif
6592
6593 #if defined (HAVE_DEV_FD)
6594 dev_fd_list[parent_pipe_fd] = pid;
6595 #else
6596 fifo_list[nfifo-1].proc = pid;
6597 #endif
6598
6599 last_made_pid = old_pid;
6600
6601 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
6602 close_pgrp_pipe ();
6603 #endif /* JOB_CONTROL && PGRP_PIPE */
6604
6605 #if defined (HAVE_DEV_FD)
6606 close (child_pipe_fd);
6607 #endif /* HAVE_DEV_FD */
6608
6609 return (pathname);
6610 }
6611
6612 set_sigint_handler ();
6613
6614 #if defined (JOB_CONTROL)
6615 /* make sure we don't have any job control */
6616 set_job_control (0);
6617
6618 /* Clear out any existing list of process substitutions */
6619 procsub_clear ();
6620
6621 /* The idea is that we want all the jobs we start from an async process
6622 substitution to be in the same process group, but not the same pgrp
6623 as our parent shell, since we don't want to affect our parent shell's
6624 jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example.
6625 If pipeline_pgrp != shell_pgrp, we assume that there is a job control
6626 shell somewhere in our parent process chain (since make_child initializes
6627 pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this
6628 case is to set pipeline_pgrp to our PID, so all jobs started by this
6629 process have that same pgrp and we are basically the process group leader.
6630 This should not have negative effects on child processes surviving
6631 after we exit, since we wait for the children we create, but that is
6632 something to watch for. */
6633
6634 if (pipeline_pgrp != shell_pgrp)
6635 pipeline_pgrp = getpid ();
6636 #endif /* JOB_CONTROL */
6637
6638 #if !defined (HAVE_DEV_FD)
6639 /* Open the named pipe in the child. */
6640 fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY);
6641 if (fd < 0)
6642 {
6643 /* Two separate strings for ease of translation. */
6644 if (open_for_read_in_child)
6645 sys_error (_("cannot open named pipe %s for reading"), pathname);
6646 else
6647 sys_error (_("cannot open named pipe %s for writing"), pathname);
6648
6649 exit (127);
6650 }
6651 if (open_for_read_in_child)
6652 {
6653 if (sh_unset_nodelay_mode (fd) < 0)
6654 {
6655 sys_error (_("cannot reset nodelay mode for fd %d"), fd);
6656 exit (127);
6657 }
6658 }
6659 #else /* HAVE_DEV_FD */
6660 fd = child_pipe_fd;
6661 #endif /* HAVE_DEV_FD */
6662
6663 /* Discard buffered stdio output before replacing the underlying file
6664 descriptor. */
6665 if (open_for_read_in_child == 0)
6666 fpurge (stdout);
6667
6668 if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
6669 {
6670 sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
6671 open_for_read_in_child ? 0 : 1);
6672 exit (127);
6673 }
6674
6675 if (fd != (open_for_read_in_child ? 0 : 1))
6676 close (fd);
6677
6678 /* Need to close any files that this process has open to pipes inherited
6679 from its parent. */
6680 if (current_fds_to_close)
6681 {
6682 close_fd_bitmap (current_fds_to_close);
6683 current_fds_to_close = (struct fd_bitmap *)NULL;
6684 }
6685
6686 #if defined (HAVE_DEV_FD)
6687 /* Make sure we close the parent's end of the pipe and clear the slot
6688 in the fd list so it is not closed later, if reallocated by, for
6689 instance, pipe(2). */
6690 close (parent_pipe_fd);
6691 dev_fd_list[parent_pipe_fd] = 0;
6692 #endif /* HAVE_DEV_FD */
6693
6694 /* subshells shouldn't have this flag, which controls using the temporary
6695 environment for variable lookups. We have already flushed the temporary
6696 environment above in the case we're expanding a redirection, so processes
6697 executed by this command need to be able to set it independently of their
6698 parent. */
6699 expanding_redir = 0;
6700
6701 remove_quoted_escapes (string);
6702
6703 startup_state = 2; /* see if we can avoid a fork */
6704 parse_and_execute_level = 0;
6705
6706 /* Give process substitution a place to jump back to on failure,
6707 so we don't go back up to main (). */
6708 result = setjmp_nosigs (top_level);
6709
6710 /* If we're running a process substitution inside a shell function,
6711 trap `return' so we don't return from the function in the subshell
6712 and go off to never-never land. */
6713 if (result == 0 && return_catch_flag)
6714 function_value = setjmp_nosigs (return_catch);
6715 else
6716 function_value = 0;
6717
6718 if (result == ERREXIT)
6719 rc = last_command_exit_value;
6720 else if (result == EXITPROG || result == EXITBLTIN)
6721 rc = last_command_exit_value;
6722 else if (result)
6723 rc = EXECUTION_FAILURE;
6724 else if (function_value)
6725 rc = return_catch_value;
6726 else
6727 {
6728 subshell_level++;
6729 rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
6730 /* leave subshell level intact for any exit trap */
6731 }
6732
6733 #if !defined (HAVE_DEV_FD)
6734 /* Make sure we close the named pipe in the child before we exit. */
6735 close (open_for_read_in_child ? 0 : 1);
6736 #endif /* !HAVE_DEV_FD */
6737
6738 last_command_exit_value = rc;
6739 rc = run_exit_trap ();
6740 exit (rc);
6741 /*NOTREACHED*/
6742 }
6743 #endif /* PROCESS_SUBSTITUTION */
6744
6745 /***********************************/
6746 /* */
6747 /* Command Substitution */
6748 /* */
6749 /***********************************/
6750
6751 #define COMSUB_PIPEBUF 4096
6752
6753 static char *
6754 optimize_cat_file (r, quoted, flags, flagp)
6755 REDIRECT *r;
6756 int quoted, flags, *flagp;
6757 {
6758 char *ret;
6759 int fd;
6760
6761 fd = open_redir_file (r, (char **)0);
6762 if (fd < 0)
6763 return &expand_param_error;
6764
6765 ret = read_comsub (fd, quoted, flags, flagp);
6766 close (fd);
6767
6768 return ret;
6769 }
6770
6771 static char *
6772 read_comsub (fd, quoted, flags, rflag)
6773 int fd, quoted, flags;
6774 int *rflag;
6775 {
6776 char *istring, buf[COMSUB_PIPEBUF], *bufp;
6777 int c, tflag, skip_ctlesc, skip_ctlnul;
6778 int mb_cur_max;
6779 size_t istring_index;
6780 size_t istring_size;
6781 ssize_t bufn;
6782 int nullbyte;
6783 #if defined (HANDLE_MULTIBYTE)
6784 mbstate_t ps;
6785 wchar_t wc;
6786 size_t mblen;
6787 int i;
6788 #endif
6789
6790 istring = (char *)NULL;
6791 istring_index = istring_size = bufn = tflag = 0;
6792
6793 skip_ctlesc = ifs_cmap[CTLESC];
6794 skip_ctlnul = ifs_cmap[CTLNUL];
6795
6796 mb_cur_max = MB_CUR_MAX;
6797 nullbyte = 0;
6798
6799 /* Read the output of the command through the pipe. */
6800 while (1)
6801 {
6802 if (fd < 0)
6803 break;
6804 if (--bufn <= 0)
6805 {
6806 bufn = zread (fd, buf, sizeof (buf));
6807 if (bufn <= 0)
6808 break;
6809 bufp = buf;
6810 }
6811 c = *bufp++;
6812
6813 if (c == 0)
6814 {
6815 #if 1
6816 if (nullbyte == 0)
6817 {
6818 internal_warning ("%s", _("command substitution: ignored null byte in input"));
6819 nullbyte = 1;
6820 }
6821 #endif
6822 continue;
6823 }
6824
6825 /* Add the character to ISTRING, possibly after resizing it. */
6826 RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512);
6827
6828 /* This is essentially quote_string inline */
6829 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
6830 istring[istring_index++] = CTLESC;
6831 else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC)
6832 istring[istring_index++] = CTLESC;
6833 /* Escape CTLESC and CTLNUL in the output to protect those characters
6834 from the rest of the word expansions (word splitting and globbing.)
6835 This is essentially quote_escapes inline. */
6836 else if (skip_ctlesc == 0 && c == CTLESC)
6837 istring[istring_index++] = CTLESC;
6838 else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
6839 istring[istring_index++] = CTLESC;
6840
6841 #if defined (HANDLE_MULTIBYTE)
6842 if ((locale_utf8locale && (c & 0x80)) ||
6843 (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127))
6844 {
6845 /* read a multibyte character from buf */
6846 /* punt on the hard case for now */
6847 memset (&ps, '\0', sizeof (mbstate_t));
6848 mblen = mbrtowc (&wc, bufp-1, bufn, &ps);
6849 if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1)
6850 istring[istring_index++] = c;
6851 else
6852 {
6853 istring[istring_index++] = c;
6854 for (i = 0; i < mblen-1; i++)
6855 istring[istring_index++] = *bufp++;
6856 bufn -= mblen - 1;
6857 }
6858 continue;
6859 }
6860 #endif
6861
6862 istring[istring_index++] = c;
6863 }
6864
6865 if (istring)
6866 istring[istring_index] = '\0';
6867
6868 /* If we read no output, just return now and save ourselves some
6869 trouble. */
6870 if (istring_index == 0)
6871 {
6872 FREE (istring);
6873 if (rflag)
6874 *rflag = tflag;
6875 return (char *)NULL;
6876 }
6877
6878 /* Strip trailing newlines from the output of the command. */
6879 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6880 {
6881 while (istring_index > 0)
6882 {
6883 if (istring[istring_index - 1] == '\n')
6884 {
6885 --istring_index;
6886
6887 /* If the newline was quoted, remove the quoting char. */
6888 if (istring[istring_index - 1] == CTLESC)
6889 --istring_index;
6890 }
6891 else
6892 break;
6893 }
6894 istring[istring_index] = '\0';
6895 }
6896 else
6897 strip_trailing (istring, istring_index - 1, 1);
6898
6899 if (rflag)
6900 *rflag = tflag;
6901 return istring;
6902 }
6903
6904 /* Perform command substitution on STRING. This returns a WORD_DESC * with the
6905 contained string possibly quoted. */
6906 WORD_DESC *
6907 command_substitute (string, quoted, flags)
6908 char *string;
6909 int quoted;
6910 int flags;
6911 {
6912 pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
6913 char *istring, *s;
6914 int result, fildes[2], function_value, pflags, rc, tflag, fork_flags;
6915 WORD_DESC *ret;
6916 sigset_t set, oset;
6917
6918 istring = (char *)NULL;
6919
6920 /* Don't fork () if there is no need to. In the case of no command to
6921 run, just return NULL. */
6922 for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++)
6923 ;
6924 if (s == 0 || *s == 0)
6925 return ((WORD_DESC *)NULL);
6926
6927 if (*s == '<' && (s[1] != '<' && s[1] != '>' && s[1] != '&'))
6928 {
6929 COMMAND *cmd;
6930
6931 cmd = parse_string_to_command (string, 0); /* XXX - flags */
6932 if (cmd && can_optimize_cat_file (cmd))
6933 {
6934 tflag = 0;
6935 istring = optimize_cat_file (cmd->value.Simple->redirects, quoted, flags, &tflag);
6936 if (istring == &expand_param_error)
6937 {
6938 last_command_exit_value = EXECUTION_FAILURE;
6939 istring = 0;
6940 }
6941 else
6942 last_command_exit_value = EXECUTION_SUCCESS; /* compat */
6943 last_command_subst_pid = dollar_dollar_pid;
6944
6945 dispose_command (cmd);
6946 ret = alloc_word_desc ();
6947 ret->word = istring;
6948 ret->flags = tflag;
6949
6950 return ret;
6951 }
6952 dispose_command (cmd);
6953 }
6954
6955 if (wordexp_only && read_but_dont_execute)
6956 {
6957 last_command_exit_value = EX_WEXPCOMSUB;
6958 jump_to_top_level (EXITPROG);
6959 }
6960
6961 /* We're making the assumption here that the command substitution will
6962 eventually run a command from the file system. Since we'll run
6963 maybe_make_export_env in this subshell before executing that command,
6964 the parent shell and any other shells it starts will have to remake
6965 the environment. If we make it before we fork, other shells won't
6966 have to. Don't bother if we have any temporary variable assignments,
6967 though, because the export environment will be remade after this
6968 command completes anyway, but do it if all the words to be expanded
6969 are variable assignments. */
6970 if (subst_assign_varlist == 0 || garglist == 0)
6971 maybe_make_export_env (); /* XXX */
6972
6973 /* Flags to pass to parse_and_execute() */
6974 pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
6975
6976 old_pid = last_made_pid;
6977
6978 /* Pipe the output of executing STRING into the current shell. */
6979 if (pipe (fildes) < 0)
6980 {
6981 sys_error ("%s", _("cannot make pipe for command substitution"));
6982 goto error_exit;
6983 }
6984
6985 #if defined (JOB_CONTROL)
6986 old_pipeline_pgrp = pipeline_pgrp;
6987 /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline or
6988 we've already forked to run a disk command (and are expanding redirections,
6989 for example). */
6990 if ((subshell_environment & (SUBSHELL_FORK|SUBSHELL_PIPE)) == 0)
6991 pipeline_pgrp = shell_pgrp;
6992 cleanup_the_pipeline ();
6993 #endif /* JOB_CONTROL */
6994
6995 old_async_pid = last_asynchronous_pid;
6996 fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0;
6997 pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM);
6998 last_asynchronous_pid = old_async_pid;
6999
7000 if (pid == 0)
7001 {
7002 /* Reset the signal handlers in the child, but don't free the
7003 trap strings. Set a flag noting that we have to free the
7004 trap strings if we run trap to change a signal disposition. */
7005 reset_signal_handlers ();
7006 if (ISINTERRUPT)
7007 {
7008 kill (getpid (), SIGINT);
7009 CLRINTERRUPT; /* if we're ignoring SIGINT somehow */
7010 }
7011 QUIT; /* catch any interrupts we got post-fork */
7012 subshell_environment |= SUBSHELL_RESETTRAP;
7013 subshell_environment &= ~SUBSHELL_IGNTRAP;
7014 }
7015
7016 #if defined (JOB_CONTROL)
7017 /* XXX DO THIS ONLY IN PARENT ? XXX */
7018 set_sigchld_handler ();
7019 stop_making_children ();
7020 if (pid != 0)
7021 pipeline_pgrp = old_pipeline_pgrp;
7022 #else
7023 stop_making_children ();
7024 #endif /* JOB_CONTROL */
7025
7026 if (pid < 0)
7027 {
7028 sys_error (_("cannot make child for command substitution"));
7029 error_exit:
7030
7031 last_made_pid = old_pid;
7032
7033 FREE (istring);
7034 close (fildes[0]);
7035 close (fildes[1]);
7036 return ((WORD_DESC *)NULL);
7037 }
7038
7039 if (pid == 0)
7040 {
7041 /* The currently executing shell is not interactive. */
7042 interactive = 0;
7043
7044 #if defined (JOB_CONTROL)
7045 /* Invariant: in child processes started to run command substitutions,
7046 pipeline_pgrp == shell_pgrp. Other parts of the shell assume this. */
7047 if (pipeline_pgrp > 0 && pipeline_pgrp != shell_pgrp)
7048 shell_pgrp = pipeline_pgrp;
7049 #endif
7050
7051 set_sigint_handler (); /* XXX */
7052
7053 free_pushed_string_input ();
7054
7055 /* Discard buffered stdio output before replacing the underlying file
7056 descriptor. */
7057 fpurge (stdout);
7058
7059 if (dup2 (fildes[1], 1) < 0)
7060 {
7061 sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1"));
7062 exit (EXECUTION_FAILURE);
7063 }
7064
7065 /* If standard output is closed in the parent shell
7066 (such as after `exec >&-'), file descriptor 1 will be
7067 the lowest available file descriptor, and end up in
7068 fildes[0]. This can happen for stdin and stderr as well,
7069 but stdout is more important -- it will cause no output
7070 to be generated from this command. */
7071 if ((fildes[1] != fileno (stdin)) &&
7072 (fildes[1] != fileno (stdout)) &&
7073 (fildes[1] != fileno (stderr)))
7074 close (fildes[1]);
7075
7076 if ((fildes[0] != fileno (stdin)) &&
7077 (fildes[0] != fileno (stdout)) &&
7078 (fildes[0] != fileno (stderr)))
7079 close (fildes[0]);
7080
7081 #ifdef __CYGWIN__
7082 /* Let stdio know the fd may have changed from text to binary mode, and
7083 make sure to preserve stdout line buffering. */
7084 freopen (NULL, "w", stdout);
7085 sh_setlinebuf (stdout);
7086 #endif /* __CYGWIN__ */
7087
7088 /* This is a subshell environment. */
7089 subshell_environment |= SUBSHELL_COMSUB;
7090
7091 /* Many shells do not appear to inherit the -v option for command
7092 substitutions. */
7093 change_flag ('v', FLAG_OFF);
7094
7095 /* When inherit_errexit option is not enabled, command substitution does
7096 not inherit the -e flag. It is enabled when Posix mode is enabled */
7097 if (inherit_errexit == 0)
7098 {
7099 builtin_ignoring_errexit = 0;
7100 change_flag ('e', FLAG_OFF);
7101 }
7102 set_shellopts ();
7103
7104 /* If we are expanding a redirection, we can dispose of any temporary
7105 environment we received, since redirections are not supposed to have
7106 access to the temporary environment. We will have to see whether this
7107 affects temporary environments supplied to `eval', but the temporary
7108 environment gets copied to builtin_env at some point. */
7109 if (expanding_redir)
7110 {
7111 flush_temporary_env ();
7112 expanding_redir = 0;
7113 }
7114
7115 remove_quoted_escapes (string);
7116
7117 /* We want to expand aliases on this pass if we are not in posix mode
7118 for backwards compatibility. */
7119 if (expand_aliases)
7120 expand_aliases = posixly_correct == 0;
7121
7122 startup_state = 2; /* see if we can avoid a fork */
7123 parse_and_execute_level = 0;
7124
7125 /* Give command substitution a place to jump back to on failure,
7126 so we don't go back up to main (). */
7127 result = setjmp_nosigs (top_level);
7128
7129 /* If we're running a command substitution inside a shell function,
7130 trap `return' so we don't return from the function in the subshell
7131 and go off to never-never land. */
7132 if (result == 0 && return_catch_flag)
7133 function_value = setjmp_nosigs (return_catch);
7134 else
7135 function_value = 0;
7136
7137 if (result == ERREXIT)
7138 rc = last_command_exit_value;
7139 else if (result == EXITPROG || result == EXITBLTIN)
7140 rc = last_command_exit_value;
7141 else if (result)
7142 rc = EXECUTION_FAILURE;
7143 else if (function_value)
7144 rc = return_catch_value;
7145 else
7146 {
7147 subshell_level++;
7148 rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
7149 /* leave subshell level intact for any exit trap */
7150 }
7151
7152 last_command_exit_value = rc;
7153 rc = run_exit_trap ();
7154 #if defined (PROCESS_SUBSTITUTION)
7155 unlink_fifo_list ();
7156 #endif
7157 exit (rc);
7158 }
7159 else
7160 {
7161 int dummyfd;
7162
7163 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
7164 close_pgrp_pipe ();
7165 #endif /* JOB_CONTROL && PGRP_PIPE */
7166
7167 close (fildes[1]);
7168
7169 begin_unwind_frame ("read-comsub");
7170 dummyfd = fildes[0];
7171 add_unwind_protect (close, dummyfd);
7172
7173 /* Block SIGINT while we're reading from the pipe. If the child
7174 process gets a SIGINT, it will either handle it or die, and the
7175 read will return. */
7176 BLOCK_SIGNAL (SIGINT, set, oset);
7177 tflag = 0;
7178 istring = read_comsub (fildes[0], quoted, flags, &tflag);
7179
7180 close (fildes[0]);
7181 discard_unwind_frame ("read-comsub");
7182 UNBLOCK_SIGNAL (oset);
7183
7184 current_command_subst_pid = pid;
7185 last_command_exit_value = wait_for (pid, JWAIT_NOTERM);
7186 last_command_subst_pid = pid;
7187 last_made_pid = old_pid;
7188
7189 #if defined (JOB_CONTROL)
7190 /* If last_command_exit_value > 128, then the substituted command
7191 was terminated by a signal. If that signal was SIGINT, then send
7192 SIGINT to ourselves. This will break out of loops, for instance. */
7193 if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
7194 kill (getpid (), SIGINT);
7195 #endif /* JOB_CONTROL */
7196
7197 ret = alloc_word_desc ();
7198 ret->word = istring;
7199 ret->flags = tflag;
7200
7201 return ret;
7202 }
7203 }
7204
7205 /********************************************************
7206 * *
7207 * Utility functions for parameter expansion *
7208 * *
7209 ********************************************************/
7210
7211 #if defined (ARRAY_VARS)
7212
7213 static arrayind_t
7214 array_length_reference (s)
7215 char *s;
7216 {
7217 int len;
7218 arrayind_t ind;
7219 char *akey;
7220 char *t, c;
7221 ARRAY *array;
7222 HASH_TABLE *h;
7223 SHELL_VAR *var;
7224
7225 var = array_variable_part (s, 0, &t, &len);
7226
7227 /* If unbound variables should generate an error, report one and return
7228 failure. */
7229 if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
7230 {
7231 c = *--t;
7232 *t = '\0';
7233 set_exit_status (EXECUTION_FAILURE);
7234 err_unboundvar (s);
7235 *t = c;
7236 return (-1);
7237 }
7238 else if (var == 0 || invisible_p (var))
7239 return 0;
7240
7241 /* We support a couple of expansions for variables that are not arrays.
7242 We'll return the length of the value for v[0], and 1 for v[@] or
7243 v[*]. Return 0 for everything else. */
7244
7245 array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
7246 h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
7247
7248 if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK)
7249 {
7250 if (assoc_p (var))
7251 return (h ? assoc_num_elements (h) : 0);
7252 else if (array_p (var))
7253 return (array ? array_num_elements (array) : 0);
7254 else
7255 return (var_isset (var) ? 1 : 0);
7256 }
7257
7258 if (assoc_p (var))
7259 {
7260 t[len - 1] = '\0';
7261 akey = expand_subscript_string (t, 0); /* [ */
7262 t[len - 1] = RBRACK;
7263 if (akey == 0 || *akey == 0)
7264 {
7265 err_badarraysub (t);
7266 FREE (akey);
7267 return (-1);
7268 }
7269 t = assoc_reference (assoc_cell (var), akey);
7270 free (akey);
7271 }
7272 else
7273 {
7274 ind = array_expand_index (var, t, len, 0);
7275 /* negative subscripts to indexed arrays count back from end */
7276 if (var && array_p (var) && ind < 0)
7277 ind = array_max_index (array_cell (var)) + 1 + ind;
7278 if (ind < 0)
7279 {
7280 err_badarraysub (t);
7281 return (-1);
7282 }
7283 if (array_p (var))
7284 t = array_reference (array, ind);
7285 else
7286 t = (ind == 0) ? value_cell (var) : (char *)NULL;
7287 }
7288
7289 len = MB_STRLEN (t);
7290 return (len);
7291 }
7292 #endif /* ARRAY_VARS */
7293
7294 static int
7295 valid_brace_expansion_word (name, var_is_special)
7296 char *name;
7297 int var_is_special;
7298 {
7299 if (DIGIT (*name) && all_digits (name))
7300 return 1;
7301 else if (var_is_special)
7302 return 1;
7303 #if defined (ARRAY_VARS)
7304 else if (valid_array_reference (name, 0))
7305 return 1;
7306 #endif /* ARRAY_VARS */
7307 else if (legal_identifier (name))
7308 return 1;
7309 else
7310 return 0;
7311 }
7312
7313 static int
7314 chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
7315 char *name;
7316 int quoted, pflags;
7317 int *quoted_dollar_atp, *contains_dollar_at;
7318 {
7319 char *temp1;
7320
7321 if (name == 0)
7322 {
7323 if (quoted_dollar_atp)
7324 *quoted_dollar_atp = 0;
7325 if (contains_dollar_at)
7326 *contains_dollar_at = 0;
7327 return 0;
7328 }
7329
7330 /* check for $@ and $* */
7331 if (name[0] == '@' && name[1] == 0)
7332 {
7333 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7334 *quoted_dollar_atp = 1;
7335 if (contains_dollar_at)
7336 *contains_dollar_at = 1;
7337 return 1;
7338 }
7339 else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
7340 {
7341 /* Need more checks here that parallel what string_list_pos_params and
7342 param_expand do. Check expand_no_split_dollar_star and ??? */
7343 if (contains_dollar_at && expand_no_split_dollar_star == 0)
7344 *contains_dollar_at = 1;
7345 return 1;
7346 }
7347
7348 /* Now check for ${array[@]} and ${array[*]} */
7349 #if defined (ARRAY_VARS)
7350 else if (valid_array_reference (name, 0))
7351 {
7352 temp1 = mbschr (name, LBRACK);
7353 if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK)
7354 {
7355 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
7356 *quoted_dollar_atp = 1;
7357 if (contains_dollar_at)
7358 *contains_dollar_at = 1;
7359 return 1;
7360 }
7361 /* ${array[*]}, when unquoted, should be treated like ${array[@]},
7362 which should result in separate words even when IFS is unset. */
7363 if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0)
7364 {
7365 if (contains_dollar_at)
7366 *contains_dollar_at = 1;
7367 return 1;
7368 }
7369 }
7370 #endif
7371 return 0;
7372 }
7373
7374 /* Parameter expand NAME, and return a new string which is the expansion,
7375 or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}.
7376 VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
7377 the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
7378 NAME was found inside of a double-quoted expression. */
7379 static WORD_DESC *
7380 parameter_brace_expand_word (name, var_is_special, quoted, pflags, estatep)
7381 char *name;
7382 int var_is_special, quoted, pflags;
7383 array_eltstate_t *estatep;
7384 {
7385 WORD_DESC *ret;
7386 char *temp, *tt;
7387 intmax_t arg_index;
7388 SHELL_VAR *var;
7389 int rflags;
7390 array_eltstate_t es;
7391
7392 ret = 0;
7393 temp = 0;
7394 rflags = 0;
7395
7396 #if defined (ARRAY_VARS)
7397 if (estatep)
7398 es = *estatep; /* structure copy */
7399 else
7400 {
7401 init_eltstate (&es);
7402 es.ind = INTMAX_MIN;
7403 }
7404 #endif
7405
7406 /* Handle multiple digit arguments, as in ${11}. */
7407 if (legal_number (name, &arg_index))
7408 {
7409 tt = get_dollar_var_value (arg_index);
7410 if (tt)
7411 temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7412 ? quote_string (tt)
7413 : quote_escapes (tt);
7414 else
7415 temp = (char *)NULL;
7416 FREE (tt);
7417 }
7418 else if (var_is_special) /* ${@} */
7419 {
7420 int sindex;
7421 tt = (char *)xmalloc (2 + strlen (name));
7422 tt[sindex = 0] = '$';
7423 strcpy (tt + 1, name);
7424
7425 ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
7426 (int *)NULL, (int *)NULL, pflags);
7427
7428 /* Make sure we note that we saw a quoted null string and pass the flag back
7429 to the caller in addition to the value. */
7430 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && STR_DOLLAR_AT_STAR (name) &&
7431 ret && ret->word && QUOTED_NULL (ret->word))
7432 ret->flags |= W_HASQUOTEDNULL;
7433
7434 free (tt);
7435 }
7436 #if defined (ARRAY_VARS)
7437 else if (valid_array_reference (name, 0))
7438 {
7439 expand_arrayref:
7440 var = array_variable_part (name, 0, &tt, (int *)0);
7441 /* These are the cases where word splitting will not be performed */
7442 if (pflags & PF_ASSIGNRHS)
7443 {
7444 if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK)
7445 {
7446 /* Only treat as double quoted if array variable */
7447 if (var && (array_p (var) || assoc_p (var)))
7448 temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &es);
7449 else
7450 temp = array_value (name, quoted, 0, &es);
7451 }
7452 else
7453 temp = array_value (name, quoted, 0, &es);
7454 }
7455 /* Posix interp 888 */
7456 else if (pflags & PF_NOSPLIT2)
7457 {
7458 /* Special cases, then general case, for each of A[@], A[*], A[n] */
7459 #if defined (HANDLE_MULTIBYTE)
7460 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
7461 #else
7462 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
7463 #endif
7464 temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &es);
7465 else if (tt[0] == '@' && tt[1] == RBRACK)
7466 temp = array_value (name, quoted, 0, &es);
7467 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
7468 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &es);
7469 else if (tt[0] == '*' && tt[1] == RBRACK)
7470 temp = array_value (name, quoted, 0, &es);
7471 else
7472 temp = array_value (name, quoted, 0, &es);
7473 }
7474 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
7475 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &es);
7476 else
7477 temp = array_value (name, quoted, 0, &es);
7478 if (es.subtype == 0 && temp)
7479 {
7480 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7481 ? quote_string (temp)
7482 : quote_escapes (temp);
7483 rflags |= W_ARRAYIND;
7484 if (estatep)
7485 *estatep = es; /* structure copy */
7486 }
7487 /* Note that array[*] and array[@] expanded to a quoted null string by
7488 returning the W_HASQUOTEDNULL flag to the caller in addition to TEMP. */
7489 else if (es.subtype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7490 rflags |= W_HASQUOTEDNULL;
7491 else if (es.subtype == 2 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7492 rflags |= W_HASQUOTEDNULL;
7493
7494 if (estatep == 0)
7495 flush_eltstate (&es);
7496 }
7497 #endif
7498 else if (var = find_variable (name))
7499 {
7500 if (var_isset (var) && invisible_p (var) == 0)
7501 {
7502 #if defined (ARRAY_VARS)
7503 /* We avoid a memory leak by saving TT as the memory allocated by
7504 assoc_to_string or array_to_string and leaving it 0 otherwise,
7505 then freeing TT after quoting temp. */
7506 tt = (char *)NULL;
7507 if ((pflags & PF_ALLINDS) && assoc_p (var))
7508 tt = temp = assoc_empty (assoc_cell (var)) ? (char *)NULL : assoc_to_string (assoc_cell (var), " ", quoted);
7509 else if ((pflags & PF_ALLINDS) && array_p (var))
7510 tt = temp = array_empty (array_cell (var)) ? (char *)NULL : array_to_string (array_cell (var), " ", quoted);
7511 else if (assoc_p (var))
7512 temp = assoc_reference (assoc_cell (var), "0");
7513 else if (array_p (var))
7514 temp = array_reference (array_cell (var), 0);
7515 else
7516 temp = value_cell (var);
7517 #else
7518 temp = value_cell (var);
7519 #endif
7520
7521 if (temp)
7522 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
7523 ? quote_string (temp)
7524 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
7525 : quote_escapes (temp));
7526 FREE (tt);
7527 }
7528 else
7529 temp = (char *)NULL;
7530 }
7531 else if (var = find_variable_last_nameref (name, 0))
7532 {
7533 temp = nameref_cell (var);
7534 #if defined (ARRAY_VARS)
7535 /* Handle expanding nameref whose value is x[n] */
7536 if (temp && *temp && valid_array_reference (temp, 0))
7537 {
7538 name = temp;
7539 goto expand_arrayref;
7540 }
7541 else
7542 #endif
7543 /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */
7544 if (temp && *temp && legal_identifier (temp) == 0)
7545 {
7546 set_exit_status (EXECUTION_FAILURE);
7547 report_error (_("%s: invalid variable name for name reference"), temp);
7548 temp = &expand_param_error;
7549 }
7550 else
7551 temp = (char *)NULL;
7552 }
7553 else
7554 temp = (char *)NULL;
7555
7556 if (ret == 0)
7557 {
7558 ret = alloc_word_desc ();
7559 ret->word = temp;
7560 ret->flags |= rflags;
7561 }
7562 return ret;
7563 }
7564
7565 static char *
7566 parameter_brace_find_indir (name, var_is_special, quoted, find_nameref)
7567 char *name;
7568 int var_is_special, quoted, find_nameref;
7569 {
7570 char *temp, *t;
7571 WORD_DESC *w;
7572 SHELL_VAR *v;
7573 int pflags, oldex;
7574
7575 if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) &&
7576 nameref_p (v) && (t = nameref_cell (v)) && *t)
7577 return (savestring (t));
7578
7579 /* If var_is_special == 0, and name is not an array reference, this does
7580 more expansion than necessary. It should really look up the variable's
7581 value and not try to expand it. */
7582 pflags = PF_IGNUNBOUND;
7583 /* Note that we're not going to be doing word splitting here */
7584 if (var_is_special)
7585 {
7586 pflags |= PF_ASSIGNRHS; /* suppresses word splitting */
7587 oldex = expand_no_split_dollar_star;
7588 expand_no_split_dollar_star = 1;
7589 }
7590 w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0);
7591 if (var_is_special)
7592 expand_no_split_dollar_star = oldex;
7593
7594 t = w->word;
7595 /* Have to dequote here if necessary */
7596 if (t)
7597 {
7598 temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special)
7599 ? dequote_string (t)
7600 : dequote_escapes (t);
7601 free (t);
7602 t = temp;
7603 }
7604 dispose_word_desc (w);
7605
7606 return t;
7607 }
7608
7609 /* Expand an indirect reference to a variable: ${!NAME} expands to the
7610 value of the variable whose name is the value of NAME. */
7611 static WORD_DESC *
7612 parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
7613 char *name;
7614 int var_is_special, quoted, pflags;
7615 int *quoted_dollar_atp, *contains_dollar_at;
7616 {
7617 char *t;
7618 WORD_DESC *w;
7619 SHELL_VAR *v;
7620
7621 /* See if it's a nameref first, behave in ksh93-compatible fashion.
7622 There is at least one incompatibility: given ${!foo[0]} where foo=bar,
7623 bash performs an indirect lookup on foo[0] and expands the result;
7624 ksh93 expands bar[0]. We could do that here -- there are enough usable
7625 primitives to do that -- but do not at this point. */
7626 if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0)))
7627 {
7628 if (nameref_p (v) && (t = nameref_cell (v)) && *t)
7629 {
7630 w = alloc_word_desc ();
7631 w->word = savestring (t);
7632 w->flags = 0;
7633 return w;
7634 }
7635 }
7636
7637 /* An indirect reference to a positional parameter or a special parameter
7638 is ok. Indirect references to array references, as explained above, are
7639 ok (currently). Only references to unset variables are errors at this
7640 point. */
7641 if (legal_identifier (name) && v == 0)
7642 {
7643 report_error (_("%s: invalid indirect expansion"), name);
7644 w = alloc_word_desc ();
7645 w->word = &expand_param_error;
7646 w->flags = 0;
7647 return (w);
7648 }
7649
7650 t = parameter_brace_find_indir (name, var_is_special, quoted, 0);
7651
7652 chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at);
7653
7654 #if defined (ARRAY_VARS)
7655 /* Array references to unset variables are also an error */
7656 if (t == 0 && valid_array_reference (name, 0))
7657 {
7658 v = array_variable_part (name, 0, (char **)0, (int *)0);
7659 if (v == 0)
7660 {
7661 report_error (_("%s: invalid indirect expansion"), name);
7662 w = alloc_word_desc ();
7663 w->word = &expand_param_error;
7664 w->flags = 0;
7665 return (w);
7666 }
7667 else
7668 return (WORD_DESC *)NULL;
7669 }
7670 #endif
7671
7672 if (t == 0)
7673 return (WORD_DESC *)NULL;
7674
7675 if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0)
7676 {
7677 report_error (_("%s: invalid variable name"), t);
7678 free (t);
7679 w = alloc_word_desc ();
7680 w->word = &expand_param_error;
7681 w->flags = 0;
7682 return (w);
7683 }
7684
7685 w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0);
7686 free (t);
7687
7688 return w;
7689 }
7690
7691 /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
7692 depending on the value of C, the separating character. C can be one of
7693 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
7694 between double quotes. */
7695 static WORD_DESC *
7696 parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat)
7697 char *name, *value;
7698 int op, quoted, pflags, *qdollaratp, *hasdollarat;
7699 {
7700 WORD_DESC *w;
7701 WORD_LIST *l, *tl;
7702 char *t, *t1, *temp, *vname, *newval;
7703 int l_hasdollat, sindex, arrayref;
7704 SHELL_VAR *v;
7705 array_eltstate_t es;
7706
7707 /*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/
7708 /* If the entire expression is between double quotes, we want to treat
7709 the value as a double-quoted string, with the exception that we strip
7710 embedded unescaped double quotes (for sh backwards compatibility). */
7711 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
7712 {
7713 sindex = 0;
7714 temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ);
7715 }
7716 else
7717 temp = value;
7718
7719 w = alloc_word_desc ();
7720 l_hasdollat = 0;
7721 l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL)
7722 : (WORD_LIST *)0;
7723 if (hasdollarat)
7724 *hasdollarat = l_hasdollat || (l && l->next);
7725 if (temp != value)
7726 free (temp);
7727
7728 /* list_string takes multiple CTLNULs and turns them into an empty word
7729 with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the
7730 rest of this function and the caller. */
7731 for (tl = l; tl; tl = tl->next)
7732 {
7733 if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) &&
7734 (tl->word->flags | W_SAWQUOTEDNULL))
7735 {
7736 t = make_quoted_char ('\0');
7737 FREE (tl->word->word);
7738 tl->word->word = t;
7739 tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL;
7740 tl->word->flags &= ~W_SAWQUOTEDNULL;
7741 }
7742 }
7743
7744 if (l)
7745 {
7746 /* If l->next is not null, we know that TEMP contained "$@", since that
7747 is the only expansion that creates more than one word. */
7748 if (qdollaratp && ((l_hasdollat && quoted) || l->next))
7749 {
7750 /*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/
7751 *qdollaratp = 1;
7752 }
7753
7754 /* The expansion of TEMP returned something. We need to treat things
7755 slightly differently if L_HASDOLLAT is non-zero. If we have "$@",
7756 the individual words have already been quoted. We need to turn them
7757 into a string with the words separated by the first character of
7758 $IFS without any additional quoting, so string_list_dollar_at won't
7759 do the right thing. If IFS is null, we want "$@" to split into
7760 separate arguments, not be concatenated, so we use string_list_internal
7761 and mark the word to be split on spaces later. We use
7762 string_list_dollar_star for "$@" otherwise. */
7763 if (l->next && ifs_is_null)
7764 {
7765 temp = string_list_internal (l, " ");
7766 w->flags |= W_SPLITSPACE;
7767 }
7768 else if (l_hasdollat || l->next)
7769 temp = string_list_dollar_star (l, quoted, 0);
7770 else
7771 {
7772 temp = string_list (l);
7773 if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL))
7774 w->flags |= W_SAWQUOTEDNULL; /* XXX */
7775 }
7776
7777 /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
7778 a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
7779 flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
7780 expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7781 (which is more paranoia than anything else), we need to return the
7782 quoted null string and set the flags to indicate it. */
7783 if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL))
7784 {
7785 w->flags |= W_HASQUOTEDNULL;
7786 /*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/
7787 /* If we return a quoted null with L_HASDOLLARAT, we either have a
7788 construct like "${@-$@}" or "${@-${@-$@}}" with no positional
7789 parameters or a quoted expansion of "$@" with $1 == ''. In either
7790 case, we don't want to enable special handling of $@. */
7791 if (qdollaratp && l_hasdollat)
7792 *qdollaratp = 0;
7793 }
7794 dispose_words (l);
7795 }
7796 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat)
7797 {
7798 /* Posix interp 221 changed the rules on this. The idea is that
7799 something like "$xxx$@" should expand the same as "${foo-$xxx$@}"
7800 when foo and xxx are unset. The problem is that it's not in any
7801 way backwards compatible and few other shells do it. We're eventually
7802 going to try and split the difference (heh) a little bit here. */
7803 /* l_hasdollat == 1 means we saw a quoted dollar at. */
7804
7805 /* The brace expansion occurred between double quotes and there was
7806 a $@ in TEMP. It does not matter if the $@ is quoted, as long as
7807 it does not expand to anything. In this case, we want to return
7808 a quoted empty string. Posix interp 888 */
7809 temp = make_quoted_char ('\0');
7810 w->flags |= W_HASQUOTEDNULL;
7811 /*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/
7812 }
7813 else
7814 temp = (char *)NULL;
7815
7816 if (op == '-' || op == '+')
7817 {
7818 w->word = temp;
7819 return w;
7820 }
7821
7822 /* op == '=' */
7823 t1 = temp ? dequote_string (temp) : savestring ("");
7824 free (temp);
7825
7826 /* bash-4.4/5.0 */
7827 vname = name;
7828 if (*name == '!' &&
7829 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1])))
7830 {
7831 vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1);
7832 if (vname == 0 || *vname == 0)
7833 {
7834 report_error (_("%s: invalid indirect expansion"), name);
7835 free (vname);
7836 free (t1);
7837 dispose_word (w);
7838 return &expand_wdesc_error;
7839 }
7840 if (legal_identifier (vname) == 0)
7841 {
7842 report_error (_("%s: invalid variable name"), vname);
7843 free (vname);
7844 free (t1);
7845 dispose_word (w);
7846 return &expand_wdesc_error;
7847 }
7848 }
7849
7850 arrayref = 0;
7851 #if defined (ARRAY_VARS)
7852 if (valid_array_reference (vname, 0))
7853 {
7854 init_eltstate (&es);
7855 v = assign_array_element (vname, t1, ASS_ALLOWALLSUB, &es);
7856 arrayref = 1;
7857 newval = es.value;
7858 }
7859 else
7860 #endif /* ARRAY_VARS */
7861 v = bind_variable (vname, t1, 0);
7862
7863 if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */
7864 {
7865 if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct)
7866 {
7867 last_command_exit_value = EXECUTION_FAILURE;
7868 exp_jump_to_top_level (FORCE_EOF);
7869 }
7870 else
7871 {
7872 if (vname != name)
7873 free (vname);
7874 last_command_exit_value = EX_BADUSAGE;
7875 exp_jump_to_top_level (DISCARD);
7876 }
7877 }
7878
7879 stupidly_hack_special_variables (vname);
7880
7881 /* "In all cases, the final value of parameter shall be substituted." */
7882 if (shell_compatibility_level > 51)
7883 {
7884 FREE (t1);
7885 #if defined (ARRAY_VARS)
7886 if (arrayref)
7887 {
7888 t1 = newval;
7889 flush_eltstate (&es);
7890 }
7891 else
7892 t1 = get_variable_value (v);
7893 #else
7894 t1 = value_cell (v);
7895 #endif
7896 }
7897
7898 if (vname != name)
7899 free (vname);
7900
7901 /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
7902
7903 /* If we are double-quoted or if we are not going to be performing word
7904 splitting, we want to quote the value we return appropriately, like
7905 the other expansions this function handles. */
7906 w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1);
7907 /* If we have something that's non-null, but not a quoted null string,
7908 and we're not going to be performing word splitting (we know we're not
7909 because the operator is `='), we can forget we saw a quoted null. */
7910 if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0)
7911 w->flags &= ~W_SAWQUOTEDNULL;
7912
7913 /* If we convert a null string into a quoted null, make sure the caller
7914 knows it. */
7915 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word))
7916 w->flags |= W_HASQUOTEDNULL;
7917
7918 return w;
7919 }
7920
7921 /* Deal with the right hand side of a ${name:?value} expansion in the case
7922 that NAME is null or not set. If VALUE is non-null it is expanded and
7923 used as the error message to print, otherwise a standard message is
7924 printed. */
7925 static void
7926 parameter_brace_expand_error (name, value, check_null)
7927 char *name, *value;
7928 int check_null;
7929 {
7930 WORD_LIST *l;
7931 char *temp;
7932
7933 set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */
7934 if (value && *value)
7935 {
7936 l = expand_string (value, 0);
7937 temp = string_list (l);
7938 report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
7939 FREE (temp);
7940 dispose_words (l);
7941 }
7942 else if (check_null == 0)
7943 report_error (_("%s: parameter not set"), name);
7944 else
7945 report_error (_("%s: parameter null or not set"), name);
7946
7947 /* Free the data we have allocated during this expansion, since we
7948 are about to longjmp out. */
7949 free (name);
7950 FREE (value);
7951 }
7952
7953 /* Return 1 if NAME is something for which parameter_brace_expand_length is
7954 OK to do. */
7955 static int
7956 valid_length_expression (name)
7957 char *name;
7958 {
7959 return (name[1] == '\0' || /* ${#} */
7960 ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */
7961 (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
7962 #if defined (ARRAY_VARS)
7963 valid_array_reference (name + 1, 0) || /* ${#a[7]} */
7964 #endif
7965 legal_identifier (name + 1)); /* ${#PS1} */
7966 }
7967
7968 /* Handle the parameter brace expansion that requires us to return the
7969 length of a parameter. */
7970 static intmax_t
7971 parameter_brace_expand_length (name)
7972 char *name;
7973 {
7974 char *t, *newname;
7975 intmax_t number, arg_index;
7976 WORD_LIST *list;
7977 SHELL_VAR *var;
7978
7979 var = (SHELL_VAR *)NULL;
7980
7981 if (name[1] == '\0') /* ${#} */
7982 number = number_of_args ();
7983 else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */
7984 number = number_of_args ();
7985 else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
7986 {
7987 /* Take the lengths of some of the shell's special parameters. */
7988 switch (name[1])
7989 {
7990 case '-':
7991 t = which_set_flags ();
7992 break;
7993 case '?':
7994 t = itos (last_command_exit_value);
7995 break;
7996 case '$':
7997 t = itos (dollar_dollar_pid);
7998 break;
7999 case '!':
8000 if (last_asynchronous_pid == NO_PID)
8001 t = (char *)NULL; /* XXX - error if set -u set? */
8002 else
8003 t = itos (last_asynchronous_pid);
8004 break;
8005 case '#':
8006 t = itos (number_of_args ());
8007 break;
8008 }
8009 number = STRLEN (t);
8010 FREE (t);
8011 }
8012 #if defined (ARRAY_VARS)
8013 else if (valid_array_reference (name + 1, 0))
8014 number = array_length_reference (name + 1);
8015 #endif /* ARRAY_VARS */
8016 else
8017 {
8018 number = 0;
8019
8020 if (legal_number (name + 1, &arg_index)) /* ${#1} */
8021 {
8022 t = get_dollar_var_value (arg_index);
8023 if (t == 0 && unbound_vars_is_error)
8024 return INTMAX_MIN;
8025 number = MB_STRLEN (t);
8026 FREE (t);
8027 }
8028 #if defined (ARRAY_VARS)
8029 else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
8030 {
8031 if (assoc_p (var))
8032 t = assoc_reference (assoc_cell (var), "0");
8033 else
8034 t = array_reference (array_cell (var), 0);
8035 if (t == 0 && unbound_vars_is_error)
8036 return INTMAX_MIN;
8037 number = MB_STRLEN (t);
8038 }
8039 #endif
8040 /* Fast path for the common case of taking the length of a non-dynamic
8041 scalar variable value. */
8042 else if ((var || (var = find_variable (name + 1))) &&
8043 invisible_p (var) == 0 &&
8044 array_p (var) == 0 && assoc_p (var) == 0 &&
8045 var->dynamic_value == 0)
8046 number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0;
8047 else if (var == 0 && unbound_vars_is_error == 0)
8048 number = 0;
8049 else /* ${#PS1} */
8050 {
8051 newname = savestring (name);
8052 newname[0] = '$';
8053 list = expand_string (newname, Q_DOUBLE_QUOTES);
8054 t = list ? string_list (list) : (char *)NULL;
8055 free (newname);
8056 if (list)
8057 dispose_words (list);
8058
8059 number = t ? MB_STRLEN (t) : 0;
8060 FREE (t);
8061 }
8062 }
8063
8064 return (number);
8065 }
8066
8067 /* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression,
8068 so we do some ad-hoc parsing of an arithmetic expression to find
8069 the first DELIM, instead of using strchr(3). Two rules:
8070 1. If the substring contains a `(', read until closing `)'.
8071 2. If the substring contains a `?', read past one `:' for each `?'.
8072 The SD_ARITHEXP flag to skip_to_delim takes care of doing this.
8073 */
8074
8075 static char *
8076 skiparith (substr, delim)
8077 char *substr;
8078 int delim;
8079 {
8080 int i;
8081 char delims[2];
8082
8083 delims[0] = delim;
8084 delims[1] = '\0';
8085
8086 i = skip_to_delim (substr, 0, delims, SD_ARITHEXP);
8087 return (substr + i);
8088 }
8089
8090 /* Verify and limit the start and end of the desired substring. If
8091 VTYPE == 0, a regular shell variable is being used; if it is 1,
8092 then the positional parameters are being used; if it is 2, then
8093 VALUE is really a pointer to an array variable that should be used.
8094 Return value is 1 if both values were OK, 0 if there was a problem
8095 with an invalid expression, or -1 if the values were out of range. */
8096 static int
8097 verify_substring_values (v, value, substr, vtype, e1p, e2p)
8098 SHELL_VAR *v;
8099 char *value, *substr;
8100 int vtype;
8101 intmax_t *e1p, *e2p;
8102 {
8103 char *t, *temp1, *temp2;
8104 arrayind_t len;
8105 int expok, eflag;
8106 #if defined (ARRAY_VARS)
8107 ARRAY *a;
8108 HASH_TABLE *h;
8109 #endif
8110
8111 /* duplicate behavior of strchr(3) */
8112 t = skiparith (substr, ':');
8113 if (*t && *t == ':')
8114 *t = '\0';
8115 else
8116 t = (char *)0;
8117
8118 temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES|Q_ARITH);
8119 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
8120
8121 *e1p = evalexp (temp1, eflag, &expok);
8122 free (temp1);
8123 if (expok == 0)
8124 return (0);
8125
8126 len = -1; /* paranoia */
8127 switch (vtype)
8128 {
8129 case VT_VARIABLE:
8130 case VT_ARRAYMEMBER:
8131 len = MB_STRLEN (value);
8132 break;
8133 case VT_POSPARMS:
8134 len = number_of_args () + 1;
8135 if (*e1p == 0)
8136 len++; /* add one arg if counting from $0 */
8137 break;
8138 #if defined (ARRAY_VARS)
8139 case VT_ARRAYVAR:
8140 /* For arrays, the first value deals with array indices. Negative
8141 offsets count from one past the array's maximum index. Associative
8142 arrays treat the number of elements as the maximum index. */
8143 if (assoc_p (v))
8144 {
8145 h = assoc_cell (v);
8146 len = assoc_num_elements (h) + (*e1p < 0);
8147 }
8148 else
8149 {
8150 a = (ARRAY *)value;
8151 len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
8152 }
8153 break;
8154 #endif
8155 }
8156
8157 if (len == -1) /* paranoia */
8158 return -1;
8159
8160 if (*e1p < 0) /* negative offsets count from end */
8161 *e1p += len;
8162
8163 if (*e1p > len || *e1p < 0)
8164 return (-1);
8165
8166 #if defined (ARRAY_VARS)
8167 /* For arrays, the second offset deals with the number of elements. */
8168 if (vtype == VT_ARRAYVAR)
8169 len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
8170 #endif
8171
8172 if (t)
8173 {
8174 t++;
8175 temp2 = savestring (t);
8176 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
8177 free (temp2);
8178 t[-1] = ':';
8179 *e2p = evalexp (temp1, eflag, &expok);
8180 free (temp1);
8181 if (expok == 0)
8182 return (0);
8183
8184 /* Should we allow positional parameter length < 0 to count backwards
8185 from end of positional parameters? */
8186 #if 1
8187 if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
8188 #else /* XXX - postponed; this isn't really a valuable feature */
8189 if (vtype == VT_ARRAYVAR && *e2p < 0)
8190 #endif
8191 {
8192 internal_error (_("%s: substring expression < 0"), t);
8193 return (0);
8194 }
8195 #if defined (ARRAY_VARS)
8196 /* In order to deal with sparse arrays, push the intelligence about how
8197 to deal with the number of elements desired down to the array-
8198 specific functions. */
8199 if (vtype != VT_ARRAYVAR)
8200 #endif
8201 {
8202 if (*e2p < 0)
8203 {
8204 *e2p += len;
8205 if (*e2p < 0 || *e2p < *e1p)
8206 {
8207 internal_error (_("%s: substring expression < 0"), t);
8208 return (0);
8209 }
8210 }
8211 else
8212 *e2p += *e1p; /* want E2 chars starting at E1 */
8213 if (*e2p > len)
8214 *e2p = len;
8215 }
8216 }
8217 else
8218 *e2p = len;
8219
8220 return (1);
8221 }
8222
8223 /* Return the type of variable specified by VARNAME (simple variable,
8224 positional param, or array variable). Also return the value specified
8225 by VARNAME (value of a variable or a reference to an array element).
8226 QUOTED is the standard description of quoting state, using Q_* defines.
8227 FLAGS is currently a set of flags to pass to array_value. If IND is
8228 not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
8229 passed to array_value so the array index is not computed again.
8230 If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
8231 characters in the value are quoted with CTLESC and takes appropriate
8232 steps. For convenience, *VALP is set to the dequoted VALUE. */
8233 static int
8234 get_var_and_type (varname, value, estatep, quoted, flags, varp, valp)
8235 char *varname, *value;
8236 array_eltstate_t *estatep;
8237 int quoted, flags;
8238 SHELL_VAR **varp;
8239 char **valp;
8240 {
8241 int vtype, want_indir;
8242 char *temp, *vname;
8243 SHELL_VAR *v;
8244
8245 want_indir = *varname == '!' &&
8246 (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1])
8247 || VALID_INDIR_PARAM (varname[1]));
8248 if (want_indir)
8249 vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1);
8250 /* XXX - what if vname == 0 || *vname == 0 ? */
8251 else
8252 vname = varname;
8253
8254 if (vname == 0)
8255 {
8256 vtype = VT_VARIABLE;
8257 *varp = (SHELL_VAR *)NULL;
8258 *valp = (char *)NULL;
8259 return (vtype);
8260 }
8261
8262 /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
8263 vtype = STR_DOLLAR_AT_STAR (vname);
8264 if (vtype == VT_POSPARMS && vname[0] == '*')
8265 vtype |= VT_STARSUB;
8266 *varp = (SHELL_VAR *)NULL;
8267
8268 #if defined (ARRAY_VARS)
8269 if (valid_array_reference (vname, 0))
8270 {
8271 v = array_variable_part (vname, 0, &temp, (int *)0);
8272 /* If we want to signal array_value to use an already-computed index,
8273 the caller will set ESTATEP->IND to that index and pass AV_USEIND in
8274 FLAGS. */
8275 if (estatep && (flags & AV_USEIND) == 0)
8276 estatep->ind = INTMAX_MIN;
8277
8278 if (v && invisible_p (v))
8279 {
8280 vtype = VT_ARRAYMEMBER;
8281 *varp = (SHELL_VAR *)NULL;
8282 *valp = (char *)NULL;
8283 }
8284 if (v && (array_p (v) || assoc_p (v)))
8285 {
8286 if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)
8287 {
8288 /* Callers have to differentiate between indexed and associative */
8289 vtype = VT_ARRAYVAR;
8290 if (temp[0] == '*')
8291 vtype |= VT_STARSUB;
8292 *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
8293 }
8294 else
8295 {
8296 vtype = VT_ARRAYMEMBER;
8297 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
8298 }
8299 *varp = v;
8300 }
8301 else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK))
8302 {
8303 vtype = VT_VARIABLE;
8304 *varp = v;
8305 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8306 *valp = value ? dequote_string (value) : (char *)NULL;
8307 else
8308 *valp = value ? dequote_escapes (value) : (char *)NULL;
8309 }
8310 else
8311 {
8312 vtype = VT_ARRAYMEMBER;
8313 *varp = v;
8314 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
8315 }
8316 }
8317 else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
8318 {
8319 vtype = VT_ARRAYMEMBER;
8320 *varp = v;
8321 *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
8322 }
8323 else
8324 #endif
8325 {
8326 if (value && vtype == VT_VARIABLE)
8327 {
8328 *varp = find_variable (vname);
8329 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8330 *valp = dequote_string (value);
8331 else
8332 *valp = dequote_escapes (value);
8333 }
8334 else
8335 *valp = value;
8336 }
8337
8338 if (want_indir)
8339 free (vname);
8340
8341 return vtype;
8342 }
8343
8344 /***********************************************************/
8345 /* */
8346 /* Functions to perform transformations on variable values */
8347 /* */
8348 /***********************************************************/
8349
8350 static char *
8351 string_var_assignment (v, s)
8352 SHELL_VAR *v;
8353 char *s;
8354 {
8355 char flags[MAX_ATTRIBUTES], *ret, *val;
8356 int i;
8357
8358 val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0);
8359 i = var_attribute_string (v, 0, flags);
8360 if (i == 0 && val == 0)
8361 return (char *)NULL;
8362
8363 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES);
8364 if (i > 0 && val == 0)
8365 sprintf (ret, "declare -%s %s", flags, v->name);
8366 else if (i > 0)
8367 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
8368 else
8369 sprintf (ret, "%s=%s", v->name, val);
8370 free (val);
8371 return ret;
8372 }
8373
8374 #if defined (ARRAY_VARS)
8375 static char *
8376 array_var_assignment (v, itype, quoted, atype)
8377 SHELL_VAR *v;
8378 int itype, quoted, atype;
8379 {
8380 char *ret, *val, flags[MAX_ATTRIBUTES];
8381 int i;
8382
8383 if (v == 0)
8384 return (char *)NULL;
8385 if (atype == 2)
8386 val = array_p (v) ? array_to_kvpair (array_cell (v), 0)
8387 : assoc_to_kvpair (assoc_cell (v), 0);
8388 else
8389 val = array_p (v) ? array_to_assign (array_cell (v), 0)
8390 : assoc_to_assign (assoc_cell (v), 0);
8391
8392 if (val == 0 && (invisible_p (v) || var_isset (v) == 0))
8393 ; /* placeholder */
8394 else if (val == 0)
8395 {
8396 val = (char *)xmalloc (3);
8397 val[0] = LPAREN;
8398 val[1] = RPAREN;
8399 val[2] = 0;
8400 }
8401 else
8402 {
8403 ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val);
8404 free (val);
8405 val = ret;
8406 }
8407
8408 if (atype == 2)
8409 return val;
8410
8411 i = var_attribute_string (v, 0, flags);
8412 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16);
8413 if (val)
8414 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
8415 else
8416 sprintf (ret, "declare -%s %s", flags, v->name);
8417 free (val);
8418 return ret;
8419 }
8420 #endif
8421
8422 static char *
8423 pos_params_assignment (list, itype, quoted)
8424 WORD_LIST *list;
8425 int itype;
8426 int quoted;
8427 {
8428 char *temp, *ret;
8429
8430 /* first, we transform the list to quote each word. */
8431 temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted);
8432 ret = (char *)xmalloc (strlen (temp) + 8);
8433 strcpy (ret, "set -- ");
8434 strcpy (ret + 7, temp);
8435 free (temp);
8436 return ret;
8437 }
8438
8439 static char *
8440 string_transform (xc, v, s)
8441 int xc;
8442 SHELL_VAR *v;
8443 char *s;
8444 {
8445 char *ret, flags[MAX_ATTRIBUTES], *t;
8446 int i;
8447
8448 if (((xc == 'A' || xc == 'a') && v == 0))
8449 return (char *)NULL;
8450 else if (xc != 'a' && xc != 'A' && s == 0)
8451 return (char *)NULL;
8452
8453 switch (xc)
8454 {
8455 /* Transformations that interrogate the variable */
8456 case 'a':
8457 i = var_attribute_string (v, 0, flags);
8458 ret = (i > 0) ? savestring (flags) : (char *)NULL;
8459 break;
8460 case 'A':
8461 ret = string_var_assignment (v, s);
8462 break;
8463 case 'K':
8464 case 'k':
8465 ret = sh_quote_reusable (s, 0);
8466 break;
8467 /* Transformations that modify the variable's value */
8468 case 'E':
8469 t = ansiexpand (s, 0, strlen (s), (int *)0);
8470 ret = dequote_escapes (t);
8471 free (t);
8472 break;
8473 case 'P':
8474 ret = decode_prompt_string (s);
8475 break;
8476 case 'Q':
8477 ret = sh_quote_reusable (s, 0);
8478 break;
8479 case 'U':
8480 ret = sh_modcase (s, 0, CASE_UPPER);
8481 break;
8482 case 'u':
8483 ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */
8484 break;
8485 case 'L':
8486 ret = sh_modcase (s, 0, CASE_LOWER);
8487 break;
8488 default:
8489 ret = (char *)NULL;
8490 break;
8491 }
8492 return ret;
8493 }
8494
8495 static char *
8496 list_transform (xc, v, list, itype, quoted)
8497 int xc;
8498 SHELL_VAR *v;
8499 WORD_LIST *list;
8500 int itype, quoted;
8501 {
8502 WORD_LIST *new, *l;
8503 WORD_DESC *w;
8504 char *tword;
8505 int qflags;
8506
8507 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
8508 {
8509 tword = string_transform (xc, v, l->word->word);
8510 w = alloc_word_desc ();
8511 w->word = tword ? tword : savestring (""); /* XXX */
8512 new = make_word_list (w, new);
8513 }
8514 l = REVERSE_LIST (new, WORD_LIST *);
8515
8516 qflags = quoted;
8517 /* If we are expanding in a context where word splitting will not be
8518 performed, treat as quoted. This changes how $* will be expanded. */
8519 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
8520 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8521
8522 tword = string_list_pos_params (itype, l, qflags, 0);
8523 dispose_words (l);
8524
8525 return (tword);
8526 }
8527
8528 static char *
8529 parameter_list_transform (xc, itype, quoted)
8530 int xc;
8531 int itype;
8532 int quoted;
8533 {
8534 char *ret;
8535 WORD_LIST *list;
8536
8537 list = list_rest_of_args ();
8538 if (list == 0)
8539 return ((char *)NULL);
8540 if (xc == 'A')
8541 ret = pos_params_assignment (list, itype, quoted);
8542 else
8543 ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted);
8544 dispose_words (list);
8545 return (ret);
8546 }
8547
8548 #if defined (ARRAY_VARS)
8549 static char *
8550 array_transform (xc, var, starsub, quoted)
8551 int xc;
8552 SHELL_VAR *var;
8553 int starsub; /* so we can figure out how it's indexed */
8554 int quoted;
8555 {
8556 ARRAY *a;
8557 HASH_TABLE *h;
8558 int itype, qflags;
8559 char *ret;
8560 WORD_LIST *list;
8561 SHELL_VAR *v;
8562
8563 v = var; /* XXX - for now */
8564
8565 itype = starsub ? '*' : '@';
8566
8567 if (xc == 'A')
8568 return (array_var_assignment (v, itype, quoted, 1));
8569 else if (xc == 'K')
8570 return (array_var_assignment (v, itype, quoted, 2));
8571
8572 /* special case for unset arrays and attributes */
8573 if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0))
8574 {
8575 char flags[MAX_ATTRIBUTES];
8576 int i;
8577
8578 i = var_attribute_string (v, 0, flags);
8579 return ((i > 0) ? savestring (flags) : (char *)NULL);
8580 }
8581
8582 a = (v && array_p (v)) ? array_cell (v) : 0;
8583 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
8584
8585 /* XXX - for now */
8586 if (xc == 'k')
8587 {
8588 if (v == 0)
8589 return ((char *)NULL);
8590 list = array_p (v) ? array_to_kvpair_list (a) : assoc_to_kvpair_list (h);
8591 qflags = quoted;
8592 /* If we are expanding in a context where word splitting will not be
8593 performed, treat as quoted. This changes how $* will be expanded. */
8594 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
8595 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8596
8597 ret = string_list_pos_params (itype, list, qflags, 0);
8598 dispose_words (list);
8599 return ret;
8600 }
8601
8602 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
8603 if (list == 0)
8604 return ((char *)NULL);
8605 ret = list_transform (xc, v, list, itype, quoted);
8606 dispose_words (list);
8607
8608 return ret;
8609 }
8610 #endif /* ARRAY_VARS */
8611
8612 static int
8613 valid_parameter_transform (xform)
8614 char *xform;
8615 {
8616 if (xform[1])
8617 return 0;
8618
8619 /* check for valid values of xform[0] */
8620 switch (xform[0])
8621 {
8622 case 'a': /* expand to a string with just attributes */
8623 case 'A': /* expand as an assignment statement with attributes */
8624 case 'K': /* expand assoc array to list of key/value pairs */
8625 case 'k': /* XXX - for now */
8626 case 'E': /* expand like $'...' */
8627 case 'P': /* expand like prompt string */
8628 case 'Q': /* quote reusably */
8629 case 'U': /* transform to uppercase */
8630 case 'u': /* transform by capitalizing */
8631 case 'L': /* transform to lowercase */
8632 return 1;
8633 default:
8634 return 0;
8635 }
8636 }
8637
8638 static char *
8639 parameter_brace_transform (varname, value, estatep, xform, rtype, quoted, pflags, flags)
8640 char *varname, *value;
8641 array_eltstate_t *estatep;
8642 char *xform;
8643 int rtype, quoted, pflags, flags;
8644 {
8645 int vtype, xc, starsub;
8646 char *temp1, *val, *oname;
8647 SHELL_VAR *v;
8648
8649 xc = xform[0];
8650 if (value == 0 && xc != 'A' && xc != 'a')
8651 return ((char *)NULL);
8652
8653 oname = this_command_name;
8654 this_command_name = varname;
8655
8656 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
8657 if (vtype == -1)
8658 {
8659 this_command_name = oname;
8660 return ((char *)NULL);
8661 }
8662
8663 if (xform[0] == 0 || valid_parameter_transform (xform) == 0)
8664 {
8665 this_command_name = oname;
8666 if (vtype == VT_VARIABLE)
8667 FREE (val);
8668 return (interactive_shell ? &expand_param_error : &expand_param_fatal);
8669 }
8670
8671 starsub = vtype & VT_STARSUB;
8672 vtype &= ~VT_STARSUB;
8673
8674 /* If we are asked to display the attributes of an unset variable, V will
8675 be NULL after the call to get_var_and_type. Double-check here. */
8676 if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0)
8677 v = find_variable (varname);
8678
8679 temp1 = (char *)NULL; /* shut up gcc */
8680 switch (vtype)
8681 {
8682 case VT_VARIABLE:
8683 case VT_ARRAYMEMBER:
8684 temp1 = string_transform (xc, v, val);
8685 if (vtype == VT_VARIABLE)
8686 FREE (val);
8687 if (temp1)
8688 {
8689 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8690 ? quote_string (temp1)
8691 : quote_escapes (temp1);
8692 free (temp1);
8693 temp1 = val;
8694 }
8695 break;
8696 #if defined (ARRAY_VARS)
8697 case VT_ARRAYVAR:
8698 temp1 = array_transform (xc, v, starsub, quoted);
8699 if (temp1 && quoted == 0 && ifs_is_null)
8700 {
8701 /* Posix interp 888 */
8702 }
8703 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
8704 {
8705 val = quote_escapes (temp1);
8706 free (temp1);
8707 temp1 = val;
8708 }
8709 break;
8710 #endif
8711 case VT_POSPARMS:
8712 temp1 = parameter_list_transform (xc, varname[0], quoted);
8713 if (temp1 && quoted == 0 && ifs_is_null)
8714 {
8715 /* Posix interp 888 */
8716 }
8717 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
8718 {
8719 val = quote_escapes (temp1);
8720 free (temp1);
8721 temp1 = val;
8722 }
8723 break;
8724 }
8725
8726 this_command_name = oname;
8727 return temp1;
8728 }
8729
8730 /******************************************************/
8731 /* */
8732 /* Functions to extract substrings of variable values */
8733 /* */
8734 /******************************************************/
8735
8736 #if defined (HANDLE_MULTIBYTE)
8737 /* Character-oriented rather than strictly byte-oriented substrings. S and
8738 E, rather being strict indices into STRING, indicate character (possibly
8739 multibyte character) positions that require calculation.
8740 Used by the ${param:offset[:length]} expansion. */
8741 static char *
8742 mb_substring (string, s, e)
8743 char *string;
8744 int s, e;
8745 {
8746 char *tt;
8747 int start, stop, i;
8748 size_t slen;
8749 DECLARE_MBSTATE;
8750
8751 start = 0;
8752 /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
8753 slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
8754
8755 i = s;
8756 while (string[start] && i--)
8757 ADVANCE_CHAR (string, slen, start);
8758 stop = start;
8759 i = e - s;
8760 while (string[stop] && i--)
8761 ADVANCE_CHAR (string, slen, stop);
8762 tt = substring (string, start, stop);
8763 return tt;
8764 }
8765 #endif
8766
8767 /* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
8768 is `@', use the positional parameters; otherwise, use the value of
8769 VARNAME. If VARNAME is an array variable, use the array elements. */
8770
8771 static char *
8772 parameter_brace_substring (varname, value, estatep, substr, quoted, pflags, flags)
8773 char *varname, *value;
8774 array_eltstate_t *estatep;
8775 char *substr;
8776 int quoted, pflags, flags;
8777 {
8778 intmax_t e1, e2;
8779 int vtype, r, starsub;
8780 char *temp, *val, *tt, *oname;
8781 SHELL_VAR *v;
8782
8783 if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1]))
8784 return ((char *)NULL);
8785
8786 oname = this_command_name;
8787 this_command_name = varname;
8788
8789 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
8790 if (vtype == -1)
8791 {
8792 this_command_name = oname;
8793 return ((char *)NULL);
8794 }
8795
8796 starsub = vtype & VT_STARSUB;
8797 vtype &= ~VT_STARSUB;
8798
8799 r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
8800 this_command_name = oname;
8801 if (r <= 0)
8802 {
8803 if (vtype == VT_VARIABLE)
8804 FREE (val);
8805 return ((r == 0) ? &expand_param_error : (char *)NULL);
8806 }
8807
8808 switch (vtype)
8809 {
8810 case VT_VARIABLE:
8811 case VT_ARRAYMEMBER:
8812 #if defined (HANDLE_MULTIBYTE)
8813 if (MB_CUR_MAX > 1)
8814 tt = mb_substring (val, e1, e2);
8815 else
8816 #endif
8817 tt = substring (val, e1, e2);
8818
8819 if (vtype == VT_VARIABLE)
8820 FREE (val);
8821 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8822 temp = quote_string (tt);
8823 else
8824 temp = tt ? quote_escapes (tt) : (char *)NULL;
8825 FREE (tt);
8826 break;
8827 case VT_POSPARMS:
8828 case VT_ARRAYVAR:
8829 if (vtype == VT_POSPARMS)
8830 tt = pos_params (varname, e1, e2, quoted, pflags);
8831 #if defined (ARRAY_VARS)
8832 /* assoc_subrange and array_subrange both call string_list_pos_params,
8833 so we can treat this case just like VT_POSPARAMS. */
8834 else if (assoc_p (v))
8835 /* we convert to list and take first e2 elements starting at e1th
8836 element -- officially undefined for now */
8837 tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags);
8838 else
8839 /* We want E2 to be the number of elements desired (arrays can be
8840 sparse, so verify_substring_values just returns the numbers
8841 specified and we rely on array_subrange to understand how to
8842 deal with them). */
8843 tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags);
8844 #endif
8845 /* We want to leave this alone in every case where pos_params/
8846 string_list_pos_params quotes the list members */
8847 if (tt && quoted == 0 && ifs_is_null)
8848 {
8849 temp = tt; /* Posix interp 888 */
8850 }
8851 else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS))
8852 {
8853 temp = tt; /* Posix interp 888 */
8854 }
8855 else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
8856 {
8857 temp = tt ? quote_escapes (tt) : (char *)NULL;
8858 FREE (tt);
8859 }
8860 else
8861 temp = tt;
8862 break;
8863
8864 default:
8865 temp = (char *)NULL;
8866 }
8867
8868 return temp;
8869 }
8870
8871 /****************************************************************/
8872 /* */
8873 /* Functions to perform pattern substitution on variable values */
8874 /* */
8875 /****************************************************************/
8876
8877 static int
8878 shouldexp_replacement (s)
8879 char *s;
8880 {
8881 size_t slen;
8882 int sindex, c;
8883 DECLARE_MBSTATE;
8884
8885 sindex = 0;
8886 slen = STRLEN (s);
8887 while (c = s[sindex])
8888 {
8889 if (c == '\\')
8890 {
8891 sindex++;
8892 if (s[sindex] == 0)
8893 return 0;
8894 /* We want to remove this backslash because we treat it as special
8895 in this context. THIS ASSUMES THE STRING IS PROCESSED BY
8896 strcreplace() OR EQUIVALENT that handles removing backslashes
8897 preceding the special character. */
8898 if (s[sindex] == '&')
8899 return 1;
8900 if (s[sindex] == '\\')
8901 return 1;
8902 }
8903 else if (c == '&')
8904 return 1;
8905 ADVANCE_CHAR (s, slen, sindex);
8906 }
8907 return 0;
8908 }
8909
8910 char *
8911 pat_subst (string, pat, rep, mflags)
8912 char *string, *pat, *rep;
8913 int mflags;
8914 {
8915 char *ret, *s, *e, *str, *rstr, *mstr, *send;
8916 int rptr, mtype, rxpand, mlen;
8917 size_t rsize, l, replen, rslen;
8918 DECLARE_MBSTATE;
8919
8920 if (string == 0)
8921 return (savestring (""));
8922
8923 mtype = mflags & MATCH_TYPEMASK;
8924 rxpand = mflags & MATCH_EXPREP;
8925
8926 /* Special cases:
8927 * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
8928 * with REP and return the result.
8929 * 2. A null pattern with mtype == MATCH_END means to append REP to
8930 * STRING and return the result.
8931 * 3. A null STRING with a matching pattern means to append REP to
8932 * STRING and return the result.
8933 *
8934 * These process `&' in the replacement string, like `sed' does when
8935 * presented with a BRE of `^' or `$'.
8936 */
8937 if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
8938 {
8939 rstr = (mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2) : rep;
8940 rslen = STRLEN (rstr);
8941 l = STRLEN (string);
8942 ret = (char *)xmalloc (rslen + l + 2);
8943 if (rslen == 0)
8944 strcpy (ret, string);
8945 else if (mtype == MATCH_BEG)
8946 {
8947 strcpy (ret, rstr);
8948 strcpy (ret + rslen, string);
8949 }
8950 else
8951 {
8952 strcpy (ret, string);
8953 strcpy (ret + l, rstr);
8954 }
8955 if (rstr != rep)
8956 free (rstr);
8957 return (ret);
8958 }
8959 else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
8960 return ((mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2) : savestring (rep));
8961
8962 ret = (char *)xmalloc (rsize = 64);
8963 ret[0] = '\0';
8964 send = string + strlen (string);
8965
8966 for (replen = STRLEN (rep), rptr = 0, str = string; *str;)
8967 {
8968 if (match_pattern (str, pat, mtype, &s, &e) == 0)
8969 break;
8970 l = s - str;
8971
8972 if (rep && rxpand)
8973 {
8974 int x;
8975 mlen = e - s;
8976 mstr = xmalloc (mlen + 1);
8977 for (x = 0; x < mlen; x++)
8978 mstr[x] = s[x];
8979 mstr[mlen] = '\0';
8980 rstr = strcreplace (rep, '&', mstr, 2);
8981 free (mstr);
8982 rslen = strlen (rstr);
8983 }
8984 else
8985 {
8986 rstr = rep;
8987 rslen = replen;
8988 }
8989
8990 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
8991
8992 /* OK, now copy the leading unmatched portion of the string (from
8993 str to s) to ret starting at rptr (the current offset). Then copy
8994 the replacement string at ret + rptr + (s - str). Increment
8995 rptr (if necessary) and str and go on. */
8996 if (l)
8997 {
8998 strncpy (ret + rptr, str, l);
8999 rptr += l;
9000 }
9001 if (replen)
9002 {
9003 strncpy (ret + rptr, rstr, rslen);
9004 rptr += rslen;
9005 }
9006 str = e; /* e == end of match */
9007
9008 if (rstr != rep)
9009 free (rstr);
9010
9011 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
9012 break;
9013
9014 if (s == e)
9015 {
9016 /* On a zero-length match, make sure we copy one character, since
9017 we increment one character to avoid infinite recursion. */
9018 char *p, *origp, *origs;
9019 size_t clen;
9020
9021 RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64);
9022 #if defined (HANDLE_MULTIBYTE)
9023 p = origp = ret + rptr;
9024 origs = str;
9025 COPY_CHAR_P (p, str, send);
9026 rptr += p - origp;
9027 e += str - origs;
9028 #else
9029 ret[rptr++] = *str++;
9030 e++; /* avoid infinite recursion on zero-length match */
9031 #endif
9032 }
9033 }
9034
9035 /* Now copy the unmatched portion of the input string */
9036 if (str && *str)
9037 {
9038 l = send - str + 1;
9039 RESIZE_MALLOCED_BUFFER (ret, rptr, l, rsize, 64);
9040 strcpy (ret + rptr, str);
9041 }
9042 else
9043 ret[rptr] = '\0';
9044
9045 return ret;
9046 }
9047
9048 /* Do pattern match and replacement on the positional parameters. */
9049 static char *
9050 pos_params_pat_subst (string, pat, rep, mflags)
9051 char *string, *pat, *rep;
9052 int mflags;
9053 {
9054 WORD_LIST *save, *params;
9055 WORD_DESC *w;
9056 char *ret;
9057 int pchar, qflags, pflags;
9058
9059 save = params = list_rest_of_args ();
9060 if (save == 0)
9061 return ((char *)NULL);
9062
9063 for ( ; params; params = params->next)
9064 {
9065 ret = pat_subst (params->word->word, pat, rep, mflags);
9066 w = alloc_word_desc ();
9067 w->word = ret ? ret : savestring ("");
9068 dispose_word (params->word);
9069 params->word = w;
9070 }
9071
9072 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
9073 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
9074 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
9075
9076 /* If we are expanding in a context where word splitting will not be
9077 performed, treat as quoted. This changes how $* will be expanded. */
9078 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null)
9079 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
9080
9081 ret = string_list_pos_params (pchar, save, qflags, pflags);
9082 dispose_words (save);
9083
9084 return (ret);
9085 }
9086
9087 /* Perform pattern substitution on VALUE, which is the expansion of
9088 VARNAME. PATSUB is an expression supplying the pattern to match
9089 and the string to substitute. QUOTED is a flags word containing
9090 the type of quoting currently in effect. */
9091 static char *
9092 parameter_brace_patsub (varname, value, estatep, patsub, quoted, pflags, flags)
9093 char *varname, *value;
9094 array_eltstate_t *estatep;
9095 char *patsub;
9096 int quoted, pflags, flags;
9097 {
9098 int vtype, mflags, starsub, delim;
9099 char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname;
9100 SHELL_VAR *v;
9101
9102 if (value == 0)
9103 return ((char *)NULL);
9104
9105 oname = this_command_name;
9106 this_command_name = varname; /* error messages */
9107
9108 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
9109 if (vtype == -1)
9110 {
9111 this_command_name = oname;
9112 return ((char *)NULL);
9113 }
9114
9115 starsub = vtype & VT_STARSUB;
9116 vtype &= ~VT_STARSUB;
9117
9118 mflags = 0;
9119 /* PATSUB is never NULL when this is called. */
9120 if (*patsub == '/')
9121 {
9122 mflags |= MATCH_GLOBREP;
9123 patsub++;
9124 }
9125
9126 /* Malloc this because expand_string_if_necessary or one of the expansion
9127 functions in its call chain may free it on a substitution error. */
9128 lpatsub = savestring (patsub);
9129
9130 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9131 mflags |= MATCH_QUOTED;
9132
9133 if (starsub)
9134 mflags |= MATCH_STARSUB;
9135
9136 if (pflags & PF_ASSIGNRHS)
9137 mflags |= MATCH_ASSIGNRHS;
9138
9139 /* If the pattern starts with a `/', make sure we skip over it when looking
9140 for the replacement delimiter. */
9141 delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
9142 if (lpatsub[delim] == '/')
9143 {
9144 lpatsub[delim] = 0;
9145 rep = lpatsub + delim + 1;
9146 }
9147 else
9148 rep = (char *)NULL;
9149
9150 if (rep && *rep == '\0')
9151 rep = (char *)NULL;
9152
9153 /* Perform the same expansions on the pattern as performed by the
9154 pattern removal expansions. */
9155 pat = getpattern (lpatsub, quoted, 1);
9156
9157 if (rep)
9158 {
9159 /* We want to perform quote removal on the expanded replacement even if
9160 the entire expansion is double-quoted because the parser and string
9161 extraction functions treated quotes in the replacement string as
9162 special. THIS IS NOT BACKWARDS COMPATIBLE WITH BASH-4.2. */
9163 if (shell_compatibility_level > 42 && patsub_replacement == 0)
9164 rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
9165 else if (shell_compatibility_level > 42 && patsub_replacement)
9166 rep = expand_string_for_patsub (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT));
9167 /* This is the bash-4.2 code. */
9168 else if ((mflags & MATCH_QUOTED) == 0)
9169 rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
9170 else
9171 rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
9172
9173 /* Check whether or not to replace `&' in the replacement string after
9174 expanding it, since we want to treat backslashes quoting the `&'
9175 consistently. */
9176 if (patsub_replacement && rep && *rep && shouldexp_replacement (rep))
9177 mflags |= MATCH_EXPREP;
9178
9179 }
9180
9181 /* ksh93 doesn't allow the match specifier to be a part of the expanded
9182 pattern. This is an extension. Make sure we don't anchor the pattern
9183 at the beginning or end of the string if we're doing global replacement,
9184 though. */
9185 p = pat;
9186 if (mflags & MATCH_GLOBREP)
9187 mflags |= MATCH_ANY;
9188 else if (pat && pat[0] == '#')
9189 {
9190 mflags |= MATCH_BEG;
9191 p++;
9192 }
9193 else if (pat && pat[0] == '%')
9194 {
9195 mflags |= MATCH_END;
9196 p++;
9197 }
9198 else
9199 mflags |= MATCH_ANY;
9200
9201 /* OK, we now want to substitute REP for PAT in VAL. If
9202 flags & MATCH_GLOBREP is non-zero, the substitution is done
9203 everywhere, otherwise only the first occurrence of PAT is
9204 replaced. The pattern matching code doesn't understand
9205 CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
9206 values passed in (VT_VARIABLE) so the pattern substitution
9207 code works right. We need to requote special chars after
9208 we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
9209 other cases if QUOTED == 0, since the posparams and arrays
9210 indexed by * or @ do special things when QUOTED != 0. */
9211
9212 switch (vtype)
9213 {
9214 case VT_VARIABLE:
9215 case VT_ARRAYMEMBER:
9216 temp = pat_subst (val, p, rep, mflags);
9217 if (vtype == VT_VARIABLE)
9218 FREE (val);
9219 if (temp)
9220 {
9221 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
9222 free (temp);
9223 temp = tt;
9224 }
9225 break;
9226 case VT_POSPARMS:
9227 /* This does the right thing for the case where we are not performing
9228 word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and
9229 pos_params_pat_subst/string_list_pos_params will do the right thing
9230 in turn for the case where ifs_is_null. Posix interp 888 */
9231 if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB))
9232 mflags |= MATCH_ASSIGNRHS;
9233 temp = pos_params_pat_subst (val, p, rep, mflags);
9234 if (temp && quoted == 0 && ifs_is_null)
9235 {
9236 /* Posix interp 888 */
9237 }
9238 else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS))
9239 {
9240 /* Posix interp 888 */
9241 }
9242 else if (temp && (mflags & MATCH_QUOTED) == 0)
9243 {
9244 tt = quote_escapes (temp);
9245 free (temp);
9246 temp = tt;
9247 }
9248 break;
9249 #if defined (ARRAY_VARS)
9250 case VT_ARRAYVAR:
9251 /* If we are expanding in a context where word splitting will not be
9252 performed, treat as quoted. This changes how ${A[*]} will be
9253 expanded to make it identical to $*. */
9254 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9255 mflags |= MATCH_QUOTED; /* Posix interp 888 */
9256
9257 /* these eventually call string_list_pos_params */
9258 if (assoc_p (v))
9259 temp = assoc_patsub (assoc_cell (v), p, rep, mflags);
9260 else
9261 temp = array_patsub (array_cell (v), p, rep, mflags);
9262
9263 if (temp && quoted == 0 && ifs_is_null)
9264 {
9265 /* Posix interp 888 */
9266 }
9267 else if (temp && (mflags & MATCH_QUOTED) == 0)
9268 {
9269 tt = quote_escapes (temp);
9270 free (temp);
9271 temp = tt;
9272 }
9273 break;
9274 #endif
9275 }
9276
9277 FREE (pat);
9278 FREE (rep);
9279 free (lpatsub);
9280
9281 this_command_name = oname;
9282
9283 return temp;
9284 }
9285
9286 /****************************************************************/
9287 /* */
9288 /* Functions to perform case modification on variable values */
9289 /* */
9290 /****************************************************************/
9291
9292 /* Do case modification on the positional parameters. */
9293
9294 static char *
9295 pos_params_modcase (string, pat, modop, mflags)
9296 char *string, *pat;
9297 int modop;
9298 int mflags;
9299 {
9300 WORD_LIST *save, *params;
9301 WORD_DESC *w;
9302 char *ret;
9303 int pchar, qflags, pflags;
9304
9305 save = params = list_rest_of_args ();
9306 if (save == 0)
9307 return ((char *)NULL);
9308
9309 for ( ; params; params = params->next)
9310 {
9311 ret = sh_modcase (params->word->word, pat, modop);
9312 w = alloc_word_desc ();
9313 w->word = ret ? ret : savestring ("");
9314 dispose_word (params->word);
9315 params->word = w;
9316 }
9317
9318 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
9319 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
9320 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
9321
9322 /* If we are expanding in a context where word splitting will not be
9323 performed, treat as quoted. This changes how $* will be expanded. */
9324 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9325 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
9326
9327 ret = string_list_pos_params (pchar, save, qflags, pflags);
9328 dispose_words (save);
9329
9330 return (ret);
9331 }
9332
9333 /* Perform case modification on VALUE, which is the expansion of
9334 VARNAME. MODSPEC is an expression supplying the type of modification
9335 to perform. QUOTED is a flags word containing the type of quoting
9336 currently in effect. */
9337 static char *
9338 parameter_brace_casemod (varname, value, estatep, modspec, patspec, quoted, pflags, flags)
9339 char *varname, *value;
9340 array_eltstate_t *estatep;
9341 int modspec;
9342 char *patspec;
9343 int quoted, pflags, flags;
9344 {
9345 int vtype, starsub, modop, mflags, x;
9346 char *val, *temp, *pat, *p, *lpat, *tt, *oname;
9347 SHELL_VAR *v;
9348
9349 if (value == 0)
9350 return ((char *)NULL);
9351
9352 oname = this_command_name;
9353 this_command_name = varname;
9354
9355 vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
9356 if (vtype == -1)
9357 {
9358 this_command_name = oname;
9359 return ((char *)NULL);
9360 }
9361
9362 starsub = vtype & VT_STARSUB;
9363 vtype &= ~VT_STARSUB;
9364
9365 modop = 0;
9366 mflags = 0;
9367 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9368 mflags |= MATCH_QUOTED;
9369 if (starsub)
9370 mflags |= MATCH_STARSUB;
9371 if (pflags & PF_ASSIGNRHS)
9372 mflags |= MATCH_ASSIGNRHS;
9373
9374 p = patspec;
9375 if (modspec == '^')
9376 {
9377 x = p && p[0] == modspec;
9378 modop = x ? CASE_UPPER : CASE_UPFIRST;
9379 p += x;
9380 }
9381 else if (modspec == ',')
9382 {
9383 x = p && p[0] == modspec;
9384 modop = x ? CASE_LOWER : CASE_LOWFIRST;
9385 p += x;
9386 }
9387 else if (modspec == '~')
9388 {
9389 x = p && p[0] == modspec;
9390 modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
9391 p += x;
9392 }
9393
9394 lpat = p ? savestring (p) : 0;
9395 /* Perform the same expansions on the pattern as performed by the
9396 pattern removal expansions. */
9397 pat = lpat ? getpattern (lpat, quoted, 1) : 0;
9398
9399 /* OK, now we do the case modification. */
9400 switch (vtype)
9401 {
9402 case VT_VARIABLE:
9403 case VT_ARRAYMEMBER:
9404 temp = sh_modcase (val, pat, modop);
9405 if (vtype == VT_VARIABLE)
9406 FREE (val);
9407 if (temp)
9408 {
9409 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
9410 free (temp);
9411 temp = tt;
9412 }
9413 break;
9414
9415 case VT_POSPARMS:
9416 temp = pos_params_modcase (val, pat, modop, mflags);
9417 if (temp && quoted == 0 && ifs_is_null)
9418 {
9419 /* Posix interp 888 */
9420 }
9421 else if (temp && (mflags & MATCH_QUOTED) == 0)
9422 {
9423 tt = quote_escapes (temp);
9424 free (temp);
9425 temp = tt;
9426 }
9427 break;
9428
9429 #if defined (ARRAY_VARS)
9430 case VT_ARRAYVAR:
9431 /* If we are expanding in a context where word splitting will not be
9432 performed, treat as quoted. This changes how ${A[*]} will be
9433 expanded to make it identical to $*. */
9434 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
9435 mflags |= MATCH_QUOTED; /* Posix interp 888 */
9436
9437 temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
9438 : array_modcase (array_cell (v), pat, modop, mflags);
9439
9440 if (temp && quoted == 0 && ifs_is_null)
9441 {
9442 /* Posix interp 888 */
9443 }
9444 else if (temp && (mflags & MATCH_QUOTED) == 0)
9445 {
9446 tt = quote_escapes (temp);
9447 free (temp);
9448 temp = tt;
9449 }
9450
9451 break;
9452 #endif
9453 }
9454
9455 FREE (pat);
9456 free (lpat);
9457
9458 this_command_name = oname;
9459
9460 return temp;
9461 }
9462
9463 /* Check for unbalanced parens in S, which is the contents of $(( ... )). If
9464 any occur, this must be a nested command substitution, so return 0.
9465 Otherwise, return 1. A valid arithmetic expression must always have a
9466 ( before a matching ), so any cases where there are more right parens
9467 means that this must not be an arithmetic expression, though the parser
9468 will not accept it without a balanced total number of parens. */
9469 static int
9470 chk_arithsub (s, len)
9471 const char *s;
9472 int len;
9473 {
9474 int i, count;
9475 DECLARE_MBSTATE;
9476
9477 i = count = 0;
9478 while (i < len)
9479 {
9480 if (s[i] == LPAREN)
9481 count++;
9482 else if (s[i] == RPAREN)
9483 {
9484 count--;
9485 if (count < 0)
9486 return 0;
9487 }
9488
9489 switch (s[i])
9490 {
9491 default:
9492 ADVANCE_CHAR (s, len, i);
9493 break;
9494
9495 case '\\':
9496 i++;
9497 if (s[i])
9498 ADVANCE_CHAR (s, len, i);
9499 break;
9500
9501 case '\'':
9502 i = skip_single_quoted (s, len, ++i, 0);
9503 break;
9504
9505 case '"':
9506 i = skip_double_quoted ((char *)s, len, ++i, 0);
9507 break;
9508 }
9509 }
9510
9511 return (count == 0);
9512 }
9513
9514 /****************************************************************/
9515 /* */
9516 /* Functions to perform parameter expansion on a string */
9517 /* */
9518 /****************************************************************/
9519
9520 /* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
9521 static WORD_DESC *
9522 parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
9523 char *string;
9524 int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at;
9525 {
9526 int check_nullness, var_is_set, var_is_null, var_is_special;
9527 int want_substring, want_indir, want_patsub, want_casemod, want_attributes;
9528 char *name, *value, *temp, *temp1;
9529 WORD_DESC *tdesc, *ret;
9530 int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref;
9531 intmax_t number;
9532 array_eltstate_t es;
9533
9534 temp = temp1 = value = (char *)NULL;
9535 var_is_set = var_is_null = var_is_special = check_nullness = 0;
9536 want_substring = want_indir = want_patsub = want_casemod = want_attributes = 0;
9537
9538 local_pflags = 0;
9539 all_element_arrayref = 0;
9540
9541 sindex = *indexp;
9542 t_index = ++sindex;
9543 /* ${#var} doesn't have any of the other parameter expansions on it. */
9544 if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
9545 name = string_extract (string, &t_index, "}", SX_VARNAME);
9546 else
9547 #if defined (CASEMOD_EXPANSIONS)
9548 /* To enable case-toggling expansions using the `~' operator character
9549 define CASEMOD_TOGGLECASE in config-top.h */
9550 # if defined (CASEMOD_TOGGLECASE)
9551 name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME);
9552 # else
9553 name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME);
9554 # endif /* CASEMOD_TOGGLECASE */
9555 #else
9556 name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME);
9557 #endif /* CASEMOD_EXPANSIONS */
9558
9559 /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly
9560 the cleanest code ever. */
9561 if (*name == 0 && sindex == t_index && string[sindex] == '@')
9562 {
9563 name = (char *)xrealloc (name, 2);
9564 name[0] = '@';
9565 name[1] = '\0';
9566 t_index++;
9567 }
9568 else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE)
9569 {
9570 name = (char *)xrealloc (name, t_index - sindex + 2);
9571 name[t_index - sindex] = '@';
9572 name[t_index - sindex + 1] = '\0';
9573 t_index++;
9574 }
9575
9576 ret = 0;
9577 tflag = 0;
9578
9579 #if defined (ARRAY_VARS)
9580 init_eltstate (&es);
9581 #endif
9582 es.ind = INTMAX_MIN; /* XXX */
9583
9584 /* If the name really consists of a special variable, then make sure
9585 that we have the entire name. We don't allow indirect references
9586 to special variables except `#', `?', `@' and `*'. This clause is
9587 designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more
9588 general. */
9589 if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
9590 (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) ||
9591 (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
9592 {
9593 t_index++;
9594 temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0);
9595 name = (char *)xrealloc (name, 3 + (strlen (temp1)));
9596 *name = string[sindex];
9597 if (string[sindex] == '!')
9598 {
9599 /* indirect reference of $#, $?, $@, or $* */
9600 name[1] = string[sindex + 1];
9601 strcpy (name + 2, temp1);
9602 }
9603 else
9604 strcpy (name + 1, temp1);
9605 free (temp1);
9606 }
9607 sindex = t_index;
9608
9609 /* Find out what character ended the variable name. Then
9610 do the appropriate thing. */
9611 if (c = string[sindex])
9612 sindex++;
9613
9614 /* If c is followed by one of the valid parameter expansion
9615 characters, move past it as normal. If not, assume that
9616 a substring specification is being given, and do not move
9617 past it. */
9618 if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
9619 {
9620 check_nullness++;
9621 if (c = string[sindex])
9622 sindex++;
9623 }
9624 else if (c == ':' && string[sindex] != RBRACE)
9625 want_substring = 1;
9626 else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */
9627 want_patsub = 1;
9628 #if defined (CASEMOD_EXPANSIONS)
9629 else if (c == '^' || c == ',' || c == '~')
9630 {
9631 modspec = c;
9632 want_casemod = 1;
9633 }
9634 #endif
9635 else if (c == '@' && (string[sindex] == 'a' || string[sindex] == 'A') && string[sindex+1] == RBRACE)
9636 {
9637 /* special case because we do not want to shortcut foo as foo[0] here */
9638 want_attributes = 1;
9639 local_pflags |= PF_ALLINDS;
9640 }
9641
9642 /* Catch the valid and invalid brace expressions that made it through the
9643 tests above. */
9644 /* ${#-} is a valid expansion and means to take the length of $-.
9645 Similarly for ${#?} and ${##}... */
9646 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
9647 VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
9648 {
9649 name = (char *)xrealloc (name, 3);
9650 name[1] = c;
9651 name[2] = '\0';
9652 c = string[sindex++];
9653 }
9654
9655 /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
9656 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
9657 member (c, "%:=+/") && string[sindex] == RBRACE)
9658 {
9659 temp = (char *)NULL;
9660 goto bad_substitution; /* XXX - substitution error */
9661 }
9662
9663 /* Indirect expansion begins with a `!'. A valid indirect expansion is
9664 either a variable name, one of the positional parameters or a special
9665 variable that expands to one of the positional parameters. */
9666 want_indir = *name == '!' &&
9667 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
9668 || VALID_INDIR_PARAM (name[1]));
9669
9670 /* Determine the value of this variable whose name is NAME. */
9671
9672 /* Check for special variables, directly referenced. */
9673 if (SPECIAL_VAR (name, want_indir))
9674 var_is_special++;
9675
9676 /* Check for special expansion things, like the length of a parameter */
9677 if (*name == '#' && name[1])
9678 {
9679 /* If we are not pointing at the character just after the
9680 closing brace, then we haven't gotten all of the name.
9681 Since it begins with a special character, this is a bad
9682 substitution. Also check NAME for validity before trying
9683 to go on. */
9684 if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
9685 {
9686 temp = (char *)NULL;
9687 goto bad_substitution; /* substitution error */
9688 }
9689
9690 number = parameter_brace_expand_length (name);
9691 if (number == INTMAX_MIN && unbound_vars_is_error)
9692 {
9693 set_exit_status (EXECUTION_FAILURE);
9694 err_unboundvar (name+1);
9695 free (name);
9696 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9697 }
9698 free (name);
9699
9700 *indexp = sindex;
9701 if (number < 0)
9702 return (&expand_wdesc_error);
9703 else
9704 {
9705 ret = alloc_word_desc ();
9706 ret->word = itos (number);
9707 return ret;
9708 }
9709 }
9710
9711 /* ${@} is identical to $@. */
9712 if (name[0] == '@' && name[1] == '\0')
9713 {
9714 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9715 *quoted_dollar_atp = 1;
9716
9717 if (contains_dollar_at)
9718 *contains_dollar_at = 1;
9719
9720 tflag |= W_DOLLARAT;
9721 }
9722
9723 /* Process ${!PREFIX*} expansion. */
9724 if (want_indir && string[sindex - 1] == RBRACE &&
9725 (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
9726 legal_variable_starter ((unsigned char) name[1]))
9727 {
9728 char **x;
9729 WORD_LIST *xlist;
9730
9731 temp1 = savestring (name + 1);
9732 number = strlen (temp1);
9733 temp1[number - 1] = '\0';
9734 x = all_variables_matching_prefix (temp1);
9735 xlist = strvec_to_word_list (x, 0, 0);
9736 if (string[sindex - 2] == '*')
9737 temp = string_list_dollar_star (xlist, quoted, 0);
9738 else
9739 {
9740 temp = string_list_dollar_at (xlist, quoted, 0);
9741 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9742 *quoted_dollar_atp = 1;
9743 if (contains_dollar_at)
9744 *contains_dollar_at = 1;
9745
9746 tflag |= W_DOLLARAT;
9747 }
9748 free (x);
9749 dispose_words (xlist);
9750 free (temp1);
9751 *indexp = sindex;
9752
9753 free (name);
9754
9755 ret = alloc_word_desc ();
9756 ret->word = temp;
9757 ret->flags = tflag; /* XXX */
9758 return ret;
9759 }
9760
9761 #if defined (ARRAY_VARS)
9762 /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */
9763 if (want_indir && string[sindex - 1] == RBRACE &&
9764 string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0))
9765 {
9766 char *x, *x1;
9767
9768 temp1 = savestring (name + 1);
9769 x = array_variable_name (temp1, 0, &x1, (int *)0);
9770 FREE (x);
9771 if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK)
9772 {
9773 temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */
9774 if (x1[0] == '@')
9775 {
9776 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9777 *quoted_dollar_atp = 1;
9778 if (contains_dollar_at)
9779 *contains_dollar_at = 1;
9780
9781 tflag |= W_DOLLARAT;
9782 }
9783
9784 free (name);
9785 free (temp1);
9786 *indexp = sindex;
9787
9788 ret = alloc_word_desc ();
9789 ret->word = temp;
9790 ret->flags = tflag; /* XXX */
9791 return ret;
9792 }
9793
9794 free (temp1);
9795 }
9796 #endif /* ARRAY_VARS */
9797
9798 /* Make sure that NAME is valid before trying to go on. */
9799 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
9800 var_is_special) == 0)
9801 {
9802 temp = (char *)NULL;
9803 goto bad_substitution; /* substitution error */
9804 }
9805
9806 if (want_indir)
9807 {
9808 tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags|local_pflags, quoted_dollar_atp, contains_dollar_at);
9809 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9810 {
9811 temp = (char *)NULL;
9812 goto bad_substitution;
9813 }
9814
9815 /* Turn off the W_ARRAYIND flag because there is no way for this function
9816 to return the index we're supposed to be using. */
9817 if (tdesc && tdesc->flags)
9818 tdesc->flags &= ~W_ARRAYIND;
9819
9820 /* If the indir expansion contains $@/$*, extend the special treatment
9821 of the case of no positional parameters and `set -u' to it. */
9822 if (contains_dollar_at && *contains_dollar_at)
9823 all_element_arrayref = 1;
9824 }
9825 else
9826 {
9827 local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS));
9828 tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &es);
9829 }
9830
9831 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9832 {
9833 tflag = 0;
9834 tdesc = 0;
9835 }
9836
9837 if (tdesc)
9838 {
9839 temp = tdesc->word;
9840 tflag = tdesc->flags;
9841 dispose_word_desc (tdesc);
9842 }
9843 else
9844 temp = (char *)0;
9845
9846 if (temp == &expand_param_error || temp == &expand_param_fatal)
9847 {
9848 FREE (name);
9849 FREE (value);
9850 return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9851 }
9852
9853 #if defined (ARRAY_VARS)
9854 if (valid_array_reference (name, 0))
9855 {
9856 int qflags;
9857 char *t;
9858
9859 qflags = quoted;
9860 /* If in a context where word splitting will not take place, treat as
9861 if double-quoted. Has effects with $* and ${array[*]} */
9862
9863 if (pflags & PF_ASSIGNRHS)
9864 qflags |= Q_DOUBLE_QUOTES;
9865 /* We duplicate a little code here */
9866 t = mbschr (name, LBRACK);
9867 if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK)
9868 {
9869 all_element_arrayref = 1;
9870 if (expand_no_split_dollar_star && t[1] == '*') /* XXX */
9871 qflags |= Q_DOUBLE_QUOTES;
9872 }
9873 chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at);
9874 }
9875 #endif
9876
9877 var_is_set = temp != (char *)0;
9878 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
9879 /* XXX - this may not need to be restricted to special variables */
9880 if (check_nullness)
9881 var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp);
9882 #if defined (ARRAY_VARS)
9883 if (check_nullness)
9884 var_is_null |= var_is_set &&
9885 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) &&
9886 QUOTED_NULL (temp) &&
9887 valid_array_reference (name, 0) &&
9888 chk_atstar (name, 0, 0, (int *)0, (int *)0);
9889 #endif
9890
9891 /* Get the rest of the stuff inside the braces. */
9892 if (c && c != RBRACE)
9893 {
9894 /* Extract the contents of the ${ ... } expansion
9895 according to the Posix.2 rules. */
9896 value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
9897 if (string[sindex] == RBRACE)
9898 sindex++;
9899 else
9900 goto bad_substitution; /* substitution error */
9901 }
9902 else
9903 value = (char *)NULL;
9904
9905 *indexp = sindex;
9906
9907 /* All the cases where an expansion can possibly generate an unbound
9908 variable error. */
9909 if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE)
9910 {
9911 if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0)
9912 {
9913 set_exit_status (EXECUTION_FAILURE);
9914 err_unboundvar (name);
9915 FREE (value);
9916 FREE (temp);
9917 free (name);
9918 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9919 }
9920 }
9921
9922 /* If this is a substring spec, process it and add the result. */
9923 if (want_substring)
9924 {
9925 temp1 = parameter_brace_substring (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9926 FREE (value);
9927 FREE (temp);
9928 #if defined (ARRAY_VARS)
9929 flush_eltstate (&es);
9930 #endif
9931
9932 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9933 {
9934 FREE (name);
9935 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9936 }
9937
9938 ret = alloc_word_desc ();
9939 ret->word = temp1;
9940 /* We test quoted_dollar_atp because we want variants with double-quoted
9941 "$@" to take a different code path. In fact, we make sure at the end
9942 of expand_word_internal that we're only looking at these flags if
9943 quoted_dollar_at == 0. */
9944 if (temp1 &&
9945 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9946 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9947 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9948 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 &&
9949 (pflags & PF_ASSIGNRHS))
9950 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9951 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9952 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9953 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9954
9955 FREE (name);
9956 return ret;
9957 }
9958 else if (want_patsub)
9959 {
9960 temp1 = parameter_brace_patsub (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9961 FREE (value);
9962 FREE (temp);
9963 #if defined (ARRAY_VARS)
9964 flush_eltstate (&es);
9965 #endif
9966
9967 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9968 {
9969 FREE (name);
9970 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9971 }
9972
9973 ret = alloc_word_desc ();
9974 ret->word = temp1;
9975 if (temp1 &&
9976 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9977 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9978 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9979 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9980 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9981 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9982
9983 FREE (name);
9984 return ret;
9985 }
9986 #if defined (CASEMOD_EXPANSIONS)
9987 else if (want_casemod)
9988 {
9989 temp1 = parameter_brace_casemod (name, temp, &es, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9990 FREE (value);
9991 FREE (temp);
9992 #if defined (ARRAY_VARS)
9993 flush_eltstate (&es);
9994 #endif
9995
9996 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9997 {
9998 FREE (name);
9999 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
10000 }
10001
10002 ret = alloc_word_desc ();
10003 ret->word = temp1;
10004 if (temp1 &&
10005 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
10006 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10007 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
10008 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10009 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10010 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10011
10012 FREE (name);
10013 return ret;
10014 }
10015 #endif
10016
10017 /* Do the right thing based on which character ended the variable name. */
10018 switch (c)
10019 {
10020 default:
10021 case '\0':
10022 bad_substitution:
10023 set_exit_status (EXECUTION_FAILURE);
10024 report_error (_("%s: bad substitution"), string ? string : "??");
10025 FREE (value);
10026 FREE (temp);
10027 free (name);
10028 #if defined (ARRAY_VARS)
10029 flush_eltstate (&es);
10030 #endif
10031 if (shell_compatibility_level <= 43)
10032 return &expand_wdesc_error;
10033 else
10034 return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error);
10035
10036 case RBRACE:
10037 break;
10038
10039 case '@':
10040 temp1 = parameter_brace_transform (name, temp, &es, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
10041 free (temp);
10042 free (value);
10043 #if defined (ARRAY_VARS)
10044 flush_eltstate (&es);
10045 #endif
10046
10047 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
10048 {
10049 free (name);
10050 set_exit_status (EXECUTION_FAILURE);
10051 report_error (_("%s: bad substitution"), string ? string : "??");
10052 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
10053 }
10054
10055 ret = alloc_word_desc ();
10056 ret->word = temp1;
10057 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10058 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
10059 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10060 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10061 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10062
10063 free (name);
10064 return ret;
10065
10066 case '#': /* ${param#[#]pattern} */
10067 case '%': /* ${param%[%]pattern} */
10068 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
10069 {
10070 FREE (value);
10071 break;
10072 }
10073 temp1 = parameter_brace_remove_pattern (name, temp, &es, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
10074 free (temp);
10075 free (value);
10076 #if defined (ARRAY_VARS)
10077 flush_eltstate (&es);
10078 #endif
10079
10080 ret = alloc_word_desc ();
10081 ret->word = temp1;
10082 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10083 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
10084 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
10085 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
10086 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
10087
10088 free (name);
10089 return ret;
10090
10091 case '-':
10092 case '=':
10093 case '?':
10094 case '+':
10095 if (var_is_set && var_is_null == 0)
10096 {
10097 /* If the operator is `+', we don't want the value of the named
10098 variable for anything, just the value of the right hand side. */
10099 if (c == '+')
10100 {
10101 /* XXX -- if we're double-quoted and the named variable is "$@",
10102 we want to turn off any special handling of "$@" --
10103 we're not using it, so whatever is on the rhs applies. */
10104 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
10105 *quoted_dollar_atp = 0;
10106 if (contains_dollar_at)
10107 *contains_dollar_at = 0;
10108
10109 FREE (temp);
10110 if (value)
10111 {
10112 /* From Posix discussion on austin-group list. Issue 221
10113 requires that backslashes escaping `}' inside
10114 double-quoted ${...} be removed. */
10115 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10116 quoted |= Q_DOLBRACE;
10117 ret = parameter_brace_expand_rhs (name, value, c,
10118 quoted,
10119 pflags,
10120 quoted_dollar_atp,
10121 contains_dollar_at);
10122 /* XXX - fix up later, esp. noting presence of
10123 W_HASQUOTEDNULL in ret->flags */
10124 free (value);
10125 }
10126 else
10127 temp = (char *)NULL;
10128 }
10129 else
10130 {
10131 FREE (value);
10132 }
10133 /* Otherwise do nothing; just use the value in TEMP. */
10134 }
10135 else /* VAR not set or VAR is NULL. */
10136 {
10137 /* If we're freeing a quoted null here, we need to remember we saw
10138 it so we can restore it later if needed, or the caller can note it.
10139 The check against `+' doesn't really matter, since the other cases
10140 don't use or return TFLAG, but it's good for clarity. */
10141 if (c == '+' && temp && QUOTED_NULL (temp) &&
10142 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
10143 tflag |= W_HASQUOTEDNULL;
10144
10145 FREE (temp);
10146 temp = (char *)NULL;
10147 if (c == '=' && var_is_special)
10148 {
10149 set_exit_status (EXECUTION_FAILURE);
10150 report_error (_("$%s: cannot assign in this way"), name);
10151 free (name);
10152 free (value);
10153 #if defined (ARRAY_VARS)
10154 flush_eltstate (&es);
10155 #endif
10156 return &expand_wdesc_error;
10157 }
10158 else if (c == '?')
10159 {
10160 parameter_brace_expand_error (name, value, check_nullness);
10161 #if defined (ARRAY_VARS)
10162 flush_eltstate (&es);
10163 #endif
10164 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10165 }
10166 else if (c != '+')
10167 {
10168 /* XXX -- if we're double-quoted and the named variable is "$@",
10169 we want to turn off any special handling of "$@" --
10170 we're not using it, so whatever is on the rhs applies. */
10171 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
10172 *quoted_dollar_atp = 0;
10173 if (contains_dollar_at)
10174 *contains_dollar_at = 0;
10175
10176 /* From Posix discussion on austin-group list. Issue 221 requires
10177 that backslashes escaping `}' inside double-quoted ${...} be
10178 removed. */
10179 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10180 quoted |= Q_DOLBRACE;
10181 ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags,
10182 quoted_dollar_atp,
10183 contains_dollar_at);
10184 /* XXX - fix up later, esp. noting presence of
10185 W_HASQUOTEDNULL in tdesc->flags */
10186 }
10187 free (value);
10188 }
10189
10190 break;
10191 }
10192 free (name);
10193 #if defined (ARRAY_VARS)
10194 flush_eltstate (&es);
10195 #endif
10196
10197 if (ret == 0)
10198 {
10199 ret = alloc_word_desc ();
10200 ret->flags = tflag;
10201 ret->word = temp;
10202 }
10203 return (ret);
10204 }
10205
10206 /* Expand a single ${xxx} expansion. The braces are optional. When
10207 the braces are used, parameter_brace_expand() does the work,
10208 possibly calling param_expand recursively. */
10209 static WORD_DESC *
10210 param_expand (string, sindex, quoted, expanded_something,
10211 contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
10212 pflags)
10213 char *string;
10214 int *sindex, quoted, *expanded_something, *contains_dollar_at;
10215 int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
10216 {
10217 char *temp, *temp1, uerror[3], *savecmd;
10218 int zindex, t_index, expok, eflag;
10219 unsigned char c;
10220 intmax_t number;
10221 SHELL_VAR *var;
10222 WORD_LIST *list, *l;
10223 WORD_DESC *tdesc, *ret;
10224 int tflag, nullarg;
10225
10226 /*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/
10227 zindex = *sindex;
10228 c = string[++zindex];
10229
10230 temp = (char *)NULL;
10231 ret = tdesc = (WORD_DESC *)NULL;
10232 tflag = 0;
10233
10234 /* Do simple cases first. Switch on what follows '$'. */
10235 switch (c)
10236 {
10237 /* $0 .. $9? */
10238 case '0':
10239 case '1':
10240 case '2':
10241 case '3':
10242 case '4':
10243 case '5':
10244 case '6':
10245 case '7':
10246 case '8':
10247 case '9':
10248 temp1 = dollar_vars[TODIGIT (c)];
10249 /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */
10250 if (unbound_vars_is_error && temp1 == (char *)NULL)
10251 {
10252 uerror[0] = '$';
10253 uerror[1] = c;
10254 uerror[2] = '\0';
10255 set_exit_status (EXECUTION_FAILURE);
10256 err_unboundvar (uerror);
10257 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10258 }
10259 if (temp1)
10260 temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10261 ? quote_string (temp1)
10262 : quote_escapes (temp1);
10263 else
10264 temp = (char *)NULL;
10265
10266 break;
10267
10268 /* $$ -- pid of the invoking shell. */
10269 case '$':
10270 temp = itos (dollar_dollar_pid);
10271 break;
10272
10273 /* $# -- number of positional parameters. */
10274 case '#':
10275 temp = itos (number_of_args ());
10276 break;
10277
10278 /* $? -- return value of the last synchronous command. */
10279 case '?':
10280 temp = itos (last_command_exit_value);
10281 break;
10282
10283 /* $- -- flags supplied to the shell on invocation or by `set'. */
10284 case '-':
10285 temp = which_set_flags ();
10286 break;
10287
10288 /* $! -- Pid of the last asynchronous command. */
10289 case '!':
10290 /* If no asynchronous pids have been created, expand to nothing.
10291 If `set -u' has been executed, and no async processes have
10292 been created, this is an expansion error. */
10293 if (last_asynchronous_pid == NO_PID)
10294 {
10295 if (expanded_something)
10296 *expanded_something = 0;
10297 temp = (char *)NULL;
10298 if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
10299 {
10300 uerror[0] = '$';
10301 uerror[1] = c;
10302 uerror[2] = '\0';
10303 set_exit_status (EXECUTION_FAILURE);
10304 err_unboundvar (uerror);
10305 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10306 }
10307 }
10308 else
10309 temp = itos (last_asynchronous_pid);
10310 break;
10311
10312 /* The only difference between this and $@ is when the arg is quoted. */
10313 case '*': /* `$*' */
10314 list = list_rest_of_args ();
10315
10316 #if 0
10317 /* According to austin-group posix proposal by Geoff Clare in
10318 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
10319
10320 "The shell shall write a message to standard error and
10321 immediately exit when it tries to expand an unset parameter
10322 other than the '@' and '*' special parameters."
10323 */
10324
10325 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
10326 {
10327 uerror[0] = '$';
10328 uerror[1] = '*';
10329 uerror[2] = '\0';
10330 set_exit_status (EXECUTION_FAILURE);
10331 err_unboundvar (uerror);
10332 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10333 }
10334 #endif
10335
10336 /* If there are no command-line arguments, this should just
10337 disappear if there are other characters in the expansion,
10338 even if it's quoted. */
10339 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
10340 temp = (char *)NULL;
10341 else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
10342 {
10343 /* If we have "$*" we want to make a string of the positional
10344 parameters, separated by the first character of $IFS, and
10345 quote the whole string, including the separators. If IFS
10346 is unset, the parameters are separated by ' '; if $IFS is
10347 null, the parameters are concatenated. */
10348 temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list);
10349 if (temp)
10350 {
10351 temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp;
10352 if (*temp == 0)
10353 tflag |= W_HASQUOTEDNULL;
10354 if (temp != temp1)
10355 free (temp);
10356 temp = temp1;
10357 }
10358 }
10359 else
10360 {
10361 /* We check whether or not we're eventually going to split $* here,
10362 for example when IFS is empty and we are processing the rhs of
10363 an assignment statement. In that case, we don't separate the
10364 arguments at all. Otherwise, if the $* is not quoted it is
10365 identical to $@ */
10366 if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS))
10367 {
10368 /* Posix interp 888: RHS of assignment, IFS unset: no splitting,
10369 separate with space */
10370 temp1 = string_list_dollar_star (list, quoted, pflags);
10371 temp = temp1 ? quote_string (temp1) : temp1;
10372 /* XXX - tentative - note that we saw a quoted null here */
10373 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
10374 tflag |= W_SAWQUOTEDNULL;
10375 FREE (temp1);
10376 }
10377 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS))
10378 {
10379 /* Posix interp 888: RHS of assignment, IFS set to '' */
10380 temp1 = string_list_dollar_star (list, quoted, pflags);
10381 temp = temp1 ? quote_escapes (temp1) : temp1;
10382 FREE (temp1);
10383 }
10384 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS))
10385 {
10386 /* Posix interp 888: RHS of assignment, IFS set to non-null value */
10387 temp1 = string_list_dollar_star (list, quoted, pflags);
10388 temp = temp1 ? quote_string (temp1) : temp1;
10389
10390 /* XXX - tentative - note that we saw a quoted null here */
10391 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
10392 tflag |= W_SAWQUOTEDNULL;
10393 FREE (temp1);
10394 }
10395 /* XXX - should we check ifs_is_set here as well? */
10396 # if defined (HANDLE_MULTIBYTE)
10397 else if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
10398 # else
10399 else if (expand_no_split_dollar_star && ifs_firstc == 0)
10400 # endif
10401 /* Posix interp 888: not RHS, no splitting, IFS set to '' */
10402 temp = string_list_dollar_star (list, quoted, 0);
10403 else
10404 {
10405 temp = string_list_dollar_at (list, quoted, 0);
10406 /* Set W_SPLITSPACE to make sure the individual positional
10407 parameters are split into separate arguments */
10408 #if 0
10409 if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null))
10410 #else /* change with bash-5.0 */
10411 if (quoted == 0 && ifs_is_null)
10412 #endif
10413 tflag |= W_SPLITSPACE;
10414 /* If we're not quoted but we still don't want word splitting, make
10415 we quote the IFS characters to protect them from splitting (e.g.,
10416 when $@ is in the string as well). */
10417 else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS))
10418 {
10419 temp1 = quote_string (temp);
10420 free (temp);
10421 temp = temp1;
10422 }
10423 }
10424
10425 if (expand_no_split_dollar_star == 0 && contains_dollar_at)
10426 *contains_dollar_at = 1;
10427 }
10428
10429 dispose_words (list);
10430 break;
10431
10432 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
10433 means that we have to turn quoting off after we split into
10434 the individually quoted arguments so that the final split
10435 on the first character of $IFS is still done. */
10436 case '@': /* `$@' */
10437 list = list_rest_of_args ();
10438
10439 #if 0
10440 /* According to austin-group posix proposal by Geoff Clare in
10441 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
10442
10443 "The shell shall write a message to standard error and
10444 immediately exit when it tries to expand an unset parameter
10445 other than the '@' and '*' special parameters."
10446 */
10447
10448 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
10449 {
10450 uerror[0] = '$';
10451 uerror[1] = '@';
10452 uerror[2] = '\0';
10453 set_exit_status (EXECUTION_FAILURE);
10454 err_unboundvar (uerror);
10455 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
10456 }
10457 #endif
10458
10459 for (nullarg = 0, l = list; l; l = l->next)
10460 {
10461 if (l->word && (l->word->word == 0 || l->word->word[0] == 0))
10462 nullarg = 1;
10463 }
10464
10465 /* We want to flag the fact that we saw this. We can't turn
10466 off quoting entirely, because other characters in the
10467 string might need it (consider "\"$@\""), but we need some
10468 way to signal that the final split on the first character
10469 of $IFS should be done, even though QUOTED is 1. */
10470 /* XXX - should this test include Q_PATQUOTE? */
10471 if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10472 *quoted_dollar_at_p = 1;
10473 if (contains_dollar_at)
10474 *contains_dollar_at = 1;
10475
10476 /* We want to separate the positional parameters with the first
10477 character of $IFS in case $IFS is something other than a space.
10478 We also want to make sure that splitting is done no matter what --
10479 according to POSIX.2, this expands to a list of the positional
10480 parameters no matter what IFS is set to. */
10481 /* XXX - what to do when in a context where word splitting is not
10482 performed? Even when IFS is not the default, posix seems to imply
10483 that we have to expand $@ to all the positional parameters and
10484 separate them with spaces, which are preserved because word splitting
10485 doesn't take place. See below for how we use PF_NOSPLIT2 here. */
10486
10487 /* These are the cases where word splitting will not be performed. */
10488 if (pflags & PF_ASSIGNRHS)
10489 {
10490 temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags);
10491 if (nullarg)
10492 tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */
10493 }
10494
10495 /* This needs to match what expand_word_internal does with non-quoted $@
10496 does with separating with spaces. Passing Q_DOUBLE_QUOTES means that
10497 the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that
10498 they will separated by spaces. After doing this, we need the special
10499 handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC
10500 quotes. */
10501 else if (pflags & PF_NOSPLIT2)
10502 {
10503 #if defined (HANDLE_MULTIBYTE)
10504 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
10505 #else
10506 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
10507 #endif
10508 /* Posix interp 888 */
10509 temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags);
10510 else
10511 temp = string_list_dollar_at (list, quoted, pflags);
10512 }
10513 else
10514 temp = string_list_dollar_at (list, quoted, pflags);
10515
10516 tflag |= W_DOLLARAT;
10517 dispose_words (list);
10518 break;
10519
10520 case LBRACE:
10521 tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
10522 quoted_dollar_at_p,
10523 contains_dollar_at);
10524
10525 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
10526 return (tdesc);
10527 temp = tdesc ? tdesc->word : (char *)0;
10528
10529 /* XXX */
10530 /* Quoted nulls should be removed if there is anything else
10531 in the string. */
10532 /* Note that we saw the quoted null so we can add one back at
10533 the end of this function if there are no other characters
10534 in the string, discard TEMP, and go on. The exception to
10535 this is when we have "${@}" and $1 is '', since $@ needs
10536 special handling. */
10537 if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
10538 {
10539 if (had_quoted_null_p)
10540 *had_quoted_null_p = 1;
10541 if (*quoted_dollar_at_p == 0)
10542 {
10543 free (temp);
10544 tdesc->word = temp = (char *)NULL;
10545 }
10546
10547 }
10548
10549 ret = tdesc;
10550 goto return0;
10551
10552 /* Do command or arithmetic substitution. */
10553 case LPAREN:
10554 /* We have to extract the contents of this paren substitution. */
10555 t_index = zindex + 1;
10556 /* XXX - might want to check for string[t_index+2] == LPAREN and parse
10557 as arithmetic substitution immediately. */
10558 temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0);
10559 zindex = t_index;
10560
10561 /* For Posix.2-style `$(( ))' arithmetic substitution,
10562 extract the expression and pass it to the evaluator. */
10563 if (temp && *temp == LPAREN)
10564 {
10565 char *temp2;
10566 temp1 = temp + 1;
10567 temp2 = savestring (temp1);
10568 t_index = strlen (temp2) - 1;
10569
10570 if (temp2[t_index] != RPAREN)
10571 {
10572 free (temp2);
10573 goto comsub;
10574 }
10575
10576 /* Cut off ending `)' */
10577 temp2[t_index] = '\0';
10578
10579 if (chk_arithsub (temp2, t_index) == 0)
10580 {
10581 free (temp2);
10582 #if 0
10583 internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
10584 #endif
10585 goto comsub;
10586 }
10587
10588 /* Expand variables found inside the expression. */
10589 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
10590 free (temp2);
10591
10592 arithsub:
10593 /* No error messages. */
10594 savecmd = this_command_name;
10595 this_command_name = (char *)NULL;
10596
10597 eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
10598 number = evalexp (temp1, eflag, &expok);
10599 this_command_name = savecmd;
10600 free (temp);
10601 free (temp1);
10602 if (expok == 0)
10603 {
10604 if (interactive_shell == 0 && posixly_correct)
10605 {
10606 set_exit_status (EXECUTION_FAILURE);
10607 return (&expand_wdesc_fatal);
10608 }
10609 else
10610 return (&expand_wdesc_error);
10611 }
10612 temp = itos (number);
10613 break;
10614 }
10615
10616 comsub:
10617 if (pflags & PF_NOCOMSUB)
10618 /* we need zindex+1 because string[zindex] == RPAREN */
10619 temp1 = substring (string, *sindex, zindex+1);
10620 else
10621 {
10622 tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS);
10623 temp1 = tdesc ? tdesc->word : (char *)NULL;
10624 if (tdesc)
10625 dispose_word_desc (tdesc);
10626 }
10627 FREE (temp);
10628 temp = temp1;
10629 break;
10630
10631 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
10632 away in a future bash release. */
10633 case '[': /*]*/
10634 /* Extract the contents of this arithmetic substitution. */
10635 t_index = zindex + 1;
10636 temp = extract_arithmetic_subst (string, &t_index);
10637 zindex = t_index;
10638 if (temp == 0)
10639 {
10640 temp = savestring (string);
10641 if (expanded_something)
10642 *expanded_something = 0;
10643 goto return0;
10644 }
10645
10646 /* Do initial variable expansion. */
10647 temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH);
10648
10649 goto arithsub;
10650
10651 default:
10652 /* Find the variable in VARIABLE_LIST. */
10653 temp = (char *)NULL;
10654
10655 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
10656 ;
10657 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
10658
10659 /* If this isn't a variable name, then just output the `$'. */
10660 if (temp1 == 0 || *temp1 == '\0')
10661 {
10662 FREE (temp1);
10663 temp = (char *)xmalloc (2);
10664 temp[0] = '$';
10665 temp[1] = '\0';
10666 if (expanded_something)
10667 *expanded_something = 0;
10668 goto return0;
10669 }
10670
10671 /* If the variable exists, return its value cell. */
10672 var = find_variable (temp1);
10673
10674 if (var && invisible_p (var) == 0 && var_isset (var))
10675 {
10676 #if defined (ARRAY_VARS)
10677 if (assoc_p (var) || array_p (var))
10678 {
10679 temp = array_p (var) ? array_reference (array_cell (var), 0)
10680 : assoc_reference (assoc_cell (var), "0");
10681 if (temp)
10682 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10683 ? quote_string (temp)
10684 : quote_escapes (temp);
10685 else if (unbound_vars_is_error)
10686 goto unbound_variable;
10687 }
10688 else
10689 #endif
10690 {
10691 temp = value_cell (var);
10692
10693 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
10694 ? quote_string (temp)
10695 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
10696 : quote_escapes (temp));
10697 }
10698
10699 free (temp1);
10700
10701 goto return0;
10702 }
10703 else if (var && (invisible_p (var) || var_isset (var) == 0))
10704 temp = (char *)NULL;
10705 else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0)
10706 {
10707 temp = nameref_cell (var);
10708 #if defined (ARRAY_VARS)
10709 if (temp && *temp && valid_array_reference (temp, 0))
10710 {
10711 chk_atstar (temp, quoted, pflags, quoted_dollar_at_p, contains_dollar_at);
10712 tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, 0);
10713 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
10714 return (tdesc);
10715 ret = tdesc;
10716 goto return0;
10717 }
10718 else
10719 #endif
10720 /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */
10721 if (temp && *temp && legal_identifier (temp) == 0)
10722 {
10723 set_exit_status (EXECUTION_FAILURE);
10724 report_error (_("%s: invalid variable name for name reference"), temp);
10725 return (&expand_wdesc_error); /* XXX */
10726 }
10727 else
10728 temp = (char *)NULL;
10729 }
10730
10731 temp = (char *)NULL;
10732
10733 unbound_variable:
10734 if (unbound_vars_is_error)
10735 {
10736 set_exit_status (EXECUTION_FAILURE);
10737 err_unboundvar (temp1);
10738 }
10739 else
10740 {
10741 free (temp1);
10742 goto return0;
10743 }
10744
10745 free (temp1);
10746 set_exit_status (EXECUTION_FAILURE);
10747 return ((unbound_vars_is_error && interactive_shell == 0)
10748 ? &expand_wdesc_fatal
10749 : &expand_wdesc_error);
10750 }
10751
10752 if (string[zindex])
10753 zindex++;
10754
10755 return0:
10756 *sindex = zindex;
10757
10758 if (ret == 0)
10759 {
10760 ret = alloc_word_desc ();
10761 ret->flags = tflag; /* XXX */
10762 ret->word = temp;
10763 }
10764 return ret;
10765 }
10766
10767 #if defined (ARRAY_VARS)
10768 /* Characters that need to be backslash-quoted after expanding array subscripts */
10769 static char abstab[256] = { '\1' };
10770
10771 /* Run an array subscript through the appropriate word expansions. */
10772 char *
10773 expand_subscript_string (string, quoted)
10774 char *string;
10775 int quoted;
10776 {
10777 WORD_DESC td;
10778 WORD_LIST *tlist;
10779 int oe;
10780 char *ret;
10781
10782 if (string == 0 || *string == 0)
10783 return (char *)NULL;
10784
10785 oe = expand_no_split_dollar_star;
10786 ret = (char *)NULL;
10787
10788 td.flags = W_NOPROCSUB|W_NOTILDE|W_NOSPLIT2; /* XXX - W_NOCOMSUB? */
10789 td.word = savestring (string); /* in case it's freed on error */
10790
10791 expand_no_split_dollar_star = 1;
10792 tlist = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
10793 expand_no_split_dollar_star = oe;
10794
10795 if (tlist)
10796 {
10797 if (tlist->word)
10798 {
10799 remove_quoted_nulls (tlist->word->word);
10800 tlist->word->flags &= ~W_HASQUOTEDNULL;
10801 }
10802 dequote_list (tlist);
10803 ret = string_list (tlist);
10804 dispose_words (tlist);
10805 }
10806
10807 free (td.word);
10808 return (ret);
10809 }
10810
10811 /* Expand the subscript in STRING, which is an array reference. To ensure we
10812 only expand it once, we quote the characters that would start another
10813 expansion and the bracket characters that are special to array subscripts. */
10814 static char *
10815 expand_array_subscript (string, sindex, quoted, flags)
10816 char *string;
10817 int *sindex;
10818 int quoted, flags;
10819 {
10820 char *ret, *exp, *t;
10821 size_t slen;
10822 int si, ni;
10823
10824 si = *sindex;
10825 slen = STRLEN (string);
10826
10827 if (abstab[0] == '\1')
10828 {
10829 /* These are basically the characters that start shell expansions plus
10830 the characters that delimit subscripts. */
10831 memset (abstab, '\0', sizeof (abstab));
10832 abstab[LBRACK] = abstab[RBRACK] = 1;
10833 abstab['$'] = abstab['`'] = abstab['~'] = 1;
10834 abstab['\\'] = abstab['\''] = 1;
10835 abstab['"'] = 1; /* XXX */
10836 /* We don't quote `@' or `*' in the subscript at all. */
10837 }
10838
10839 /* string[si] == LBRACK */
10840 ni = skipsubscript (string, si, 0);
10841 /* These checks mirror the ones in valid_array_reference. The check for
10842 (ni - si) == 1 checks for empty subscripts. We don't check that the
10843 subscript is a separate word if we're parsing an arithmetic expression. */
10844 if (ni >= slen || string[ni] != RBRACK || (ni - si) == 1 ||
10845 (string[ni+1] != '\0' && (quoted & Q_ARITH) == 0))
10846 {
10847 /* let's check and see what fails this check */
10848 INTERNAL_DEBUG (("expand_array_subscript: bad subscript string: `%s'", string+si));
10849 ret = (char *)xmalloc (2); /* badly-formed subscript */
10850 ret[0] = string[si];
10851 ret[1] = '\0';
10852 *sindex = si + 1;
10853 return ret;
10854 }
10855
10856 /* STRING[ni] == RBRACK */
10857 exp = substring (string, si+1, ni);
10858 t = expand_subscript_string (exp, quoted & ~(Q_ARITH|Q_DOUBLE_QUOTES));
10859 free (exp);
10860 exp = t ? sh_backslash_quote (t, abstab, 0) : savestring ("");
10861 free (t);
10862
10863 slen = STRLEN (exp);
10864 ret = xmalloc (slen + 2 + 1);
10865 ret[0] ='[';
10866 strcpy (ret + 1, exp);
10867 ret[slen + 1] = ']';
10868 ret[slen + 2] = '\0';
10869
10870 free (exp);
10871 *sindex = ni + 1;
10872
10873 return ret;
10874 }
10875 #endif
10876
10877 void
10878 invalidate_cached_quoted_dollar_at ()
10879 {
10880 dispose_words (cached_quoted_dollar_at);
10881 cached_quoted_dollar_at = 0;
10882 }
10883
10884 /* Make a word list which is the result of parameter and variable
10885 expansion, command substitution, arithmetic substitution, and
10886 quote removal of WORD. Return a pointer to a WORD_LIST which is
10887 the result of the expansion. If WORD contains a null word, the
10888 word list returned is also null.
10889
10890 QUOTED contains flag values defined in shell.h.
10891
10892 ISEXP is used to tell expand_word_internal that the word should be
10893 treated as the result of an expansion. This has implications for
10894 how IFS characters in the word are treated.
10895
10896 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
10897 they point to an integer value which receives information about expansion.
10898 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
10899 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
10900 else zero.
10901
10902 This only does word splitting in the case of $@ expansion. In that
10903 case, we split on ' '. */
10904
10905 /* Values for the local variable quoted_state. */
10906 #define UNQUOTED 0
10907 #define PARTIALLY_QUOTED 1
10908 #define WHOLLY_QUOTED 2
10909
10910 static WORD_LIST *
10911 expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
10912 WORD_DESC *word;
10913 int quoted, isexp;
10914 int *contains_dollar_at;
10915 int *expanded_something;
10916 {
10917 WORD_LIST *list;
10918 WORD_DESC *tword;
10919
10920 /* The intermediate string that we build while expanding. */
10921 char *istring;
10922
10923 /* The current size of the above object. */
10924 size_t istring_size;
10925
10926 /* Index into ISTRING. */
10927 size_t istring_index;
10928
10929 /* Temporary string storage. */
10930 char *temp, *temp1;
10931
10932 /* The text of WORD. */
10933 register char *string;
10934
10935 /* The size of STRING. */
10936 size_t string_size;
10937
10938 /* The index into STRING. */
10939 int sindex;
10940
10941 /* This gets 1 if we see a $@ while quoted. */
10942 int quoted_dollar_at;
10943
10944 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
10945 whether WORD contains no quoting characters, a partially quoted
10946 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
10947 int quoted_state;
10948
10949 /* State flags */
10950 int had_quoted_null;
10951 int has_quoted_ifs; /* did we add a quoted $IFS character here? */
10952 int has_dollar_at, temp_has_dollar_at;
10953 int internal_tilde;
10954 int split_on_spaces;
10955 int local_expanded;
10956 int tflag;
10957 int pflags; /* flags passed to param_expand */
10958 int mb_cur_max;
10959
10960 int assignoff; /* If assignment, offset of `=' */
10961
10962 register unsigned char c; /* Current character. */
10963 int t_index; /* For calls to string_extract_xxx. */
10964
10965 char twochars[2];
10966
10967 DECLARE_MBSTATE;
10968
10969 /* OK, let's see if we can optimize a common idiom: "$@". This needs to make sure
10970 that all of the flags callers care about (e.g., W_HASQUOTEDNULL) are set in
10971 list->flags. */
10972 if (STREQ (word->word, "\"$@\"") &&
10973 (word->flags == (W_HASDOLLAR|W_QUOTED)) &&
10974 dollar_vars[1]) /* XXX - check IFS here as well? */
10975 {
10976 if (contains_dollar_at)
10977 *contains_dollar_at = 1;
10978 if (expanded_something)
10979 *expanded_something = 1;
10980 if (cached_quoted_dollar_at)
10981 return (copy_word_list (cached_quoted_dollar_at));
10982 list = list_rest_of_args ();
10983 list = quote_list (list);
10984 cached_quoted_dollar_at = copy_word_list (list);
10985 return (list);
10986 }
10987
10988 istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
10989 istring[istring_index = 0] = '\0';
10990 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
10991 has_quoted_ifs = 0;
10992 split_on_spaces = 0;
10993 internal_tilde = 0; /* expanding =~ or :~ */
10994 quoted_state = UNQUOTED;
10995
10996 string = word->word;
10997 if (string == 0)
10998 goto finished_with_string;
10999 mb_cur_max = MB_CUR_MAX;
11000
11001 /* Don't need the string length for the SADD... and COPY_ macros unless
11002 multibyte characters are possible, but do need it for bounds checking. */
11003 string_size = (mb_cur_max > 1) ? strlen (string) : 1;
11004
11005 if (contains_dollar_at)
11006 *contains_dollar_at = 0;
11007
11008 assignoff = -1;
11009
11010 /* Begin the expansion. */
11011
11012 for (sindex = 0; ;)
11013 {
11014 c = string[sindex];
11015
11016 /* Case on top-level character. */
11017 switch (c)
11018 {
11019 case '\0':
11020 goto finished_with_string;
11021
11022 case CTLESC:
11023 sindex++;
11024 #if HANDLE_MULTIBYTE
11025 if (mb_cur_max > 1 && string[sindex])
11026 {
11027 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
11028 }
11029 else
11030 #endif
11031 {
11032 temp = (char *)xmalloc (3);
11033 temp[0] = CTLESC;
11034 temp[1] = c = string[sindex];
11035 temp[2] = '\0';
11036 }
11037
11038 dollar_add_string:
11039 if (string[sindex])
11040 sindex++;
11041
11042 add_string:
11043 if (temp)
11044 {
11045 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
11046 temp = (char *)0;
11047 }
11048
11049 break;
11050
11051 #if defined (PROCESS_SUBSTITUTION)
11052 /* Process substitution. */
11053 case '<':
11054 case '>':
11055 {
11056 /* XXX - technically this should only be expanded at the start
11057 of a word */
11058 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & W_NOPROCSUB))
11059 {
11060 sindex--; /* add_character: label increments sindex */
11061 goto add_character;
11062 }
11063 else
11064 t_index = sindex + 1; /* skip past both '<' and LPAREN */
11065
11066 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/
11067 sindex = t_index;
11068
11069 /* If the process substitution specification is `<()', we want to
11070 open the pipe for writing in the child and produce output; if
11071 it is `>()', we want to open the pipe for reading in the child
11072 and consume input. */
11073 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
11074
11075 FREE (temp1);
11076
11077 goto dollar_add_string;
11078 }
11079 #endif /* PROCESS_SUBSTITUTION */
11080
11081 #if defined (ARRAY_VARS)
11082 case '[': /*]*/
11083 if ((quoted & Q_ARITH) == 0 || shell_compatibility_level <= 51)
11084 {
11085 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
11086 goto add_ifs_character;
11087 else
11088 goto add_character;
11089 }
11090 else
11091 {
11092 temp = expand_array_subscript (string, &sindex, quoted, word->flags);
11093 goto add_string;
11094 }
11095 #endif
11096
11097 case '=':
11098 /* Posix.2 section 3.6.1 says that tildes following `=' in words
11099 which are not assignment statements are not expanded. If the
11100 shell isn't in posix mode, though, we perform tilde expansion
11101 on `likely candidate' unquoted assignment statements (flags
11102 include W_ASSIGNMENT but not W_QUOTED). A likely candidate
11103 contains an unquoted :~ or =~. Something to think about: we
11104 now have a flag that says to perform tilde expansion on arguments
11105 to `assignment builtins' like declare and export that look like
11106 assignment statements. We now do tilde expansion on such words
11107 even in POSIX mode. */
11108 if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
11109 {
11110 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11111 goto add_ifs_character;
11112 else
11113 goto add_character;
11114 }
11115 /* If we're not in posix mode or forcing assignment-statement tilde
11116 expansion, note where the first `=' appears in the word and prepare
11117 to do tilde expansion following the first `='. We have to keep
11118 track of the first `=' (using assignoff) to avoid being confused
11119 by an `=' in the rhs of the assignment statement. */
11120 if ((word->flags & W_ASSIGNMENT) &&
11121 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
11122 assignoff == -1 && sindex > 0)
11123 assignoff = sindex;
11124 if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
11125 internal_tilde = 1;
11126
11127 if (word->flags & W_ASSIGNARG)
11128 word->flags |= W_ASSIGNRHS; /* affects $@ */
11129
11130 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11131 {
11132 has_quoted_ifs++;
11133 goto add_ifs_character;
11134 }
11135 else
11136 goto add_character;
11137
11138 case ':':
11139 if (word->flags & (W_NOTILDE|W_NOASSNTILDE))
11140 {
11141 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11142 goto add_ifs_character;
11143 else
11144 goto add_character;
11145 }
11146
11147 if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) &&
11148 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
11149 string[sindex+1] == '~')
11150 internal_tilde = 1;
11151
11152 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
11153 goto add_ifs_character;
11154 else
11155 goto add_character;
11156
11157 case '~':
11158 /* If the word isn't supposed to be tilde expanded, or we're not
11159 at the start of a word or after an unquoted : or = in an
11160 assignment statement, we don't do tilde expansion. We don't
11161 do tilde expansion if quoted or in an arithmetic context. */
11162
11163 if ((word->flags & W_NOTILDE) ||
11164 (sindex > 0 && (internal_tilde == 0)) ||
11165 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
11166 {
11167 internal_tilde = 0;
11168 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
11169 goto add_ifs_character;
11170 else
11171 goto add_character;
11172 }
11173
11174 if (word->flags & W_ASSIGNRHS)
11175 tflag = 2;
11176 else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
11177 tflag = 1;
11178 else
11179 tflag = 0;
11180
11181 temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
11182
11183 internal_tilde = 0;
11184
11185 if (temp && *temp && t_index > 0)
11186 {
11187 temp1 = bash_tilde_expand (temp, tflag);
11188 if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
11189 {
11190 FREE (temp);
11191 FREE (temp1);
11192 goto add_character; /* tilde expansion failed */
11193 }
11194 free (temp);
11195 temp = temp1;
11196 sindex += t_index;
11197 goto add_quoted_string; /* XXX was add_string */
11198 }
11199 else
11200 {
11201 FREE (temp);
11202 goto add_character;
11203 }
11204
11205 case '$':
11206 if (expanded_something)
11207 *expanded_something = 1;
11208 local_expanded = 1;
11209
11210 temp_has_dollar_at = 0;
11211 pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
11212 if (word->flags & W_NOSPLIT2)
11213 pflags |= PF_NOSPLIT2;
11214 if (word->flags & W_ASSIGNRHS)
11215 pflags |= PF_ASSIGNRHS;
11216 if (word->flags & W_COMPLETE)
11217 pflags |= PF_COMPLETE;
11218
11219 tword = param_expand (string, &sindex, quoted, expanded_something,
11220 &temp_has_dollar_at, &quoted_dollar_at,
11221 &had_quoted_null, pflags);
11222 has_dollar_at += temp_has_dollar_at;
11223 split_on_spaces += (tword->flags & W_SPLITSPACE);
11224
11225 if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
11226 {
11227 free (string);
11228 free (istring);
11229 return ((tword == &expand_wdesc_error) ? &expand_word_error
11230 : &expand_word_fatal);
11231 }
11232 if (contains_dollar_at && has_dollar_at)
11233 *contains_dollar_at = 1;
11234
11235 if (tword && (tword->flags & W_HASQUOTEDNULL))
11236 had_quoted_null = 1; /* note for later */
11237 if (tword && (tword->flags & W_SAWQUOTEDNULL))
11238 had_quoted_null = 1; /* XXX */
11239
11240 temp = tword ? tword->word : (char *)NULL;
11241 dispose_word_desc (tword);
11242
11243 /* Kill quoted nulls; we will add them back at the end of
11244 expand_word_internal if nothing else in the string */
11245 if (had_quoted_null && temp && QUOTED_NULL (temp))
11246 {
11247 FREE (temp);
11248 temp = (char *)NULL;
11249 }
11250
11251 goto add_string;
11252 break;
11253
11254 case '`': /* Backquoted command substitution. */
11255 {
11256 t_index = sindex++;
11257
11258 temp = string_extract (string, &sindex, "`", (word->flags & W_COMPLETE) ? SX_COMPLETE : SX_REQMATCH);
11259 /* The test of sindex against t_index is to allow bare instances of
11260 ` to pass through, for backwards compatibility. */
11261 if (temp == &extract_string_error || temp == &extract_string_fatal)
11262 {
11263 if (sindex - 1 == t_index)
11264 {
11265 sindex = t_index;
11266 goto add_character;
11267 }
11268 set_exit_status (EXECUTION_FAILURE);
11269 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
11270 free (string);
11271 free (istring);
11272 return ((temp == &extract_string_error) ? &expand_word_error
11273 : &expand_word_fatal);
11274 }
11275
11276 if (expanded_something)
11277 *expanded_something = 1;
11278 local_expanded = 1;
11279
11280 if (word->flags & W_NOCOMSUB)
11281 /* sindex + 1 because string[sindex] == '`' */
11282 temp1 = substring (string, t_index, sindex + 1);
11283 else
11284 {
11285 de_backslash (temp);
11286 tword = command_substitute (temp, quoted, 0);
11287 temp1 = tword ? tword->word : (char *)NULL;
11288 if (tword)
11289 dispose_word_desc (tword);
11290 }
11291 FREE (temp);
11292 temp = temp1;
11293 goto dollar_add_string;
11294 }
11295
11296 case '\\':
11297 if (string[sindex + 1] == '\n')
11298 {
11299 sindex += 2;
11300 continue;
11301 }
11302
11303 c = string[++sindex];
11304
11305 /* "However, the double-quote character ( '"' ) shall not be treated
11306 specially within a here-document, except when the double-quote
11307 appears within "$()", "``", or "${}"." */
11308 if ((quoted & Q_HERE_DOCUMENT) && (quoted & Q_DOLBRACE) && c == '"')
11309 tflag = CBSDQUOTE; /* special case */
11310 else if (quoted & Q_HERE_DOCUMENT)
11311 tflag = CBSHDOC;
11312 else if (quoted & Q_DOUBLE_QUOTES)
11313 tflag = CBSDQUOTE;
11314 else
11315 tflag = 0;
11316
11317 /* From Posix discussion on austin-group list: Backslash escaping
11318 a } in ${...} is removed. Issue 0000221 */
11319 if ((quoted & Q_DOLBRACE) && c == RBRACE)
11320 {
11321 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11322 }
11323 /* This is the fix for " $@\ " */
11324 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c))
11325 {
11326 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11327 DEFAULT_ARRAY_SIZE);
11328 istring[istring_index++] = CTLESC;
11329 istring[istring_index++] = '\\';
11330 istring[istring_index] = '\0';
11331
11332 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11333 }
11334 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0)
11335 {
11336 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11337 DEFAULT_ARRAY_SIZE);
11338 istring[istring_index++] = CTLESC;
11339 istring[istring_index++] = '\\';
11340 istring[istring_index] = '\0';
11341 break;
11342 }
11343 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
11344 {
11345 SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
11346 }
11347 else if (c == 0)
11348 {
11349 c = CTLNUL;
11350 sindex--; /* add_character: label increments sindex */
11351 goto add_character;
11352 }
11353 else
11354 {
11355 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
11356 }
11357
11358 sindex++;
11359 add_twochars:
11360 /* BEFORE jumping here, we need to increment sindex if appropriate */
11361 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
11362 DEFAULT_ARRAY_SIZE);
11363 istring[istring_index++] = twochars[0];
11364 istring[istring_index++] = twochars[1];
11365 istring[istring_index] = '\0';
11366
11367 break;
11368
11369 case '"':
11370 /* XXX - revisit this */
11371 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0))
11372 goto add_character;
11373
11374 t_index = ++sindex;
11375 temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0);
11376
11377 /* If the quotes surrounded the entire string, then the
11378 whole word was quoted. */
11379 quoted_state = (t_index == 1 && string[sindex] == '\0')
11380 ? WHOLLY_QUOTED
11381 : PARTIALLY_QUOTED;
11382
11383 if (temp && *temp)
11384 {
11385 tword = alloc_word_desc ();
11386 tword->word = temp;
11387
11388 if (word->flags & W_ASSIGNARG)
11389 tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */
11390 if (word->flags & W_COMPLETE)
11391 tword->flags |= W_COMPLETE; /* for command substitutions */
11392 if (word->flags & W_NOCOMSUB)
11393 tword->flags |= W_NOCOMSUB;
11394 if (word->flags & W_NOPROCSUB)
11395 tword->flags |= W_NOPROCSUB;
11396
11397 if (word->flags & W_ASSIGNRHS)
11398 tword->flags |= W_ASSIGNRHS;
11399
11400 temp = (char *)NULL;
11401
11402 temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */
11403 /* Need to get W_HASQUOTEDNULL flag through this function. */
11404 /* XXX - preserve Q_ARITH here? */
11405 list = expand_word_internal (tword, Q_DOUBLE_QUOTES|(quoted&Q_ARITH), 0, &temp_has_dollar_at, (int *)NULL);
11406 has_dollar_at += temp_has_dollar_at;
11407
11408 if (list == &expand_word_error || list == &expand_word_fatal)
11409 {
11410 free (istring);
11411 free (string);
11412 /* expand_word_internal has already freed temp_word->word
11413 for us because of the way it prints error messages. */
11414 tword->word = (char *)NULL;
11415 dispose_word (tword);
11416 return list;
11417 }
11418
11419 dispose_word (tword);
11420
11421 /* "$@" (a double-quoted dollar-at) expands into nothing,
11422 not even a NULL word, when there are no positional
11423 parameters. Posix interp 888 says that other parts of the
11424 word that expand to quoted nulls result in quoted nulls, so
11425 we can't just throw the entire word away if we have "$@"
11426 anywhere in it. We use had_quoted_null to keep track */
11427 if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */
11428 {
11429 quoted_dollar_at++;
11430 break;
11431 }
11432
11433 /* If this list comes back with a quoted null from expansion,
11434 we have either "$x" or "$@" with $1 == ''. In either case,
11435 we need to make sure we add a quoted null argument and
11436 disable the special handling that "$@" gets. */
11437 if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL))
11438 {
11439 if (had_quoted_null && temp_has_dollar_at)
11440 quoted_dollar_at++;
11441 had_quoted_null = 1; /* XXX */
11442 }
11443
11444 /* If we get "$@", we know we have expanded something, so we
11445 need to remember it for the final split on $IFS. This is
11446 a special case; it's the only case where a quoted string
11447 can expand into more than one word. It's going to come back
11448 from the above call to expand_word_internal as a list with
11449 multiple words. */
11450 if (list)
11451 dequote_list (list);
11452
11453 if (temp_has_dollar_at) /* XXX - was has_dollar_at */
11454 {
11455 quoted_dollar_at++;
11456 if (contains_dollar_at)
11457 *contains_dollar_at = 1;
11458 if (expanded_something)
11459 *expanded_something = 1;
11460 local_expanded = 1;
11461 }
11462 }
11463 else
11464 {
11465 /* What we have is "". This is a minor optimization. */
11466 FREE (temp);
11467 list = (WORD_LIST *)NULL;
11468 had_quoted_null = 1; /* note for later */
11469 }
11470
11471 /* The code above *might* return a list (consider the case of "$@",
11472 where it returns "$1", "$2", etc.). We can't throw away the
11473 rest of the list, and we have to make sure each word gets added
11474 as quoted. We test on tresult->next: if it is non-NULL, we
11475 quote the whole list, save it to a string with string_list, and
11476 add that string. We don't need to quote the results of this
11477 (and it would be wrong, since that would quote the separators
11478 as well), so we go directly to add_string. */
11479 if (list)
11480 {
11481 if (list->next)
11482 {
11483 /* Testing quoted_dollar_at makes sure that "$@" is
11484 split correctly when $IFS does not contain a space. */
11485 temp = quoted_dollar_at
11486 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0)
11487 : string_list (quote_list (list));
11488 dispose_words (list);
11489 goto add_string;
11490 }
11491 else
11492 {
11493 temp = savestring (list->word->word);
11494 tflag = list->word->flags;
11495 dispose_words (list);
11496
11497 /* If the string is not a quoted null string, we want
11498 to remove any embedded unquoted CTLNUL characters.
11499 We do not want to turn quoted null strings back into
11500 the empty string, though. We do this because we
11501 want to remove any quoted nulls from expansions that
11502 contain other characters. For example, if we have
11503 x"$*"y or "x$*y" and there are no positional parameters,
11504 the $* should expand into nothing. */
11505 /* We use the W_HASQUOTEDNULL flag to differentiate the
11506 cases: a quoted null character as above and when
11507 CTLNUL is contained in the (non-null) expansion
11508 of some variable. We use the had_quoted_null flag to
11509 pass the value through this function to its caller. */
11510 if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
11511 remove_quoted_nulls (temp); /* XXX */
11512 }
11513 }
11514 else
11515 temp = (char *)NULL;
11516
11517 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
11518 had_quoted_null = 1; /* note for later */
11519
11520 /* We do not want to add quoted nulls to strings that are only
11521 partially quoted; we can throw them away. The exception to
11522 this is when we are going to be performing word splitting,
11523 since we have to preserve a null argument if the next character
11524 will cause word splitting. */
11525 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
11526 {
11527 c = CTLNUL;
11528 sindex--;
11529 had_quoted_null = 1;
11530 goto add_character;
11531 }
11532 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
11533 continue;
11534
11535 add_quoted_string:
11536
11537 if (temp)
11538 {
11539 temp1 = temp;
11540 temp = quote_string (temp);
11541 free (temp1);
11542 goto add_string;
11543 }
11544 else
11545 {
11546 /* Add NULL arg. */
11547 c = CTLNUL;
11548 sindex--; /* add_character: label increments sindex */
11549 had_quoted_null = 1; /* note for later */
11550 goto add_character;
11551 }
11552
11553 /* break; */
11554
11555 case '\'':
11556 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
11557 goto add_character;
11558
11559 t_index = ++sindex;
11560 temp = string_extract_single_quoted (string, &sindex, 0);
11561
11562 /* If the entire STRING was surrounded by single quotes,
11563 then the string is wholly quoted. */
11564 quoted_state = (t_index == 1 && string[sindex] == '\0')
11565 ? WHOLLY_QUOTED
11566 : PARTIALLY_QUOTED;
11567
11568 /* If all we had was '', it is a null expansion. */
11569 if (*temp == '\0')
11570 {
11571 free (temp);
11572 temp = (char *)NULL;
11573 }
11574 else
11575 remove_quoted_escapes (temp); /* ??? */
11576
11577 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
11578 had_quoted_null = 1; /* note for later */
11579
11580 /* We do not want to add quoted nulls to strings that are only
11581 partially quoted; such nulls are discarded. See above for the
11582 exception, which is when the string is going to be split.
11583 Posix interp 888/1129 */
11584 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
11585 {
11586 c = CTLNUL;
11587 sindex--;
11588 goto add_character;
11589 }
11590
11591 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
11592 continue;
11593
11594 /* If we have a quoted null expansion, add a quoted NULL to istring. */
11595 if (temp == 0)
11596 {
11597 c = CTLNUL;
11598 sindex--; /* add_character: label increments sindex */
11599 goto add_character;
11600 }
11601 else
11602 goto add_quoted_string;
11603
11604 /* break; */
11605
11606 case ' ':
11607 /* If we are in a context where the word is not going to be split, but
11608 we need to account for $@ and $* producing one word for each
11609 positional parameter, add quoted spaces so the spaces in the
11610 expansion of "$@", if any, behave correctly. We still may need to
11611 split if we are expanding the rhs of a word expansion. */
11612 if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0))
11613 {
11614 if (string[sindex])
11615 sindex++;
11616 twochars[0] = CTLESC;
11617 twochars[1] = c;
11618 goto add_twochars;
11619 }
11620 /* FALLTHROUGH */
11621
11622 default:
11623 /* This is the fix for " $@ " */
11624 add_ifs_character:
11625 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0))
11626 {
11627 if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)
11628 has_quoted_ifs++;
11629 add_quoted_character:
11630 if (string[sindex]) /* from old goto dollar_add_string */
11631 sindex++;
11632 if (c == 0)
11633 {
11634 c = CTLNUL;
11635 goto add_character;
11636 }
11637 else
11638 {
11639 #if HANDLE_MULTIBYTE
11640 /* XXX - should make sure that c is actually multibyte,
11641 otherwise we can use the twochars branch */
11642 if (mb_cur_max > 1)
11643 sindex--;
11644
11645 if (mb_cur_max > 1)
11646 {
11647 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
11648 }
11649 else
11650 #endif
11651 {
11652 twochars[0] = CTLESC;
11653 twochars[1] = c;
11654 goto add_twochars;
11655 }
11656 }
11657 }
11658
11659 SADD_MBCHAR (temp, string, sindex, string_size);
11660
11661 add_character:
11662 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
11663 DEFAULT_ARRAY_SIZE);
11664 istring[istring_index++] = c;
11665 istring[istring_index] = '\0';
11666
11667 /* Next character. */
11668 sindex++;
11669 }
11670 }
11671
11672 finished_with_string:
11673 /* OK, we're ready to return. If we have a quoted string, and
11674 quoted_dollar_at is not set, we do no splitting at all; otherwise
11675 we split on ' '. The routines that call this will handle what to
11676 do if nothing has been expanded. */
11677
11678 /* Partially and wholly quoted strings which expand to the empty
11679 string are retained as an empty arguments. Unquoted strings
11680 which expand to the empty string are discarded. The single
11681 exception is the case of expanding "$@" when there are no
11682 positional parameters. In that case, we discard the expansion. */
11683
11684 /* Because of how the code that handles "" and '' in partially
11685 quoted strings works, we need to make ISTRING into a QUOTED_NULL
11686 if we saw quoting characters, but the expansion was empty.
11687 "" and '' are tossed away before we get to this point when
11688 processing partially quoted strings. This makes "" and $xxx""
11689 equivalent when xxx is unset. We also look to see whether we
11690 saw a quoted null from a ${} expansion and add one back if we
11691 need to. */
11692
11693 /* If we expand to nothing and there were no single or double quotes
11694 in the word, we throw it away. Otherwise, we return a NULL word.
11695 The single exception is for $@ surrounded by double quotes when
11696 there are no positional parameters. In that case, we also throw
11697 the word away. */
11698
11699 if (*istring == '\0')
11700 {
11701 #if 0
11702 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
11703 #else
11704 if (had_quoted_null || (quoted_dollar_at == 0 && quoted_state == PARTIALLY_QUOTED))
11705 #endif
11706 {
11707 istring[0] = CTLNUL;
11708 istring[1] = '\0';
11709 tword = alloc_word_desc ();
11710 tword->word = istring;
11711 istring = 0; /* avoid later free() */
11712 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11713 list = make_word_list (tword, (WORD_LIST *)NULL);
11714 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
11715 tword->flags |= W_QUOTED;
11716 }
11717 /* According to sh, ksh, and Posix.2, if a word expands into nothing
11718 and a double-quoted "$@" appears anywhere in it, then the entire
11719 word is removed. */
11720 /* XXX - exception appears to be that quoted null strings result in
11721 null arguments */
11722 else if (quoted_state == UNQUOTED || quoted_dollar_at)
11723 list = (WORD_LIST *)NULL;
11724 else
11725 list = (WORD_LIST *)NULL;
11726 }
11727 else if (word->flags & W_NOSPLIT)
11728 {
11729 tword = alloc_word_desc ();
11730 tword->word = istring;
11731 if (had_quoted_null && QUOTED_NULL (istring))
11732 tword->flags |= W_HASQUOTEDNULL;
11733 istring = 0; /* avoid later free() */
11734 if (word->flags & W_ASSIGNMENT)
11735 tword->flags |= W_ASSIGNMENT; /* XXX */
11736 if (word->flags & W_COMPASSIGN)
11737 tword->flags |= W_COMPASSIGN; /* XXX */
11738 if (word->flags & W_NOGLOB)
11739 tword->flags |= W_NOGLOB; /* XXX */
11740 if (word->flags & W_NOBRACE)
11741 tword->flags |= W_NOBRACE; /* XXX */
11742 if (word->flags & W_ARRAYREF)
11743 tword->flags |= W_ARRAYREF;
11744 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
11745 tword->flags |= W_QUOTED;
11746 list = make_word_list (tword, (WORD_LIST *)NULL);
11747 }
11748 else if (word->flags & W_ASSIGNRHS)
11749 {
11750 list = list_string (istring, "", quoted);
11751 tword = list->word;
11752 if (had_quoted_null && QUOTED_NULL (istring))
11753 tword->flags |= W_HASQUOTEDNULL;
11754 free (list);
11755 free (istring);
11756 istring = 0; /* avoid later free() */
11757 goto set_word_flags;
11758 }
11759 else
11760 {
11761 char *ifs_chars;
11762
11763 ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
11764
11765 /* If we have $@, we need to split the results no matter what. If
11766 IFS is unset or NULL, string_list_dollar_at has separated the
11767 positional parameters with a space, so we split on space (we have
11768 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
11769 string_list_dollar_at has separated the positional parameters
11770 with the first character of $IFS, so we split on $IFS. If
11771 SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
11772 unset or null, and we want to make sure that we split on spaces
11773 regardless of what else has happened to IFS since the expansion,
11774 or we expanded "$@" with IFS null and we need to split the positional
11775 parameters into separate words. */
11776 if (split_on_spaces)
11777 {
11778 /* If IFS is not set, and the word is not quoted, we want to split
11779 the individual words on $' \t\n'. We rely on previous steps to
11780 quote the portions of the word that should not be split */
11781 if (ifs_is_set == 0)
11782 list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */
11783 else
11784 list = list_string (istring, " ", 1); /* XXX quoted == 1? */
11785 }
11786
11787 /* If we have $@ (has_dollar_at != 0) and we are in a context where we
11788 don't want to split the result (W_NOSPLIT2), and we are not quoted,
11789 we have already separated the arguments with the first character of
11790 $IFS. In this case, we want to return a list with a single word
11791 with the separator possibly replaced with a space (it's what other
11792 shells seem to do).
11793 quoted_dollar_at is internal to this function and is set if we are
11794 passed an argument that is unquoted (quoted == 0) but we encounter a
11795 double-quoted $@ while expanding it. */
11796 else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2))
11797 {
11798 tword = alloc_word_desc ();
11799 /* Only split and rejoin if we have to */
11800 if (*ifs_chars && *ifs_chars != ' ')
11801 {
11802 /* list_string dequotes CTLESCs in the string it's passed, so we
11803 need it to get the space separation right if space isn't the
11804 first character in IFS (but is present) and to remove the
11805 quoting we added back in param_expand(). */
11806 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
11807 /* This isn't exactly right in the case where we're expanding
11808 the RHS of an expansion like ${var-$@} where IFS=: (for
11809 example). The W_NOSPLIT2 means we do the separation with :;
11810 the list_string removes the quotes and breaks the string into
11811 a list, and the string_list rejoins it on spaces. When we
11812 return, we expect to be able to split the results, but the
11813 space separation means the right split doesn't happen. */
11814 tword->word = string_list (list);
11815 }
11816 else
11817 tword->word = istring;
11818 if (had_quoted_null && QUOTED_NULL (istring))
11819 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11820 if (tword->word != istring)
11821 free (istring);
11822 istring = 0; /* avoid later free() */
11823 goto set_word_flags;
11824 }
11825 else if (has_dollar_at && ifs_chars)
11826 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
11827 else
11828 {
11829 tword = alloc_word_desc ();
11830 if (expanded_something && *expanded_something == 0 && has_quoted_ifs)
11831 tword->word = remove_quoted_ifs (istring);
11832 else
11833 tword->word = istring;
11834 if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */
11835 tword->flags |= W_HASQUOTEDNULL; /* XXX */
11836 else if (had_quoted_null)
11837 tword->flags |= W_SAWQUOTEDNULL; /* XXX */
11838 if (tword->word != istring)
11839 free (istring);
11840 istring = 0; /* avoid later free() */
11841 set_word_flags:
11842 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
11843 tword->flags |= W_QUOTED;
11844 if (word->flags & W_ASSIGNMENT)
11845 tword->flags |= W_ASSIGNMENT;
11846 if (word->flags & W_COMPASSIGN)
11847 tword->flags |= W_COMPASSIGN;
11848 if (word->flags & W_NOGLOB)
11849 tword->flags |= W_NOGLOB;
11850 if (word->flags & W_NOBRACE)
11851 tword->flags |= W_NOBRACE;
11852 if (word->flags & W_ARRAYREF)
11853 tword->flags |= W_ARRAYREF;
11854 list = make_word_list (tword, (WORD_LIST *)NULL);
11855 }
11856 }
11857
11858 free (istring);
11859 return (list);
11860 }
11861
11862 /* **************************************************************** */
11863 /* */
11864 /* Functions for Quote Removal */
11865 /* */
11866 /* **************************************************************** */
11867
11868 /* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
11869 backslash quoting rules for within double quotes or a here document. */
11870 char *
11871 string_quote_removal (string, quoted)
11872 char *string;
11873 int quoted;
11874 {
11875 size_t slen;
11876 char *r, *result_string, *temp, *send;
11877 int sindex, tindex, dquote;
11878 unsigned char c;
11879 DECLARE_MBSTATE;
11880
11881 /* The result can be no longer than the original string. */
11882 slen = strlen (string);
11883 send = string + slen;
11884
11885 r = result_string = (char *)xmalloc (slen + 1);
11886
11887 for (dquote = sindex = 0; c = string[sindex];)
11888 {
11889 switch (c)
11890 {
11891 case '\\':
11892 c = string[++sindex];
11893 if (c == 0)
11894 {
11895 *r++ = '\\';
11896 break;
11897 }
11898 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
11899 *r++ = '\\';
11900 /* FALLTHROUGH */
11901
11902 default:
11903 SCOPY_CHAR_M (r, string, send, sindex);
11904 break;
11905
11906 case '\'':
11907 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
11908 {
11909 *r++ = c;
11910 sindex++;
11911 break;
11912 }
11913 tindex = sindex + 1;
11914 temp = string_extract_single_quoted (string, &tindex, 0);
11915 if (temp)
11916 {
11917 strcpy (r, temp);
11918 r += strlen (r);
11919 free (temp);
11920 }
11921 sindex = tindex;
11922 break;
11923
11924 case '"':
11925 dquote = 1 - dquote;
11926 sindex++;
11927 break;
11928 }
11929 }
11930 *r = '\0';
11931 return (result_string);
11932 }
11933
11934 #if 0
11935 /* UNUSED */
11936 /* Perform quote removal on word WORD. This allocates and returns a new
11937 WORD_DESC *. */
11938 WORD_DESC *
11939 word_quote_removal (word, quoted)
11940 WORD_DESC *word;
11941 int quoted;
11942 {
11943 WORD_DESC *w;
11944 char *t;
11945
11946 t = string_quote_removal (word->word, quoted);
11947 w = alloc_word_desc ();
11948 w->word = t ? t : savestring ("");
11949 return (w);
11950 }
11951
11952 /* Perform quote removal on all words in LIST. If QUOTED is non-zero,
11953 the members of the list are treated as if they are surrounded by
11954 double quotes. Return a new list, or NULL if LIST is NULL. */
11955 WORD_LIST *
11956 word_list_quote_removal (list, quoted)
11957 WORD_LIST *list;
11958 int quoted;
11959 {
11960 WORD_LIST *result, *t, *tresult, *e;
11961
11962 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
11963 {
11964 tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
11965 #if 0
11966 result = (WORD_LIST *) list_append (result, tresult);
11967 #else
11968 if (result == 0)
11969 result = e = tresult;
11970 else
11971 {
11972 e->next = tresult;
11973 while (e->next)
11974 e = e->next;
11975 }
11976 #endif
11977 }
11978 return (result);
11979 }
11980 #endif
11981
11982 /*******************************************
11983 * *
11984 * Functions to perform word splitting *
11985 * *
11986 *******************************************/
11987
11988 void
11989 setifs (v)
11990 SHELL_VAR *v;
11991 {
11992 char *t;
11993 unsigned char uc;
11994
11995 ifs_var = v;
11996 ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
11997
11998 ifs_is_set = ifs_var != 0;
11999 ifs_is_null = ifs_is_set && (*ifs_value == 0);
12000
12001 /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
12002 handle multibyte chars in IFS */
12003 memset (ifs_cmap, '\0', sizeof (ifs_cmap));
12004 for (t = ifs_value ; t && *t; t++)
12005 {
12006 uc = *t;
12007 ifs_cmap[uc] = 1;
12008 }
12009
12010 #if defined (HANDLE_MULTIBYTE)
12011 if (ifs_value == 0)
12012 {
12013 ifs_firstc[0] = '\0'; /* XXX - ? */
12014 ifs_firstc_len = 1;
12015 }
12016 else
12017 {
12018 if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value))
12019 ifs_firstc_len = (*ifs_value != 0) ? 1 : 0;
12020 else
12021 {
12022 size_t ifs_len;
12023 ifs_len = strnlen (ifs_value, MB_CUR_MAX);
12024 ifs_firstc_len = MBLEN (ifs_value, ifs_len);
12025 }
12026 if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
12027 {
12028 ifs_firstc[0] = ifs_value[0];
12029 ifs_firstc[1] = '\0';
12030 ifs_firstc_len = 1;
12031 }
12032 else
12033 memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
12034 }
12035 #else
12036 ifs_firstc = ifs_value ? *ifs_value : 0;
12037 #endif
12038 }
12039
12040 char *
12041 getifs ()
12042 {
12043 return ifs_value;
12044 }
12045
12046 /* This splits a single word into a WORD LIST on $IFS, but only if the word
12047 is not quoted. list_string () performs quote removal for us, even if we
12048 don't do any splitting. */
12049 WORD_LIST *
12050 word_split (w, ifs_chars)
12051 WORD_DESC *w;
12052 char *ifs_chars;
12053 {
12054 WORD_LIST *result;
12055
12056 if (w)
12057 {
12058 char *xifs;
12059
12060 xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
12061 result = list_string (w->word, xifs, w->flags & W_QUOTED);
12062 }
12063 else
12064 result = (WORD_LIST *)NULL;
12065
12066 return (result);
12067 }
12068
12069 /* Perform word splitting on LIST and return the RESULT. It is possible
12070 to return (WORD_LIST *)NULL. */
12071 static WORD_LIST *
12072 word_list_split (list)
12073 WORD_LIST *list;
12074 {
12075 WORD_LIST *result, *t, *tresult, *e;
12076 WORD_DESC *w;
12077
12078 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
12079 {
12080 tresult = word_split (t->word, ifs_value);
12081 /* POSIX 2.6: "If the complete expansion appropriate for a word results
12082 in an empty field, that empty field shall be deleted from the list
12083 of fields that form the completely expanded command, unless the
12084 original word contained single-quote or double-quote characters."
12085 This is where we handle these words that contain quoted null strings
12086 and other characters that expand to nothing after word splitting. */
12087 if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */
12088 {
12089 w = alloc_word_desc ();
12090 w->word = (char *)xmalloc (1);
12091 w->word[0] = '\0';
12092 tresult = make_word_list (w, (WORD_LIST *)NULL);
12093 }
12094 #if defined (ARRAY_VARS)
12095 /* pass W_ARRAYREF through for words that are not split and are
12096 identical to the original word. */
12097 if (tresult && tresult->next == 0 && t->next == 0 && (t->word->flags & W_ARRAYREF) && STREQ (t->word->word, tresult->word->word))
12098 tresult->word->flags |= W_ARRAYREF;
12099 #endif
12100 if (result == 0)
12101 result = e = tresult;
12102 else
12103 {
12104 e->next = tresult;
12105 while (e->next)
12106 e = e->next;
12107 }
12108 }
12109 return (result);
12110 }
12111
12112 /**************************************************
12113 * *
12114 * Functions to expand an entire WORD_LIST *
12115 * *
12116 **************************************************/
12117
12118 /* Do any word-expansion-specific cleanup and jump to top_level */
12119 static void
12120 exp_jump_to_top_level (v)
12121 int v;
12122 {
12123 set_pipestatus_from_exit (last_command_exit_value);
12124
12125 /* Cleanup code goes here. */
12126 expand_no_split_dollar_star = 0; /* XXX */
12127 if (expanding_redir)
12128 undo_partial_redirects ();
12129 expanding_redir = 0;
12130 assigning_in_environment = 0;
12131
12132 if (parse_and_execute_level == 0)
12133 top_level_cleanup (); /* from sig.c */
12134
12135 jump_to_top_level (v);
12136 }
12137
12138 /* Put NLIST (which is a WORD_LIST * of only one element) at the front of
12139 ELIST, and set ELIST to the new list. */
12140 #define PREPEND_LIST(nlist, elist) \
12141 do { nlist->next = elist; elist = nlist; } while (0)
12142
12143 /* Separate out any initial variable assignments from TLIST. If set -k has
12144 been executed, remove all assignment statements from TLIST. Initial
12145 variable assignments and other environment assignments are placed
12146 on SUBST_ASSIGN_VARLIST. */
12147 static WORD_LIST *
12148 separate_out_assignments (tlist)
12149 WORD_LIST *tlist;
12150 {
12151 register WORD_LIST *vp, *lp;
12152
12153 if (tlist == 0)
12154 return ((WORD_LIST *)NULL);
12155
12156 if (subst_assign_varlist)
12157 dispose_words (subst_assign_varlist); /* Clean up after previous error */
12158
12159 subst_assign_varlist = (WORD_LIST *)NULL;
12160 vp = lp = tlist;
12161
12162 /* Separate out variable assignments at the start of the command.
12163 Loop invariant: vp->next == lp
12164 Loop postcondition:
12165 lp = list of words left after assignment statements skipped
12166 tlist = original list of words
12167 */
12168 while (lp && (lp->word->flags & W_ASSIGNMENT))
12169 {
12170 vp = lp;
12171 lp = lp->next;
12172 }
12173
12174 /* If lp != tlist, we have some initial assignment statements.
12175 We make SUBST_ASSIGN_VARLIST point to the list of assignment
12176 words and TLIST point to the remaining words. */
12177 if (lp != tlist)
12178 {
12179 subst_assign_varlist = tlist;
12180 /* ASSERT(vp->next == lp); */
12181 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
12182 tlist = lp; /* remainder of word list */
12183 }
12184
12185 /* vp == end of variable list */
12186 /* tlist == remainder of original word list without variable assignments */
12187 if (!tlist)
12188 /* All the words in tlist were assignment statements */
12189 return ((WORD_LIST *)NULL);
12190
12191 /* ASSERT(tlist != NULL); */
12192 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
12193
12194 /* If the -k option is in effect, we need to go through the remaining
12195 words, separate out the assignment words, and place them on
12196 SUBST_ASSIGN_VARLIST. */
12197 if (place_keywords_in_env)
12198 {
12199 WORD_LIST *tp; /* tp == running pointer into tlist */
12200
12201 tp = tlist;
12202 lp = tlist->next;
12203
12204 /* Loop Invariant: tp->next == lp */
12205 /* Loop postcondition: tlist == word list without assignment statements */
12206 while (lp)
12207 {
12208 if (lp->word->flags & W_ASSIGNMENT)
12209 {
12210 /* Found an assignment statement, add this word to end of
12211 subst_assign_varlist (vp). */
12212 if (!subst_assign_varlist)
12213 subst_assign_varlist = vp = lp;
12214 else
12215 {
12216 vp->next = lp;
12217 vp = lp;
12218 }
12219
12220 /* Remove the word pointed to by LP from TLIST. */
12221 tp->next = lp->next;
12222 /* ASSERT(vp == lp); */
12223 lp->next = (WORD_LIST *)NULL;
12224 lp = tp->next;
12225 }
12226 else
12227 {
12228 tp = lp;
12229 lp = lp->next;
12230 }
12231 }
12232 }
12233 return (tlist);
12234 }
12235
12236 #define WEXP_VARASSIGN 0x001
12237 #define WEXP_BRACEEXP 0x002
12238 #define WEXP_TILDEEXP 0x004
12239 #define WEXP_PARAMEXP 0x008
12240 #define WEXP_PATHEXP 0x010
12241
12242 /* All of the expansions, including variable assignments at the start of
12243 the list. */
12244 #define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
12245
12246 /* All of the expansions except variable assignments at the start of
12247 the list. */
12248 #define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
12249
12250 /* All of the `shell expansions': brace expansion, tilde expansion, parameter
12251 expansion, command substitution, arithmetic expansion, word splitting, and
12252 quote removal. */
12253 #define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
12254
12255 /* Take the list of words in LIST and do the various substitutions. Return
12256 a new list of words which is the expanded list, and without things like
12257 variable assignments. */
12258
12259 WORD_LIST *
12260 expand_words (list)
12261 WORD_LIST *list;
12262 {
12263 return (expand_word_list_internal (list, WEXP_ALL));
12264 }
12265
12266 /* Same as expand_words (), but doesn't hack variable or environment
12267 variables. */
12268 WORD_LIST *
12269 expand_words_no_vars (list)
12270 WORD_LIST *list;
12271 {
12272 return (expand_word_list_internal (list, WEXP_NOVARS));
12273 }
12274
12275 WORD_LIST *
12276 expand_words_shellexp (list)
12277 WORD_LIST *list;
12278 {
12279 return (expand_word_list_internal (list, WEXP_SHELLEXP));
12280 }
12281
12282 static WORD_LIST *
12283 glob_expand_word_list (tlist, eflags)
12284 WORD_LIST *tlist;
12285 int eflags;
12286 {
12287 char **glob_array, *temp_string;
12288 register int glob_index;
12289 WORD_LIST *glob_list, *output_list, *disposables, *next;
12290 WORD_DESC *tword;
12291 int x;
12292
12293 output_list = disposables = (WORD_LIST *)NULL;
12294 glob_array = (char **)NULL;
12295 while (tlist)
12296 {
12297 /* For each word, either globbing is attempted or the word is
12298 added to orig_list. If globbing succeeds, the results are
12299 added to orig_list and the word (tlist) is added to the list
12300 of disposable words. If globbing fails and failed glob
12301 expansions are left unchanged (the shell default), the
12302 original word is added to orig_list. If globbing fails and
12303 failed glob expansions are removed, the original word is
12304 added to the list of disposable words. orig_list ends up
12305 in reverse order and requires a call to REVERSE_LIST to
12306 be set right. After all words are examined, the disposable
12307 words are freed. */
12308 next = tlist->next;
12309
12310 /* If the word isn't an assignment and contains an unquoted
12311 pattern matching character, then glob it. */
12312 if ((tlist->word->flags & W_NOGLOB) == 0 &&
12313 unquoted_glob_pattern_p (tlist->word->word))
12314 {
12315 glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */
12316
12317 /* Handle error cases.
12318 I don't think we should report errors like "No such file
12319 or directory". However, I would like to report errors
12320 like "Read failed". */
12321
12322 if (glob_array == 0 || GLOB_FAILED (glob_array))
12323 {
12324 glob_array = (char **)xmalloc (sizeof (char *));
12325 glob_array[0] = (char *)NULL;
12326 }
12327
12328 /* Dequote the current word in case we have to use it. */
12329 if (glob_array[0] == NULL)
12330 {
12331 temp_string = dequote_string (tlist->word->word);
12332 free (tlist->word->word);
12333 tlist->word->word = temp_string;
12334 }
12335
12336 /* Make the array into a word list. */
12337 glob_list = (WORD_LIST *)NULL;
12338 for (glob_index = 0; glob_array[glob_index]; glob_index++)
12339 {
12340 tword = make_bare_word (glob_array[glob_index]);
12341 glob_list = make_word_list (tword, glob_list);
12342 }
12343
12344 if (glob_list)
12345 {
12346 output_list = (WORD_LIST *)list_append (glob_list, output_list);
12347 PREPEND_LIST (tlist, disposables);
12348 }
12349 else if (fail_glob_expansion != 0)
12350 {
12351 last_command_exit_value = EXECUTION_FAILURE;
12352 report_error (_("no match: %s"), tlist->word->word);
12353 exp_jump_to_top_level (DISCARD);
12354 }
12355 else if (allow_null_glob_expansion == 0)
12356 {
12357 /* Failed glob expressions are left unchanged. */
12358 PREPEND_LIST (tlist, output_list);
12359 }
12360 else
12361 {
12362 /* Failed glob expressions are removed. */
12363 PREPEND_LIST (tlist, disposables);
12364 }
12365 }
12366 else
12367 {
12368 /* Dequote the string. */
12369 temp_string = dequote_string (tlist->word->word);
12370 free (tlist->word->word);
12371 tlist->word->word = temp_string;
12372 PREPEND_LIST (tlist, output_list);
12373 }
12374
12375 strvec_dispose (glob_array);
12376 glob_array = (char **)NULL;
12377
12378 tlist = next;
12379 }
12380
12381 if (disposables)
12382 dispose_words (disposables);
12383
12384 if (output_list)
12385 output_list = REVERSE_LIST (output_list, WORD_LIST *);
12386
12387 return (output_list);
12388 }
12389
12390 #if defined (BRACE_EXPANSION)
12391 static WORD_LIST *
12392 brace_expand_word_list (tlist, eflags)
12393 WORD_LIST *tlist;
12394 int eflags;
12395 {
12396 register char **expansions;
12397 char *temp_string;
12398 WORD_LIST *disposables, *output_list, *next;
12399 WORD_DESC *w;
12400 int eindex;
12401
12402 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
12403 {
12404 next = tlist->next;
12405
12406 if (tlist->word->flags & W_NOBRACE)
12407 {
12408 /*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/
12409 PREPEND_LIST (tlist, output_list);
12410 continue;
12411 }
12412
12413 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
12414 {
12415 /*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
12416 PREPEND_LIST (tlist, output_list);
12417 continue;
12418 }
12419
12420 /* Only do brace expansion if the word has a brace character. If
12421 not, just add the word list element to BRACES and continue. In
12422 the common case, at least when running shell scripts, this will
12423 degenerate to a bunch of calls to `mbschr', and then what is
12424 basically a reversal of TLIST into BRACES, which is corrected
12425 by a call to REVERSE_LIST () on BRACES when the end of TLIST
12426 is reached. */
12427 if (mbschr (tlist->word->word, LBRACE))
12428 {
12429 expansions = brace_expand (tlist->word->word);
12430
12431 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
12432 {
12433 w = alloc_word_desc ();
12434 w->word = temp_string;
12435
12436 /* If brace expansion didn't change the word, preserve
12437 the flags. We may want to preserve the flags
12438 unconditionally someday -- XXX */
12439 if (STREQ (temp_string, tlist->word->word))
12440 w->flags = tlist->word->flags;
12441 else
12442 w = make_word_flags (w, temp_string);
12443
12444 output_list = make_word_list (w, output_list);
12445 }
12446 free (expansions);
12447
12448 /* Add TLIST to the list of words to be freed after brace
12449 expansion has been performed. */
12450 PREPEND_LIST (tlist, disposables);
12451 }
12452 else
12453 PREPEND_LIST (tlist, output_list);
12454 }
12455
12456 if (disposables)
12457 dispose_words (disposables);
12458
12459 if (output_list)
12460 output_list = REVERSE_LIST (output_list, WORD_LIST *);
12461
12462 return (output_list);
12463 }
12464 #endif
12465
12466 #if defined (ARRAY_VARS)
12467 /* Take WORD, a compound array assignment, and internally run (for example),
12468 'declare -A w', where W is the variable name portion of WORD. OPTION is
12469 the list of options to supply to `declare'. CMD is the declaration command
12470 we are expanding right now; it's unused currently. */
12471 static int
12472 make_internal_declare (word, option, cmd)
12473 char *word;
12474 char *option;
12475 char *cmd;
12476 {
12477 int t, r;
12478 WORD_LIST *wl;
12479 WORD_DESC *w;
12480
12481 w = make_word (word);
12482
12483 t = assignment (w->word, 0);
12484 if (w->word[t] == '=')
12485 {
12486 w->word[t] = '\0';
12487 if (w->word[t - 1] == '+') /* cut off any append op */
12488 w->word[t - 1] = '\0';
12489 }
12490
12491 wl = make_word_list (w, (WORD_LIST *)NULL);
12492 wl = make_word_list (make_word (option), wl);
12493
12494 r = declare_builtin (wl);
12495
12496 dispose_words (wl);
12497 return r;
12498 }
12499
12500 /* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME
12501 is an associative array.
12502
12503 If we are processing an indexed array, expand_compound_array_assignment
12504 will expand all the individual words and quote_compound_array_list will
12505 single-quote them. If we are processing an associative array, we use
12506 parse_string_to_word_list to split VALUE into a list of words instead of
12507 faking up a shell variable and calling expand_compound_array_assignment.
12508 expand_and_quote_assoc_word expands and single-quotes each word in VALUE
12509 together so we don't have problems finding the end of the subscript when
12510 quoting it.
12511
12512 Words in VALUE can be individual words, which are expanded and single-quoted,
12513 or words of the form [IND]=VALUE, which end up as explained below, as
12514 ['expanded-ind']='expanded-value'. */
12515
12516 static WORD_LIST *
12517 expand_oneword (value, flags)
12518 char *value;
12519 int flags;
12520 {
12521 WORD_LIST *l, *nl;
12522 char *t;
12523 int kvpair;
12524
12525 if (flags == 0)
12526 {
12527 /* Indexed array */
12528 l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags);
12529 /* Now we quote the results of the expansion above to prevent double
12530 expansion. */
12531 quote_compound_array_list (l, flags);
12532 return l;
12533 }
12534 else
12535 {
12536 /* Associative array */
12537 l = parse_string_to_word_list (value, 1, "array assign");
12538 #if ASSOC_KVPAIR_ASSIGNMENT
12539 kvpair = kvpair_assignment_p (l);
12540 #endif
12541
12542 /* For associative arrays, with their arbitrary subscripts, we have to
12543 expand and quote in one step so we don't have to search for the
12544 closing right bracket more than once. */
12545 for (nl = l; nl; nl = nl->next)
12546 {
12547 #if ASSOC_KVPAIR_ASSIGNMENT
12548 if (kvpair)
12549 /* keys and values undergo the same set of expansions */
12550 t = expand_and_quote_kvpair_word (nl->word->word);
12551 else
12552 #endif
12553 if ((nl->word->flags & W_ASSIGNMENT) == 0)
12554 t = sh_single_quote (nl->word->word ? nl->word->word : "");
12555 else
12556 t = expand_and_quote_assoc_word (nl->word->word, flags);
12557 free (nl->word->word);
12558 nl->word->word = t;
12559 }
12560 return l;
12561 }
12562 }
12563
12564 /* Expand a single compound assignment argument to a declaration builtin.
12565 This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through
12566 unchanged. The VALUE is expanded and each word in the result is single-
12567 quoted. Words of the form [key]=value end up as
12568 ['expanded-key']='expanded-value'. Associative arrays have special
12569 handling, see expand_oneword() above. The return value is
12570 NAME[+]=( expanded-and-quoted-VALUE ). */
12571 static void
12572 expand_compound_assignment_word (tlist, flags)
12573 WORD_LIST *tlist;
12574 int flags;
12575 {
12576 WORD_LIST *l;
12577 int wlen, oind, t;
12578 char *value, *temp;
12579
12580 /*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/
12581 t = assignment (tlist->word->word, 0);
12582
12583 /* value doesn't have the open and close parens */
12584 oind = 1;
12585 value = extract_array_assignment_list (tlist->word->word + t + 1, &oind);
12586 /* This performs one round of expansion on the index/key and value and
12587 single-quotes each word in the result. */
12588 l = expand_oneword (value, flags);
12589 free (value);
12590
12591 value = string_list (l);
12592 dispose_words (l);
12593
12594 wlen = STRLEN (value);
12595
12596 /* Now, let's rebuild the string */
12597 temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */
12598 memcpy (temp, tlist->word->word, ++t);
12599 temp[t++] = '(';
12600 if (value)
12601 memcpy (temp + t, value, wlen);
12602 t += wlen;
12603 temp[t++] = ')';
12604 temp[t] = '\0';
12605 /*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/
12606
12607 free (tlist->word->word);
12608 tlist->word->word = temp;
12609
12610 free (value);
12611 }
12612
12613 /* Expand and process an argument to a declaration command. We have already
12614 set flags in TLIST->word->flags depending on the declaration command
12615 (declare, local, etc.) and the options supplied to it (-a, -A, etc.).
12616 TLIST->word->word is of the form NAME[+]=( VALUE ).
12617
12618 This does several things, all using pieces of other functions to get the
12619 evaluation sequence right. It's called for compound array assignments with
12620 the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs).
12621 It parses out which flags need to be set for declare to create the variable
12622 correctly, then calls declare internally (make_internal_declare) to make
12623 sure the variable exists with the correct attributes. Before the variable
12624 is created, it calls expand_compound_assignment_word to expand VALUE to a
12625 list of words, appropriately quoted for further evaluation. This preserves
12626 the semantics of word-expansion-before-calling-builtins. Finally, it calls
12627 do_word_assignment to perform the expansion and assignment with the same
12628 expansion semantics as a standalone assignment statement (no word splitting,
12629 etc.) even though the word is single-quoted so all that needs to happen is
12630 quote removal. */
12631 static WORD_LIST *
12632 expand_declaration_argument (tlist, wcmd)
12633 WORD_LIST *tlist, *wcmd;
12634 {
12635 char opts[16], omap[128];
12636 int t, opti, oind, skip, inheriting;
12637 WORD_LIST *l;
12638
12639 inheriting = localvar_inherit;
12640 opti = 0;
12641 if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY))
12642 opts[opti++] = '-';
12643
12644 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
12645 {
12646 opts[opti++] = 'g';
12647 opts[opti++] = 'A';
12648 }
12649 else if (tlist->word->flags & W_ASSIGNASSOC)
12650 {
12651 opts[opti++] = 'A';
12652 }
12653 else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
12654 {
12655 opts[opti++] = 'g';
12656 opts[opti++] = 'a';
12657 }
12658 else if (tlist->word->flags & W_ASSIGNARRAY)
12659 {
12660 opts[opti++] = 'a';
12661 }
12662 else if (tlist->word->flags & W_ASSNGLOBAL)
12663 opts[opti++] = 'g';
12664
12665 if (tlist->word->flags & W_CHKLOCAL)
12666 opts[opti++] = 'G';
12667
12668 /* If we have special handling note the integer attribute and others
12669 that transform the value upon assignment. What we do is take all
12670 of the option arguments and scan through them looking for options
12671 that cause such transformations, and add them to the `opts' array. */
12672
12673 memset (omap, '\0', sizeof (omap));
12674 for (l = wcmd->next; l != tlist; l = l->next)
12675 {
12676 int optchar;
12677
12678 if (l->word->word[0] != '-' && l->word->word[0] != '+')
12679 break; /* non-option argument */
12680 if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0)
12681 break; /* -- signals end of options */
12682 optchar = l->word->word[0];
12683 for (oind = 1; l->word->word[oind]; oind++)
12684 switch (l->word->word[oind])
12685 {
12686 case 'I':
12687 inheriting = 1;
12688 case 'i':
12689 case 'l':
12690 case 'u':
12691 case 'c':
12692 omap[l->word->word[oind]] = 1;
12693 if (opti == 0)
12694 opts[opti++] = optchar;
12695 break;
12696 default:
12697 break;
12698 }
12699 }
12700
12701 for (oind = 0; oind < sizeof (omap); oind++)
12702 if (omap[oind])
12703 opts[opti++] = oind;
12704
12705 /* If there are no -a/-A options, but we have a compound assignment,
12706 we have a choice: we can set opts[0]='-', opts[1]='a', since the
12707 default is to create an indexed array, and call
12708 make_internal_declare with that, or we can just skip the -a and let
12709 declare_builtin deal with it. Once we're here, we're better set
12710 up for the latter, since we don't want to deal with looking up
12711 any existing variable here -- better to let declare_builtin do it.
12712 We need the variable created, though, especially if it's local, so
12713 we get the scoping right before we call do_word_assignment.
12714 To ensure that make_local_declare gets called, we add `--' if there
12715 aren't any options. */
12716 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0)
12717 {
12718 if (opti == 0)
12719 {
12720 opts[opti++] = '-';
12721 opts[opti++] = '-';
12722 }
12723 }
12724 opts[opti] = '\0';
12725
12726 /* This isn't perfect, but it's a start. Improvements later. We expand
12727 tlist->word->word and single-quote the results to avoid multiple
12728 expansions by, say, do_assignment_internal(). We have to weigh the
12729 cost of reconstructing the compound assignment string with its single
12730 quoting and letting the declare builtin handle it. The single quotes
12731 will prevent any unwanted additional expansion or word splitting. */
12732 expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0);
12733
12734 skip = 0;
12735 if (opti > 0)
12736 {
12737 t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0);
12738 if (t != EXECUTION_SUCCESS)
12739 {
12740 last_command_exit_value = t;
12741 if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */
12742 skip = 1;
12743 else
12744 exp_jump_to_top_level (DISCARD);
12745 }
12746 }
12747
12748 if (skip == 0)
12749 {
12750 t = do_word_assignment (tlist->word, 0);
12751 if (t == 0)
12752 {
12753 last_command_exit_value = EXECUTION_FAILURE;
12754 exp_jump_to_top_level (DISCARD);
12755 }
12756 }
12757
12758 /* Now transform the word as ksh93 appears to do and go on */
12759 t = assignment (tlist->word->word, 0);
12760 tlist->word->word[t] = '\0';
12761 if (tlist->word->word[t - 1] == '+')
12762 tlist->word->word[t - 1] = '\0'; /* cut off append op */
12763 tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
12764
12765 return (tlist);
12766 }
12767 #endif /* ARRAY_VARS */
12768
12769 static WORD_LIST *
12770 shell_expand_word_list (tlist, eflags)
12771 WORD_LIST *tlist;
12772 int eflags;
12773 {
12774 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd;
12775 int expanded_something, has_dollar_at;
12776
12777 /* We do tilde expansion all the time. This is what 1003.2 says. */
12778 wcmd = new_list = (WORD_LIST *)NULL;
12779
12780 for (orig_list = tlist; tlist; tlist = next)
12781 {
12782 if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN))
12783 wcmd = tlist;
12784
12785 next = tlist->next;
12786
12787 #if defined (ARRAY_VARS)
12788 /* If this is a compound array assignment to a builtin that accepts
12789 such assignments (e.g., `declare'), take the assignment and perform
12790 it separately, handling the semantics of declarations inside shell
12791 functions. This avoids the double-evaluation of such arguments,
12792 because `declare' does some evaluation of compound assignments on
12793 its own. */
12794 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
12795 expand_declaration_argument (tlist, wcmd);
12796 #endif
12797
12798 expanded_something = 0;
12799 expanded = expand_word_internal
12800 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
12801
12802 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
12803 {
12804 /* By convention, each time this error is returned,
12805 tlist->word->word has already been freed. */
12806 tlist->word->word = (char *)NULL;
12807
12808 /* Dispose our copy of the original list. */
12809 dispose_words (orig_list);
12810 /* Dispose the new list we're building. */
12811 dispose_words (new_list);
12812
12813 last_command_exit_value = EXECUTION_FAILURE;
12814 if (expanded == &expand_word_error)
12815 exp_jump_to_top_level (DISCARD);
12816 else
12817 exp_jump_to_top_level (FORCE_EOF);
12818 }
12819
12820 /* Don't split words marked W_NOSPLIT. */
12821 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
12822 {
12823 temp_list = word_list_split (expanded);
12824 dispose_words (expanded);
12825 }
12826 else
12827 {
12828 /* If no parameter expansion, command substitution, process
12829 substitution, or arithmetic substitution took place, then
12830 do not do word splitting. We still have to remove quoted
12831 null characters from the result. */
12832 word_list_remove_quoted_nulls (expanded);
12833 temp_list = expanded;
12834 }
12835
12836 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
12837 new_list = (WORD_LIST *)list_append (expanded, new_list);
12838 }
12839
12840 if (orig_list)
12841 dispose_words (orig_list);
12842
12843 if (new_list)
12844 new_list = REVERSE_LIST (new_list, WORD_LIST *);
12845
12846 return (new_list);
12847 }
12848
12849 /* Perform assignment statements optionally preceding a command name COMMAND.
12850 If COMMAND == NULL, is_nullcmd usually == 1. Follow the POSIX rules for
12851 variable assignment errors. */
12852 static int
12853 do_assignment_statements (varlist, command, is_nullcmd)
12854 WORD_LIST *varlist;
12855 char *command;
12856 int is_nullcmd;
12857 {
12858 WORD_LIST *temp_list;
12859 char *savecmd;
12860 sh_wassign_func_t *assign_func;
12861 int is_special_builtin, is_builtin_or_func, tint;
12862
12863 /* If the remainder of the words expand to nothing, Posix.2 requires
12864 that the variable and environment assignments affect the shell's
12865 environment (do_word_assignment). */
12866 assign_func = is_nullcmd ? do_word_assignment : assign_in_env;
12867 tempenv_assign_error = 0;
12868
12869 is_builtin_or_func = command && (find_shell_builtin (command) || find_function (command));
12870 /* Posix says that special builtins exit if a variable assignment error
12871 occurs in an assignment preceding it. (XXX - this is old -- current Posix
12872 says that any variable assignment error causes a non-interactive shell
12873 to exit. See the STRICT_POSIX checks below. */
12874 is_special_builtin = posixly_correct && command && find_special_builtin (command);
12875
12876 savecmd = this_command_name;
12877 for (temp_list = varlist; temp_list; temp_list = temp_list->next)
12878 {
12879 this_command_name = (char *)NULL;
12880 assigning_in_environment = is_nullcmd == 0;
12881 tint = (*assign_func) (temp_list->word, is_builtin_or_func);
12882 assigning_in_environment = 0;
12883 this_command_name = savecmd;
12884
12885 /* Variable assignment errors in non-interactive shells running
12886 in posix mode cause the shell to exit. */
12887 if (tint == 0)
12888 {
12889 if (is_nullcmd) /* assignment statement */
12890 {
12891 last_command_exit_value = EXECUTION_FAILURE;
12892 #if defined (STRICT_POSIX)
12893 if (posixly_correct && interactive_shell == 0)
12894 #else
12895 if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
12896 #endif
12897 exp_jump_to_top_level (FORCE_EOF);
12898 else
12899 exp_jump_to_top_level (DISCARD);
12900 }
12901 /* In posix mode, assignment errors in the temporary environment
12902 cause a non-interactive shell executing a special builtin to
12903 exit and a non-interactive shell to otherwise jump back to the
12904 top level. This is what POSIX says to do for variable assignment
12905 errors, and POSIX says errors in assigning to the temporary
12906 environment are treated as variable assignment errors.
12907 (XXX - this is not what current POSIX says - look at the
12908 STRICT_POSIX defines. */
12909 else if (posixly_correct)
12910 {
12911 last_command_exit_value = EXECUTION_FAILURE;
12912 #if defined (STRICT_POSIX)
12913 exp_jump_to_top_level ((interactive_shell == 0) ? FORCE_EOF : DISCARD);
12914 #else
12915 if (interactive_shell == 0 && is_special_builtin)
12916 exp_jump_to_top_level (FORCE_EOF);
12917 else if (interactive_shell == 0)
12918 exp_jump_to_top_level (DISCARD); /* XXX - maybe change later */
12919 else
12920 exp_jump_to_top_level (DISCARD);
12921 #endif
12922 }
12923 else
12924 tempenv_assign_error++;
12925 }
12926 }
12927 return (tempenv_assign_error);
12928 }
12929
12930 /* The workhorse for expand_words () and expand_words_no_vars ().
12931 First arg is LIST, a WORD_LIST of words.
12932 Second arg EFLAGS is a flags word controlling which expansions are
12933 performed.
12934
12935 This does all of the substitutions: brace expansion, tilde expansion,
12936 parameter expansion, command substitution, arithmetic expansion,
12937 process substitution, word splitting, and pathname expansion, according
12938 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
12939 set, or for which no expansion is done, do not undergo word splitting.
12940 Words with the W_NOGLOB bit set do not undergo pathname expansion; words
12941 with W_NOBRACE set do not undergo brace expansion (see
12942 brace_expand_word_list above). */
12943 static WORD_LIST *
12944 expand_word_list_internal (list, eflags)
12945 WORD_LIST *list;
12946 int eflags;
12947 {
12948 WORD_LIST *new_list, *temp_list;
12949
12950 tempenv_assign_error = 0;
12951 if (list == 0)
12952 return ((WORD_LIST *)NULL);
12953
12954 garglist = new_list = copy_word_list (list);
12955 if (eflags & WEXP_VARASSIGN)
12956 {
12957 garglist = new_list = separate_out_assignments (new_list);
12958 if (new_list == 0)
12959 {
12960 if (subst_assign_varlist)
12961 do_assignment_statements (subst_assign_varlist, (char *)NULL, 1);
12962
12963 dispose_words (subst_assign_varlist);
12964 subst_assign_varlist = (WORD_LIST *)NULL;
12965
12966 return ((WORD_LIST *)NULL);
12967 }
12968 }
12969
12970 /* Begin expanding the words that remain. The expansions take place on
12971 things that aren't really variable assignments. */
12972
12973 #if defined (BRACE_EXPANSION)
12974 /* Do brace expansion on this word if there are any brace characters
12975 in the string. */
12976 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
12977 new_list = brace_expand_word_list (new_list, eflags);
12978 #endif /* BRACE_EXPANSION */
12979
12980 /* Perform the `normal' shell expansions: tilde expansion, parameter and
12981 variable substitution, command substitution, arithmetic expansion,
12982 and word splitting. */
12983 new_list = shell_expand_word_list (new_list, eflags);
12984
12985 /* Okay, we're almost done. Now let's just do some filename
12986 globbing. */
12987 if (new_list)
12988 {
12989 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
12990 /* Glob expand the word list unless globbing has been disabled. */
12991 new_list = glob_expand_word_list (new_list, eflags);
12992 else
12993 /* Dequote the words, because we're not performing globbing. */
12994 new_list = dequote_list (new_list);
12995 }
12996
12997 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
12998 {
12999 do_assignment_statements (subst_assign_varlist, (new_list && new_list->word) ? new_list->word->word : (char *)NULL, new_list == 0);
13000
13001 dispose_words (subst_assign_varlist);
13002 subst_assign_varlist = (WORD_LIST *)NULL;
13003 }
13004
13005 return (new_list);
13006 }