]> git.ipfire.org Git - thirdparty/bash.git/blob - subst.c
880d0ecd08660dc486c6fb79126da5c53e26c695
[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-2020 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 "flags.h"
49 #include "jobs.h"
50 #include "execute_cmd.h"
51 #include "filecntl.h"
52 #include "trap.h"
53 #include "pathexp.h"
54 #include "mailcheck.h"
55
56 #include "shmbutil.h"
57 #if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
58 # include <mbstr.h> /* mbschr */
59 #endif
60 #include "typemax.h"
61
62 #include "builtins/getopt.h"
63 #include "builtins/common.h"
64
65 #include "builtins/builtext.h"
66
67 #include <tilde/tilde.h>
68 #include <glob/strmatch.h>
69
70 #if !defined (errno)
71 extern int errno;
72 #endif /* !errno */
73
74 /* The size that strings change by. */
75 #define DEFAULT_INITIAL_ARRAY_SIZE 112
76 #define DEFAULT_ARRAY_SIZE 128
77
78 /* Variable types. */
79 #define VT_VARIABLE 0
80 #define VT_POSPARMS 1
81 #define VT_ARRAYVAR 2
82 #define VT_ARRAYMEMBER 3
83 #define VT_ASSOCVAR 4
84
85 #define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
86
87 /* Flags for quoted_strchr */
88 #define ST_BACKSL 0x01
89 #define ST_CTLESC 0x02
90 #define ST_SQUOTE 0x04 /* unused yet */
91 #define ST_DQUOTE 0x08 /* unused yet */
92
93 /* These defs make it easier to use the editor. */
94 #define LBRACE '{'
95 #define RBRACE '}'
96 #define LPAREN '('
97 #define RPAREN ')'
98 #define LBRACK '['
99 #define RBRACK ']'
100
101 #if defined (HANDLE_MULTIBYTE)
102 #define WLPAREN L'('
103 #define WRPAREN L')'
104 #endif
105
106 #define DOLLAR_AT_STAR(c) ((c) == '@' || (c) == '*')
107 #define STR_DOLLAR_AT_STAR(s) (DOLLAR_AT_STAR ((s)[0]) && (s)[1] == '\0')
108
109 /* Evaluates to 1 if C is one of the shell's special parameters whose length
110 can be taken, but is also one of the special expansion characters. */
111 #define VALID_SPECIAL_LENGTH_PARAM(c) \
112 ((c) == '-' || (c) == '?' || (c) == '#' || (c) == '@')
113
114 /* Evaluates to 1 if C is one of the shell's special parameters for which an
115 indirect variable reference may be made. */
116 #define VALID_INDIR_PARAM(c) \
117 ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
118
119 /* Evaluates to 1 if C is one of the OP characters that follows the parameter
120 in ${parameter[:]OPword}. */
121 #define VALID_PARAM_EXPAND_CHAR(c) (sh_syntaxtab[(unsigned char)c] & CSUBSTOP)
122
123 /* Evaluates to 1 if this is one of the shell's special variables. */
124 #define SPECIAL_VAR(name, wi) \
125 (*name && ((DIGIT (*name) && all_digits (name)) || \
126 (name[1] == '\0' && (sh_syntaxtab[(unsigned char)*name] & CSPECVAR)) || \
127 (wi && name[2] == '\0' && VALID_INDIR_PARAM (name[1]))))
128
129 /* This can be used by all of the *_extract_* functions that have a similar
130 structure. It can't just be wrapped in a do...while(0) loop because of
131 the embedded `break'. The dangling else accommodates a trailing semicolon;
132 we could also put in a do ; while (0) */
133
134 #define CHECK_STRING_OVERRUN(oind, ind, len, ch) \
135 if (ind >= len) \
136 { \
137 oind = len; \
138 ch = 0; \
139 break; \
140 } \
141 else \
142
143 /* An expansion function that takes a string and a quoted flag and returns
144 a WORD_LIST *. Used as the type of the third argument to
145 expand_string_if_necessary(). */
146 typedef WORD_LIST *EXPFUNC PARAMS((char *, int));
147
148 /* Process ID of the last command executed within command substitution. */
149 pid_t last_command_subst_pid = NO_PID;
150 pid_t current_command_subst_pid = NO_PID;
151
152 /* Variables used to keep track of the characters in IFS. */
153 SHELL_VAR *ifs_var;
154 char *ifs_value;
155 unsigned char ifs_cmap[UCHAR_MAX + 1];
156 int ifs_is_set, ifs_is_null;
157
158 #if defined (HANDLE_MULTIBYTE)
159 unsigned char ifs_firstc[MB_LEN_MAX];
160 size_t ifs_firstc_len;
161 #else
162 unsigned char ifs_firstc;
163 #endif
164
165 /* If non-zero, command substitution inherits the value of errexit option */
166 int inherit_errexit = 0;
167
168 /* Sentinel to tell when we are performing variable assignments preceding a
169 command name and putting them into the environment. Used to make sure
170 we use the temporary environment when looking up variable values. */
171 int assigning_in_environment;
172
173 /* Used to hold a list of variable assignments preceding a command. Global
174 so the SIGCHLD handler in jobs.c can unwind-protect it when it runs a
175 SIGCHLD trap and so it can be saved and restored by the trap handlers. */
176 WORD_LIST *subst_assign_varlist = (WORD_LIST *)NULL;
177
178 /* Tell the expansion functions to not longjmp back to top_level on fatal
179 errors. Enabled when doing completion and prompt string expansion. */
180 int no_longjmp_on_fatal_error = 0;
181
182 /* Non-zero means to allow unmatched globbed filenames to expand to
183 a null file. */
184 int allow_null_glob_expansion;
185
186 /* Non-zero means to throw an error when globbing fails to match anything. */
187 int fail_glob_expansion;
188
189 /* Extern functions and variables from different files. */
190 extern struct fd_bitmap *current_fds_to_close;
191 extern int wordexp_only;
192
193 #if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION)
194 extern PROCESS *last_procsub_child;
195 #endif
196
197 #if !defined (HAVE_WCSDUP) && defined (HANDLE_MULTIBYTE)
198 extern wchar_t *wcsdup PARAMS((const wchar_t *));
199 #endif
200
201 #if 0
202 /* Variables to keep track of which words in an expanded word list (the
203 output of expand_word_list_internal) are the result of globbing
204 expansions. GLOB_ARGV_FLAGS is used by execute_cmd.c.
205 (CURRENTLY UNUSED). */
206 char *glob_argv_flags;
207 static int glob_argv_flags_size;
208 #endif
209
210 static WORD_LIST *cached_quoted_dollar_at = 0;
211
212 /* Distinguished error values to return from expansion functions */
213 static WORD_LIST expand_word_error, expand_word_fatal;
214 static WORD_DESC expand_wdesc_error, expand_wdesc_fatal;
215 static char expand_param_error, expand_param_fatal, expand_param_unset;
216 static char extract_string_error, extract_string_fatal;
217
218 /* Set by expand_word_unsplit and several of the expand_string_XXX functions;
219 used to inhibit splitting and re-joining $* on $IFS, primarily when doing
220 assignment statements. The idea is that if we're in a context where this
221 is set, we're not going to be performing word splitting, so we use the same
222 rules to expand $* as we would if it appeared within double quotes. */
223 static int expand_no_split_dollar_star = 0;
224
225 /* A WORD_LIST of words to be expanded by expand_word_list_internal,
226 without any leading variable assignments. */
227 static WORD_LIST *garglist = (WORD_LIST *)NULL;
228
229 static char *quoted_substring PARAMS((char *, int, int));
230 static int quoted_strlen PARAMS((char *));
231 static char *quoted_strchr PARAMS((char *, int, int));
232
233 static char *expand_string_if_necessary PARAMS((char *, int, EXPFUNC *));
234 static inline char *expand_string_to_string_internal PARAMS((char *, int, EXPFUNC *));
235 static WORD_LIST *call_expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *));
236 static WORD_LIST *expand_string_internal PARAMS((char *, int));
237 static WORD_LIST *expand_string_leave_quoted PARAMS((char *, int));
238 static WORD_LIST *expand_string_for_rhs PARAMS((char *, int, int, int, int *, int *));
239 static WORD_LIST *expand_string_for_pat PARAMS((char *, int, int *, int *));
240
241 static char *quote_escapes_internal PARAMS((const char *, int));
242
243 static WORD_LIST *list_quote_escapes PARAMS((WORD_LIST *));
244 static WORD_LIST *list_dequote_escapes PARAMS((WORD_LIST *));
245
246 static char *make_quoted_char PARAMS((int));
247 static WORD_LIST *quote_list PARAMS((WORD_LIST *));
248
249 static int unquoted_substring PARAMS((char *, char *));
250 static int unquoted_member PARAMS((int, char *));
251
252 #if defined (ARRAY_VARS)
253 static SHELL_VAR *do_compound_assignment PARAMS((char *, char *, int));
254 #endif
255 static int do_assignment_internal PARAMS((const WORD_DESC *, int));
256
257 static char *string_extract_verbatim PARAMS((char *, size_t, int *, char *, int));
258 static char *string_extract PARAMS((char *, int *, char *, int));
259 static char *string_extract_double_quoted PARAMS((char *, int *, int));
260 static inline char *string_extract_single_quoted PARAMS((char *, int *));
261 static inline int skip_single_quoted PARAMS((const char *, size_t, int, int));
262 static int skip_double_quoted PARAMS((char *, size_t, int, int));
263 static char *extract_delimited_string PARAMS((char *, int *, char *, char *, char *, int));
264 static char *extract_dollar_brace_string PARAMS((char *, int *, int, int));
265 static int skip_matched_pair PARAMS((const char *, int, int, int, int));
266
267 static char *pos_params PARAMS((char *, int, int, int, int));
268
269 static unsigned char *mb_getcharlens PARAMS((char *, int));
270
271 static char *remove_upattern PARAMS((char *, char *, int));
272 #if defined (HANDLE_MULTIBYTE)
273 static wchar_t *remove_wpattern PARAMS((wchar_t *, size_t, wchar_t *, int));
274 #endif
275 static char *remove_pattern PARAMS((char *, char *, int));
276
277 static int match_upattern PARAMS((char *, char *, int, char **, char **));
278 #if defined (HANDLE_MULTIBYTE)
279 static int match_wpattern PARAMS((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
280 #endif
281 static int match_pattern PARAMS((char *, char *, int, char **, char **));
282 static int getpatspec PARAMS((int, char *));
283 static char *getpattern PARAMS((char *, int, int));
284 static char *variable_remove_pattern PARAMS((char *, char *, int, int));
285 static char *list_remove_pattern PARAMS((WORD_LIST *, char *, int, int, int));
286 static char *parameter_list_remove_pattern PARAMS((int, char *, int, int));
287 #ifdef ARRAY_VARS
288 static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int));
289 #endif
290 static char *parameter_brace_remove_pattern PARAMS((char *, char *, int, char *, int, int, int));
291
292 static char *string_var_assignment PARAMS((SHELL_VAR *, char *));
293 #if defined (ARRAY_VARS)
294 static char *array_var_assignment PARAMS((SHELL_VAR *, int, int, int));
295 #endif
296 static char *pos_params_assignment PARAMS((WORD_LIST *, int, int));
297 static char *string_transform PARAMS((int, SHELL_VAR *, char *));
298 static char *list_transform PARAMS((int, SHELL_VAR *, WORD_LIST *, int, int));
299 static char *parameter_list_transform PARAMS((int, int, int));
300 #if defined ARRAY_VARS
301 static char *array_transform PARAMS((int, SHELL_VAR *, int, int));
302 #endif
303 static char *parameter_brace_transform PARAMS((char *, char *, int, char *, int, int, int, int));
304
305 static char *process_substitute PARAMS((char *, int));
306
307 static char *read_comsub PARAMS((int, int, int, int *));
308
309 #ifdef ARRAY_VARS
310 static arrayind_t array_length_reference PARAMS((char *));
311 #endif
312
313 static int valid_brace_expansion_word PARAMS((char *, int));
314 static int chk_atstar PARAMS((char *, int, int, int *, int *));
315 static int chk_arithsub PARAMS((const char *, int));
316
317 static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, arrayind_t *));
318 static char *parameter_brace_find_indir PARAMS((char *, int, int, int));
319 static WORD_DESC *parameter_brace_expand_indir PARAMS((char *, int, int, int, int *, int *));
320 static WORD_DESC *parameter_brace_expand_rhs PARAMS((char *, char *, int, int, int, int *, int *));
321 static void parameter_brace_expand_error PARAMS((char *, char *, int));
322
323 static int valid_length_expression PARAMS((char *));
324 static intmax_t parameter_brace_expand_length PARAMS((char *));
325
326 static char *skiparith PARAMS((char *, int));
327 static int verify_substring_values PARAMS((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
328 static int get_var_and_type PARAMS((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **));
329 static char *mb_substring PARAMS((char *, int, int));
330 static char *parameter_brace_substring PARAMS((char *, char *, int, char *, int, int, int));
331
332 static int shouldexp_replacement PARAMS((char *));
333
334 static char *pos_params_pat_subst PARAMS((char *, char *, char *, int));
335
336 static char *parameter_brace_patsub PARAMS((char *, char *, int, char *, int, int, int));
337
338 static char *pos_params_casemod PARAMS((char *, char *, int, int));
339 static char *parameter_brace_casemod PARAMS((char *, char *, int, int, char *, int, int, int));
340
341 static WORD_DESC *parameter_brace_expand PARAMS((char *, int *, int, int, int *, int *));
342 static WORD_DESC *param_expand PARAMS((char *, int *, int, int *, int *, int *, int *, int));
343
344 static WORD_LIST *expand_word_internal PARAMS((WORD_DESC *, int, int, int *, int *));
345
346 static WORD_LIST *word_list_split PARAMS((WORD_LIST *));
347
348 static void exp_jump_to_top_level PARAMS((int));
349
350 static WORD_LIST *separate_out_assignments PARAMS((WORD_LIST *));
351 static WORD_LIST *glob_expand_word_list PARAMS((WORD_LIST *, int));
352 #ifdef BRACE_EXPANSION
353 static WORD_LIST *brace_expand_word_list PARAMS((WORD_LIST *, int));
354 #endif
355 #if defined (ARRAY_VARS)
356 static int make_internal_declare PARAMS((char *, char *, char *));
357 static void expand_compound_assignment_word PARAMS((WORD_LIST *, int));
358 static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *));
359 #endif
360 static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int));
361 static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int));
362
363 /* **************************************************************** */
364 /* */
365 /* Utility Functions */
366 /* */
367 /* **************************************************************** */
368
369 #if defined (DEBUG)
370 void
371 dump_word_flags (flags)
372 int flags;
373 {
374 int f;
375
376 f = flags;
377 fprintf (stderr, "%d -> ", f);
378 if (f & W_ARRAYIND)
379 {
380 f &= ~W_ARRAYIND;
381 fprintf (stderr, "W_ARRAYIND%s", f ? "|" : "");
382 }
383 if (f & W_ASSIGNASSOC)
384 {
385 f &= ~W_ASSIGNASSOC;
386 fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
387 }
388 if (f & W_ASSIGNARRAY)
389 {
390 f &= ~W_ASSIGNARRAY;
391 fprintf (stderr, "W_ASSIGNARRAY%s", f ? "|" : "");
392 }
393 if (f & W_SAWQUOTEDNULL)
394 {
395 f &= ~W_SAWQUOTEDNULL;
396 fprintf (stderr, "W_SAWQUOTEDNULL%s", f ? "|" : "");
397 }
398 if (f & W_NOPROCSUB)
399 {
400 f &= ~W_NOPROCSUB;
401 fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
402 }
403 if (f & W_DQUOTE)
404 {
405 f &= ~W_DQUOTE;
406 fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
407 }
408 if (f & W_HASQUOTEDNULL)
409 {
410 f &= ~W_HASQUOTEDNULL;
411 fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
412 }
413 if (f & W_ASSIGNARG)
414 {
415 f &= ~W_ASSIGNARG;
416 fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
417 }
418 if (f & W_ASSNBLTIN)
419 {
420 f &= ~W_ASSNBLTIN;
421 fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
422 }
423 if (f & W_ASSNGLOBAL)
424 {
425 f &= ~W_ASSNGLOBAL;
426 fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : "");
427 }
428 if (f & W_COMPASSIGN)
429 {
430 f &= ~W_COMPASSIGN;
431 fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
432 }
433 if (f & W_EXPANDRHS)
434 {
435 f &= ~W_EXPANDRHS;
436 fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : "");
437 }
438 if (f & W_ITILDE)
439 {
440 f &= ~W_ITILDE;
441 fprintf (stderr, "W_ITILDE%s", f ? "|" : "");
442 }
443 if (f & W_NOTILDE)
444 {
445 f &= ~W_NOTILDE;
446 fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
447 }
448 if (f & W_ASSIGNRHS)
449 {
450 f &= ~W_ASSIGNRHS;
451 fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
452 }
453 if (f & W_NOASSNTILDE)
454 {
455 f &= ~W_NOASSNTILDE;
456 fprintf (stderr, "W_NOASSNTILDE%s", f ? "|" : "");
457 }
458 if (f & W_NOCOMSUB)
459 {
460 f &= ~W_NOCOMSUB;
461 fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
462 }
463 if (f & W_DOLLARSTAR)
464 {
465 f &= ~W_DOLLARSTAR;
466 fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : "");
467 }
468 if (f & W_DOLLARAT)
469 {
470 f &= ~W_DOLLARAT;
471 fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
472 }
473 if (f & W_TILDEEXP)
474 {
475 f &= ~W_TILDEEXP;
476 fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
477 }
478 if (f & W_NOSPLIT2)
479 {
480 f &= ~W_NOSPLIT2;
481 fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
482 }
483 if (f & W_NOSPLIT)
484 {
485 f &= ~W_NOSPLIT;
486 fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
487 }
488 if (f & W_NOBRACE)
489 {
490 f &= ~W_NOBRACE;
491 fprintf (stderr, "W_NOBRACE%s", f ? "|" : "");
492 }
493 if (f & W_NOGLOB)
494 {
495 f &= ~W_NOGLOB;
496 fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
497 }
498 if (f & W_SPLITSPACE)
499 {
500 f &= ~W_SPLITSPACE;
501 fprintf (stderr, "W_SPLITSPACE%s", f ? "|" : "");
502 }
503 if (f & W_ASSIGNMENT)
504 {
505 f &= ~W_ASSIGNMENT;
506 fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
507 }
508 if (f & W_QUOTED)
509 {
510 f &= ~W_QUOTED;
511 fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
512 }
513 if (f & W_HASDOLLAR)
514 {
515 f &= ~W_HASDOLLAR;
516 fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
517 }
518 if (f & W_COMPLETE)
519 {
520 f &= ~W_COMPLETE;
521 fprintf (stderr, "W_COMPLETE%s", f ? "|" : "");
522 }
523 if (f & W_CHKLOCAL)
524 {
525 f &= ~W_CHKLOCAL;
526 fprintf (stderr, "W_CHKLOCAL%s", f ? "|" : "");
527 }
528 if (f & W_FORCELOCAL)
529 {
530 f &= ~W_FORCELOCAL;
531 fprintf (stderr, "W_FORCELOCAL%s", f ? "|" : "");
532 }
533
534 fprintf (stderr, "\n");
535 fflush (stderr);
536 }
537 #endif
538
539 #ifdef INCLUDE_UNUSED
540 static char *
541 quoted_substring (string, start, end)
542 char *string;
543 int start, end;
544 {
545 register int len, l;
546 register char *result, *s, *r;
547
548 len = end - start;
549
550 /* Move to string[start], skipping quoted characters. */
551 for (s = string, l = 0; *s && l < start; )
552 {
553 if (*s == CTLESC)
554 {
555 s++;
556 continue;
557 }
558 l++;
559 if (*s == 0)
560 break;
561 }
562
563 r = result = (char *)xmalloc (2*len + 1); /* save room for quotes */
564
565 /* Copy LEN characters, including quote characters. */
566 s = string + l;
567 for (l = 0; l < len; s++)
568 {
569 if (*s == CTLESC)
570 *r++ = *s++;
571 *r++ = *s;
572 l++;
573 if (*s == 0)
574 break;
575 }
576 *r = '\0';
577 return result;
578 }
579 #endif
580
581 #ifdef INCLUDE_UNUSED
582 /* Return the length of S, skipping over quoted characters */
583 static int
584 quoted_strlen (s)
585 char *s;
586 {
587 register char *p;
588 int i;
589
590 i = 0;
591 for (p = s; *p; p++)
592 {
593 if (*p == CTLESC)
594 {
595 p++;
596 if (*p == 0)
597 return (i + 1);
598 }
599 i++;
600 }
601
602 return i;
603 }
604 #endif
605
606 #ifdef INCLUDE_UNUSED
607 /* Find the first occurrence of character C in string S, obeying shell
608 quoting rules. If (FLAGS & ST_BACKSL) is non-zero, backslash-escaped
609 characters are skipped. If (FLAGS & ST_CTLESC) is non-zero, characters
610 escaped with CTLESC are skipped. */
611 static char *
612 quoted_strchr (s, c, flags)
613 char *s;
614 int c, flags;
615 {
616 register char *p;
617
618 for (p = s; *p; p++)
619 {
620 if (((flags & ST_BACKSL) && *p == '\\')
621 || ((flags & ST_CTLESC) && *p == CTLESC))
622 {
623 p++;
624 if (*p == '\0')
625 return ((char *)NULL);
626 continue;
627 }
628 else if (*p == c)
629 return p;
630 }
631 return ((char *)NULL);
632 }
633
634 /* Return 1 if CHARACTER appears in an unquoted portion of
635 STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */
636 static int
637 unquoted_member (character, string)
638 int character;
639 char *string;
640 {
641 size_t slen;
642 int sindex, c;
643 DECLARE_MBSTATE;
644
645 slen = strlen (string);
646 sindex = 0;
647 while (c = string[sindex])
648 {
649 if (c == character)
650 return (1);
651
652 switch (c)
653 {
654 default:
655 ADVANCE_CHAR (string, slen, sindex);
656 break;
657
658 case '\\':
659 sindex++;
660 if (string[sindex])
661 ADVANCE_CHAR (string, slen, sindex);
662 break;
663
664 case '\'':
665 sindex = skip_single_quoted (string, slen, ++sindex, 0);
666 break;
667
668 case '"':
669 sindex = skip_double_quoted (string, slen, ++sindex, 0);
670 break;
671 }
672 }
673 return (0);
674 }
675
676 /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
677 static int
678 unquoted_substring (substr, string)
679 char *substr, *string;
680 {
681 size_t slen;
682 int sindex, c, sublen;
683 DECLARE_MBSTATE;
684
685 if (substr == 0 || *substr == '\0')
686 return (0);
687
688 slen = strlen (string);
689 sublen = strlen (substr);
690 for (sindex = 0; c = string[sindex]; )
691 {
692 if (STREQN (string + sindex, substr, sublen))
693 return (1);
694
695 switch (c)
696 {
697 case '\\':
698 sindex++;
699 if (string[sindex])
700 ADVANCE_CHAR (string, slen, sindex);
701 break;
702
703 case '\'':
704 sindex = skip_single_quoted (string, slen, ++sindex, 0);
705 break;
706
707 case '"':
708 sindex = skip_double_quoted (string, slen, ++sindex, 0);
709 break;
710
711 default:
712 ADVANCE_CHAR (string, slen, sindex);
713 break;
714 }
715 }
716 return (0);
717 }
718 #endif
719
720 /* Most of the substitutions must be done in parallel. In order
721 to avoid using tons of unclear goto's, I have some functions
722 for manipulating malloc'ed strings. They all take INDX, a
723 pointer to an integer which is the offset into the string
724 where manipulation is taking place. They also take SIZE, a
725 pointer to an integer which is the current length of the
726 character array for this string. */
727
728 /* Append SOURCE to TARGET at INDEX. SIZE is the current amount
729 of space allocated to TARGET. SOURCE can be NULL, in which
730 case nothing happens. Gets rid of SOURCE by freeing it.
731 Returns TARGET in case the location has changed. */
732 INLINE char *
733 sub_append_string (source, target, indx, size)
734 char *source, *target;
735 int *indx;
736 size_t *size;
737 {
738 if (source)
739 {
740 int n;
741 size_t srclen;
742
743 srclen = STRLEN (source);
744 if (srclen >= (int)(*size - *indx))
745 {
746 n = srclen + *indx;
747 n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);
748 target = (char *)xrealloc (target, (*size = n));
749 }
750
751 FASTCOPY (source, target + *indx, srclen);
752 *indx += srclen;
753 target[*indx] = '\0';
754
755 free (source);
756 }
757 return (target);
758 }
759
760 #if 0
761 /* UNUSED */
762 /* Append the textual representation of NUMBER to TARGET.
763 INDX and SIZE are as in SUB_APPEND_STRING. */
764 char *
765 sub_append_number (number, target, indx, size)
766 intmax_t number;
767 char *target;
768 int *indx;
769 size_t *size;
770 {
771 char *temp;
772
773 temp = itos (number);
774 return (sub_append_string (temp, target, indx, size));
775 }
776 #endif
777
778 /* Extract a substring from STRING, starting at SINDEX and ending with
779 one of the characters in CHARLIST. Don't make the ending character
780 part of the string. Leave SINDEX pointing at the ending character.
781 Understand about backslashes in the string. If (flags & SX_VARNAME)
782 is non-zero, and array variables have been compiled into the shell,
783 everything between a `[' and a corresponding `]' is skipped over.
784 If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
785 update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must
786 contain a closing character from CHARLIST. */
787 static char *
788 string_extract (string, sindex, charlist, flags)
789 char *string;
790 int *sindex;
791 char *charlist;
792 int flags;
793 {
794 register int c, i;
795 int found;
796 size_t slen;
797 char *temp;
798 DECLARE_MBSTATE;
799
800 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
801 i = *sindex;
802 found = 0;
803 while (c = string[i])
804 {
805 if (c == '\\')
806 {
807 if (string[i + 1])
808 i++;
809 else
810 break;
811 }
812 #if defined (ARRAY_VARS)
813 else if ((flags & SX_VARNAME) && c == LBRACK)
814 {
815 int ni;
816 /* If this is an array subscript, skip over it and continue. */
817 ni = skipsubscript (string, i, 0);
818 if (string[ni] == RBRACK)
819 i = ni;
820 }
821 #endif
822 else if (MEMBER (c, charlist))
823 {
824 found = 1;
825 break;
826 }
827
828 ADVANCE_CHAR (string, slen, i);
829 }
830
831 /* If we had to have a matching delimiter and didn't find one, return an
832 error and let the caller deal with it. */
833 if ((flags & SX_REQMATCH) && found == 0)
834 {
835 *sindex = i;
836 return (&extract_string_error);
837 }
838
839 temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
840 *sindex = i;
841
842 return (temp);
843 }
844
845 /* Extract the contents of STRING as if it is enclosed in double quotes.
846 SINDEX, when passed in, is the offset of the character immediately
847 following the opening double quote; on exit, SINDEX is left pointing after
848 the closing double quote. If STRIPDQ is non-zero, unquoted double
849 quotes are stripped and the string is terminated by a null byte.
850 Backslashes between the embedded double quotes are processed. If STRIPDQ
851 is zero, an unquoted `"' terminates the string. */
852 static char *
853 string_extract_double_quoted (string, sindex, flags)
854 char *string;
855 int *sindex, flags;
856 {
857 size_t slen;
858 char *send;
859 int j, i, t;
860 unsigned char c;
861 char *temp, *ret; /* The new string we return. */
862 int pass_next, backquote, si; /* State variables for the machine. */
863 int dquote;
864 int stripdq;
865 DECLARE_MBSTATE;
866
867 slen = strlen (string + *sindex) + *sindex;
868 send = string + slen;
869
870 stripdq = (flags & SX_STRIPDQ);
871
872 pass_next = backquote = dquote = 0;
873 temp = (char *)xmalloc (1 + slen - *sindex);
874
875 j = 0;
876 i = *sindex;
877 while (c = string[i])
878 {
879 /* Process a character that was quoted by a backslash. */
880 if (pass_next)
881 {
882 /* XXX - take another look at this in light of Interp 221 */
883 /* Posix.2 sez:
884
885 ``The backslash shall retain its special meaning as an escape
886 character only when followed by one of the characters:
887 $ ` " \ <newline>''.
888
889 If STRIPDQ is zero, we handle the double quotes here and let
890 expand_word_internal handle the rest. If STRIPDQ is non-zero,
891 we have already been through one round of backslash stripping,
892 and want to strip these backslashes only if DQUOTE is non-zero,
893 indicating that we are inside an embedded double-quoted string. */
894
895 /* If we are in an embedded quoted string, then don't strip
896 backslashes before characters for which the backslash
897 retains its special meaning, but remove backslashes in
898 front of other characters. If we are not in an
899 embedded quoted string, don't strip backslashes at all.
900 This mess is necessary because the string was already
901 surrounded by double quotes (and sh has some really weird
902 quoting rules).
903 The returned string will be run through expansion as if
904 it were double-quoted. */
905 if ((stripdq == 0 && c != '"') ||
906 (stripdq && ((dquote && (sh_syntaxtab[c] & CBSDQUOTE)) || dquote == 0)))
907 temp[j++] = '\\';
908 pass_next = 0;
909
910 add_one_character:
911 COPY_CHAR_I (temp, j, string, send, i);
912 continue;
913 }
914
915 /* A backslash protects the next character. The code just above
916 handles preserving the backslash in front of any character but
917 a double quote. */
918 if (c == '\\')
919 {
920 pass_next++;
921 i++;
922 continue;
923 }
924
925 /* Inside backquotes, ``the portion of the quoted string from the
926 initial backquote and the characters up to the next backquote
927 that is not preceded by a backslash, having escape characters
928 removed, defines that command''. */
929 if (backquote)
930 {
931 if (c == '`')
932 backquote = 0;
933 temp[j++] = c; /* COPY_CHAR_I? */
934 i++;
935 continue;
936 }
937
938 if (c == '`')
939 {
940 temp[j++] = c;
941 backquote++;
942 i++;
943 continue;
944 }
945
946 /* Pass everything between `$(' and the matching `)' or a quoted
947 ${ ... } pair through according to the Posix.2 specification. */
948 if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
949 {
950 int free_ret = 1;
951
952 si = i + 2;
953 if (string[i + 1] == LPAREN)
954 ret = extract_command_subst (string, &si, (flags & SX_COMPLETE));
955 else
956 ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, 0);
957
958 temp[j++] = '$';
959 temp[j++] = string[i + 1];
960
961 /* Just paranoia; ret will not be 0 unless no_longjmp_on_fatal_error
962 is set. */
963 if (ret == 0 && no_longjmp_on_fatal_error)
964 {
965 free_ret = 0;
966 ret = string + i + 2;
967 }
968
969 /* XXX - CHECK_STRING_OVERRUN here? */
970 for (t = 0; ret[t]; t++, j++)
971 temp[j] = ret[t];
972 temp[j] = string[si];
973
974 if (si < i + 2) /* we went back? */
975 i += 2;
976 else if (string[si])
977 {
978 j++;
979 i = si + 1;
980 }
981 else
982 i = si;
983
984 if (free_ret)
985 free (ret);
986 continue;
987 }
988
989 /* Add any character but a double quote to the quoted string we're
990 accumulating. */
991 if (c != '"')
992 goto add_one_character;
993
994 /* c == '"' */
995 if (stripdq)
996 {
997 dquote ^= 1;
998 i++;
999 continue;
1000 }
1001
1002 break;
1003 }
1004 temp[j] = '\0';
1005
1006 /* Point to after the closing quote. */
1007 if (c)
1008 i++;
1009 *sindex = i;
1010
1011 return (temp);
1012 }
1013
1014 /* This should really be another option to string_extract_double_quoted. */
1015 static int
1016 skip_double_quoted (string, slen, sind, flags)
1017 char *string;
1018 size_t slen;
1019 int sind;
1020 int flags;
1021 {
1022 int c, i;
1023 char *ret;
1024 int pass_next, backquote, si;
1025 DECLARE_MBSTATE;
1026
1027 pass_next = backquote = 0;
1028 i = sind;
1029 while (c = string[i])
1030 {
1031 if (pass_next)
1032 {
1033 pass_next = 0;
1034 ADVANCE_CHAR (string, slen, i);
1035 continue;
1036 }
1037 else if (c == '\\')
1038 {
1039 pass_next++;
1040 i++;
1041 continue;
1042 }
1043 else if (backquote)
1044 {
1045 if (c == '`')
1046 backquote = 0;
1047 ADVANCE_CHAR (string, slen, i);
1048 continue;
1049 }
1050 else if (c == '`')
1051 {
1052 backquote++;
1053 i++;
1054 continue;
1055 }
1056 else if (c == '$' && ((string[i + 1] == LPAREN) || (string[i + 1] == LBRACE)))
1057 {
1058 si = i + 2;
1059 if (string[i + 1] == LPAREN)
1060 ret = extract_command_subst (string, &si, SX_NOALLOC|(flags&SX_COMPLETE));
1061 else
1062 ret = extract_dollar_brace_string (string, &si, Q_DOUBLE_QUOTES, SX_NOALLOC);
1063
1064 /* These can consume the entire string if they are unterminated */
1065 CHECK_STRING_OVERRUN (i, si, slen, c);
1066
1067 i = si + 1;
1068 continue;
1069 }
1070 else if (c != '"')
1071 {
1072 ADVANCE_CHAR (string, slen, i);
1073 continue;
1074 }
1075 else
1076 break;
1077 }
1078
1079 if (c)
1080 i++;
1081
1082 return (i);
1083 }
1084
1085 /* Extract the contents of STRING as if it is enclosed in single quotes.
1086 SINDEX, when passed in, is the offset of the character immediately
1087 following the opening single quote; on exit, SINDEX is left pointing after
1088 the closing single quote. */
1089 static inline char *
1090 string_extract_single_quoted (string, sindex)
1091 char *string;
1092 int *sindex;
1093 {
1094 register int i;
1095 size_t slen;
1096 char *t;
1097 DECLARE_MBSTATE;
1098
1099 /* Don't need slen for ADVANCE_CHAR unless multibyte chars possible. */
1100 slen = (MB_CUR_MAX > 1) ? strlen (string + *sindex) + *sindex : 0;
1101 i = *sindex;
1102 while (string[i] && string[i] != '\'')
1103 ADVANCE_CHAR (string, slen, i);
1104
1105 t = substring (string, *sindex, i);
1106
1107 if (string[i])
1108 i++;
1109 *sindex = i;
1110
1111 return (t);
1112 }
1113
1114 /* Skip over a single-quoted string. We overload the SX_COMPLETE flag to mean
1115 that we are splitting out words for completion and have encountered a $'...'
1116 string, which allows backslash-escaped single quotes. */
1117 static inline int
1118 skip_single_quoted (string, slen, sind, flags)
1119 const char *string;
1120 size_t slen;
1121 int sind;
1122 int flags;
1123 {
1124 register int c;
1125 DECLARE_MBSTATE;
1126
1127 c = sind;
1128 while (string[c] && string[c] != '\'')
1129 {
1130 if ((flags & SX_COMPLETE) && string[c] == '\\' && string[c+1] == '\'' && string[c+2])
1131 ADVANCE_CHAR (string, slen, c);
1132 ADVANCE_CHAR (string, slen, c);
1133 }
1134
1135 if (string[c])
1136 c++;
1137 return c;
1138 }
1139
1140 /* Just like string_extract, but doesn't hack backslashes or any of
1141 that other stuff. Obeys CTLESC quoting. Used to do splitting on $IFS. */
1142 static char *
1143 string_extract_verbatim (string, slen, sindex, charlist, flags)
1144 char *string;
1145 size_t slen;
1146 int *sindex;
1147 char *charlist;
1148 int flags;
1149 {
1150 register int i;
1151 #if defined (HANDLE_MULTIBYTE)
1152 wchar_t *wcharlist;
1153 #endif
1154 int c;
1155 char *temp;
1156 DECLARE_MBSTATE;
1157
1158 if ((flags & SX_NOCTLESC) && charlist[0] == '\'' && charlist[1] == '\0')
1159 {
1160 temp = string_extract_single_quoted (string, sindex);
1161 --*sindex; /* leave *sindex at separator character */
1162 return temp;
1163 }
1164
1165 /* This can never be called with charlist == NULL. If *charlist == NULL,
1166 we can skip the loop and just return a copy of the string, updating
1167 *sindex */
1168 if (*charlist == 0)
1169 {
1170 temp = string + *sindex;
1171 c = (*sindex == 0) ? slen : STRLEN (temp);
1172 temp = savestring (temp);
1173 *sindex += c;
1174 return temp;
1175 }
1176
1177 i = *sindex;
1178 #if defined (HANDLE_MULTIBYTE)
1179 wcharlist = 0;
1180 #endif
1181 while (c = string[i])
1182 {
1183 #if defined (HANDLE_MULTIBYTE)
1184 size_t mblength;
1185 #endif
1186 if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
1187 {
1188 i += 2;
1189 CHECK_STRING_OVERRUN (i, i, slen, c);
1190 continue;
1191 }
1192 /* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
1193 through, to protect the CTLNULs from later calls to
1194 remove_quoted_nulls. */
1195 else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
1196 {
1197 i += 2;
1198 CHECK_STRING_OVERRUN (i, i, slen, c);
1199 continue;
1200 }
1201
1202 #if defined (HANDLE_MULTIBYTE)
1203 if (locale_utf8locale && slen > i && UTF8_SINGLEBYTE (string[i]))
1204 mblength = (string[i] != 0) ? 1 : 0;
1205 else
1206 mblength = MBLEN (string + i, slen - i);
1207 if (mblength > 1)
1208 {
1209 wchar_t wc;
1210 mblength = mbtowc (&wc, string + i, slen - i);
1211 if (MB_INVALIDCH (mblength))
1212 {
1213 if (MEMBER (c, charlist))
1214 break;
1215 }
1216 else
1217 {
1218 if (wcharlist == 0)
1219 {
1220 size_t len;
1221 len = mbstowcs (wcharlist, charlist, 0);
1222 if (len == -1)
1223 len = 0;
1224 wcharlist = (wchar_t *)xmalloc (sizeof (wchar_t) * (len + 1));
1225 mbstowcs (wcharlist, charlist, len + 1);
1226 }
1227
1228 if (wcschr (wcharlist, wc))
1229 break;
1230 }
1231 }
1232 else
1233 #endif
1234 if (MEMBER (c, charlist))
1235 break;
1236
1237 ADVANCE_CHAR (string, slen, i);
1238 }
1239
1240 #if defined (HANDLE_MULTIBYTE)
1241 FREE (wcharlist);
1242 #endif
1243
1244 temp = substring (string, *sindex, i);
1245 *sindex = i;
1246
1247 return (temp);
1248 }
1249
1250 /* Extract the $( construct in STRING, and return a new string.
1251 Start extracting at (SINDEX) as if we had just seen "$(".
1252 Make (SINDEX) get the position of the matching ")". )
1253 XFLAGS is additional flags to pass to other extraction functions. */
1254 char *
1255 extract_command_subst (string, sindex, xflags)
1256 char *string;
1257 int *sindex;
1258 int xflags;
1259 {
1260 char *ret;
1261
1262 if (string[*sindex] == LPAREN || (xflags & SX_COMPLETE))
1263 return (extract_delimited_string (string, sindex, "$(", "(", ")", xflags|SX_COMMAND)); /*)*/
1264 else
1265 {
1266 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1267 ret = xparse_dolparen (string, string+*sindex, sindex, xflags);
1268 return ret;
1269 }
1270 }
1271
1272 /* Extract the $[ construct in STRING, and return a new string. (])
1273 Start extracting at (SINDEX) as if we had just seen "$[".
1274 Make (SINDEX) get the position of the matching "]". */
1275 char *
1276 extract_arithmetic_subst (string, sindex)
1277 char *string;
1278 int *sindex;
1279 {
1280 return (extract_delimited_string (string, sindex, "$[", "[", "]", 0)); /*]*/
1281 }
1282
1283 #if defined (PROCESS_SUBSTITUTION)
1284 /* Extract the <( or >( construct in STRING, and return a new string.
1285 Start extracting at (SINDEX) as if we had just seen "<(".
1286 Make (SINDEX) get the position of the matching ")". */ /*))*/
1287 char *
1288 extract_process_subst (string, starter, sindex, xflags)
1289 char *string;
1290 char *starter;
1291 int *sindex;
1292 int xflags;
1293 {
1294 #if 0
1295 /* XXX - check xflags&SX_COMPLETE here? */
1296 return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND));
1297 #else
1298 xflags |= (no_longjmp_on_fatal_error ? SX_NOLONGJMP : 0);
1299 return (xparse_dolparen (string, string+*sindex, sindex, xflags));
1300 #endif
1301 }
1302 #endif /* PROCESS_SUBSTITUTION */
1303
1304 #if defined (ARRAY_VARS)
1305 /* This can be fooled by unquoted right parens in the passed string. If
1306 each caller verifies that the last character in STRING is a right paren,
1307 we don't even need to call extract_delimited_string. */
1308 char *
1309 extract_array_assignment_list (string, sindex)
1310 char *string;
1311 int *sindex;
1312 {
1313 int slen;
1314 char *ret;
1315
1316 slen = strlen (string);
1317 if (string[slen - 1] == RPAREN)
1318 {
1319 ret = substring (string, *sindex, slen - 1);
1320 *sindex = slen - 1;
1321 return ret;
1322 }
1323 return 0;
1324 }
1325 #endif
1326
1327 /* Extract and create a new string from the contents of STRING, a
1328 character string delimited with OPENER and CLOSER. SINDEX is
1329 the address of an int describing the current offset in STRING;
1330 it should point to just after the first OPENER found. On exit,
1331 SINDEX gets the position of the last character of the matching CLOSER.
1332 If OPENER is more than a single character, ALT_OPENER, if non-null,
1333 contains a character string that can also match CLOSER and thus
1334 needs to be skipped. */
1335 static char *
1336 extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
1337 char *string;
1338 int *sindex;
1339 char *opener, *alt_opener, *closer;
1340 int flags;
1341 {
1342 int i, c, si;
1343 size_t slen;
1344 char *t, *result;
1345 int pass_character, nesting_level, in_comment;
1346 int len_closer, len_opener, len_alt_opener;
1347 DECLARE_MBSTATE;
1348
1349 slen = strlen (string + *sindex) + *sindex;
1350 len_opener = STRLEN (opener);
1351 len_alt_opener = STRLEN (alt_opener);
1352 len_closer = STRLEN (closer);
1353
1354 pass_character = in_comment = 0;
1355
1356 nesting_level = 1;
1357 i = *sindex;
1358
1359 while (nesting_level)
1360 {
1361 c = string[i];
1362
1363 /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond
1364 the end of the string, catch it and cut the loop. */
1365 if (i > slen)
1366 {
1367 i = slen;
1368 c = string[i = slen];
1369 break;
1370 }
1371
1372 if (c == 0)
1373 break;
1374
1375 if (in_comment)
1376 {
1377 if (c == '\n')
1378 in_comment = 0;
1379 ADVANCE_CHAR (string, slen, i);
1380 continue;
1381 }
1382
1383 if (pass_character) /* previous char was backslash */
1384 {
1385 pass_character = 0;
1386 ADVANCE_CHAR (string, slen, i);
1387 continue;
1388 }
1389
1390 /* Not exactly right yet; should handle shell metacharacters and
1391 multibyte characters, too. See COMMENT_BEGIN define in parse.y */
1392 if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || shellblank (string[i - 1])))
1393 {
1394 in_comment = 1;
1395 ADVANCE_CHAR (string, slen, i);
1396 continue;
1397 }
1398
1399 if (c == CTLESC || c == '\\')
1400 {
1401 pass_character++;
1402 i++;
1403 continue;
1404 }
1405
1406 /* Process a nested command substitution, but only if we're parsing an
1407 arithmetic substitution. */
1408 if ((flags & SX_COMMAND) && string[i] == '$' && string[i+1] == LPAREN)
1409 {
1410 si = i + 2;
1411 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1412 CHECK_STRING_OVERRUN (i, si, slen, c);
1413 i = si + 1;
1414 continue;
1415 }
1416
1417 /* Process a nested OPENER. */
1418 if (STREQN (string + i, opener, len_opener))
1419 {
1420 si = i + len_opener;
1421 t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
1422 CHECK_STRING_OVERRUN (i, si, slen, c);
1423 i = si + 1;
1424 continue;
1425 }
1426
1427 /* Process a nested ALT_OPENER */
1428 if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
1429 {
1430 si = i + len_alt_opener;
1431 t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
1432 CHECK_STRING_OVERRUN (i, si, slen, c);
1433 i = si + 1;
1434 continue;
1435 }
1436
1437 /* If the current substring terminates the delimited string, decrement
1438 the nesting level. */
1439 if (STREQN (string + i, closer, len_closer))
1440 {
1441 i += len_closer - 1; /* move to last byte of the closer */
1442 nesting_level--;
1443 if (nesting_level == 0)
1444 break;
1445 }
1446
1447 /* Pass old-style command substitution through verbatim. */
1448 if (c == '`')
1449 {
1450 si = i + 1;
1451 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1452 CHECK_STRING_OVERRUN (i, si, slen, c);
1453 i = si + 1;
1454 continue;
1455 }
1456
1457 /* Pass single-quoted and double-quoted strings through verbatim. */
1458 if (c == '\'' || c == '"')
1459 {
1460 si = i + 1;
1461 i = (c == '\'') ? skip_single_quoted (string, slen, si, 0)
1462 : skip_double_quoted (string, slen, si, 0);
1463 continue;
1464 }
1465
1466 /* move past this character, which was not special. */
1467 ADVANCE_CHAR (string, slen, i);
1468 }
1469
1470 if (c == 0 && nesting_level)
1471 {
1472 if (no_longjmp_on_fatal_error == 0)
1473 {
1474 last_command_exit_value = EXECUTION_FAILURE;
1475 report_error (_("bad substitution: no closing `%s' in %s"), closer, string);
1476 exp_jump_to_top_level (DISCARD);
1477 }
1478 else
1479 {
1480 *sindex = i;
1481 return (char *)NULL;
1482 }
1483 }
1484
1485 si = i - *sindex - len_closer + 1;
1486 if (flags & SX_NOALLOC)
1487 result = (char *)NULL;
1488 else
1489 {
1490 result = (char *)xmalloc (1 + si);
1491 strncpy (result, string + *sindex, si);
1492 result[si] = '\0';
1493 }
1494 *sindex = i;
1495
1496 return (result);
1497 }
1498
1499 /* Extract a parameter expansion expression within ${ and } from STRING.
1500 Obey the Posix.2 rules for finding the ending `}': count braces while
1501 skipping over enclosed quoted strings and command substitutions.
1502 SINDEX is the address of an int describing the current offset in STRING;
1503 it should point to just after the first `{' found. On exit, SINDEX
1504 gets the position of the matching `}'. QUOTED is non-zero if this
1505 occurs inside double quotes. */
1506 /* XXX -- this is very similar to extract_delimited_string -- XXX */
1507 static char *
1508 extract_dollar_brace_string (string, sindex, quoted, flags)
1509 char *string;
1510 int *sindex, quoted, flags;
1511 {
1512 register int i, c;
1513 size_t slen;
1514 int pass_character, nesting_level, si, dolbrace_state;
1515 char *result, *t;
1516 DECLARE_MBSTATE;
1517
1518 pass_character = 0;
1519 nesting_level = 1;
1520 slen = strlen (string + *sindex) + *sindex;
1521
1522 /* The handling of dolbrace_state needs to agree with the code in parse.y:
1523 parse_matched_pair(). The different initial value is to handle the
1524 case where this function is called to parse the word in
1525 ${param op word} (SX_WORD). */
1526 dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM;
1527 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP))
1528 dolbrace_state = DOLBRACE_QUOTE;
1529
1530 i = *sindex;
1531 while (c = string[i])
1532 {
1533 if (pass_character)
1534 {
1535 pass_character = 0;
1536 ADVANCE_CHAR (string, slen, i);
1537 continue;
1538 }
1539
1540 /* CTLESCs and backslashes quote the next character. */
1541 if (c == CTLESC || c == '\\')
1542 {
1543 pass_character++;
1544 i++;
1545 continue;
1546 }
1547
1548 if (string[i] == '$' && string[i+1] == LBRACE)
1549 {
1550 nesting_level++;
1551 i += 2;
1552 continue;
1553 }
1554
1555 if (c == RBRACE)
1556 {
1557 nesting_level--;
1558 if (nesting_level == 0)
1559 break;
1560 i++;
1561 continue;
1562 }
1563
1564 /* Pass the contents of old-style command substitutions through
1565 verbatim. */
1566 if (c == '`')
1567 {
1568 si = i + 1;
1569 t = string_extract (string, &si, "`", flags|SX_NOALLOC);
1570
1571 CHECK_STRING_OVERRUN (i, si, slen, c);
1572
1573 i = si + 1;
1574 continue;
1575 }
1576
1577 /* Pass the contents of new-style command substitutions and
1578 arithmetic substitutions through verbatim. */
1579 if (string[i] == '$' && string[i+1] == LPAREN)
1580 {
1581 si = i + 2;
1582 t = extract_command_subst (string, &si, flags|SX_NOALLOC);
1583
1584 CHECK_STRING_OVERRUN (i, si, slen, c);
1585
1586 i = si + 1;
1587 continue;
1588 }
1589
1590 #if defined (PROCESS_SUBSTITUTION)
1591 /* Technically this should only work at the start of a word */
1592 if ((string[i] == '<' || string[i] == '>') && string[i+1] == LPAREN)
1593 {
1594 si = i + 2;
1595 t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags|SX_NOALLOC);
1596
1597 CHECK_STRING_OVERRUN (i, si, slen, c);
1598
1599 i = si + 1;
1600 continue;
1601 }
1602 #endif
1603
1604 /* Pass the contents of double-quoted strings through verbatim. */
1605 if (c == '"')
1606 {
1607 si = i + 1;
1608 i = skip_double_quoted (string, slen, si, 0);
1609 /* skip_XXX_quoted leaves index one past close quote */
1610 continue;
1611 }
1612
1613 if (c == '\'')
1614 {
1615 /*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
1616 if (posixly_correct && shell_compatibility_level > 42 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
1617 ADVANCE_CHAR (string, slen, i);
1618 else
1619 {
1620 si = i + 1;
1621 i = skip_single_quoted (string, slen, si, 0);
1622 }
1623
1624 continue;
1625 }
1626
1627 #if defined (ARRAY_VARS)
1628 if (c == LBRACK && dolbrace_state == DOLBRACE_PARAM)
1629 {
1630 si = skipsubscript (string, i, 0);
1631 CHECK_STRING_OVERRUN (i, si, slen, c);
1632 if (string[si] == RBRACK)
1633 c = string[i = si];
1634 }
1635 #endif
1636
1637 /* move past this character, which was not special. */
1638 ADVANCE_CHAR (string, slen, i);
1639
1640 /* This logic must agree with parse.y:parse_matched_pair, since they
1641 share the same defines. */
1642 if (dolbrace_state == DOLBRACE_PARAM && c == '%' && (i - *sindex) > 1)
1643 dolbrace_state = DOLBRACE_QUOTE;
1644 else if (dolbrace_state == DOLBRACE_PARAM && c == '#' && (i - *sindex) > 1)
1645 dolbrace_state = DOLBRACE_QUOTE;
1646 else if (dolbrace_state == DOLBRACE_PARAM && c == '/' && (i - *sindex) > 1)
1647 dolbrace_state = DOLBRACE_QUOTE2; /* XXX */
1648 else if (dolbrace_state == DOLBRACE_PARAM && c == '^' && (i - *sindex) > 1)
1649 dolbrace_state = DOLBRACE_QUOTE;
1650 else if (dolbrace_state == DOLBRACE_PARAM && c == ',' && (i - *sindex) > 1)
1651 dolbrace_state = DOLBRACE_QUOTE;
1652 /* This is intended to handle all of the [:]op expansions and the substring/
1653 length/pattern removal/pattern substitution expansions. */
1654 else if (dolbrace_state == DOLBRACE_PARAM && strchr ("#%^,~:-=?+/", c) != 0)
1655 dolbrace_state = DOLBRACE_OP;
1656 else if (dolbrace_state == DOLBRACE_OP && strchr ("#%^,~:-=?+/", c) == 0)
1657 dolbrace_state = DOLBRACE_WORD;
1658 }
1659
1660 if (c == 0 && nesting_level)
1661 {
1662 if (no_longjmp_on_fatal_error == 0)
1663 { /* { */
1664 last_command_exit_value = EXECUTION_FAILURE;
1665 report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
1666 exp_jump_to_top_level (DISCARD);
1667 }
1668 else
1669 {
1670 *sindex = i;
1671 return ((char *)NULL);
1672 }
1673 }
1674
1675 result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
1676 *sindex = i;
1677
1678 return (result);
1679 }
1680
1681 /* Remove backslashes which are quoting backquotes from STRING. Modifies
1682 STRING, and returns a pointer to it. */
1683 char *
1684 de_backslash (string)
1685 char *string;
1686 {
1687 register size_t slen;
1688 register int i, j, prev_i;
1689 DECLARE_MBSTATE;
1690
1691 slen = strlen (string);
1692 i = j = 0;
1693
1694 /* Loop copying string[i] to string[j], i >= j. */
1695 while (i < slen)
1696 {
1697 if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
1698 string[i + 1] == '$'))
1699 i++;
1700 prev_i = i;
1701 ADVANCE_CHAR (string, slen, i);
1702 if (j < prev_i)
1703 do string[j++] = string[prev_i++]; while (prev_i < i);
1704 else
1705 j = i;
1706 }
1707 string[j] = '\0';
1708
1709 return (string);
1710 }
1711
1712 #if 0
1713 /*UNUSED*/
1714 /* Replace instances of \! in a string with !. */
1715 void
1716 unquote_bang (string)
1717 char *string;
1718 {
1719 register int i, j;
1720 register char *temp;
1721
1722 temp = (char *)xmalloc (1 + strlen (string));
1723
1724 for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
1725 {
1726 if (string[i] == '\\' && string[i + 1] == '!')
1727 {
1728 temp[j] = '!';
1729 i++;
1730 }
1731 }
1732 strcpy (string, temp);
1733 free (temp);
1734 }
1735 #endif
1736
1737 #define CQ_RETURN(x) do { no_longjmp_on_fatal_error = oldjmp; return (x); } while (0)
1738
1739 /* This function assumes s[i] == open; returns with s[ret] == close; used to
1740 parse array subscripts. FLAGS & 1 means to not attempt to skip over
1741 matched pairs of quotes or backquotes, or skip word expansions; it is
1742 intended to be used after expansion has been performed and during final
1743 assignment parsing (see arrayfunc.c:assign_compound_array_list()) or
1744 during execution by a builtin which has already undergone word expansion. */
1745 static int
1746 skip_matched_pair (string, start, open, close, flags)
1747 const char *string;
1748 int start, open, close, flags;
1749 {
1750 int i, pass_next, backq, si, c, count, oldjmp;
1751 size_t slen;
1752 char *temp, *ss;
1753 DECLARE_MBSTATE;
1754
1755 slen = strlen (string + start) + start;
1756 oldjmp = no_longjmp_on_fatal_error;
1757 no_longjmp_on_fatal_error = 1;
1758
1759 i = start + 1; /* skip over leading bracket */
1760 count = 1;
1761 pass_next = backq = 0;
1762 ss = (char *)string;
1763 while (c = string[i])
1764 {
1765 if (pass_next)
1766 {
1767 pass_next = 0;
1768 if (c == 0)
1769 CQ_RETURN(i);
1770 ADVANCE_CHAR (string, slen, i);
1771 continue;
1772 }
1773 else if ((flags & 1) == 0 && c == '\\')
1774 {
1775 pass_next = 1;
1776 i++;
1777 continue;
1778 }
1779 else if (backq)
1780 {
1781 if (c == '`')
1782 backq = 0;
1783 ADVANCE_CHAR (string, slen, i);
1784 continue;
1785 }
1786 else if ((flags & 1) == 0 && c == '`')
1787 {
1788 backq = 1;
1789 i++;
1790 continue;
1791 }
1792 else if ((flags & 1) == 0 && c == open)
1793 {
1794 count++;
1795 i++;
1796 continue;
1797 }
1798 else if (c == close)
1799 {
1800 count--;
1801 if (count == 0)
1802 break;
1803 i++;
1804 continue;
1805 }
1806 else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
1807 {
1808 i = (c == '\'') ? skip_single_quoted (ss, slen, ++i, 0)
1809 : skip_double_quoted (ss, slen, ++i, 0);
1810 /* no increment, the skip functions increment past the closing quote. */
1811 }
1812 else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
1813 {
1814 si = i + 2;
1815 if (string[si] == '\0')
1816 CQ_RETURN(si);
1817
1818 /* XXX - extract_command_subst here? */
1819 if (string[i+1] == LPAREN)
1820 temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
1821 else
1822 temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
1823
1824 CHECK_STRING_OVERRUN (i, si, slen, c);
1825
1826 i = si;
1827 if (string[i] == '\0') /* don't increment i past EOS in loop */
1828 break;
1829 i++;
1830 continue;
1831 }
1832 else
1833 ADVANCE_CHAR (string, slen, i);
1834 }
1835
1836 CQ_RETURN(i);
1837 }
1838
1839 #if defined (ARRAY_VARS)
1840 /* Flags has 1 as a reserved value, since skip_matched_pair uses it for
1841 skipping over quoted strings and taking the first instance of the
1842 closing character. */
1843 int
1844 skipsubscript (string, start, flags)
1845 const char *string;
1846 int start, flags;
1847 {
1848 return (skip_matched_pair (string, start, '[', ']', flags));
1849 }
1850 #endif
1851
1852 /* Skip characters in STRING until we find a character in DELIMS, and return
1853 the index of that character. START is the index into string at which we
1854 begin. This is similar in spirit to strpbrk, but it returns an index into
1855 STRING and takes a starting index. This little piece of code knows quite
1856 a lot of shell syntax. It's very similar to skip_double_quoted and other
1857 functions of that ilk. */
1858 int
1859 skip_to_delim (string, start, delims, flags)
1860 char *string;
1861 int start;
1862 char *delims;
1863 int flags;
1864 {
1865 int i, pass_next, backq, dquote, si, c, oldjmp;
1866 int invert, skipquote, skipcmd, noprocsub, completeflag;
1867 int arithexp, skipcol;
1868 size_t slen;
1869 char *temp, open[3];
1870 DECLARE_MBSTATE;
1871
1872 slen = strlen (string + start) + start;
1873 oldjmp = no_longjmp_on_fatal_error;
1874 if (flags & SD_NOJMP)
1875 no_longjmp_on_fatal_error = 1;
1876 invert = (flags & SD_INVERT);
1877 skipcmd = (flags & SD_NOSKIPCMD) == 0;
1878 noprocsub = (flags & SD_NOPROCSUB);
1879 completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0;
1880
1881 arithexp = (flags & SD_ARITHEXP);
1882 skipcol = 0;
1883
1884 i = start;
1885 pass_next = backq = dquote = 0;
1886 while (c = string[i])
1887 {
1888 /* If this is non-zero, we should not let quote characters be delimiters
1889 and the current character is a single or double quote. We should not
1890 test whether or not it's a delimiter until after we skip single- or
1891 double-quoted strings. */
1892 skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
1893 if (pass_next)
1894 {
1895 pass_next = 0;
1896 if (c == 0)
1897 CQ_RETURN(i);
1898 ADVANCE_CHAR (string, slen, i);
1899 continue;
1900 }
1901 else if (c == '\\')
1902 {
1903 pass_next = 1;
1904 i++;
1905 continue;
1906 }
1907 else if (backq)
1908 {
1909 if (c == '`')
1910 backq = 0;
1911 ADVANCE_CHAR (string, slen, i);
1912 continue;
1913 }
1914 else if (c == '`')
1915 {
1916 backq = 1;
1917 i++;
1918 continue;
1919 }
1920 else if (arithexp && skipcol && c == ':')
1921 {
1922 skipcol--;
1923 i++;
1924 continue;
1925 }
1926 else if (arithexp && c == '?')
1927 {
1928 skipcol++;
1929 i++;
1930 continue;
1931 }
1932 else if (skipquote == 0 && invert == 0 && member (c, delims))
1933 break;
1934 /* the usual case is to use skip_xxx_quoted, but we don't skip over double
1935 quoted strings when looking for the history expansion character as a
1936 delimiter. */
1937 /* special case for programmable completion which takes place before
1938 parser converts backslash-escaped single quotes between $'...' to
1939 `regular' single-quoted strings. */
1940 else if (completeflag && i > 0 && string[i-1] == '$' && c == '\'')
1941 i = skip_single_quoted (string, slen, ++i, SX_COMPLETE);
1942 else if (c == '\'')
1943 i = skip_single_quoted (string, slen, ++i, 0);
1944 else if (c == '"')
1945 i = skip_double_quoted (string, slen, ++i, completeflag);
1946 else if (c == LPAREN && arithexp)
1947 {
1948 si = i + 1;
1949 if (string[si] == '\0')
1950 CQ_RETURN(si);
1951
1952 temp = extract_delimited_string (string, &si, "(", "(", ")", SX_NOALLOC); /* ) */
1953 i = si;
1954 if (string[i] == '\0') /* don't increment i past EOS in loop */
1955 break;
1956 i++;
1957 continue;
1958 }
1959 else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
1960 {
1961 si = i + 2;
1962 if (string[si] == '\0')
1963 CQ_RETURN(si);
1964
1965 if (string[i+1] == LPAREN)
1966 temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
1967 else
1968 temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
1969 CHECK_STRING_OVERRUN (i, si, slen, c);
1970 i = si;
1971 if (string[i] == '\0') /* don't increment i past EOS in loop */
1972 break;
1973 i++;
1974 continue;
1975 }
1976 #if defined (PROCESS_SUBSTITUTION)
1977 else if (skipcmd && noprocsub == 0 && (c == '<' || c == '>') && string[i+1] == LPAREN)
1978 {
1979 si = i + 2;
1980 if (string[si] == '\0')
1981 CQ_RETURN(si);
1982
1983 temp = extract_delimited_string (string, &si, (c == '<') ? "<(" : ">(", "(", ")", SX_COMMAND|SX_NOALLOC); /* )) */
1984 CHECK_STRING_OVERRUN (i, si, slen, c);
1985 i = si;
1986 if (string[i] == '\0')
1987 break;
1988 i++;
1989 continue;
1990 }
1991 #endif /* PROCESS_SUBSTITUTION */
1992 #if defined (EXTENDED_GLOB)
1993 else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@"))
1994 {
1995 si = i + 2;
1996 if (string[si] == '\0')
1997 CQ_RETURN(si);
1998
1999 open[0] = c;
2000 open[1] = LPAREN;
2001 open[2] = '\0';
2002 temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */
2003
2004 CHECK_STRING_OVERRUN (i, si, slen, c);
2005 i = si;
2006 if (string[i] == '\0') /* don't increment i past EOS in loop */
2007 break;
2008 i++;
2009 continue;
2010 }
2011 #endif
2012 else if ((flags & SD_GLOB) && c == LBRACK)
2013 {
2014 si = i + 1;
2015 if (string[si] == '\0')
2016 CQ_RETURN(si);
2017
2018 temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */
2019
2020 i = si;
2021 if (string[i] == '\0') /* don't increment i past EOS in loop */
2022 break;
2023 i++;
2024 continue;
2025 }
2026 else if ((skipquote || invert) && (member (c, delims) == 0))
2027 break;
2028 else
2029 ADVANCE_CHAR (string, slen, i);
2030 }
2031
2032 CQ_RETURN(i);
2033 }
2034
2035 #if defined (BANG_HISTORY)
2036 /* Skip to the history expansion character (delims[0]), paying attention to
2037 quoted strings and command and process substitution. This is a stripped-
2038 down version of skip_to_delims. The essential difference is that this
2039 resets the quoting state when starting a command substitution */
2040 int
2041 skip_to_histexp (string, start, delims, flags)
2042 char *string;
2043 int start;
2044 char *delims;
2045 int flags;
2046 {
2047 int i, pass_next, backq, dquote, c, oldjmp;
2048 int histexp_comsub, histexp_backq, old_dquote;
2049 size_t slen;
2050 DECLARE_MBSTATE;
2051
2052 slen = strlen (string + start) + start;
2053 oldjmp = no_longjmp_on_fatal_error;
2054 if (flags & SD_NOJMP)
2055 no_longjmp_on_fatal_error = 1;
2056
2057 histexp_comsub = histexp_backq = old_dquote = 0;
2058
2059 i = start;
2060 pass_next = backq = dquote = 0;
2061 while (c = string[i])
2062 {
2063 if (pass_next)
2064 {
2065 pass_next = 0;
2066 if (c == 0)
2067 CQ_RETURN(i);
2068 ADVANCE_CHAR (string, slen, i);
2069 continue;
2070 }
2071 else if (c == '\\')
2072 {
2073 pass_next = 1;
2074 i++;
2075 continue;
2076 }
2077 else if (backq && c == '`')
2078 {
2079 backq = 0;
2080 histexp_backq--;
2081 dquote = old_dquote;
2082 i++;
2083 continue;
2084 }
2085 else if (c == '`')
2086 {
2087 backq = 1;
2088 histexp_backq++;
2089 old_dquote = dquote; /* simple - one level for now */
2090 dquote = 0;
2091 i++;
2092 continue;
2093 }
2094 /* When in double quotes, act as if the double quote is a member of
2095 history_no_expand_chars, like the history library does */
2096 else if (dquote && c == delims[0] && string[i+1] == '"')
2097 {
2098 i++;
2099 continue;
2100 }
2101 else if (c == delims[0])
2102 break;
2103 /* the usual case is to use skip_xxx_quoted, but we don't skip over double
2104 quoted strings when looking for the history expansion character as a
2105 delimiter. */
2106 else if (dquote && c == '\'')
2107 {
2108 i++;
2109 continue;
2110 }
2111 else if (c == '\'')
2112 i = skip_single_quoted (string, slen, ++i, 0);
2113 /* The posixly_correct test makes posix-mode shells allow double quotes
2114 to quote the history expansion character */
2115 else if (posixly_correct == 0 && c == '"')
2116 {
2117 dquote = 1 - dquote;
2118 i++;
2119 continue;
2120 }
2121 else if (c == '"')
2122 i = skip_double_quoted (string, slen, ++i, 0);
2123 #if defined (PROCESS_SUBSTITUTION)
2124 else if ((c == '$' || c == '<' || c == '>') && string[i+1] == LPAREN && string[i+2] != LPAREN)
2125 #else
2126 else if (c == '$' && string[i+1] == LPAREN && string[i+2] != LPAREN)
2127 #endif
2128 {
2129 if (string[i+2] == '\0')
2130 CQ_RETURN(i+2);
2131 i += 2;
2132 histexp_comsub++;
2133 old_dquote = dquote;
2134 dquote = 0;
2135 }
2136 else if (histexp_comsub && c == RPAREN)
2137 {
2138 histexp_comsub--;
2139 dquote = old_dquote;
2140 i++;
2141 continue;
2142 }
2143 else if (backq) /* placeholder */
2144 {
2145 ADVANCE_CHAR (string, slen, i);
2146 continue;
2147 }
2148 else
2149 ADVANCE_CHAR (string, slen, i);
2150 }
2151
2152 CQ_RETURN(i);
2153 }
2154 #endif /* BANG_HISTORY */
2155
2156 #if defined (READLINE)
2157 /* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
2158 an unclosed quoted string), or if the character at EINDEX is quoted
2159 by a backslash. NO_LONGJMP_ON_FATAL_ERROR is used to flag that the various
2160 single and double-quoted string parsing functions should not return an
2161 error if there are unclosed quotes or braces. The characters that this
2162 recognizes need to be the same as the contents of
2163 rl_completer_quote_characters. */
2164
2165 int
2166 char_is_quoted (string, eindex)
2167 char *string;
2168 int eindex;
2169 {
2170 int i, pass_next, c, oldjmp;
2171 size_t slen;
2172 DECLARE_MBSTATE;
2173
2174 slen = strlen (string);
2175 oldjmp = no_longjmp_on_fatal_error;
2176 no_longjmp_on_fatal_error = 1;
2177 i = pass_next = 0;
2178 while (i <= eindex)
2179 {
2180 c = string[i];
2181
2182 if (pass_next)
2183 {
2184 pass_next = 0;
2185 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
2186 CQ_RETURN(1);
2187 ADVANCE_CHAR (string, slen, i);
2188 continue;
2189 }
2190 else if (c == '\\')
2191 {
2192 pass_next = 1;
2193 i++;
2194 continue;
2195 }
2196 else if (c == '$' && string[i+1] == '\'' && string[i+2])
2197 {
2198 i += 2;
2199 i = skip_single_quoted (string, slen, i, SX_COMPLETE);
2200 if (i > eindex)
2201 CQ_RETURN (i);
2202 }
2203 else if (c == '\'' || c == '"')
2204 {
2205 i = (c == '\'') ? skip_single_quoted (string, slen, ++i, 0)
2206 : skip_double_quoted (string, slen, ++i, SX_COMPLETE);
2207 if (i > eindex)
2208 CQ_RETURN(1);
2209 /* no increment, the skip_xxx functions go one past end */
2210 }
2211 else
2212 ADVANCE_CHAR (string, slen, i);
2213 }
2214
2215 CQ_RETURN(0);
2216 }
2217
2218 int
2219 unclosed_pair (string, eindex, openstr)
2220 char *string;
2221 int eindex;
2222 char *openstr;
2223 {
2224 int i, pass_next, openc, olen;
2225 size_t slen;
2226 DECLARE_MBSTATE;
2227
2228 slen = strlen (string);
2229 olen = strlen (openstr);
2230 i = pass_next = openc = 0;
2231 while (i <= eindex)
2232 {
2233 if (pass_next)
2234 {
2235 pass_next = 0;
2236 if (i >= eindex) /* XXX was if (i >= eindex - 1) */
2237 return 0;
2238 ADVANCE_CHAR (string, slen, i);
2239 continue;
2240 }
2241 else if (string[i] == '\\')
2242 {
2243 pass_next = 1;
2244 i++;
2245 continue;
2246 }
2247 else if (STREQN (string + i, openstr, olen))
2248 {
2249 openc = 1 - openc;
2250 i += olen;
2251 }
2252 /* XXX - may want to handle $'...' specially here */
2253 else if (string[i] == '\'' || string[i] == '"')
2254 {
2255 i = (string[i] == '\'') ? skip_single_quoted (string, slen, i, 0)
2256 : skip_double_quoted (string, slen, i, SX_COMPLETE);
2257 if (i > eindex)
2258 return 0;
2259 }
2260 else
2261 ADVANCE_CHAR (string, slen, i);
2262 }
2263 return (openc);
2264 }
2265
2266 /* Split STRING (length SLEN) at DELIMS, and return a WORD_LIST with the
2267 individual words. If DELIMS is NULL, the current value of $IFS is used
2268 to split the string, and the function follows the shell field splitting
2269 rules. SENTINEL is an index to look for. NWP, if non-NULL,
2270 gets the number of words in the returned list. CWP, if non-NULL, gets
2271 the index of the word containing SENTINEL. Non-whitespace chars in
2272 DELIMS delimit separate fields. This is used by programmable completion. */
2273 WORD_LIST *
2274 split_at_delims (string, slen, delims, sentinel, flags, nwp, cwp)
2275 char *string;
2276 int slen;
2277 char *delims;
2278 int sentinel, flags;
2279 int *nwp, *cwp;
2280 {
2281 int ts, te, i, nw, cw, ifs_split, dflags;
2282 char *token, *d, *d2;
2283 WORD_LIST *ret, *tl;
2284
2285 if (string == 0 || *string == '\0')
2286 {
2287 if (nwp)
2288 *nwp = 0;
2289 if (cwp)
2290 *cwp = 0;
2291 return ((WORD_LIST *)NULL);
2292 }
2293
2294 d = (delims == 0) ? ifs_value : delims;
2295 ifs_split = delims == 0;
2296
2297 /* Make d2 the non-whitespace characters in delims */
2298 d2 = 0;
2299 if (delims)
2300 {
2301 size_t slength;
2302 #if defined (HANDLE_MULTIBYTE)
2303 size_t mblength = 1;
2304 #endif
2305 DECLARE_MBSTATE;
2306
2307 slength = strlen (delims);
2308 d2 = (char *)xmalloc (slength + 1);
2309 i = ts = 0;
2310 while (delims[i])
2311 {
2312 #if defined (HANDLE_MULTIBYTE)
2313 mbstate_t state_bak;
2314 state_bak = state;
2315 mblength = MBRLEN (delims + i, slength, &state);
2316 if (MB_INVALIDCH (mblength))
2317 state = state_bak;
2318 else if (mblength > 1)
2319 {
2320 memcpy (d2 + ts, delims + i, mblength);
2321 ts += mblength;
2322 i += mblength;
2323 slength -= mblength;
2324 continue;
2325 }
2326 #endif
2327 if (whitespace (delims[i]) == 0)
2328 d2[ts++] = delims[i];
2329
2330 i++;
2331 slength--;
2332 }
2333 d2[ts] = '\0';
2334 }
2335
2336 ret = (WORD_LIST *)NULL;
2337
2338 /* Remove sequences of whitespace characters at the start of the string, as
2339 long as those characters are delimiters. */
2340 for (i = 0; member (string[i], d) && spctabnl (string[i]); i++)
2341 ;
2342 if (string[i] == '\0')
2343 {
2344 FREE (d2);
2345 return (ret);
2346 }
2347
2348 ts = i;
2349 nw = 0;
2350 cw = -1;
2351 dflags = flags|SD_NOJMP;
2352 while (1)
2353 {
2354 te = skip_to_delim (string, ts, d, dflags);
2355
2356 /* If we have a non-whitespace delimiter character, use it to make a
2357 separate field. This is just about what $IFS splitting does and
2358 is closer to the behavior of the shell parser. */
2359 if (ts == te && d2 && member (string[ts], d2))
2360 {
2361 te = ts + 1;
2362 /* If we're using IFS splitting, the non-whitespace delimiter char
2363 and any additional IFS whitespace delimits a field. */
2364 if (ifs_split)
2365 while (member (string[te], d) && spctabnl (string[te]) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2366 te++;
2367 else
2368 while (member (string[te], d2) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2369 te++;
2370 }
2371
2372 token = substring (string, ts, te);
2373
2374 ret = add_string_to_list (token, ret); /* XXX */
2375 free (token);
2376 nw++;
2377
2378 if (sentinel >= ts && sentinel <= te)
2379 cw = nw;
2380
2381 /* If the cursor is at whitespace just before word start, set the
2382 sentinel word to the current word. */
2383 if (cwp && cw == -1 && sentinel == ts-1)
2384 cw = nw;
2385
2386 /* If the cursor is at whitespace between two words, make a new, empty
2387 word, add it before (well, after, since the list is in reverse order)
2388 the word we just added, and set the current word to that one. */
2389 if (cwp && cw == -1 && sentinel < ts)
2390 {
2391 tl = make_word_list (make_word (""), ret->next);
2392 ret->next = tl;
2393 cw = nw;
2394 nw++;
2395 }
2396
2397 if (string[te] == 0)
2398 break;
2399
2400 i = te;
2401 /* XXX - honor SD_NOQUOTEDELIM here */
2402 while (member (string[i], d) && (ifs_split || spctabnl(string[i])) && ((flags&SD_NOQUOTEDELIM) == 0 || (string[te] != '\'' && string[te] != '"')))
2403 i++;
2404
2405 if (string[i])
2406 ts = i;
2407 else
2408 break;
2409 }
2410
2411 /* Special case for SENTINEL at the end of STRING. If we haven't found
2412 the word containing SENTINEL yet, and the index we're looking for is at
2413 the end of STRING (or past the end of the previously-found token,
2414 possible if the end of the line is composed solely of IFS whitespace)
2415 add an additional null argument and set the current word pointer to that. */
2416 if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
2417 {
2418 if (whitespace (string[sentinel - 1]))
2419 {
2420 token = "";
2421 ret = add_string_to_list (token, ret);
2422 nw++;
2423 }
2424 cw = nw;
2425 }
2426
2427 if (nwp)
2428 *nwp = nw;
2429 if (cwp)
2430 *cwp = cw;
2431
2432 FREE (d2);
2433
2434 return (REVERSE_LIST (ret, WORD_LIST *));
2435 }
2436 #endif /* READLINE */
2437
2438 #if 0
2439 /* UNUSED */
2440 /* Extract the name of the variable to bind to from the assignment string. */
2441 char *
2442 assignment_name (string)
2443 char *string;
2444 {
2445 int offset;
2446 char *temp;
2447
2448 offset = assignment (string, 0);
2449 if (offset == 0)
2450 return (char *)NULL;
2451 temp = substring (string, 0, offset);
2452 return (temp);
2453 }
2454 #endif
2455
2456 /* **************************************************************** */
2457 /* */
2458 /* Functions to convert strings to WORD_LISTs and vice versa */
2459 /* */
2460 /* **************************************************************** */
2461
2462 /* Return a single string of all the words in LIST. SEP is the separator
2463 to put between individual elements of LIST in the output string. */
2464 char *
2465 string_list_internal (list, sep)
2466 WORD_LIST *list;
2467 char *sep;
2468 {
2469 register WORD_LIST *t;
2470 char *result, *r;
2471 size_t word_len, sep_len, result_size;
2472
2473 if (list == 0)
2474 return ((char *)NULL);
2475
2476 /* Short-circuit quickly if we don't need to separate anything. */
2477 if (list->next == 0)
2478 return (savestring (list->word->word));
2479
2480 /* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
2481 sep_len = STRLEN (sep);
2482 result_size = 0;
2483
2484 for (t = list; t; t = t->next)
2485 {
2486 if (t != list)
2487 result_size += sep_len;
2488 result_size += strlen (t->word->word);
2489 }
2490
2491 r = result = (char *)xmalloc (result_size + 1);
2492
2493 for (t = list; t; t = t->next)
2494 {
2495 if (t != list && sep_len)
2496 {
2497 if (sep_len > 1)
2498 {
2499 FASTCOPY (sep, r, sep_len);
2500 r += sep_len;
2501 }
2502 else
2503 *r++ = sep[0];
2504 }
2505
2506 word_len = strlen (t->word->word);
2507 FASTCOPY (t->word->word, r, word_len);
2508 r += word_len;
2509 }
2510
2511 *r = '\0';
2512 return (result);
2513 }
2514
2515 /* Return a single string of all the words present in LIST, separating
2516 each word with a space. */
2517 char *
2518 string_list (list)
2519 WORD_LIST *list;
2520 {
2521 return (string_list_internal (list, " "));
2522 }
2523
2524 /* An external interface that can be used by the rest of the shell to
2525 obtain a string containing the first character in $IFS. Handles all
2526 the multibyte complications. If LENP is non-null, it is set to the
2527 length of the returned string. */
2528 char *
2529 ifs_firstchar (lenp)
2530 int *lenp;
2531 {
2532 char *ret;
2533 int len;
2534
2535 ret = xmalloc (MB_LEN_MAX + 1);
2536 #if defined (HANDLE_MULTIBYTE)
2537 if (ifs_firstc_len == 1)
2538 {
2539 ret[0] = ifs_firstc[0];
2540 ret[1] = '\0';
2541 len = ret[0] ? 1 : 0;
2542 }
2543 else
2544 {
2545 memcpy (ret, ifs_firstc, ifs_firstc_len);
2546 ret[len = ifs_firstc_len] = '\0';
2547 }
2548 #else
2549 ret[0] = ifs_firstc;
2550 ret[1] = '\0';
2551 len = ret[0] ? 0 : 1;
2552 #endif
2553
2554 if (lenp)
2555 *lenp = len;
2556
2557 return ret;
2558 }
2559
2560 /* Return a single string of all the words present in LIST, obeying the
2561 quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2) "If the
2562 expansion [of $*] appears within a double quoted string, it expands
2563 to a single field with the value of each parameter separated by the
2564 first character of the IFS variable, or by a <space> if IFS is unset." */
2565 /* Posix interpretation 888 changes this when IFS is null by specifying
2566 that when unquoted, this expands to separate arguments */
2567 char *
2568 string_list_dollar_star (list, quoted, flags)
2569 WORD_LIST *list;
2570 int quoted, flags;
2571 {
2572 char *ret;
2573 #if defined (HANDLE_MULTIBYTE)
2574 # if defined (__GNUC__)
2575 char sep[MB_CUR_MAX + 1];
2576 # else
2577 char *sep = 0;
2578 # endif
2579 #else
2580 char sep[2];
2581 #endif
2582
2583 #if defined (HANDLE_MULTIBYTE)
2584 # if !defined (__GNUC__)
2585 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2586 # endif /* !__GNUC__ */
2587 if (ifs_firstc_len == 1)
2588 {
2589 sep[0] = ifs_firstc[0];
2590 sep[1] = '\0';
2591 }
2592 else
2593 {
2594 memcpy (sep, ifs_firstc, ifs_firstc_len);
2595 sep[ifs_firstc_len] = '\0';
2596 }
2597 #else
2598 sep[0] = ifs_firstc;
2599 sep[1] = '\0';
2600 #endif
2601
2602 ret = string_list_internal (list, sep);
2603 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2604 free (sep);
2605 #endif
2606 return ret;
2607 }
2608
2609 /* Turn $@ into a string. If (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
2610 is non-zero, the $@ appears within double quotes, and we should quote
2611 the list before converting it into a string. If IFS is unset, and the
2612 word is not quoted, we just need to quote CTLESC and CTLNUL characters
2613 in the words in the list, because the default value of $IFS is
2614 <space><tab><newline>, IFS characters in the words in the list should
2615 also be split. If IFS is null, and the word is not quoted, we need
2616 to quote the words in the list to preserve the positional parameters
2617 exactly.
2618 Valid values for the FLAGS argument are the PF_ flags in command.h,
2619 the only one we care about is PF_ASSIGNRHS. $@ is supposed to expand
2620 to the positional parameters separated by spaces no matter what IFS is
2621 set to if in a context where word splitting is not performed. The only
2622 one that we didn't handle before is assignment statement arguments to
2623 declaration builtins like `declare'. */
2624 char *
2625 string_list_dollar_at (list, quoted, flags)
2626 WORD_LIST *list;
2627 int quoted;
2628 int flags;
2629 {
2630 char *ifs, *ret;
2631 #if defined (HANDLE_MULTIBYTE)
2632 # if defined (__GNUC__)
2633 char sep[MB_CUR_MAX + 1];
2634 # else
2635 char *sep = 0;
2636 # endif /* !__GNUC__ */
2637 #else
2638 char sep[2];
2639 #endif
2640 WORD_LIST *tlist;
2641
2642 /* XXX this could just be ifs = ifs_value; */
2643 ifs = ifs_var ? value_cell (ifs_var) : (char *)0;
2644
2645 #if defined (HANDLE_MULTIBYTE)
2646 # if !defined (__GNUC__)
2647 sep = (char *)xmalloc (MB_CUR_MAX + 1);
2648 # endif /* !__GNUC__ */
2649 /* XXX - testing PF_ASSIGNRHS to make sure positional parameters are
2650 separated with a space even when word splitting will not occur. */
2651 if (flags & PF_ASSIGNRHS)
2652 {
2653 sep[0] = ' ';
2654 sep[1] = '\0';
2655 }
2656 else if (ifs && *ifs)
2657 {
2658 if (ifs_firstc_len == 1)
2659 {
2660 sep[0] = ifs_firstc[0];
2661 sep[1] = '\0';
2662 }
2663 else
2664 {
2665 memcpy (sep, ifs_firstc, ifs_firstc_len);
2666 sep[ifs_firstc_len] = '\0';
2667 }
2668 }
2669 else
2670 {
2671 sep[0] = ' ';
2672 sep[1] = '\0';
2673 }
2674 #else /* !HANDLE_MULTIBYTE */
2675 /* XXX - PF_ASSIGNRHS means no word splitting, so we want positional
2676 parameters separated by a space. */
2677 sep[0] = ((flags & PF_ASSIGNRHS) || ifs == 0 || *ifs == 0) ? ' ' : *ifs;
2678 sep[1] = '\0';
2679 #endif /* !HANDLE_MULTIBYTE */
2680
2681 /* XXX -- why call quote_list if ifs == 0? we can get away without doing
2682 it now that quote_escapes quotes spaces */
2683 tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
2684 ? quote_list (list)
2685 : list_quote_escapes (list);
2686
2687 ret = string_list_internal (tlist, sep);
2688 #if defined (HANDLE_MULTIBYTE) && !defined (__GNUC__)
2689 free (sep);
2690 #endif
2691 return ret;
2692 }
2693
2694 /* Turn the positional parameters into a string, understanding quoting and
2695 the various subtleties of using the first character of $IFS as the
2696 separator. Calls string_list_dollar_at, string_list_dollar_star, and
2697 string_list as appropriate. */
2698 /* This needs to fully understand the additional contexts where word
2699 splitting does not occur (W_ASSIGNRHS, etc.) */
2700 char *
2701 string_list_pos_params (pchar, list, quoted, pflags)
2702 int pchar;
2703 WORD_LIST *list;
2704 int quoted, pflags;
2705 {
2706 char *ret;
2707 WORD_LIST *tlist;
2708
2709 if (pchar == '*' && (quoted & Q_DOUBLE_QUOTES))
2710 {
2711 tlist = quote_list (list);
2712 word_list_remove_quoted_nulls (tlist);
2713 ret = string_list_dollar_star (tlist, 0, 0);
2714 }
2715 else if (pchar == '*' && (quoted & Q_HERE_DOCUMENT))
2716 {
2717 tlist = quote_list (list);
2718 word_list_remove_quoted_nulls (tlist);
2719 ret = string_list (tlist);
2720 }
2721 else if (pchar == '*' && quoted == 0 && ifs_is_null) /* XXX */
2722 ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
2723 else if (pchar == '*' && quoted == 0 && (pflags & PF_ASSIGNRHS)) /* XXX */
2724 ret = expand_no_split_dollar_star ? string_list_dollar_star (list, quoted, 0) : string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
2725 else if (pchar == '*')
2726 {
2727 /* Even when unquoted, string_list_dollar_star does the right thing
2728 making sure that the first character of $IFS is used as the
2729 separator. */
2730 ret = string_list_dollar_star (list, quoted, 0);
2731 }
2732 else if (pchar == '@' && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
2733 /* We use string_list_dollar_at, but only if the string is quoted, since
2734 that quotes the escapes if it's not, which we don't want. We could
2735 use string_list (the old code did), but that doesn't do the right
2736 thing if the first character of $IFS is not a space. We use
2737 string_list_dollar_star if the string is unquoted so we make sure that
2738 the elements of $@ are separated by the first character of $IFS for
2739 later splitting. */
2740 ret = string_list_dollar_at (list, quoted, 0);
2741 else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */
2742 ret = string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */
2743 else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS))
2744 ret = string_list_dollar_at (list, quoted, pflags); /* Posix interp 888 */
2745 else if (pchar == '@')
2746 ret = string_list_dollar_star (list, quoted, 0);
2747 else
2748 ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
2749
2750 return ret;
2751 }
2752
2753 /* Return the list of words present in STRING. Separate the string into
2754 words at any of the characters found in SEPARATORS. If QUOTED is
2755 non-zero then word in the list will have its quoted flag set, otherwise
2756 the quoted flag is left as make_word () deemed fit.
2757
2758 This obeys the P1003.2 word splitting semantics. If `separators' is
2759 exactly <space><tab><newline>, then the splitting algorithm is that of
2760 the Bourne shell, which treats any sequence of characters from `separators'
2761 as a delimiter. If IFS is unset, which results in `separators' being set
2762 to "", no splitting occurs. If separators has some other value, the
2763 following rules are applied (`IFS white space' means zero or more
2764 occurrences of <space>, <tab>, or <newline>, as long as those characters
2765 are in `separators'):
2766
2767 1) IFS white space is ignored at the start and the end of the
2768 string.
2769 2) Each occurrence of a character in `separators' that is not
2770 IFS white space, along with any adjacent occurrences of
2771 IFS white space delimits a field.
2772 3) Any nonzero-length sequence of IFS white space delimits a field.
2773 */
2774
2775 /* BEWARE! list_string strips null arguments. Don't call it twice and
2776 expect to have "" preserved! */
2777
2778 /* This performs word splitting and quoted null character removal on
2779 STRING. */
2780 #define issep(c) \
2781 (((separators)[0]) ? ((separators)[1] ? isifs(c) \
2782 : (c) == (separators)[0]) \
2783 : 0)
2784
2785 /* member of the space character class in the current locale */
2786 #define ifs_whitespace(c) ISSPACE(c)
2787
2788 /* "adjacent IFS white space" */
2789 #define ifs_whitesep(c) ((sh_style_split || separators == 0) ? spctabnl (c) \
2790 : ifs_whitespace (c))
2791
2792 WORD_LIST *
2793 list_string (string, separators, quoted)
2794 register char *string, *separators;
2795 int quoted;
2796 {
2797 WORD_LIST *result;
2798 WORD_DESC *t;
2799 char *current_word, *s;
2800 int sindex, sh_style_split, whitesep, xflags, free_word;
2801 size_t slen;
2802
2803 if (!string || !*string)
2804 return ((WORD_LIST *)NULL);
2805
2806 sh_style_split = separators && separators[0] == ' ' &&
2807 separators[1] == '\t' &&
2808 separators[2] == '\n' &&
2809 separators[3] == '\0';
2810 for (xflags = 0, s = ifs_value; s && *s; s++)
2811 {
2812 if (*s == CTLESC) xflags |= SX_NOCTLESC;
2813 else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
2814 }
2815
2816 slen = 0;
2817 /* Remove sequences of whitespace at the beginning of STRING, as
2818 long as those characters appear in IFS. Do not do this if
2819 STRING is quoted or if there are no separator characters. We use the
2820 Posix definition of whitespace as a member of the space character
2821 class in the current locale. */
2822 #if 0
2823 if (!quoted || !separators || !*separators)
2824 #else
2825 /* issep() requires that separators be non-null, and always returns 0 if
2826 separator is the empty string, so don't bother if we get an empty string
2827 for separators. We already returned NULL above if STRING is empty. */
2828 if (!quoted && separators && *separators)
2829 #endif
2830 {
2831 for (s = string; *s && issep (*s) && ifs_whitespace (*s); s++);
2832
2833 if (!*s)
2834 return ((WORD_LIST *)NULL);
2835
2836 string = s;
2837 }
2838
2839 /* OK, now STRING points to a word that does not begin with white space.
2840 The splitting algorithm is:
2841 extract a word, stopping at a separator
2842 skip sequences of whitespace characters as long as they are separators
2843 This obeys the field splitting rules in Posix.2. */
2844 slen = STRLEN (string);
2845 for (result = (WORD_LIST *)NULL, sindex = 0; string[sindex]; )
2846 {
2847 /* Don't need string length in ADVANCE_CHAR unless multibyte chars are
2848 possible, but need it in string_extract_verbatim for bounds checking */
2849 current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
2850 if (current_word == 0)
2851 break;
2852
2853 free_word = 1; /* If non-zero, we free current_word */
2854
2855 /* If we have a quoted empty string, add a quoted null argument. We
2856 want to preserve the quoted null character iff this is a quoted
2857 empty string; otherwise the quoted null characters are removed
2858 below. */
2859 if (QUOTED_NULL (current_word))
2860 {
2861 t = alloc_word_desc ();
2862 t->word = make_quoted_char ('\0');
2863 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
2864 result = make_word_list (t, result);
2865 }
2866 else if (current_word[0] != '\0')
2867 {
2868 /* If we have something, then add it regardless. However,
2869 perform quoted null character removal on the current word. */
2870 remove_quoted_nulls (current_word);
2871
2872 /* We don't want to set the word flags based on the string contents
2873 here -- that's mostly for the parser -- so we just allocate a
2874 WORD_DESC *, assign current_word (noting that we don't want to
2875 free it), and skip all of make_word. */
2876 t = alloc_word_desc ();
2877 t->word = current_word;
2878 result = make_word_list (t, result);
2879 free_word = 0;
2880 result->word->flags &= ~W_HASQUOTEDNULL; /* just to be sure */
2881 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
2882 result->word->flags |= W_QUOTED;
2883 /* If removing quoted null characters leaves an empty word, note
2884 that we saw this for the caller to act on. */
2885 if (current_word == 0 || current_word[0] == '\0')
2886 result->word->flags |= W_SAWQUOTEDNULL;
2887 }
2888
2889 /* If we're not doing sequences of separators in the traditional
2890 Bourne shell style, then add a quoted null argument. */
2891 else if (!sh_style_split && !ifs_whitespace (string[sindex]))
2892 {
2893 t = alloc_word_desc ();
2894 t->word = make_quoted_char ('\0');
2895 t->flags |= W_QUOTED|W_HASQUOTEDNULL;
2896 result = make_word_list (t, result);
2897 }
2898
2899 if (free_word)
2900 free (current_word);
2901
2902 /* Note whether or not the separator is IFS whitespace, used later. */
2903 whitesep = string[sindex] && ifs_whitesep (string[sindex]);
2904
2905 /* Move past the current separator character. */
2906 if (string[sindex])
2907 {
2908 DECLARE_MBSTATE;
2909 ADVANCE_CHAR (string, slen, sindex);
2910 }
2911
2912 /* Now skip sequences of whitespace characters if they are
2913 in the list of separators. */
2914 while (string[sindex] && ifs_whitesep (string[sindex]) && issep (string[sindex]))
2915 sindex++;
2916
2917 /* If the first separator was IFS whitespace and the current character
2918 is a non-whitespace IFS character, it should be part of the current
2919 field delimiter, not a separate delimiter that would result in an
2920 empty field. Look at POSIX.2, 3.6.5, (3)(b). */
2921 if (string[sindex] && whitesep && issep (string[sindex]) && !ifs_whitesep (string[sindex]))
2922 {
2923 sindex++;
2924 /* An IFS character that is not IFS white space, along with any
2925 adjacent IFS white space, shall delimit a field. (SUSv3) */
2926 while (string[sindex] && ifs_whitesep (string[sindex]) && isifs (string[sindex]))
2927 sindex++;
2928 }
2929 }
2930 return (REVERSE_LIST (result, WORD_LIST *));
2931 }
2932
2933 /* Parse a single word from STRING, using SEPARATORS to separate fields.
2934 ENDPTR is set to the first character after the word. This is used by
2935 the `read' builtin.
2936
2937 This is never called with SEPARATORS != $IFS, and takes advantage of that.
2938
2939 XXX - this function is very similar to list_string; they should be
2940 combined - XXX */
2941
2942 /* character is in $IFS */
2943 #define islocalsep(c) (local_cmap[(unsigned char)(c)] != 0)
2944
2945 char *
2946 get_word_from_string (stringp, separators, endptr)
2947 char **stringp, *separators, **endptr;
2948 {
2949 register char *s;
2950 char *current_word;
2951 int sindex, sh_style_split, whitesep, xflags;
2952 unsigned char local_cmap[UCHAR_MAX+1]; /* really only need single-byte chars here */
2953 size_t slen;
2954
2955 if (!stringp || !*stringp || !**stringp)
2956 return ((char *)NULL);
2957
2958 sh_style_split = separators && separators[0] == ' ' &&
2959 separators[1] == '\t' &&
2960 separators[2] == '\n' &&
2961 separators[3] == '\0';
2962 memset (local_cmap, '\0', sizeof (local_cmap));
2963 for (xflags = 0, s = separators; s && *s; s++)
2964 {
2965 if (*s == CTLESC) xflags |= SX_NOCTLESC;
2966 if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
2967 local_cmap[(unsigned char)*s] = 1; /* local charmap of separators */
2968 }
2969
2970 s = *stringp;
2971 slen = 0;
2972
2973 /* Remove sequences of whitespace at the beginning of STRING, as
2974 long as those characters appear in SEPARATORS. This happens if
2975 SEPARATORS == $' \t\n' or if IFS is unset. */
2976 if (sh_style_split || separators == 0)
2977 for (; *s && spctabnl (*s) && islocalsep (*s); s++);
2978 else
2979 for (; *s && ifs_whitespace (*s) && islocalsep (*s); s++);
2980
2981 /* If the string is nothing but whitespace, update it and return. */
2982 if (!*s)
2983 {
2984 *stringp = s;
2985 if (endptr)
2986 *endptr = s;
2987 return ((char *)NULL);
2988 }
2989
2990 /* OK, S points to a word that does not begin with white space.
2991 Now extract a word, stopping at a separator, save a pointer to
2992 the first character after the word, then skip sequences of spc,
2993 tab, or nl as long as they are separators.
2994
2995 This obeys the field splitting rules in Posix.2. */
2996 sindex = 0;
2997 /* Don't need string length in ADVANCE_CHAR unless multibyte chars are
2998 possible, but need it in string_extract_verbatim for bounds checking */
2999 slen = STRLEN (s);
3000 current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
3001
3002 /* Set ENDPTR to the first character after the end of the word. */
3003 if (endptr)
3004 *endptr = s + sindex;
3005
3006 /* Note whether or not the separator is IFS whitespace, used later. */
3007 whitesep = s[sindex] && ifs_whitesep (s[sindex]);
3008
3009 /* Move past the current separator character. */
3010 if (s[sindex])
3011 {
3012 DECLARE_MBSTATE;
3013 ADVANCE_CHAR (s, slen, sindex);
3014 }
3015
3016 /* Now skip sequences of space, tab, or newline characters if they are
3017 in the list of separators. */
3018 while (s[sindex] && spctabnl (s[sindex]) && islocalsep (s[sindex]))
3019 sindex++;
3020
3021 /* If the first separator was IFS whitespace and the current character is
3022 a non-whitespace IFS character, it should be part of the current field
3023 delimiter, not a separate delimiter that would result in an empty field.
3024 Look at POSIX.2, 3.6.5, (3)(b). */
3025 if (s[sindex] && whitesep && islocalsep (s[sindex]) && !ifs_whitesep (s[sindex]))
3026 {
3027 sindex++;
3028 /* An IFS character that is not IFS white space, along with any adjacent
3029 IFS white space, shall delimit a field. */
3030 while (s[sindex] && ifs_whitesep (s[sindex]) && islocalsep(s[sindex]))
3031 sindex++;
3032 }
3033
3034 /* Update STRING to point to the next field. */
3035 *stringp = s + sindex;
3036 return (current_word);
3037 }
3038
3039 /* Remove IFS white space at the end of STRING. Start at the end
3040 of the string and walk backwards until the beginning of the string
3041 or we find a character that's not IFS white space and not CTLESC.
3042 Only let CTLESC escape a white space character if SAW_ESCAPE is
3043 non-zero. */
3044 char *
3045 strip_trailing_ifs_whitespace (string, separators, saw_escape)
3046 char *string, *separators;
3047 int saw_escape;
3048 {
3049 char *s;
3050
3051 s = string + STRLEN (string) - 1;
3052 while (s > string && ((spctabnl (*s) && isifs (*s)) ||
3053 (saw_escape && *s == CTLESC && spctabnl (s[1]))))
3054 s--;
3055 *++s = '\0';
3056 return string;
3057 }
3058
3059 #if 0
3060 /* UNUSED */
3061 /* Split STRING into words at whitespace. Obeys shell-style quoting with
3062 backslashes, single and double quotes. */
3063 WORD_LIST *
3064 list_string_with_quotes (string)
3065 char *string;
3066 {
3067 WORD_LIST *list;
3068 char *token, *s;
3069 size_t s_len;
3070 int c, i, tokstart, len;
3071
3072 for (s = string; s && *s && spctabnl (*s); s++)
3073 ;
3074 if (s == 0 || *s == 0)
3075 return ((WORD_LIST *)NULL);
3076
3077 s_len = strlen (s);
3078 tokstart = i = 0;
3079 list = (WORD_LIST *)NULL;
3080 while (1)
3081 {
3082 c = s[i];
3083 if (c == '\\')
3084 {
3085 i++;
3086 if (s[i])
3087 i++;
3088 }
3089 else if (c == '\'')
3090 i = skip_single_quoted (s, s_len, ++i, 0);
3091 else if (c == '"')
3092 i = skip_double_quoted (s, s_len, ++i, 0);
3093 else if (c == 0 || spctabnl (c))
3094 {
3095 /* We have found the end of a token. Make a word out of it and
3096 add it to the word list. */
3097 token = substring (s, tokstart, i);
3098 list = add_string_to_list (token, list);
3099 free (token);
3100 while (spctabnl (s[i]))
3101 i++;
3102 if (s[i])
3103 tokstart = i;
3104 else
3105 break;
3106 }
3107 else
3108 i++; /* normal character */
3109 }
3110 return (REVERSE_LIST (list, WORD_LIST *));
3111 }
3112 #endif
3113
3114 /********************************************************/
3115 /* */
3116 /* Functions to perform assignment statements */
3117 /* */
3118 /********************************************************/
3119
3120 #if defined (ARRAY_VARS)
3121 static SHELL_VAR *
3122 do_compound_assignment (name, value, flags)
3123 char *name, *value;
3124 int flags;
3125 {
3126 SHELL_VAR *v;
3127 int mklocal, mkassoc, mkglobal, chklocal;
3128 WORD_LIST *list;
3129 char *newname; /* used for local nameref references */
3130
3131 mklocal = flags & ASS_MKLOCAL;
3132 mkassoc = flags & ASS_MKASSOC;
3133 mkglobal = flags & ASS_MKGLOBAL;
3134 chklocal = flags & ASS_CHKLOCAL;
3135
3136 if (mklocal && variable_context)
3137 {
3138 v = find_variable (name); /* follows namerefs */
3139 newname = (v == 0) ? nameref_transform_name (name, flags) : v->name;
3140 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3141 {
3142 if (readonly_p (v))
3143 err_readonly (name);
3144 return (v); /* XXX */
3145 }
3146 list = expand_compound_array_assignment (v, value, flags);
3147 if (mkassoc)
3148 v = make_local_assoc_variable (newname, 0);
3149 else if (v == 0 || (array_p (v) == 0 && assoc_p (v) == 0) || v->context != variable_context)
3150 v = make_local_array_variable (newname, 0);
3151 if (v)
3152 assign_compound_array_list (v, list, flags);
3153 if (list)
3154 dispose_words (list);
3155 }
3156 /* In a function but forcing assignment in global context. CHKLOCAL means to
3157 check for an existing local variable first. */
3158 else if (mkglobal && variable_context)
3159 {
3160 v = chklocal ? find_variable (name) : 0;
3161 if (v && (local_p (v) == 0 || v->context != variable_context))
3162 v = 0;
3163 if (v == 0)
3164 v = find_global_variable (name);
3165 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3166 {
3167 if (readonly_p (v))
3168 err_readonly (name);
3169 return (v); /* XXX */
3170 }
3171 /* sanity check */
3172 newname = (v == 0) ? nameref_transform_name (name, flags) : name;
3173 list = expand_compound_array_assignment (v, value, flags);
3174 if (v == 0 && mkassoc)
3175 v = make_new_assoc_variable (newname);
3176 else if (v && mkassoc && assoc_p (v) == 0)
3177 v = convert_var_to_assoc (v);
3178 else if (v == 0)
3179 v = make_new_array_variable (newname);
3180 else if (v && mkassoc == 0 && array_p (v) == 0)
3181 v = convert_var_to_array (v);
3182 if (v)
3183 assign_compound_array_list (v, list, flags);
3184 if (list)
3185 dispose_words (list);
3186 }
3187 else
3188 {
3189 v = assign_array_from_string (name, value, flags);
3190 if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
3191 {
3192 if (readonly_p (v))
3193 err_readonly (name);
3194 return (v); /* XXX */
3195 }
3196 }
3197
3198 return (v);
3199 }
3200 #endif
3201
3202 /* Given STRING, an assignment string, get the value of the right side
3203 of the `=', and bind it to the left side. If EXPAND is true, then
3204 perform parameter expansion, command substitution, and arithmetic
3205 expansion on the right-hand side. Perform tilde expansion in any
3206 case. Do not perform word splitting on the result of expansion. */
3207 static int
3208 do_assignment_internal (word, expand)
3209 const WORD_DESC *word;
3210 int expand;
3211 {
3212 int offset, appendop, assign_list, aflags, retval;
3213 char *name, *value, *temp;
3214 SHELL_VAR *entry;
3215 #if defined (ARRAY_VARS)
3216 char *t;
3217 int ni;
3218 #endif
3219 const char *string;
3220
3221 if (word == 0 || word->word == 0)
3222 return 0;
3223
3224 appendop = assign_list = aflags = 0;
3225 string = word->word;
3226 offset = assignment (string, 0);
3227 name = savestring (string);
3228 value = (char *)NULL;
3229
3230 if (name[offset] == '=')
3231 {
3232 if (name[offset - 1] == '+')
3233 {
3234 appendop = 1;
3235 name[offset - 1] = '\0';
3236 }
3237
3238 name[offset] = 0; /* might need this set later */
3239 temp = name + offset + 1;
3240
3241 #if defined (ARRAY_VARS)
3242 if (expand && (word->flags & W_COMPASSIGN))
3243 {
3244 assign_list = ni = 1;
3245 value = extract_array_assignment_list (temp, &ni);
3246 }
3247 else
3248 #endif
3249 if (expand && temp[0])
3250 value = expand_string_if_necessary (temp, 0, expand_string_assignment);
3251 else
3252 value = savestring (temp);
3253 }
3254
3255 if (value == 0)
3256 {
3257 value = (char *)xmalloc (1);
3258 value[0] = '\0';
3259 }
3260
3261 if (echo_command_at_execute)
3262 {
3263 if (appendop)
3264 name[offset - 1] = '+';
3265 xtrace_print_assignment (name, value, assign_list, 1);
3266 if (appendop)
3267 name[offset - 1] = '\0';
3268 }
3269
3270 #define ASSIGN_RETURN(r) do { FREE (value); free (name); return (r); } while (0)
3271
3272 if (appendop)
3273 aflags |= ASS_APPEND;
3274
3275 #if defined (ARRAY_VARS)
3276 if (t = mbschr (name, LBRACK))
3277 {
3278 if (assign_list)
3279 {
3280 report_error (_("%s: cannot assign list to array member"), name);
3281 ASSIGN_RETURN (0);
3282 }
3283 entry = assign_array_element (name, value, aflags);
3284 if (entry == 0)
3285 ASSIGN_RETURN (0);
3286 }
3287 else if (assign_list)
3288 {
3289 if ((word->flags & W_ASSIGNARG) && (word->flags & W_CHKLOCAL))
3290 aflags |= ASS_CHKLOCAL;
3291 if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0)
3292 aflags |= ASS_MKLOCAL;
3293 if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL))
3294 aflags |= ASS_MKGLOBAL;
3295 if (word->flags & W_ASSIGNASSOC)
3296 aflags |= ASS_MKASSOC;
3297 entry = do_compound_assignment (name, value, aflags);
3298 }
3299 else
3300 #endif /* ARRAY_VARS */
3301 entry = bind_variable (name, value, aflags);
3302
3303 stupidly_hack_special_variables (name);
3304
3305 /* Return 1 if the assignment seems to have been performed correctly. */
3306 if (entry == 0 || readonly_p (entry))
3307 retval = 0; /* assignment failure */
3308 else if (noassign_p (entry))
3309 {
3310 set_exit_status (EXECUTION_FAILURE);
3311 retval = 1; /* error status, but not assignment failure */
3312 }
3313 else
3314 retval = 1;
3315
3316 if (entry && retval != 0 && noassign_p (entry) == 0)
3317 VUNSETATTR (entry, att_invisible);
3318
3319 ASSIGN_RETURN (retval);
3320 }
3321
3322 /* Perform the assignment statement in STRING, and expand the
3323 right side by doing tilde, command and parameter expansion. */
3324 int
3325 do_assignment (string)
3326 char *string;
3327 {
3328 WORD_DESC td;
3329
3330 td.flags = W_ASSIGNMENT;
3331 td.word = string;
3332
3333 return do_assignment_internal (&td, 1);
3334 }
3335
3336 int
3337 do_word_assignment (word, flags)
3338 WORD_DESC *word;
3339 int flags;
3340 {
3341 return do_assignment_internal (word, 1);
3342 }
3343
3344 /* Given STRING, an assignment string, get the value of the right side
3345 of the `=', and bind it to the left side. Do not perform any word
3346 expansions on the right hand side. */
3347 int
3348 do_assignment_no_expand (string)
3349 char *string;
3350 {
3351 WORD_DESC td;
3352
3353 td.flags = W_ASSIGNMENT;
3354 td.word = string;
3355
3356 return (do_assignment_internal (&td, 0));
3357 }
3358
3359 /***************************************************
3360 * *
3361 * Functions to manage the positional parameters *
3362 * *
3363 ***************************************************/
3364
3365 /* Return the word list that corresponds to `$*'. */
3366 WORD_LIST *
3367 list_rest_of_args ()
3368 {
3369 register WORD_LIST *list, *args;
3370 int i;
3371
3372 /* Break out of the loop as soon as one of the dollar variables is null. */
3373 for (i = 1, list = (WORD_LIST *)NULL; i < 10 && dollar_vars[i]; i++)
3374 list = make_word_list (make_bare_word (dollar_vars[i]), list);
3375
3376 for (args = rest_of_args; args; args = args->next)
3377 list = make_word_list (make_bare_word (args->word->word), list);
3378
3379 return (REVERSE_LIST (list, WORD_LIST *));
3380 }
3381
3382 /* Return the value of a positional parameter. This handles values > 10. */
3383 char *
3384 get_dollar_var_value (ind)
3385 intmax_t ind;
3386 {
3387 char *temp;
3388 WORD_LIST *p;
3389
3390 if (ind < 10)
3391 temp = dollar_vars[ind] ? savestring (dollar_vars[ind]) : (char *)NULL;
3392 else /* We want something like ${11} */
3393 {
3394 ind -= 10;
3395 for (p = rest_of_args; p && ind--; p = p->next)
3396 ;
3397 temp = p ? savestring (p->word->word) : (char *)NULL;
3398 }
3399 return (temp);
3400 }
3401
3402 /* Make a single large string out of the dollar digit variables,
3403 and the rest_of_args. If DOLLAR_STAR is 1, then obey the special
3404 case of "$*" with respect to IFS. */
3405 char *
3406 string_rest_of_args (dollar_star)
3407 int dollar_star;
3408 {
3409 register WORD_LIST *list;
3410 char *string;
3411
3412 list = list_rest_of_args ();
3413 string = dollar_star ? string_list_dollar_star (list, 0, 0) : string_list (list);
3414 dispose_words (list);
3415 return (string);
3416 }
3417
3418 /* Return a string containing the positional parameters from START to
3419 END, inclusive. If STRING[0] == '*', we obey the rules for $*,
3420 which only makes a difference if QUOTED is non-zero. If QUOTED includes
3421 Q_HERE_DOCUMENT or Q_DOUBLE_QUOTES, this returns a quoted list, otherwise
3422 no quoting chars are added. */
3423 static char *
3424 pos_params (string, start, end, quoted, pflags)
3425 char *string;
3426 int start, end, quoted, pflags;
3427 {
3428 WORD_LIST *save, *params, *h, *t;
3429 char *ret;
3430 int i;
3431
3432 /* see if we can short-circuit. if start == end, we want 0 parameters. */
3433 if (start == end)
3434 return ((char *)NULL);
3435
3436 save = params = list_rest_of_args ();
3437 if (save == 0 && start > 0)
3438 return ((char *)NULL);
3439
3440 if (start == 0) /* handle ${@:0[:x]} specially */
3441 {
3442 t = make_word_list (make_word (dollar_vars[0]), params);
3443 save = params = t;
3444 }
3445
3446 for (i = start ? 1 : 0; params && i < start; i++)
3447 params = params->next;
3448 if (params == 0)
3449 {
3450 dispose_words (save);
3451 return ((char *)NULL);
3452 }
3453 for (h = t = params; params && i < end; i++)
3454 {
3455 t = params;
3456 params = params->next;
3457 }
3458 t->next = (WORD_LIST *)NULL;
3459
3460 ret = string_list_pos_params (string[0], h, quoted, pflags);
3461
3462 if (t != params)
3463 t->next = params;
3464
3465 dispose_words (save);
3466 return (ret);
3467 }
3468
3469 /******************************************************************/
3470 /* */
3471 /* Functions to expand strings to strings or WORD_LISTs */
3472 /* */
3473 /******************************************************************/
3474
3475 #if defined (PROCESS_SUBSTITUTION)
3476 #define EXP_CHAR(s) (s == '$' || s == '`' || s == '<' || s == '>' || s == CTLESC || s == '~')
3477 #else
3478 #define EXP_CHAR(s) (s == '$' || s == '`' || s == CTLESC || s == '~')
3479 #endif
3480
3481 /* If there are any characters in STRING that require full expansion,
3482 then call FUNC to expand STRING; otherwise just perform quote
3483 removal if necessary. This returns a new string. */
3484 static char *
3485 expand_string_if_necessary (string, quoted, func)
3486 char *string;
3487 int quoted;
3488 EXPFUNC *func;
3489 {
3490 WORD_LIST *list;
3491 size_t slen;
3492 int i, saw_quote;
3493 char *ret;
3494 DECLARE_MBSTATE;
3495
3496 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3497 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
3498 i = saw_quote = 0;
3499 while (string[i])
3500 {
3501 if (EXP_CHAR (string[i]))
3502 break;
3503 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3504 saw_quote = 1;
3505 ADVANCE_CHAR (string, slen, i);
3506 }
3507
3508 if (string[i])
3509 {
3510 list = (*func) (string, quoted);
3511 if (list)
3512 {
3513 ret = string_list (list);
3514 dispose_words (list);
3515 }
3516 else
3517 ret = (char *)NULL;
3518 }
3519 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3520 ret = string_quote_removal (string, quoted);
3521 else
3522 ret = savestring (string);
3523
3524 return ret;
3525 }
3526
3527 static inline char *
3528 expand_string_to_string_internal (string, quoted, func)
3529 char *string;
3530 int quoted;
3531 EXPFUNC *func;
3532 {
3533 WORD_LIST *list;
3534 char *ret;
3535
3536 if (string == 0 || *string == '\0')
3537 return ((char *)NULL);
3538
3539 list = (*func) (string, quoted);
3540 if (list)
3541 {
3542 ret = string_list (list);
3543 dispose_words (list);
3544 }
3545 else
3546 ret = (char *)NULL;
3547
3548 return (ret);
3549 }
3550
3551 char *
3552 expand_string_to_string (string, quoted)
3553 char *string;
3554 int quoted;
3555 {
3556 return (expand_string_to_string_internal (string, quoted, expand_string));
3557 }
3558
3559 char *
3560 expand_string_unsplit_to_string (string, quoted)
3561 char *string;
3562 int quoted;
3563 {
3564 return (expand_string_to_string_internal (string, quoted, expand_string_unsplit));
3565 }
3566
3567 char *
3568 expand_assignment_string_to_string (string, quoted)
3569 char *string;
3570 int quoted;
3571 {
3572 return (expand_string_to_string_internal (string, quoted, expand_string_assignment));
3573 }
3574
3575 char *
3576 expand_arith_string (string, quoted)
3577 char *string;
3578 int quoted;
3579 {
3580 WORD_DESC td;
3581 WORD_LIST *list, *tlist;
3582 size_t slen;
3583 int i, saw_quote;
3584 char *ret;
3585 DECLARE_MBSTATE;
3586
3587 /* Don't need string length for ADVANCE_CHAR unless multibyte chars possible. */
3588 slen = (MB_CUR_MAX > 1) ? strlen (string) : 0;
3589 i = saw_quote = 0;
3590 while (string[i])
3591 {
3592 if (EXP_CHAR (string[i]))
3593 break;
3594 else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
3595 saw_quote = 1;
3596 ADVANCE_CHAR (string, slen, i);
3597 }
3598
3599 if (string[i])
3600 {
3601 /* This is expanded version of expand_string_internal as it's called by
3602 expand_string_leave_quoted */
3603 td.flags = W_NOPROCSUB|W_NOTILDE; /* don't want process substitution or tilde expansion */
3604 #if 0 /* TAG:bash-5.1 */
3605 if (quoted & Q_ARRAYSUB)
3606 td.flags |= W_NOCOMSUB;
3607 #endif
3608 td.word = savestring (string);
3609 list = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3610 /* This takes care of the calls from expand_string_leave_quoted and
3611 expand_string */
3612 if (list)
3613 {
3614 tlist = word_list_split (list);
3615 dispose_words (list);
3616 list = tlist;
3617 if (list)
3618 dequote_list (list);
3619 }
3620 /* This comes from expand_string_if_necessary */
3621 if (list)
3622 {
3623 ret = string_list (list);
3624 dispose_words (list);
3625 }
3626 else
3627 ret = (char *)NULL;
3628 FREE (td.word);
3629 }
3630 else if (saw_quote && (quoted & Q_ARITH))
3631 ret = string_quote_removal (string, quoted);
3632 else if (saw_quote && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
3633 ret = string_quote_removal (string, quoted);
3634 else
3635 ret = savestring (string);
3636
3637 return ret;
3638 }
3639
3640 #if defined (COND_COMMAND)
3641 /* Just remove backslashes in STRING. Returns a new string. */
3642 char *
3643 remove_backslashes (string)
3644 char *string;
3645 {
3646 char *r, *ret, *s;
3647
3648 r = ret = (char *)xmalloc (strlen (string) + 1);
3649 for (s = string; s && *s; )
3650 {
3651 if (*s == '\\')
3652 s++;
3653 if (*s == 0)
3654 break;
3655 *r++ = *s++;
3656 }
3657 *r = '\0';
3658 return ret;
3659 }
3660
3661 /* This needs better error handling. */
3662 /* Expand W for use as an argument to a unary or binary operator in a
3663 [[...]] expression. If SPECIAL is 1, this is the rhs argument
3664 to the != or == operator, and should be treated as a pattern. In
3665 this case, we quote the string specially for the globbing code. If
3666 SPECIAL is 2, this is an rhs argument for the =~ operator, and should
3667 be quoted appropriately for regcomp/regexec. The caller is responsible
3668 for removing the backslashes if the unquoted word is needed later. In
3669 any case, since we don't perform word splitting, we need to do quoted
3670 null character removal. */
3671 char *
3672 cond_expand_word (w, special)
3673 WORD_DESC *w;
3674 int special;
3675 {
3676 char *r, *p;
3677 WORD_LIST *l;
3678 int qflags;
3679
3680 if (w->word == 0 || w->word[0] == '\0')
3681 return ((char *)NULL);
3682
3683 expand_no_split_dollar_star = 1;
3684 w->flags |= W_NOSPLIT2;
3685 l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
3686 expand_no_split_dollar_star = 0;
3687 if (l)
3688 {
3689 if (special == 0) /* LHS */
3690 {
3691 if (l->word)
3692 word_list_remove_quoted_nulls (l);
3693 dequote_list (l);
3694 r = string_list (l);
3695 }
3696 else
3697 {
3698 /* Need to figure out whether or not we should call dequote_escapes
3699 or a new dequote_ctlnul function here, and under what
3700 circumstances. */
3701 qflags = QGLOB_CVTNULL|QGLOB_CTLESC;
3702 if (special == 2)
3703 qflags |= QGLOB_REGEXP;
3704 word_list_remove_quoted_nulls (l);
3705 p = string_list (l);
3706 r = quote_string_for_globbing (p, qflags);
3707 free (p);
3708 }
3709 dispose_words (l);
3710 }
3711 else
3712 r = (char *)NULL;
3713
3714 return r;
3715 }
3716 #endif
3717
3718 /* Call expand_word_internal to expand W and handle error returns.
3719 A convenience function for functions that don't want to handle
3720 any errors or free any memory before aborting. */
3721 static WORD_LIST *
3722 call_expand_word_internal (w, q, i, c, e)
3723 WORD_DESC *w;
3724 int q, i, *c, *e;
3725 {
3726 WORD_LIST *result;
3727
3728 result = expand_word_internal (w, q, i, c, e);
3729 if (result == &expand_word_error || result == &expand_word_fatal)
3730 {
3731 /* By convention, each time this error is returned, w->word has
3732 already been freed (it sometimes may not be in the fatal case,
3733 but that doesn't result in a memory leak because we're going
3734 to exit in most cases). */
3735 w->word = (char *)NULL;
3736 last_command_exit_value = EXECUTION_FAILURE;
3737 exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
3738 /* NOTREACHED */
3739 return (NULL);
3740 }
3741 else
3742 return (result);
3743 }
3744
3745 /* Perform parameter expansion, command substitution, and arithmetic
3746 expansion on STRING, as if it were a word. Leave the result quoted.
3747 Since this does not perform word splitting, it leaves quoted nulls
3748 in the result. */
3749 static WORD_LIST *
3750 expand_string_internal (string, quoted)
3751 char *string;
3752 int quoted;
3753 {
3754 WORD_DESC td;
3755 WORD_LIST *tresult;
3756
3757 if (string == 0 || *string == 0)
3758 return ((WORD_LIST *)NULL);
3759
3760 td.flags = 0;
3761 td.word = savestring (string);
3762
3763 tresult = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3764
3765 FREE (td.word);
3766 return (tresult);
3767 }
3768
3769 /* Expand STRING by performing parameter expansion, command substitution,
3770 and arithmetic expansion. Dequote the resulting WORD_LIST before
3771 returning it, but do not perform word splitting. The call to
3772 remove_quoted_nulls () is in here because word splitting normally
3773 takes care of quote removal. */
3774 WORD_LIST *
3775 expand_string_unsplit (string, quoted)
3776 char *string;
3777 int quoted;
3778 {
3779 WORD_LIST *value;
3780
3781 if (string == 0 || *string == '\0')
3782 return ((WORD_LIST *)NULL);
3783
3784 expand_no_split_dollar_star = 1;
3785 value = expand_string_internal (string, quoted);
3786 expand_no_split_dollar_star = 0;
3787
3788 if (value)
3789 {
3790 if (value->word)
3791 {
3792 remove_quoted_nulls (value->word->word); /* XXX */
3793 value->word->flags &= ~W_HASQUOTEDNULL;
3794 }
3795 dequote_list (value);
3796 }
3797 return (value);
3798 }
3799
3800 /* Expand the rhs of an assignment statement */
3801 WORD_LIST *
3802 expand_string_assignment (string, quoted)
3803 char *string;
3804 int quoted;
3805 {
3806 WORD_DESC td;
3807 WORD_LIST *value;
3808
3809 if (string == 0 || *string == '\0')
3810 return ((WORD_LIST *)NULL);
3811
3812 expand_no_split_dollar_star = 1;
3813
3814 #if 0
3815 /* Other shells (ksh93) do it this way, which affects how $@ is expanded
3816 in constructs like bar=${@#0} (preserves the spaces resulting from the
3817 expansion of $@ in a context where you don't do word splitting); Posix
3818 interp 888 makes the expansion of $@ in contexts where word splitting
3819 is not performed unspecified. */
3820 td.flags = W_ASSIGNRHS|W_NOSPLIT2; /* Posix interp 888 */
3821 #else
3822 td.flags = W_ASSIGNRHS;
3823 #endif
3824 td.word = savestring (string);
3825 value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3826 FREE (td.word);
3827
3828 expand_no_split_dollar_star = 0;
3829
3830 if (value)
3831 {
3832 if (value->word)
3833 {
3834 remove_quoted_nulls (value->word->word); /* XXX */
3835 value->word->flags &= ~W_HASQUOTEDNULL;
3836 }
3837 dequote_list (value);
3838 }
3839 return (value);
3840 }
3841
3842
3843 /* Expand one of the PS? prompt strings. This is a sort of combination of
3844 expand_string_unsplit and expand_string_internal, but returns the
3845 passed string when an error occurs. Might want to trap other calls
3846 to jump_to_top_level here so we don't endlessly loop. */
3847 WORD_LIST *
3848 expand_prompt_string (string, quoted, wflags)
3849 char *string;
3850 int quoted;
3851 int wflags;
3852 {
3853 WORD_LIST *value;
3854 WORD_DESC td;
3855
3856 if (string == 0 || *string == 0)
3857 return ((WORD_LIST *)NULL);
3858
3859 td.flags = wflags;
3860 td.word = savestring (string);
3861
3862 no_longjmp_on_fatal_error = 1;
3863 value = expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
3864 no_longjmp_on_fatal_error = 0;
3865
3866 if (value == &expand_word_error || value == &expand_word_fatal)
3867 {
3868 value = make_word_list (make_bare_word (string), (WORD_LIST *)NULL);
3869 return value;
3870 }
3871 FREE (td.word);
3872 if (value)
3873 {
3874 if (value->word)
3875 {
3876 remove_quoted_nulls (value->word->word); /* XXX */
3877 value->word->flags &= ~W_HASQUOTEDNULL;
3878 }
3879 dequote_list (value);
3880 }
3881 return (value);
3882 }
3883
3884 /* Expand STRING just as if you were expanding a word, but do not dequote
3885 the resultant WORD_LIST. This is called only from within this file,
3886 and is used to correctly preserve quoted characters when expanding
3887 things like ${1+"$@"}. This does parameter expansion, command
3888 substitution, arithmetic expansion, and word splitting. */
3889 static WORD_LIST *
3890 expand_string_leave_quoted (string, quoted)
3891 char *string;
3892 int quoted;
3893 {
3894 WORD_LIST *tlist;
3895 WORD_LIST *tresult;
3896
3897 if (string == 0 || *string == '\0')
3898 return ((WORD_LIST *)NULL);
3899
3900 tlist = expand_string_internal (string, quoted);
3901
3902 if (tlist)
3903 {
3904 tresult = word_list_split (tlist);
3905 dispose_words (tlist);
3906 return (tresult);
3907 }
3908 return ((WORD_LIST *)NULL);
3909 }
3910
3911 /* This does not perform word splitting or dequote the WORD_LIST
3912 it returns. */
3913 static WORD_LIST *
3914 expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p)
3915 char *string;
3916 int quoted, op, pflags;
3917 int *dollar_at_p, *expanded_p;
3918 {
3919 WORD_DESC td;
3920 WORD_LIST *tresult;
3921 int old_nosplit;
3922
3923 if (string == 0 || *string == '\0')
3924 return (WORD_LIST *)NULL;
3925
3926 /* We want field splitting to be determined by what is going to be done with
3927 the entire ${parameterOPword} expansion, so we don't want to split the RHS
3928 we expand here. However, the expansion of $* is determined by whether we
3929 are going to eventually perform word splitting, so we want to set this
3930 depending on whether or not are are going to be splitting: if the expansion
3931 is quoted, if the OP is `=', or if IFS is set to the empty string, we
3932 are not going to be splitting, so we set expand_no_split_dollar_star to
3933 note this to callees.
3934 We pass through PF_ASSIGNRHS as W_ASSIGNRHS if this is on the RHS of an
3935 assignment statement. */
3936 /* The updated treatment of $* is the result of Posix interp 888 */
3937 /* This was further clarified on the austin-group list in March, 2017 and
3938 in Posix bug 1129 */
3939 old_nosplit = expand_no_split_dollar_star;
3940 expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */
3941 td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword} */
3942 td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */
3943 if (pflags & PF_ASSIGNRHS) /* pass through */
3944 td.flags |= W_ASSIGNRHS;
3945 if (op == '=')
3946 #if 0
3947 td.flags |= W_ASSIGNRHS; /* expand b in ${a=b} like assignment */
3948 #else
3949 td.flags |= W_ASSIGNRHS|W_NOASSNTILDE; /* expand b in ${a=b} like assignment */
3950 #endif
3951 td.word = string;
3952 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
3953 expand_no_split_dollar_star = old_nosplit;
3954
3955 return (tresult);
3956 }
3957
3958 /* This does not perform word splitting or dequote the WORD_LIST
3959 it returns and it treats $* as if it were quoted. */
3960 static WORD_LIST *
3961 expand_string_for_pat (string, quoted, dollar_at_p, expanded_p)
3962 char *string;
3963 int quoted, *dollar_at_p, *expanded_p;
3964 {
3965 WORD_DESC td;
3966 WORD_LIST *tresult;
3967 int oexp;
3968
3969 if (string == 0 || *string == '\0')
3970 return (WORD_LIST *)NULL;
3971
3972 oexp = expand_no_split_dollar_star;
3973 expand_no_split_dollar_star = 1;
3974 td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */
3975 td.word = string;
3976 tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p);
3977 expand_no_split_dollar_star = oexp;
3978
3979 return (tresult);
3980 }
3981
3982 /* Expand STRING just as if you were expanding a word. This also returns
3983 a list of words. Note that filename globbing is *NOT* done for word
3984 or string expansion, just when the shell is expanding a command. This
3985 does parameter expansion, command substitution, arithmetic expansion,
3986 and word splitting. Dequote the resultant WORD_LIST before returning. */
3987 WORD_LIST *
3988 expand_string (string, quoted)
3989 char *string;
3990 int quoted;
3991 {
3992 WORD_LIST *result;
3993
3994 if (string == 0 || *string == '\0')
3995 return ((WORD_LIST *)NULL);
3996
3997 result = expand_string_leave_quoted (string, quoted);
3998 return (result ? dequote_list (result) : result);
3999 }
4000
4001 /*******************************************
4002 * *
4003 * Functions to expand WORD_DESCs *
4004 * *
4005 *******************************************/
4006
4007 /* Expand WORD, performing word splitting on the result. This does
4008 parameter expansion, command substitution, arithmetic expansion,
4009 word splitting, and quote removal. */
4010
4011 WORD_LIST *
4012 expand_word (word, quoted)
4013 WORD_DESC *word;
4014 int quoted;
4015 {
4016 WORD_LIST *result, *tresult;
4017
4018 tresult = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4019 result = word_list_split (tresult);
4020 dispose_words (tresult);
4021 return (result ? dequote_list (result) : result);
4022 }
4023
4024 /* Expand WORD, but do not perform word splitting on the result. This
4025 does parameter expansion, command substitution, arithmetic expansion,
4026 and quote removal. */
4027 WORD_LIST *
4028 expand_word_unsplit (word, quoted)
4029 WORD_DESC *word;
4030 int quoted;
4031 {
4032 WORD_LIST *result;
4033
4034 result = expand_word_leave_quoted (word, quoted);
4035 return (result ? dequote_list (result) : result);
4036 }
4037
4038 /* Perform shell expansions on WORD, but do not perform word splitting or
4039 quote removal on the result. Virtually identical to expand_word_unsplit;
4040 could be combined if implementations don't diverge. */
4041 WORD_LIST *
4042 expand_word_leave_quoted (word, quoted)
4043 WORD_DESC *word;
4044 int quoted;
4045 {
4046 WORD_LIST *result;
4047
4048 expand_no_split_dollar_star = 1;
4049 if (ifs_is_null)
4050 word->flags |= W_NOSPLIT;
4051 word->flags |= W_NOSPLIT2;
4052 result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL);
4053 expand_no_split_dollar_star = 0;
4054
4055 return result;
4056 }
4057
4058 /***************************************************
4059 * *
4060 * Functions to handle quoting chars *
4061 * *
4062 ***************************************************/
4063
4064 /* Conventions:
4065
4066 A string with s[0] == CTLNUL && s[1] == 0 is a quoted null string.
4067 The parser passes CTLNUL as CTLESC CTLNUL. */
4068
4069 /* Quote escape characters in string s, but no other characters. This is
4070 used to protect CTLESC and CTLNUL in variable values from the rest of
4071 the word expansion process after the variable is expanded (word splitting
4072 and filename generation). If IFS is null, we quote spaces as well, just
4073 in case we split on spaces later (in the case of unquoted $@, we will
4074 eventually attempt to split the entire word on spaces). Corresponding
4075 code exists in dequote_escapes. Even if we don't end up splitting on
4076 spaces, quoting spaces is not a problem. This should never be called on
4077 a string that is quoted with single or double quotes or part of a here
4078 document (effectively double-quoted).
4079 FLAGS says whether or not we are going to split the result. If we are not,
4080 and there is a CTLESC or CTLNUL in IFS, we need to quote CTLESC and CTLNUL,
4081 respectively, to prevent them from being removed as part of dequoting. */
4082 static char *
4083 quote_escapes_internal (string, flags)
4084 const char *string;
4085 int flags;
4086 {
4087 const char *s, *send;
4088 char *t, *result;
4089 size_t slen;
4090 int quote_spaces, skip_ctlesc, skip_ctlnul, nosplit;
4091 DECLARE_MBSTATE;
4092
4093 slen = strlen (string);
4094 send = string + slen;
4095
4096 quote_spaces = (ifs_value && *ifs_value == 0);
4097 nosplit = (flags & PF_NOSPLIT2);
4098
4099 for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
4100 {
4101 skip_ctlesc |= (nosplit == 0 && *s == CTLESC);
4102 skip_ctlnul |= (nosplit == 0 && *s == CTLNUL);
4103 }
4104
4105 t = result = (char *)xmalloc ((slen * 2) + 1);
4106 s = string;
4107
4108 while (*s)
4109 {
4110 if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
4111 *t++ = CTLESC;
4112 COPY_CHAR_P (t, s, send);
4113 }
4114 *t = '\0';
4115
4116 return (result);
4117 }
4118
4119 char *
4120 quote_escapes (string)
4121 const char *string;
4122 {
4123 return (quote_escapes_internal (string, 0));
4124 }
4125
4126 char *
4127 quote_rhs (string)
4128 const char *string;
4129 {
4130 return (quote_escapes_internal (string, PF_NOSPLIT2));
4131 }
4132
4133 static WORD_LIST *
4134 list_quote_escapes (list)
4135 WORD_LIST *list;
4136 {
4137 register WORD_LIST *w;
4138 char *t;
4139
4140 for (w = list; w; w = w->next)
4141 {
4142 t = w->word->word;
4143 w->word->word = quote_escapes (t);
4144 free (t);
4145 }
4146 return list;
4147 }
4148
4149 /* Inverse of quote_escapes; remove CTLESC protecting CTLESC or CTLNUL.
4150
4151 The parser passes us CTLESC as CTLESC CTLESC and CTLNUL as CTLESC CTLNUL.
4152 This is necessary to make unquoted CTLESC and CTLNUL characters in the
4153 data stream pass through properly.
4154
4155 We need to remove doubled CTLESC characters inside quoted strings before
4156 quoting the entire string, so we do not double the number of CTLESC
4157 characters.
4158
4159 Also used by parts of the pattern substitution code. */
4160 char *
4161 dequote_escapes (string)
4162 const char *string;
4163 {
4164 const char *s, *send;
4165 char *t, *result;
4166 size_t slen;
4167 int quote_spaces;
4168 DECLARE_MBSTATE;
4169
4170 if (string == 0)
4171 return (char *)0;
4172
4173 slen = strlen (string);
4174 send = string + slen;
4175
4176 t = result = (char *)xmalloc (slen + 1);
4177
4178 if (strchr (string, CTLESC) == 0)
4179 return (strcpy (result, string));
4180
4181 quote_spaces = (ifs_value && *ifs_value == 0);
4182
4183 s = string;
4184 while (*s)
4185 {
4186 if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
4187 {
4188 s++;
4189 if (*s == '\0')
4190 break;
4191 }
4192 COPY_CHAR_P (t, s, send);
4193 }
4194 *t = '\0';
4195
4196 return result;
4197 }
4198
4199 #if defined (INCLUDE_UNUSED)
4200 static WORD_LIST *
4201 list_dequote_escapes (list)
4202 WORD_LIST *list;
4203 {
4204 register WORD_LIST *w;
4205 char *t;
4206
4207 for (w = list; w; w = w->next)
4208 {
4209 t = w->word->word;
4210 w->word->word = dequote_escapes (t);
4211 free (t);
4212 }
4213 return list;
4214 }
4215 #endif
4216
4217 /* Return a new string with the quoted representation of character C.
4218 This turns "" into QUOTED_NULL, so the W_HASQUOTEDNULL flag needs to be
4219 set in any resultant WORD_DESC where this value is the word. */
4220 static char *
4221 make_quoted_char (c)
4222 int c;
4223 {
4224 char *temp;
4225
4226 temp = (char *)xmalloc (3);
4227 if (c == 0)
4228 {
4229 temp[0] = CTLNUL;
4230 temp[1] = '\0';
4231 }
4232 else
4233 {
4234 temp[0] = CTLESC;
4235 temp[1] = c;
4236 temp[2] = '\0';
4237 }
4238 return (temp);
4239 }
4240
4241 /* Quote STRING, returning a new string. This turns "" into QUOTED_NULL, so
4242 the W_HASQUOTEDNULL flag needs to be set in any resultant WORD_DESC where
4243 this value is the word. */
4244 char *
4245 quote_string (string)
4246 char *string;
4247 {
4248 register char *t;
4249 size_t slen;
4250 char *result, *send;
4251
4252 if (*string == 0)
4253 {
4254 result = (char *)xmalloc (2);
4255 result[0] = CTLNUL;
4256 result[1] = '\0';
4257 }
4258 else
4259 {
4260 DECLARE_MBSTATE;
4261
4262 slen = strlen (string);
4263 send = string + slen;
4264
4265 result = (char *)xmalloc ((slen * 2) + 1);
4266
4267 for (t = result; string < send; )
4268 {
4269 *t++ = CTLESC;
4270 COPY_CHAR_P (t, string, send);
4271 }
4272 *t = '\0';
4273 }
4274 return (result);
4275 }
4276
4277 /* De-quote quoted characters in STRING. */
4278 char *
4279 dequote_string (string)
4280 char *string;
4281 {
4282 register char *s, *t;
4283 size_t slen;
4284 char *result, *send;
4285 DECLARE_MBSTATE;
4286
4287 #if defined (DEBUG)
4288 if (string[0] == CTLESC && string[1] == 0)
4289 internal_inform ("dequote_string: string with bare CTLESC");
4290 #endif
4291
4292 slen = STRLEN (string);
4293
4294 t = result = (char *)xmalloc (slen + 1);
4295
4296 if (QUOTED_NULL (string))
4297 {
4298 result[0] = '\0';
4299 return (result);
4300 }
4301
4302 /* A string consisting of only a single CTLESC should pass through unchanged */
4303 if (string[0] == CTLESC && string[1] == 0)
4304 {
4305 result[0] = CTLESC;
4306 result[1] = '\0';
4307 return (result);
4308 }
4309
4310 /* If no character in the string can be quoted, don't bother examining
4311 each character. Just return a copy of the string passed to us. */
4312 if (strchr (string, CTLESC) == NULL)
4313 return (strcpy (result, string));
4314
4315 send = string + slen;
4316 s = string;
4317 while (*s)
4318 {
4319 if (*s == CTLESC)
4320 {
4321 s++;
4322 if (*s == '\0')
4323 break;
4324 }
4325 COPY_CHAR_P (t, s, send);
4326 }
4327
4328 *t = '\0';
4329 return (result);
4330 }
4331
4332 /* Quote the entire WORD_LIST list. */
4333 static WORD_LIST *
4334 quote_list (list)
4335 WORD_LIST *list;
4336 {
4337 register WORD_LIST *w;
4338 char *t;
4339
4340 for (w = list; w; w = w->next)
4341 {
4342 t = w->word->word;
4343 w->word->word = quote_string (t);
4344 if (*t == 0)
4345 w->word->flags |= W_HASQUOTEDNULL; /* XXX - turn on W_HASQUOTEDNULL here? */
4346 w->word->flags |= W_QUOTED;
4347 free (t);
4348 }
4349 return list;
4350 }
4351
4352 WORD_DESC *
4353 dequote_word (word)
4354 WORD_DESC *word;
4355 {
4356 register char *s;
4357
4358 s = dequote_string (word->word);
4359 if (QUOTED_NULL (word->word))
4360 word->flags &= ~W_HASQUOTEDNULL;
4361 free (word->word);
4362 word->word = s;
4363
4364 return word;
4365 }
4366
4367 /* De-quote quoted characters in each word in LIST. */
4368 WORD_LIST *
4369 dequote_list (list)
4370 WORD_LIST *list;
4371 {
4372 register char *s;
4373 register WORD_LIST *tlist;
4374
4375 for (tlist = list; tlist; tlist = tlist->next)
4376 {
4377 s = dequote_string (tlist->word->word);
4378 if (QUOTED_NULL (tlist->word->word))
4379 tlist->word->flags &= ~W_HASQUOTEDNULL;
4380 free (tlist->word->word);
4381 tlist->word->word = s;
4382 }
4383 return list;
4384 }
4385
4386 /* Remove CTLESC protecting a CTLESC or CTLNUL in place. Return the passed
4387 string. */
4388 char *
4389 remove_quoted_escapes (string)
4390 char *string;
4391 {
4392 char *t;
4393
4394 if (string)
4395 {
4396 t = dequote_escapes (string);
4397 strcpy (string, t);
4398 free (t);
4399 }
4400
4401 return (string);
4402 }
4403
4404 /* Remove quoted $IFS characters from STRING. Quoted IFS characters are
4405 added to protect them from word splitting, but we need to remove them
4406 if no word splitting takes place. This returns newly-allocated memory,
4407 so callers can use it to replace savestring(). */
4408 char *
4409 remove_quoted_ifs (string)
4410 char *string;
4411 {
4412 register size_t slen;
4413 register int i, j;
4414 char *ret, *send;
4415 DECLARE_MBSTATE;
4416
4417 slen = strlen (string);
4418 send = string + slen;
4419
4420 i = j = 0;
4421 ret = (char *)xmalloc (slen + 1);
4422
4423 while (i < slen)
4424 {
4425 if (string[i] == CTLESC)
4426 {
4427 i++;
4428 if (string[i] == 0 || isifs (string[i]) == 0)
4429 ret[j++] = CTLESC;
4430 if (i == slen)
4431 break;
4432 }
4433
4434 COPY_CHAR_I (ret, j, string, send, i);
4435 }
4436 ret[j] = '\0';
4437
4438 return (ret);
4439 }
4440
4441 char *
4442 remove_quoted_nulls (string)
4443 char *string;
4444 {
4445 register size_t slen;
4446 register int i, j, prev_i;
4447 DECLARE_MBSTATE;
4448
4449 if (strchr (string, CTLNUL) == 0) /* XXX */
4450 return string; /* XXX */
4451
4452 slen = strlen (string);
4453 i = j = 0;
4454
4455 while (i < slen)
4456 {
4457 if (string[i] == CTLESC)
4458 {
4459 /* Old code had j++, but we cannot assume that i == j at this
4460 point -- what if a CTLNUL has already been removed from the
4461 string? We don't want to drop the CTLESC or recopy characters
4462 that we've already copied down. */
4463 i++;
4464 string[j++] = CTLESC;
4465 if (i == slen)
4466 break;
4467 }
4468 else if (string[i] == CTLNUL)
4469 {
4470 i++;
4471 continue;
4472 }
4473
4474 prev_i = i;
4475 ADVANCE_CHAR (string, slen, i); /* COPY_CHAR_I? */
4476 if (j < prev_i)
4477 {
4478 do string[j++] = string[prev_i++]; while (prev_i < i);
4479 }
4480 else
4481 j = i;
4482 }
4483 string[j] = '\0';
4484
4485 return (string);
4486 }
4487
4488 /* Perform quoted null character removal on each element of LIST.
4489 This modifies LIST. */
4490 void
4491 word_list_remove_quoted_nulls (list)
4492 WORD_LIST *list;
4493 {
4494 register WORD_LIST *t;
4495
4496 for (t = list; t; t = t->next)
4497 {
4498 remove_quoted_nulls (t->word->word);
4499 t->word->flags &= ~W_HASQUOTEDNULL;
4500 }
4501 }
4502
4503 /* **************************************************************** */
4504 /* */
4505 /* Functions for Matching and Removing Patterns */
4506 /* */
4507 /* **************************************************************** */
4508
4509 #if defined (HANDLE_MULTIBYTE)
4510 # ifdef INCLUDE_UNUSED
4511 static unsigned char *
4512 mb_getcharlens (string, len)
4513 char *string;
4514 int len;
4515 {
4516 int i, offset, last;
4517 unsigned char *ret;
4518 char *p;
4519 DECLARE_MBSTATE;
4520
4521 i = offset = 0;
4522 last = 0;
4523 ret = (unsigned char *)xmalloc (len);
4524 memset (ret, 0, len);
4525 while (string[last])
4526 {
4527 ADVANCE_CHAR (string, len, offset);
4528 ret[last] = offset - last;
4529 last = offset;
4530 }
4531 return ret;
4532 }
4533 # endif
4534 #endif
4535
4536 /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
4537 can have one of 4 values:
4538 RP_LONG_LEFT remove longest matching portion at start of PARAM
4539 RP_SHORT_LEFT remove shortest matching portion at start of PARAM
4540 RP_LONG_RIGHT remove longest matching portion at end of PARAM
4541 RP_SHORT_RIGHT remove shortest matching portion at end of PARAM
4542 */
4543
4544 #define RP_LONG_LEFT 1
4545 #define RP_SHORT_LEFT 2
4546 #define RP_LONG_RIGHT 3
4547 #define RP_SHORT_RIGHT 4
4548
4549 /* Returns its first argument if nothing matched; new memory otherwise */
4550 static char *
4551 remove_upattern (param, pattern, op)
4552 char *param, *pattern;
4553 int op;
4554 {
4555 register size_t len;
4556 register char *end;
4557 register char *p, *ret, c;
4558
4559 len = STRLEN (param);
4560 end = param + len;
4561
4562 switch (op)
4563 {
4564 case RP_LONG_LEFT: /* remove longest match at start */
4565 for (p = end; p >= param; p--)
4566 {
4567 c = *p; *p = '\0';
4568 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4569 {
4570 *p = c;
4571 return (savestring (p));
4572 }
4573 *p = c;
4574
4575 }
4576 break;
4577
4578 case RP_SHORT_LEFT: /* remove shortest match at start */
4579 for (p = param; p <= end; p++)
4580 {
4581 c = *p; *p = '\0';
4582 if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4583 {
4584 *p = c;
4585 return (savestring (p));
4586 }
4587 *p = c;
4588 }
4589 break;
4590
4591 case RP_LONG_RIGHT: /* remove longest match at end */
4592 for (p = param; p <= end; p++)
4593 {
4594 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4595 {
4596 c = *p; *p = '\0';
4597 ret = savestring (param);
4598 *p = c;
4599 return (ret);
4600 }
4601 }
4602 break;
4603
4604 case RP_SHORT_RIGHT: /* remove shortest match at end */
4605 for (p = end; p >= param; p--)
4606 {
4607 if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4608 {
4609 c = *p; *p = '\0';
4610 ret = savestring (param);
4611 *p = c;
4612 return (ret);
4613 }
4614 }
4615 break;
4616 }
4617
4618 return (param); /* no match, return original string */
4619 }
4620
4621 #if defined (HANDLE_MULTIBYTE)
4622 /* Returns its first argument if nothing matched; new memory otherwise */
4623 static wchar_t *
4624 remove_wpattern (wparam, wstrlen, wpattern, op)
4625 wchar_t *wparam;
4626 size_t wstrlen;
4627 wchar_t *wpattern;
4628 int op;
4629 {
4630 wchar_t wc, *ret;
4631 int n;
4632
4633 switch (op)
4634 {
4635 case RP_LONG_LEFT: /* remove longest match at start */
4636 for (n = wstrlen; n >= 0; n--)
4637 {
4638 wc = wparam[n]; wparam[n] = L'\0';
4639 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4640 {
4641 wparam[n] = wc;
4642 return (wcsdup (wparam + n));
4643 }
4644 wparam[n] = wc;
4645 }
4646 break;
4647
4648 case RP_SHORT_LEFT: /* remove shortest match at start */
4649 for (n = 0; n <= wstrlen; n++)
4650 {
4651 wc = wparam[n]; wparam[n] = L'\0';
4652 if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4653 {
4654 wparam[n] = wc;
4655 return (wcsdup (wparam + n));
4656 }
4657 wparam[n] = wc;
4658 }
4659 break;
4660
4661 case RP_LONG_RIGHT: /* remove longest match at end */
4662 for (n = 0; n <= wstrlen; n++)
4663 {
4664 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4665 {
4666 wc = wparam[n]; wparam[n] = L'\0';
4667 ret = wcsdup (wparam);
4668 wparam[n] = wc;
4669 return (ret);
4670 }
4671 }
4672 break;
4673
4674 case RP_SHORT_RIGHT: /* remove shortest match at end */
4675 for (n = wstrlen; n >= 0; n--)
4676 {
4677 if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
4678 {
4679 wc = wparam[n]; wparam[n] = L'\0';
4680 ret = wcsdup (wparam);
4681 wparam[n] = wc;
4682 return (ret);
4683 }
4684 }
4685 break;
4686 }
4687
4688 return (wparam); /* no match, return original string */
4689 }
4690 #endif /* HANDLE_MULTIBYTE */
4691
4692 static char *
4693 remove_pattern (param, pattern, op)
4694 char *param, *pattern;
4695 int op;
4696 {
4697 char *xret;
4698
4699 if (param == NULL)
4700 return (param);
4701 if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
4702 return (savestring (param));
4703
4704 #if defined (HANDLE_MULTIBYTE)
4705 if (MB_CUR_MAX > 1)
4706 {
4707 wchar_t *ret, *oret;
4708 size_t n;
4709 wchar_t *wparam, *wpattern;
4710 mbstate_t ps;
4711
4712 /* XXX - could optimize here by checking param and pattern for multibyte
4713 chars with mbsmbchar and calling remove_upattern. */
4714
4715 n = xdupmbstowcs (&wpattern, NULL, pattern);
4716 if (n == (size_t)-1)
4717 {
4718 xret = remove_upattern (param, pattern, op);
4719 return ((xret == param) ? savestring (param) : xret);
4720 }
4721 n = xdupmbstowcs (&wparam, NULL, param);
4722
4723 if (n == (size_t)-1)
4724 {
4725 free (wpattern);
4726 xret = remove_upattern (param, pattern, op);
4727 return ((xret == param) ? savestring (param) : xret);
4728 }
4729 oret = ret = remove_wpattern (wparam, n, wpattern, op);
4730 /* Don't bother to convert wparam back to multibyte string if nothing
4731 matched; just return copy of original string */
4732 if (ret == wparam)
4733 {
4734 free (wparam);
4735 free (wpattern);
4736 return (savestring (param));
4737 }
4738
4739 free (wparam);
4740 free (wpattern);
4741
4742 n = strlen (param);
4743 xret = (char *)xmalloc (n + 1);
4744 memset (&ps, '\0', sizeof (mbstate_t));
4745 n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
4746 xret[n] = '\0'; /* just to make sure */
4747 free (oret);
4748 return xret;
4749 }
4750 else
4751 #endif
4752 {
4753 xret = remove_upattern (param, pattern, op);
4754 return ((xret == param) ? savestring (param) : xret);
4755 }
4756 }
4757
4758 /* Match PAT anywhere in STRING and return the match boundaries.
4759 This returns 1 in case of a successful match, 0 otherwise. SP
4760 and EP are pointers into the string where the match begins and
4761 ends, respectively. MTYPE controls what kind of match is attempted.
4762 MATCH_BEG and MATCH_END anchor the match at the beginning and end
4763 of the string, respectively. The longest match is returned. */
4764 static int
4765 match_upattern (string, pat, mtype, sp, ep)
4766 char *string, *pat;
4767 int mtype;
4768 char **sp, **ep;
4769 {
4770 int c, mlen;
4771 size_t len;
4772 register char *p, *p1, *npat;
4773 char *end;
4774
4775 /* If the pattern doesn't match anywhere in the string, go ahead and
4776 short-circuit right away. A minor optimization, saves a bunch of
4777 unnecessary calls to strmatch (up to N calls for a string of N
4778 characters) if the match is unsuccessful. To preserve the semantics
4779 of the substring matches below, we make sure that the pattern has
4780 `*' as first and last character, making a new pattern if necessary. */
4781 /* XXX - check this later if I ever implement `**' with special meaning,
4782 since this will potentially result in `**' at the beginning or end */
4783 len = STRLEN (pat);
4784 if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
4785 {
4786 int unescaped_backslash;
4787 char *pp;
4788
4789 p = npat = (char *)xmalloc (len + 3);
4790 p1 = pat;
4791 if ((mtype != MATCH_BEG) && (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob)))
4792 *p++ = '*';
4793 while (*p1)
4794 *p++ = *p1++;
4795 #if 1
4796 /* Need to also handle a pattern that ends with an unescaped backslash.
4797 For right now, we ignore it because the pattern matching code will
4798 fail the match anyway */
4799 /* If the pattern ends with a `*' we leave it alone if it's preceded by
4800 an even number of backslashes, but if it's escaped by a backslash
4801 we need to add another `*'. */
4802 if ((mtype != MATCH_END) && (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\')))
4803 {
4804 pp = p1 - 3;
4805 while (pp >= pat && *pp-- == '\\')
4806 unescaped_backslash = 1 - unescaped_backslash;
4807 if (unescaped_backslash)
4808 *p++ = '*';
4809 }
4810 else if (mtype != MATCH_END && p1[-1] != '*')
4811 *p++ = '*';
4812 #else
4813 if (p1[-1] != '*' || p1[-2] == '\\')
4814 *p++ = '*';
4815 #endif
4816 *p = '\0';
4817 }
4818 else
4819 npat = pat;
4820 c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
4821 if (npat != pat)
4822 free (npat);
4823 if (c == FNM_NOMATCH)
4824 return (0);
4825
4826 len = STRLEN (string);
4827 end = string + len;
4828
4829 mlen = umatchlen (pat, len);
4830 if (mlen > (int)len)
4831 return (0);
4832
4833 switch (mtype)
4834 {
4835 case MATCH_ANY:
4836 for (p = string; p <= end; p++)
4837 {
4838 if (match_pattern_char (pat, p, FNMATCH_IGNCASE))
4839 {
4840 p1 = (mlen == -1) ? end : p + mlen;
4841 /* p1 - p = length of portion of string to be considered
4842 p = current position in string
4843 mlen = number of characters consumed by match (-1 for entire string)
4844 end = end of string
4845 we want to break immediately if the potential match len
4846 is greater than the number of characters remaining in the
4847 string
4848 */
4849 if (p1 > end)
4850 break;
4851 for ( ; p1 >= p; p1--)
4852 {
4853 c = *p1; *p1 = '\0';
4854 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
4855 {
4856 *p1 = c;
4857 *sp = p;
4858 *ep = p1;
4859 return 1;
4860 }
4861 *p1 = c;
4862 #if 1
4863 /* If MLEN != -1, we have a fixed length pattern. */
4864 if (mlen != -1)
4865 break;
4866 #endif
4867 }
4868 }
4869 }
4870
4871 return (0);
4872
4873 case MATCH_BEG:
4874 if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0)
4875 return (0);
4876
4877 for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
4878 {
4879 c = *p; *p = '\0';
4880 if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
4881 {
4882 *p = c;
4883 *sp = string;
4884 *ep = p;
4885 return 1;
4886 }
4887 *p = c;
4888 /* If MLEN != -1, we have a fixed length pattern. */
4889 if (mlen != -1)
4890 break;
4891 }
4892
4893 return (0);
4894
4895 case MATCH_END:
4896 for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
4897 {
4898 if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
4899 {
4900 *sp = p;
4901 *ep = end;
4902 return 1;
4903 }
4904 /* If MLEN != -1, we have a fixed length pattern. */
4905 if (mlen != -1)
4906 break;
4907 }
4908
4909 return (0);
4910 }
4911
4912 return (0);
4913 }
4914
4915 #if defined (HANDLE_MULTIBYTE)
4916
4917 #define WFOLD(c) (match_ignore_case && iswupper (c) ? towlower (c) : (c))
4918
4919 /* Match WPAT anywhere in WSTRING and return the match boundaries.
4920 This returns 1 in case of a successful match, 0 otherwise. Wide
4921 character version. */
4922 static int
4923 match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
4924 wchar_t *wstring;
4925 char **indices;
4926 size_t wstrlen;
4927 wchar_t *wpat;
4928 int mtype;
4929 char **sp, **ep;
4930 {
4931 wchar_t wc, *wp, *nwpat, *wp1;
4932 size_t len;
4933 int mlen;
4934 int n, n1, n2, simple;
4935
4936 simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'[');
4937 #if defined (EXTENDED_GLOB)
4938 if (extended_glob)
4939 simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/
4940 #endif
4941
4942 /* If the pattern doesn't match anywhere in the string, go ahead and
4943 short-circuit right away. A minor optimization, saves a bunch of
4944 unnecessary calls to strmatch (up to N calls for a string of N
4945 characters) if the match is unsuccessful. To preserve the semantics
4946 of the substring matches below, we make sure that the pattern has
4947 `*' as first and last character, making a new pattern if necessary. */
4948 len = wcslen (wpat);
4949 if (wpat[0] != L'*' || (wpat[0] == L'*' && wpat[1] == WLPAREN && extended_glob) || wpat[len - 1] != L'*')
4950 {
4951 int unescaped_backslash;
4952 wchar_t *wpp;
4953
4954 wp = nwpat = (wchar_t *)xmalloc ((len + 3) * sizeof (wchar_t));
4955 wp1 = wpat;
4956 if (*wp1 != L'*' || (*wp1 == '*' && wp1[1] == WLPAREN && extended_glob))
4957 *wp++ = L'*';
4958 while (*wp1 != L'\0')
4959 *wp++ = *wp1++;
4960 #if 1
4961 /* See comments above in match_upattern. */
4962 if (wp1[-1] == L'*' && (unescaped_backslash = wp1[-2] == L'\\'))
4963 {
4964 wpp = wp1 - 3;
4965 while (wpp >= wpat && *wpp-- == L'\\')
4966 unescaped_backslash = 1 - unescaped_backslash;
4967 if (unescaped_backslash)
4968 *wp++ = L'*';
4969 }
4970 else if (wp1[-1] != L'*')
4971 *wp++ = L'*';
4972 #else
4973 if (wp1[-1] != L'*' || wp1[-2] == L'\\')
4974 *wp++ = L'*';
4975 #endif
4976 *wp = '\0';
4977 }
4978 else
4979 nwpat = wpat;
4980 len = wcsmatch (nwpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
4981 if (nwpat != wpat)
4982 free (nwpat);
4983 if (len == FNM_NOMATCH)
4984 return (0);
4985
4986 mlen = wmatchlen (wpat, wstrlen);
4987 if (mlen > (int)wstrlen)
4988 return (0);
4989
4990 /* itrace("wmatchlen (%ls) -> %d", wpat, mlen); */
4991 switch (mtype)
4992 {
4993 case MATCH_ANY:
4994 for (n = 0; n <= wstrlen; n++)
4995 {
4996 n2 = simple ? (WFOLD(*wpat) == WFOLD(wstring[n])) : match_pattern_wchar (wpat, wstring + n, FNMATCH_IGNCASE);
4997 if (n2)
4998 {
4999 n1 = (mlen == -1) ? wstrlen : n + mlen;
5000 if (n1 > wstrlen)
5001 break;
5002
5003 for ( ; n1 >= n; n1--)
5004 {
5005 wc = wstring[n1]; wstring[n1] = L'\0';
5006 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5007 {
5008 wstring[n1] = wc;
5009 *sp = indices[n];
5010 *ep = indices[n1];
5011 return 1;
5012 }
5013 wstring[n1] = wc;
5014 /* If MLEN != -1, we have a fixed length pattern. */
5015 if (mlen != -1)
5016 break;
5017 }
5018 }
5019 }
5020
5021 return (0);
5022
5023 case MATCH_BEG:
5024 if (match_pattern_wchar (wpat, wstring, FNMATCH_IGNCASE) == 0)
5025 return (0);
5026
5027 for (n = (mlen == -1) ? wstrlen : mlen; n >= 0; n--)
5028 {
5029 wc = wstring[n]; wstring[n] = L'\0';
5030 if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5031 {
5032 wstring[n] = wc;
5033 *sp = indices[0];
5034 *ep = indices[n];
5035 return 1;
5036 }
5037 wstring[n] = wc;
5038 /* If MLEN != -1, we have a fixed length pattern. */
5039 if (mlen != -1)
5040 break;
5041 }
5042
5043 return (0);
5044
5045 case MATCH_END:
5046 for (n = wstrlen - ((mlen == -1) ? wstrlen : mlen); n <= wstrlen; n++)
5047 {
5048 if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
5049 {
5050 *sp = indices[n];
5051 *ep = indices[wstrlen];
5052 return 1;
5053 }
5054 /* If MLEN != -1, we have a fixed length pattern. */
5055 if (mlen != -1)
5056 break;
5057 }
5058
5059 return (0);
5060 }
5061
5062 return (0);
5063 }
5064 #undef WFOLD
5065 #endif /* HANDLE_MULTIBYTE */
5066
5067 static int
5068 match_pattern (string, pat, mtype, sp, ep)
5069 char *string, *pat;
5070 int mtype;
5071 char **sp, **ep;
5072 {
5073 #if defined (HANDLE_MULTIBYTE)
5074 int ret;
5075 size_t n;
5076 wchar_t *wstring, *wpat;
5077 char **indices;
5078 #endif
5079
5080 if (string == 0 || pat == 0 || *pat == 0)
5081 return (0);
5082
5083 #if defined (HANDLE_MULTIBYTE)
5084 if (MB_CUR_MAX > 1)
5085 {
5086 if (mbsmbchar (string) == 0 && mbsmbchar (pat) == 0)
5087 return (match_upattern (string, pat, mtype, sp, ep));
5088
5089 n = xdupmbstowcs (&wpat, NULL, pat);
5090 if (n == (size_t)-1)
5091 return (match_upattern (string, pat, mtype, sp, ep));
5092 n = xdupmbstowcs (&wstring, &indices, string);
5093 if (n == (size_t)-1)
5094 {
5095 free (wpat);
5096 return (match_upattern (string, pat, mtype, sp, ep));
5097 }
5098 ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
5099
5100 free (wpat);
5101 free (wstring);
5102 free (indices);
5103
5104 return (ret);
5105 }
5106 else
5107 #endif
5108 return (match_upattern (string, pat, mtype, sp, ep));
5109 }
5110
5111 static int
5112 getpatspec (c, value)
5113 int c;
5114 char *value;
5115 {
5116 if (c == '#')
5117 return ((*value == '#') ? RP_LONG_LEFT : RP_SHORT_LEFT);
5118 else /* c == '%' */
5119 return ((*value == '%') ? RP_LONG_RIGHT : RP_SHORT_RIGHT);
5120 }
5121
5122 /* Posix.2 says that the WORD should be run through tilde expansion,
5123 parameter expansion, command substitution and arithmetic expansion.
5124 This leaves the result quoted, so quote_string_for_globbing () has
5125 to be called to fix it up for strmatch (). If QUOTED is non-zero,
5126 it means that the entire expression was enclosed in double quotes.
5127 This means that quoting characters in the pattern do not make any
5128 special pattern characters quoted. For example, the `*' in the
5129 following retains its special meaning: "${foo#'*'}". */
5130 static char *
5131 getpattern (value, quoted, expandpat)
5132 char *value;
5133 int quoted, expandpat;
5134 {
5135 char *pat, *tword;
5136 WORD_LIST *l;
5137 #if 0
5138 int i;
5139 #endif
5140 /* There is a problem here: how to handle single or double quotes in the
5141 pattern string when the whole expression is between double quotes?
5142 POSIX.2 says that enclosing double quotes do not cause the pattern to
5143 be quoted, but does that leave us a problem with @ and array[@] and their
5144 expansions inside a pattern? */
5145 #if 0
5146 if (expandpat && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *tword)
5147 {
5148 i = 0;
5149 pat = string_extract_double_quoted (tword, &i, SX_STRIPDQ);
5150 free (tword);
5151 tword = pat;
5152 }
5153 #endif
5154
5155 /* expand_string_for_pat () leaves WORD quoted and does not perform
5156 word splitting. */
5157 l = *value ? expand_string_for_pat (value,
5158 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? Q_PATQUOTE : quoted,
5159 (int *)NULL, (int *)NULL)
5160 : (WORD_LIST *)0;
5161 if (l)
5162 word_list_remove_quoted_nulls (l);
5163 pat = string_list (l);
5164 dispose_words (l);
5165 if (pat)
5166 {
5167 tword = quote_string_for_globbing (pat, QGLOB_CVTNULL);
5168 free (pat);
5169 pat = tword;
5170 }
5171 return (pat);
5172 }
5173
5174 #if 0
5175 /* Handle removing a pattern from a string as a result of ${name%[%]value}
5176 or ${name#[#]value}. */
5177 static char *
5178 variable_remove_pattern (value, pattern, patspec, quoted)
5179 char *value, *pattern;
5180 int patspec, quoted;
5181 {
5182 char *tword;
5183
5184 tword = remove_pattern (value, pattern, patspec);
5185
5186 return (tword);
5187 }
5188 #endif
5189
5190 static char *
5191 list_remove_pattern (list, pattern, patspec, itype, quoted)
5192 WORD_LIST *list;
5193 char *pattern;
5194 int patspec, itype, quoted;
5195 {
5196 WORD_LIST *new, *l;
5197 WORD_DESC *w;
5198 char *tword;
5199
5200 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
5201 {
5202 tword = remove_pattern (l->word->word, pattern, patspec);
5203 w = alloc_word_desc ();
5204 w->word = tword ? tword : savestring ("");
5205 new = make_word_list (w, new);
5206 }
5207
5208 l = REVERSE_LIST (new, WORD_LIST *);
5209 tword = string_list_pos_params (itype, l, quoted, 0);
5210 dispose_words (l);
5211
5212 return (tword);
5213 }
5214
5215 static char *
5216 parameter_list_remove_pattern (itype, pattern, patspec, quoted)
5217 int itype;
5218 char *pattern;
5219 int patspec, quoted;
5220 {
5221 char *ret;
5222 WORD_LIST *list;
5223
5224 list = list_rest_of_args ();
5225 if (list == 0)
5226 return ((char *)NULL);
5227 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5228 dispose_words (list);
5229 return (ret);
5230 }
5231
5232 #if defined (ARRAY_VARS)
5233 static char *
5234 array_remove_pattern (var, pattern, patspec, starsub, quoted)
5235 SHELL_VAR *var;
5236 char *pattern;
5237 int patspec;
5238 int starsub; /* so we can figure out how it's indexed */
5239 int quoted;
5240 {
5241 ARRAY *a;
5242 HASH_TABLE *h;
5243 int itype;
5244 char *ret;
5245 WORD_LIST *list;
5246 SHELL_VAR *v;
5247
5248 v = var; /* XXX - for now */
5249
5250 itype = starsub ? '*' : '@';
5251
5252 a = (v && array_p (v)) ? array_cell (v) : 0;
5253 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
5254
5255 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
5256 if (list == 0)
5257 return ((char *)NULL);
5258 ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
5259 dispose_words (list);
5260
5261 return ret;
5262 }
5263 #endif /* ARRAY_VARS */
5264
5265 static char *
5266 parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags)
5267 char *varname, *value;
5268 int ind;
5269 char *patstr;
5270 int rtype, quoted, flags;
5271 {
5272 int vtype, patspec, starsub;
5273 char *temp1, *val, *pattern, *oname;
5274 SHELL_VAR *v;
5275
5276 if (value == 0)
5277 return ((char *)NULL);
5278
5279 oname = this_command_name;
5280 this_command_name = varname;
5281
5282 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
5283 if (vtype == -1)
5284 {
5285 this_command_name = oname;
5286 return ((char *)NULL);
5287 }
5288
5289 starsub = vtype & VT_STARSUB;
5290 vtype &= ~VT_STARSUB;
5291
5292 patspec = getpatspec (rtype, patstr);
5293 if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
5294 patstr++;
5295
5296 /* Need to pass getpattern newly-allocated memory in case of expansion --
5297 the expansion code will free the passed string on an error. */
5298 temp1 = savestring (patstr);
5299 pattern = getpattern (temp1, quoted, 1);
5300 free (temp1);
5301
5302 temp1 = (char *)NULL; /* shut up gcc */
5303 switch (vtype)
5304 {
5305 case VT_VARIABLE:
5306 case VT_ARRAYMEMBER:
5307 temp1 = remove_pattern (val, pattern, patspec);
5308 if (vtype == VT_VARIABLE)
5309 FREE (val);
5310 if (temp1)
5311 {
5312 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
5313 ? quote_string (temp1)
5314 : quote_escapes (temp1);
5315 free (temp1);
5316 temp1 = val;
5317 }
5318 break;
5319 #if defined (ARRAY_VARS)
5320 case VT_ARRAYVAR:
5321 temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted);
5322 if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5323 {
5324 val = quote_escapes (temp1);
5325 free (temp1);
5326 temp1 = val;
5327 }
5328 break;
5329 #endif
5330 case VT_POSPARMS:
5331 temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
5332 if (temp1 && quoted == 0 && ifs_is_null)
5333 {
5334 /* Posix interp 888 */
5335 }
5336 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
5337 {
5338 val = quote_escapes (temp1);
5339 free (temp1);
5340 temp1 = val;
5341 }
5342 break;
5343 }
5344
5345 this_command_name = oname;
5346
5347 FREE (pattern);
5348 return temp1;
5349 }
5350
5351 #if defined (PROCESS_SUBSTITUTION)
5352
5353 static void reap_some_procsubs PARAMS((int));
5354
5355 /*****************************************************************/
5356 /* */
5357 /* Hacking Process Substitution */
5358 /* */
5359 /*****************************************************************/
5360
5361 #if !defined (HAVE_DEV_FD)
5362 /* Named pipes must be removed explicitly with `unlink'. This keeps a list
5363 of FIFOs the shell has open. unlink_fifo_list will walk the list and
5364 unlink all of them. add_fifo_list adds the name of an open FIFO to the
5365 list. NFIFO is a count of the number of FIFOs in the list. */
5366 #define FIFO_INCR 20
5367
5368 /* PROC value of -1 means the process has been reaped and the FIFO needs to
5369 be removed. PROC value of 0 means the slot is unused. */
5370 struct temp_fifo {
5371 char *file;
5372 pid_t proc;
5373 };
5374
5375 static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
5376 static int nfifo;
5377 static int fifo_list_size;
5378
5379 void
5380 clear_fifo_list ()
5381 {
5382 int i;
5383
5384 for (i = 0; i < fifo_list_size; i++)
5385 {
5386 if (fifo_list[i].file)
5387 free (fifo_list[i].file);
5388 fifo_list[i].file = NULL;
5389 fifo_list[i].proc = 0;
5390 }
5391 nfifo = 0;
5392 }
5393
5394 void *
5395 copy_fifo_list (sizep)
5396 int *sizep;
5397 {
5398 if (sizep)
5399 *sizep = 0;
5400 return (void *)NULL;
5401 }
5402
5403 static void
5404 add_fifo_list (pathname)
5405 char *pathname;
5406 {
5407 int osize, i;
5408
5409 if (nfifo >= fifo_list_size - 1)
5410 {
5411 osize = fifo_list_size;
5412 fifo_list_size += FIFO_INCR;
5413 fifo_list = (struct temp_fifo *)xrealloc (fifo_list,
5414 fifo_list_size * sizeof (struct temp_fifo));
5415 for (i = osize; i < fifo_list_size; i++)
5416 {
5417 fifo_list[i].file = (char *)NULL;
5418 fifo_list[i].proc = 0; /* unused */
5419 }
5420 }
5421
5422 fifo_list[nfifo].file = savestring (pathname);
5423 nfifo++;
5424 }
5425
5426 void
5427 unlink_fifo (i)
5428 int i;
5429 {
5430 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
5431 {
5432 unlink (fifo_list[i].file);
5433 free (fifo_list[i].file);
5434 fifo_list[i].file = (char *)NULL;
5435 fifo_list[i].proc = 0;
5436 }
5437 }
5438
5439 void
5440 unlink_fifo_list ()
5441 {
5442 int saved, i, j;
5443
5444 if (nfifo == 0)
5445 return;
5446
5447 for (i = saved = 0; i < nfifo; i++)
5448 {
5449 if ((fifo_list[i].proc == (pid_t)-1) || (fifo_list[i].proc > 0 && (kill(fifo_list[i].proc, 0) == -1)))
5450 {
5451 unlink (fifo_list[i].file);
5452 free (fifo_list[i].file);
5453 fifo_list[i].file = (char *)NULL;
5454 fifo_list[i].proc = 0;
5455 }
5456 else
5457 saved++;
5458 }
5459
5460 /* If we didn't remove some of the FIFOs, compact the list. */
5461 if (saved)
5462 {
5463 for (i = j = 0; i < nfifo; i++)
5464 if (fifo_list[i].file)
5465 {
5466 if (i != j)
5467 {
5468 fifo_list[j].file = fifo_list[i].file;
5469 fifo_list[j].proc = fifo_list[i].proc;
5470 fifo_list[i].file = (char *)NULL;
5471 fifo_list[i].proc = 0;
5472 }
5473 j++;
5474 }
5475 nfifo = j;
5476 }
5477 else
5478 nfifo = 0;
5479 }
5480
5481 /* Take LIST, which is a bitmap denoting active FIFOs in fifo_list
5482 from some point in the past, and close all open FIFOs in fifo_list
5483 that are not marked as active in LIST. If LIST is NULL, close
5484 everything in fifo_list. LSIZE is the number of elements in LIST, in
5485 case it's larger than fifo_list_size (size of fifo_list). */
5486 void
5487 close_new_fifos (list, lsize)
5488 void *list;
5489 int lsize;
5490 {
5491 int i;
5492 char *plist;
5493
5494 if (list == 0)
5495 {
5496 unlink_fifo_list ();
5497 return;
5498 }
5499
5500 for (plist = (char *)list, i = 0; i < lsize; i++)
5501 if (plist[i] == 0 && i < fifo_list_size && fifo_list[i].proc != -1)
5502 unlink_fifo (i);
5503
5504 for (i = lsize; i < fifo_list_size; i++)
5505 unlink_fifo (i);
5506 }
5507
5508 int
5509 find_procsub_child (pid)
5510 pid_t pid;
5511 {
5512 int i;
5513
5514 for (i = 0; i < nfifo; i++)
5515 if (fifo_list[i].proc == pid)
5516 return i;
5517 return -1;
5518 }
5519
5520 void
5521 set_procsub_status (ind, pid, status)
5522 int ind;
5523 pid_t pid;
5524 int status;
5525 {
5526 if (ind >= 0 && ind < nfifo)
5527 fifo_list[ind].proc = (pid_t)-1; /* sentinel */
5528 }
5529
5530 /* If we've marked the process for this procsub as dead, close the
5531 associated file descriptor and delete the FIFO. */
5532 static void
5533 reap_some_procsubs (max)
5534 int max;
5535 {
5536 int i;
5537
5538 for (i = 0; i < max; i++)
5539 if (fifo_list[i].proc == (pid_t)-1) /* reaped */
5540 unlink_fifo (i);
5541 }
5542
5543 void
5544 reap_procsubs ()
5545 {
5546 reap_some_procsubs (nfifo);
5547 }
5548
5549 #if 0
5550 /* UNUSED */
5551 void
5552 wait_procsubs ()
5553 {
5554 int i, r;
5555
5556 for (i = 0; i < nfifo; i++)
5557 {
5558 if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0)
5559 {
5560 r = wait_for (fifo_list[i].proc, 0);
5561 save_proc_status (fifo_list[i].proc, r);
5562 fifo_list[i].proc = (pid_t)-1;
5563 }
5564 }
5565 }
5566 #endif
5567
5568 int
5569 fifos_pending ()
5570 {
5571 return nfifo;
5572 }
5573
5574 int
5575 num_fifos ()
5576 {
5577 return nfifo;
5578 }
5579
5580 static char *
5581 make_named_pipe ()
5582 {
5583 char *tname;
5584
5585 tname = sh_mktmpname ("sh-np", MT_USERANDOM|MT_USETMPDIR);
5586 if (mkfifo (tname, 0600) < 0)
5587 {
5588 free (tname);
5589 return ((char *)NULL);
5590 }
5591
5592 add_fifo_list (tname);
5593 return (tname);
5594 }
5595
5596 #else /* HAVE_DEV_FD */
5597
5598 /* DEV_FD_LIST is a bitmap of file descriptors attached to pipes the shell
5599 has open to children. NFDS is a count of the number of bits currently
5600 set in DEV_FD_LIST. TOTFDS is a count of the highest possible number
5601 of open files. */
5602 /* dev_fd_list[I] value of -1 means the process has been reaped and file
5603 descriptor I needs to be closed. Value of 0 means the slot is unused. */
5604
5605 static pid_t *dev_fd_list = (pid_t *)NULL;
5606 static int nfds;
5607 static int totfds; /* The highest possible number of open files. */
5608
5609 void
5610 clear_fifo (i)
5611 int i;
5612 {
5613 if (dev_fd_list[i])
5614 {
5615 dev_fd_list[i] = 0;
5616 nfds--;
5617 }
5618 }
5619
5620 void
5621 clear_fifo_list ()
5622 {
5623 register int i;
5624
5625 if (nfds == 0)
5626 return;
5627
5628 for (i = 0; nfds && i < totfds; i++)
5629 clear_fifo (i);
5630
5631 nfds = 0;
5632 }
5633
5634 void *
5635 copy_fifo_list (sizep)
5636 int *sizep;
5637 {
5638 void *ret;
5639
5640 if (nfds == 0 || totfds == 0)
5641 {
5642 if (sizep)
5643 *sizep = 0;
5644 return (void *)NULL;
5645 }
5646
5647 if (sizep)
5648 *sizep = totfds;
5649 ret = xmalloc (totfds * sizeof (pid_t));
5650 return (memcpy (ret, dev_fd_list, totfds * sizeof (pid_t)));
5651 }
5652
5653 static void
5654 add_fifo_list (fd)
5655 int fd;
5656 {
5657 if (dev_fd_list == 0 || fd >= totfds)
5658 {
5659 int ofds;
5660
5661 ofds = totfds;
5662 totfds = getdtablesize ();
5663 if (totfds < 0 || totfds > 256)
5664 totfds = 256;
5665 if (fd >= totfds)
5666 totfds = fd + 2;
5667
5668 dev_fd_list = (pid_t *)xrealloc (dev_fd_list, totfds * sizeof (dev_fd_list[0]));
5669 /* XXX - might need a loop for this */
5670 memset (dev_fd_list + ofds, '\0', (totfds - ofds) * sizeof (pid_t));
5671 }
5672
5673 dev_fd_list[fd] = 1; /* marker; updated later */
5674 nfds++;
5675 }
5676
5677 int
5678 fifos_pending ()
5679 {
5680 return 0; /* used for cleanup; not needed with /dev/fd */
5681 }
5682
5683 int
5684 num_fifos ()
5685 {
5686 return nfds;
5687 }
5688
5689 void
5690 unlink_fifo (fd)
5691 int fd;
5692 {
5693 if (dev_fd_list[fd])
5694 {
5695 close (fd);
5696 dev_fd_list[fd] = 0;
5697 nfds--;
5698 }
5699 }
5700
5701 void
5702 unlink_fifo_list ()
5703 {
5704 register int i;
5705
5706 if (nfds == 0)
5707 return;
5708
5709 for (i = totfds-1; nfds && i >= 0; i--)
5710 unlink_fifo (i);
5711
5712 nfds = 0;
5713 }
5714
5715 /* Take LIST, which is a snapshot copy of dev_fd_list from some point in
5716 the past, and close all open fds in dev_fd_list that are not marked
5717 as open in LIST. If LIST is NULL, close everything in dev_fd_list.
5718 LSIZE is the number of elements in LIST, in case it's larger than
5719 totfds (size of dev_fd_list). */
5720 void
5721 close_new_fifos (list, lsize)
5722 void *list;
5723 int lsize;
5724 {
5725 int i;
5726 pid_t *plist;
5727
5728 if (list == 0)
5729 {
5730 unlink_fifo_list ();
5731 return;
5732 }
5733
5734 for (plist = (pid_t *)list, i = 0; i < lsize; i++)
5735 if (plist[i] == 0 && i < totfds && dev_fd_list[i])
5736 unlink_fifo (i);
5737
5738 for (i = lsize; i < totfds; i++)
5739 unlink_fifo (i);
5740 }
5741
5742 int
5743 find_procsub_child (pid)
5744 pid_t pid;
5745 {
5746 int i;
5747
5748 if (nfds == 0)
5749 return -1;
5750
5751 for (i = 0; i < totfds; i++)
5752 if (dev_fd_list[i] == pid)
5753 return i;
5754
5755 return -1;
5756 }
5757
5758 void
5759 set_procsub_status (ind, pid, status)
5760 int ind;
5761 pid_t pid;
5762 int status;
5763 {
5764 if (ind >= 0 && ind < totfds)
5765 dev_fd_list[ind] = (pid_t)-1; /* sentinel */
5766 }
5767
5768 /* If we've marked the process for this procsub as dead, close the
5769 associated file descriptor. */
5770 static void
5771 reap_some_procsubs (max)
5772 int max;
5773 {
5774 int i;
5775
5776 for (i = 0; nfds > 0 && i < max; i++)
5777 if (dev_fd_list[i] == (pid_t)-1)
5778 unlink_fifo (i);
5779 }
5780
5781 void
5782 reap_procsubs ()
5783 {
5784 reap_some_procsubs (totfds);
5785 }
5786
5787 #if 0
5788 /* UNUSED */
5789 void
5790 wait_procsubs ()
5791 {
5792 int i, r;
5793
5794 for (i = 0; nfds > 0 && i < totfds; i++)
5795 {
5796 if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0)
5797 {
5798 r = wait_for (dev_fd_list[i], 0);
5799 save_proc_status (dev_fd_list[i], r);
5800 dev_fd_list[i] = (pid_t)-1;
5801 }
5802 }
5803 }
5804 #endif
5805
5806 #if defined (NOTDEF)
5807 print_dev_fd_list ()
5808 {
5809 register int i;
5810
5811 fprintf (stderr, "pid %ld: dev_fd_list:", (long)getpid ());
5812 fflush (stderr);
5813
5814 for (i = 0; i < totfds; i++)
5815 {
5816 if (dev_fd_list[i])
5817 fprintf (stderr, " %d", i);
5818 }
5819 fprintf (stderr, "\n");
5820 }
5821 #endif /* NOTDEF */
5822
5823 static char *
5824 make_dev_fd_filename (fd)
5825 int fd;
5826 {
5827 char *ret, intbuf[INT_STRLEN_BOUND (int) + 1], *p;
5828
5829 ret = (char *)xmalloc (sizeof (DEV_FD_PREFIX) + 8);
5830
5831 strcpy (ret, DEV_FD_PREFIX);
5832 p = inttostr (fd, intbuf, sizeof (intbuf));
5833 strcpy (ret + sizeof (DEV_FD_PREFIX) - 1, p);
5834
5835 add_fifo_list (fd);
5836 return (ret);
5837 }
5838
5839 #endif /* HAVE_DEV_FD */
5840
5841 /* Return a filename that will open a connection to the process defined by
5842 executing STRING. HAVE_DEV_FD, if defined, means open a pipe and return
5843 a filename in /dev/fd corresponding to a descriptor that is one of the
5844 ends of the pipe. If not defined, we use named pipes on systems that have
5845 them. Systems without /dev/fd and named pipes are out of luck.
5846
5847 OPEN_FOR_READ_IN_CHILD, if 1, means open the named pipe for reading or
5848 use the read end of the pipe and dup that file descriptor to fd 0 in
5849 the child. If OPEN_FOR_READ_IN_CHILD is 0, we open the named pipe for
5850 writing or use the write end of the pipe in the child, and dup that
5851 file descriptor to fd 1 in the child. The parent does the opposite. */
5852
5853 static char *
5854 process_substitute (string, open_for_read_in_child)
5855 char *string;
5856 int open_for_read_in_child;
5857 {
5858 char *pathname;
5859 int fd, result, rc, function_value;
5860 pid_t old_pid, pid;
5861 #if defined (HAVE_DEV_FD)
5862 int parent_pipe_fd, child_pipe_fd;
5863 int fildes[2];
5864 #endif /* HAVE_DEV_FD */
5865 #if defined (JOB_CONTROL)
5866 pid_t old_pipeline_pgrp;
5867 #endif
5868
5869 if (!string || !*string || wordexp_only)
5870 return ((char *)NULL);
5871
5872 #if !defined (HAVE_DEV_FD)
5873 pathname = make_named_pipe ();
5874 #else /* HAVE_DEV_FD */
5875 if (pipe (fildes) < 0)
5876 {
5877 sys_error ("%s", _("cannot make pipe for process substitution"));
5878 return ((char *)NULL);
5879 }
5880 /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of
5881 the pipe in the parent, otherwise the read end. */
5882 parent_pipe_fd = fildes[open_for_read_in_child];
5883 child_pipe_fd = fildes[1 - open_for_read_in_child];
5884 /* Move the parent end of the pipe to some high file descriptor, to
5885 avoid clashes with FDs used by the script. */
5886 parent_pipe_fd = move_to_high_fd (parent_pipe_fd, 1, 64);
5887
5888 pathname = make_dev_fd_filename (parent_pipe_fd);
5889 #endif /* HAVE_DEV_FD */
5890
5891 if (pathname == 0)
5892 {
5893 sys_error ("%s", _("cannot make pipe for process substitution"));
5894 return ((char *)NULL);
5895 }
5896
5897 old_pid = last_made_pid;
5898
5899 #if defined (JOB_CONTROL)
5900 old_pipeline_pgrp = pipeline_pgrp;
5901 if (pipeline_pgrp == 0 || (subshell_environment & (SUBSHELL_PIPE|SUBSHELL_FORK|SUBSHELL_ASYNC)) == 0)
5902 pipeline_pgrp = shell_pgrp;
5903 save_pipeline (1);
5904 #endif /* JOB_CONTROL */
5905
5906 pid = make_child ((char *)NULL, FORK_ASYNC);
5907 if (pid == 0)
5908 {
5909 /* The currently-executing shell is not interactive */
5910 interactive = 0;
5911
5912 reset_terminating_signals (); /* XXX */
5913 free_pushed_string_input ();
5914 /* Cancel traps, in trap.c. */
5915 restore_original_signals (); /* XXX - what about special builtins? bash-4.2 */
5916 QUIT; /* catch any interrupts we got post-fork */
5917 setup_async_signals ();
5918 if (open_for_read_in_child == 0)
5919 async_redirect_stdin ();
5920 subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB;
5921
5922 /* We don't inherit the verbose option for command substitutions now, so
5923 let's try it for process substitutions. */
5924 change_flag ('v', FLAG_OFF);
5925
5926 /* if we're expanding a redirection, we shouldn't have access to the
5927 temporary environment, but commands in the subshell should have
5928 access to their own temporary environment. */
5929 if (expanding_redir)
5930 flush_temporary_env ();
5931 }
5932
5933 #if defined (JOB_CONTROL)
5934 set_sigchld_handler ();
5935 stop_making_children ();
5936 /* XXX - should we only do this in the parent? (as in command subst) */
5937 pipeline_pgrp = old_pipeline_pgrp;
5938 #else
5939 stop_making_children ();
5940 #endif /* JOB_CONTROL */
5941
5942 if (pid < 0)
5943 {
5944 sys_error ("%s", _("cannot make child for process substitution"));
5945 free (pathname);
5946 #if defined (HAVE_DEV_FD)
5947 close (parent_pipe_fd);
5948 close (child_pipe_fd);
5949 #endif /* HAVE_DEV_FD */
5950 #if defined (JOB_CONTROL)
5951 restore_pipeline (1);
5952 #endif
5953 return ((char *)NULL);
5954 }
5955
5956 if (pid > 0)
5957 {
5958 #if defined (JOB_CONTROL)
5959 last_procsub_child = restore_pipeline (0);
5960 /* We assume that last_procsub_child->next == last_procsub_child because
5961 of how jobs.c:add_process() works. */
5962 last_procsub_child->next = 0;
5963 procsub_add (last_procsub_child);
5964 #endif
5965
5966 #if defined (HAVE_DEV_FD)
5967 dev_fd_list[parent_pipe_fd] = pid;
5968 #else
5969 fifo_list[nfifo-1].proc = pid;
5970 #endif
5971
5972 last_made_pid = old_pid;
5973
5974 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
5975 close_pgrp_pipe ();
5976 #endif /* JOB_CONTROL && PGRP_PIPE */
5977
5978 #if defined (HAVE_DEV_FD)
5979 close (child_pipe_fd);
5980 #endif /* HAVE_DEV_FD */
5981
5982 return (pathname);
5983 }
5984
5985 set_sigint_handler ();
5986
5987 #if defined (JOB_CONTROL)
5988 /* make sure we don't have any job control */
5989 set_job_control (0);
5990
5991 /* Clear out any existing list of process substitutions */
5992 procsub_clear ();
5993
5994 /* The idea is that we want all the jobs we start from an async process
5995 substitution to be in the same process group, but not the same pgrp
5996 as our parent shell, since we don't want to affect our parent shell's
5997 jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example.
5998 If pipeline_pgrp != shell_pgrp, we assume that there is a job control
5999 shell somewhere in our parent process chain (since make_child initializes
6000 pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this
6001 case is to set pipeline_pgrp to our PID, so all jobs started by this
6002 process have that same pgrp and we are basically the process group leader.
6003 This should not have negative effects on child processes surviving
6004 after we exit, since we wait for the children we create, but that is
6005 something to watch for. */
6006
6007 if (pipeline_pgrp != shell_pgrp)
6008 pipeline_pgrp = getpid ();
6009 #endif /* JOB_CONTROL */
6010
6011 #if !defined (HAVE_DEV_FD)
6012 /* Open the named pipe in the child. */
6013 fd = open (pathname, open_for_read_in_child ? O_RDONLY : O_WRONLY);
6014 if (fd < 0)
6015 {
6016 /* Two separate strings for ease of translation. */
6017 if (open_for_read_in_child)
6018 sys_error (_("cannot open named pipe %s for reading"), pathname);
6019 else
6020 sys_error (_("cannot open named pipe %s for writing"), pathname);
6021
6022 exit (127);
6023 }
6024 if (open_for_read_in_child)
6025 {
6026 if (sh_unset_nodelay_mode (fd) < 0)
6027 {
6028 sys_error (_("cannot reset nodelay mode for fd %d"), fd);
6029 exit (127);
6030 }
6031 }
6032 #else /* HAVE_DEV_FD */
6033 fd = child_pipe_fd;
6034 #endif /* HAVE_DEV_FD */
6035
6036 /* Discard buffered stdio output before replacing the underlying file
6037 descriptor. */
6038 if (open_for_read_in_child == 0)
6039 fpurge (stdout);
6040
6041 if (dup2 (fd, open_for_read_in_child ? 0 : 1) < 0)
6042 {
6043 sys_error (_("cannot duplicate named pipe %s as fd %d"), pathname,
6044 open_for_read_in_child ? 0 : 1);
6045 exit (127);
6046 }
6047
6048 if (fd != (open_for_read_in_child ? 0 : 1))
6049 close (fd);
6050
6051 /* Need to close any files that this process has open to pipes inherited
6052 from its parent. */
6053 if (current_fds_to_close)
6054 {
6055 close_fd_bitmap (current_fds_to_close);
6056 current_fds_to_close = (struct fd_bitmap *)NULL;
6057 }
6058
6059 #if defined (HAVE_DEV_FD)
6060 /* Make sure we close the parent's end of the pipe and clear the slot
6061 in the fd list so it is not closed later, if reallocated by, for
6062 instance, pipe(2). */
6063 close (parent_pipe_fd);
6064 dev_fd_list[parent_pipe_fd] = 0;
6065 #endif /* HAVE_DEV_FD */
6066
6067 /* subshells shouldn't have this flag, which controls using the temporary
6068 environment for variable lookups. We have already flushed the temporary
6069 environment above in the case we're expanding a redirection, so processes
6070 executed by this command need to be able to set it independently of their
6071 parent. */
6072 expanding_redir = 0;
6073
6074 remove_quoted_escapes (string);
6075
6076 /* Give process substitution a place to jump back to on failure,
6077 so we don't go back up to main (). */
6078 result = setjmp_nosigs (top_level);
6079
6080 /* If we're running a process substitution inside a shell function,
6081 trap `return' so we don't return from the function in the subshell
6082 and go off to never-never land. */
6083 if (result == 0 && return_catch_flag)
6084 function_value = setjmp_nosigs (return_catch);
6085 else
6086 function_value = 0;
6087
6088 if (result == ERREXIT)
6089 rc = last_command_exit_value;
6090 else if (result == EXITPROG)
6091 rc = last_command_exit_value;
6092 else if (result)
6093 rc = EXECUTION_FAILURE;
6094 else if (function_value)
6095 rc = return_catch_value;
6096 else
6097 {
6098 subshell_level++;
6099 rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
6100 /* leave subshell level intact for any exit trap */
6101 }
6102
6103 #if !defined (HAVE_DEV_FD)
6104 /* Make sure we close the named pipe in the child before we exit. */
6105 close (open_for_read_in_child ? 0 : 1);
6106 #endif /* !HAVE_DEV_FD */
6107
6108 last_command_exit_value = rc;
6109 rc = run_exit_trap ();
6110 exit (rc);
6111 /*NOTREACHED*/
6112 }
6113 #endif /* PROCESS_SUBSTITUTION */
6114
6115 /***********************************/
6116 /* */
6117 /* Command Substitution */
6118 /* */
6119 /***********************************/
6120
6121 static char *
6122 read_comsub (fd, quoted, flags, rflag)
6123 int fd, quoted, flags;
6124 int *rflag;
6125 {
6126 char *istring, buf[512], *bufp;
6127 int istring_index, c, tflag, skip_ctlesc, skip_ctlnul;
6128 int mb_cur_max;
6129 size_t istring_size;
6130 ssize_t bufn;
6131 int nullbyte;
6132 #if defined (HANDLE_MULTIBYTE)
6133 mbstate_t ps;
6134 wchar_t wc;
6135 size_t mblen;
6136 int i;
6137 #endif
6138
6139 istring = (char *)NULL;
6140 istring_index = istring_size = bufn = tflag = 0;
6141
6142 skip_ctlesc = ifs_cmap[CTLESC];
6143 skip_ctlnul = ifs_cmap[CTLNUL];
6144
6145 mb_cur_max = MB_CUR_MAX;
6146 nullbyte = 0;
6147
6148 /* Read the output of the command through the pipe. */
6149 while (1)
6150 {
6151 if (fd < 0)
6152 break;
6153 if (--bufn <= 0)
6154 {
6155 bufn = zread (fd, buf, sizeof (buf));
6156 if (bufn <= 0)
6157 break;
6158 bufp = buf;
6159 }
6160 c = *bufp++;
6161
6162 if (c == 0)
6163 {
6164 #if 1
6165 if (nullbyte == 0)
6166 {
6167 internal_warning ("%s", _("command substitution: ignored null byte in input"));
6168 nullbyte = 1;
6169 }
6170 #endif
6171 continue;
6172 }
6173
6174 /* Add the character to ISTRING, possibly after resizing it. */
6175 RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, 512);
6176
6177 /* This is essentially quote_string inline */
6178 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
6179 istring[istring_index++] = CTLESC;
6180 else if ((flags & PF_ASSIGNRHS) && skip_ctlesc && c == CTLESC)
6181 istring[istring_index++] = CTLESC;
6182 /* Escape CTLESC and CTLNUL in the output to protect those characters
6183 from the rest of the word expansions (word splitting and globbing.)
6184 This is essentially quote_escapes inline. */
6185 else if (skip_ctlesc == 0 && c == CTLESC)
6186 istring[istring_index++] = CTLESC;
6187 else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
6188 istring[istring_index++] = CTLESC;
6189
6190 #if defined (HANDLE_MULTIBYTE)
6191 if ((locale_utf8locale && (c & 0x80)) ||
6192 (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127))
6193 {
6194 /* read a multibyte character from buf */
6195 /* punt on the hard case for now */
6196 memset (&ps, '\0', sizeof (mbstate_t));
6197 mblen = mbrtowc (&wc, bufp-1, bufn+1, &ps);
6198 if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1)
6199 istring[istring_index++] = c;
6200 else
6201 {
6202 istring[istring_index++] = c;
6203 for (i = 0; i < mblen-1; i++)
6204 istring[istring_index++] = *bufp++;
6205 bufn -= mblen - 1;
6206 }
6207 continue;
6208 }
6209 #endif
6210
6211 istring[istring_index++] = c;
6212 }
6213
6214 if (istring)
6215 istring[istring_index] = '\0';
6216
6217 /* If we read no output, just return now and save ourselves some
6218 trouble. */
6219 if (istring_index == 0)
6220 {
6221 FREE (istring);
6222 if (rflag)
6223 *rflag = tflag;
6224 return (char *)NULL;
6225 }
6226
6227 /* Strip trailing newlines from the output of the command. */
6228 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
6229 {
6230 while (istring_index > 0)
6231 {
6232 if (istring[istring_index - 1] == '\n')
6233 {
6234 --istring_index;
6235
6236 /* If the newline was quoted, remove the quoting char. */
6237 if (istring[istring_index - 1] == CTLESC)
6238 --istring_index;
6239 }
6240 else
6241 break;
6242 }
6243 istring[istring_index] = '\0';
6244 }
6245 else
6246 strip_trailing (istring, istring_index - 1, 1);
6247
6248 if (rflag)
6249 *rflag = tflag;
6250 return istring;
6251 }
6252
6253 /* Perform command substitution on STRING. This returns a WORD_DESC * with the
6254 contained string possibly quoted. */
6255 WORD_DESC *
6256 command_substitute (string, quoted, flags)
6257 char *string;
6258 int quoted;
6259 int flags;
6260 {
6261 pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
6262 char *istring, *s;
6263 int result, fildes[2], function_value, pflags, rc, tflag, fork_flags;
6264 WORD_DESC *ret;
6265 sigset_t set, oset;
6266
6267 istring = (char *)NULL;
6268
6269 /* Don't fork () if there is no need to. In the case of no command to
6270 run, just return NULL. */
6271 #if 1
6272 for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++)
6273 ;
6274 if (s == 0 || *s == 0)
6275 return ((WORD_DESC *)NULL);
6276 #else
6277 if (!string || !*string || (string[0] == '\n' && !string[1]))
6278 return ((WORD_DESC *)NULL);
6279 #endif
6280
6281 if (wordexp_only && read_but_dont_execute)
6282 {
6283 last_command_exit_value = EX_WEXPCOMSUB;
6284 jump_to_top_level (EXITPROG);
6285 }
6286
6287 /* We're making the assumption here that the command substitution will
6288 eventually run a command from the file system. Since we'll run
6289 maybe_make_export_env in this subshell before executing that command,
6290 the parent shell and any other shells it starts will have to remake
6291 the environment. If we make it before we fork, other shells won't
6292 have to. Don't bother if we have any temporary variable assignments,
6293 though, because the export environment will be remade after this
6294 command completes anyway, but do it if all the words to be expanded
6295 are variable assignments. */
6296 if (subst_assign_varlist == 0 || garglist == 0)
6297 maybe_make_export_env (); /* XXX */
6298
6299 /* Flags to pass to parse_and_execute() */
6300 pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;
6301
6302 old_pid = last_made_pid;
6303
6304 /* Pipe the output of executing STRING into the current shell. */
6305 if (pipe (fildes) < 0)
6306 {
6307 sys_error ("%s", _("cannot make pipe for command substitution"));
6308 goto error_exit;
6309 }
6310
6311 #if defined (JOB_CONTROL)
6312 old_pipeline_pgrp = pipeline_pgrp;
6313 /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */
6314 if ((subshell_environment & SUBSHELL_PIPE) == 0)
6315 pipeline_pgrp = shell_pgrp;
6316 cleanup_the_pipeline ();
6317 #endif /* JOB_CONTROL */
6318
6319 old_async_pid = last_asynchronous_pid;
6320 fork_flags = (subshell_environment&SUBSHELL_ASYNC) ? FORK_ASYNC : 0;
6321 pid = make_child ((char *)NULL, fork_flags|FORK_NOTERM);
6322 last_asynchronous_pid = old_async_pid;
6323
6324 if (pid == 0)
6325 {
6326 /* Reset the signal handlers in the child, but don't free the
6327 trap strings. Set a flag noting that we have to free the
6328 trap strings if we run trap to change a signal disposition. */
6329 reset_signal_handlers ();
6330 if (ISINTERRUPT)
6331 {
6332 kill (getpid (), SIGINT);
6333 CLRINTERRUPT; /* if we're ignoring SIGINT somehow */
6334 }
6335 QUIT; /* catch any interrupts we got post-fork */
6336 subshell_environment |= SUBSHELL_RESETTRAP;
6337 }
6338
6339 #if defined (JOB_CONTROL)
6340 /* XXX DO THIS ONLY IN PARENT ? XXX */
6341 set_sigchld_handler ();
6342 stop_making_children ();
6343 if (pid != 0)
6344 pipeline_pgrp = old_pipeline_pgrp;
6345 #else
6346 stop_making_children ();
6347 #endif /* JOB_CONTROL */
6348
6349 if (pid < 0)
6350 {
6351 sys_error (_("cannot make child for command substitution"));
6352 error_exit:
6353
6354 last_made_pid = old_pid;
6355
6356 FREE (istring);
6357 close (fildes[0]);
6358 close (fildes[1]);
6359 return ((WORD_DESC *)NULL);
6360 }
6361
6362 if (pid == 0)
6363 {
6364 /* The currently executing shell is not interactive. */
6365 interactive = 0;
6366
6367 set_sigint_handler (); /* XXX */
6368
6369 free_pushed_string_input ();
6370
6371 /* Discard buffered stdio output before replacing the underlying file
6372 descriptor. */
6373 fpurge (stdout);
6374
6375 if (dup2 (fildes[1], 1) < 0)
6376 {
6377 sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1"));
6378 exit (EXECUTION_FAILURE);
6379 }
6380
6381 /* If standard output is closed in the parent shell
6382 (such as after `exec >&-'), file descriptor 1 will be
6383 the lowest available file descriptor, and end up in
6384 fildes[0]. This can happen for stdin and stderr as well,
6385 but stdout is more important -- it will cause no output
6386 to be generated from this command. */
6387 if ((fildes[1] != fileno (stdin)) &&
6388 (fildes[1] != fileno (stdout)) &&
6389 (fildes[1] != fileno (stderr)))
6390 close (fildes[1]);
6391
6392 if ((fildes[0] != fileno (stdin)) &&
6393 (fildes[0] != fileno (stdout)) &&
6394 (fildes[0] != fileno (stderr)))
6395 close (fildes[0]);
6396
6397 #ifdef __CYGWIN__
6398 /* Let stdio know the fd may have changed from text to binary mode, and
6399 make sure to preserve stdout line buffering. */
6400 freopen (NULL, "w", stdout);
6401 sh_setlinebuf (stdout);
6402 #endif /* __CYGWIN__ */
6403
6404 /* This is a subshell environment. */
6405 subshell_environment |= SUBSHELL_COMSUB;
6406
6407 /* Many shells do not appear to inherit the -v option for command
6408 substitutions. */
6409 change_flag ('v', FLAG_OFF);
6410
6411 /* When inherit_errexit option is not enabled, command substitution does
6412 not inherit the -e flag. It is enabled when Posix mode is enabled */
6413 if (inherit_errexit == 0)
6414 {
6415 builtin_ignoring_errexit = 0;
6416 change_flag ('e', FLAG_OFF);
6417 }
6418 set_shellopts ();
6419
6420 /* If we are expanding a redirection, we can dispose of any temporary
6421 environment we received, since redirections are not supposed to have
6422 access to the temporary environment. We will have to see whether this
6423 affects temporary environments supplied to `eval', but the temporary
6424 environment gets copied to builtin_env at some point. */
6425 if (expanding_redir)
6426 {
6427 flush_temporary_env ();
6428 expanding_redir = 0;
6429 }
6430
6431 remove_quoted_escapes (string);
6432
6433 startup_state = 2; /* see if we can avoid a fork */
6434 parse_and_execute_level = 0;
6435
6436 /* Give command substitution a place to jump back to on failure,
6437 so we don't go back up to main (). */
6438 result = setjmp_nosigs (top_level);
6439
6440 /* If we're running a command substitution inside a shell function,
6441 trap `return' so we don't return from the function in the subshell
6442 and go off to never-never land. */
6443 if (result == 0 && return_catch_flag)
6444 function_value = setjmp_nosigs (return_catch);
6445 else
6446 function_value = 0;
6447
6448 if (result == ERREXIT)
6449 rc = last_command_exit_value;
6450 else if (result == EXITPROG)
6451 rc = last_command_exit_value;
6452 else if (result)
6453 rc = EXECUTION_FAILURE;
6454 else if (function_value)
6455 rc = return_catch_value;
6456 else
6457 {
6458 subshell_level++;
6459 rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
6460 /* leave subshell level intact for any exit trap */
6461 }
6462
6463 last_command_exit_value = rc;
6464 rc = run_exit_trap ();
6465 #if defined (PROCESS_SUBSTITUTION)
6466 unlink_fifo_list ();
6467 #endif
6468 exit (rc);
6469 }
6470 else
6471 {
6472 int dummyfd;
6473
6474 #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
6475 close_pgrp_pipe ();
6476 #endif /* JOB_CONTROL && PGRP_PIPE */
6477
6478 close (fildes[1]);
6479
6480 begin_unwind_frame ("read-comsub");
6481 dummyfd = fildes[0];
6482 add_unwind_protect (close, dummyfd);
6483
6484 /* Block SIGINT while we're reading from the pipe. If the child
6485 process gets a SIGINT, it will either handle it or die, and the
6486 read will return. */
6487 BLOCK_SIGNAL (SIGINT, set, oset);
6488 tflag = 0;
6489 istring = read_comsub (fildes[0], quoted, flags, &tflag);
6490
6491 close (fildes[0]);
6492 discard_unwind_frame ("read-comsub");
6493 UNBLOCK_SIGNAL (oset);
6494
6495 current_command_subst_pid = pid;
6496 last_command_exit_value = wait_for (pid, JWAIT_NOTERM);
6497 last_command_subst_pid = pid;
6498 last_made_pid = old_pid;
6499
6500 #if defined (JOB_CONTROL)
6501 /* If last_command_exit_value > 128, then the substituted command
6502 was terminated by a signal. If that signal was SIGINT, then send
6503 SIGINT to ourselves. This will break out of loops, for instance. */
6504 if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
6505 kill (getpid (), SIGINT);
6506 #endif /* JOB_CONTROL */
6507
6508 ret = alloc_word_desc ();
6509 ret->word = istring;
6510 ret->flags = tflag;
6511
6512 return ret;
6513 }
6514 }
6515
6516 /********************************************************
6517 * *
6518 * Utility functions for parameter expansion *
6519 * *
6520 ********************************************************/
6521
6522 #if defined (ARRAY_VARS)
6523
6524 static arrayind_t
6525 array_length_reference (s)
6526 char *s;
6527 {
6528 int len;
6529 arrayind_t ind;
6530 char *akey;
6531 char *t, c;
6532 ARRAY *array;
6533 HASH_TABLE *h;
6534 SHELL_VAR *var;
6535
6536 var = array_variable_part (s, 0, &t, &len);
6537
6538 /* If unbound variables should generate an error, report one and return
6539 failure. */
6540 if ((var == 0 || invisible_p (var) || (assoc_p (var) == 0 && array_p (var) == 0)) && unbound_vars_is_error)
6541 {
6542 c = *--t;
6543 *t = '\0';
6544 set_exit_status (EXECUTION_FAILURE);
6545 err_unboundvar (s);
6546 *t = c;
6547 return (-1);
6548 }
6549 else if (var == 0 || invisible_p (var))
6550 return 0;
6551
6552 /* We support a couple of expansions for variables that are not arrays.
6553 We'll return the length of the value for v[0], and 1 for v[@] or
6554 v[*]. Return 0 for everything else. */
6555
6556 array = array_p (var) ? array_cell (var) : (ARRAY *)NULL;
6557 h = assoc_p (var) ? assoc_cell (var) : (HASH_TABLE *)NULL;
6558
6559 if (ALL_ELEMENT_SUB (t[0]) && t[1] == RBRACK)
6560 {
6561 if (assoc_p (var))
6562 return (h ? assoc_num_elements (h) : 0);
6563 else if (array_p (var))
6564 return (array ? array_num_elements (array) : 0);
6565 else
6566 return (var_isset (var) ? 1 : 0);
6567 }
6568
6569 if (assoc_p (var))
6570 {
6571 t[len - 1] = '\0';
6572 akey = expand_assignment_string_to_string (t, 0); /* [ */
6573 t[len - 1] = RBRACK;
6574 if (akey == 0 || *akey == 0)
6575 {
6576 err_badarraysub (t);
6577 FREE (akey);
6578 return (-1);
6579 }
6580 t = assoc_reference (assoc_cell (var), akey);
6581 free (akey);
6582 }
6583 else
6584 {
6585 ind = array_expand_index (var, t, len, 0);
6586 /* negative subscripts to indexed arrays count back from end */
6587 if (var && array_p (var) && ind < 0)
6588 ind = array_max_index (array_cell (var)) + 1 + ind;
6589 if (ind < 0)
6590 {
6591 err_badarraysub (t);
6592 return (-1);
6593 }
6594 if (array_p (var))
6595 t = array_reference (array, ind);
6596 else
6597 t = (ind == 0) ? value_cell (var) : (char *)NULL;
6598 }
6599
6600 len = MB_STRLEN (t);
6601 return (len);
6602 }
6603 #endif /* ARRAY_VARS */
6604
6605 static int
6606 valid_brace_expansion_word (name, var_is_special)
6607 char *name;
6608 int var_is_special;
6609 {
6610 if (DIGIT (*name) && all_digits (name))
6611 return 1;
6612 else if (var_is_special)
6613 return 1;
6614 #if defined (ARRAY_VARS)
6615 else if (valid_array_reference (name, 0))
6616 return 1;
6617 #endif /* ARRAY_VARS */
6618 else if (legal_identifier (name))
6619 return 1;
6620 else
6621 return 0;
6622 }
6623
6624 static int
6625 chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
6626 char *name;
6627 int quoted, pflags;
6628 int *quoted_dollar_atp, *contains_dollar_at;
6629 {
6630 char *temp1;
6631
6632 if (name == 0)
6633 {
6634 if (quoted_dollar_atp)
6635 *quoted_dollar_atp = 0;
6636 if (contains_dollar_at)
6637 *contains_dollar_at = 0;
6638 return 0;
6639 }
6640
6641 /* check for $@ and $* */
6642 if (name[0] == '@' && name[1] == 0)
6643 {
6644 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
6645 *quoted_dollar_atp = 1;
6646 if (contains_dollar_at)
6647 *contains_dollar_at = 1;
6648 return 1;
6649 }
6650 else if (name[0] == '*' && name[1] == '\0' && quoted == 0)
6651 {
6652 /* Need more checks here that parallel what string_list_pos_params and
6653 param_expand do. Check expand_no_split_dollar_star and ??? */
6654 if (contains_dollar_at && expand_no_split_dollar_star == 0)
6655 *contains_dollar_at = 1;
6656 return 1;
6657 }
6658
6659 /* Now check for ${array[@]} and ${array[*]} */
6660 #if defined (ARRAY_VARS)
6661 else if (valid_array_reference (name, 0))
6662 {
6663 temp1 = mbschr (name, LBRACK);
6664 if (temp1 && temp1[1] == '@' && temp1[2] == RBRACK)
6665 {
6666 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
6667 *quoted_dollar_atp = 1;
6668 if (contains_dollar_at)
6669 *contains_dollar_at = 1;
6670 return 1;
6671 }
6672 /* ${array[*]}, when unquoted, should be treated like ${array[@]},
6673 which should result in separate words even when IFS is unset. */
6674 if (temp1 && temp1[1] == '*' && temp1[2] == RBRACK && quoted == 0)
6675 {
6676 if (contains_dollar_at)
6677 *contains_dollar_at = 1;
6678 return 1;
6679 }
6680 }
6681 #endif
6682 return 0;
6683 }
6684
6685 /* Parameter expand NAME, and return a new string which is the expansion,
6686 or NULL if there was no expansion. NAME is as given in ${NAMEcWORD}.
6687 VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
6688 the shell, e.g., "@", "$", "*", etc. QUOTED, if non-zero, means that
6689 NAME was found inside of a double-quoted expression. */
6690 static WORD_DESC *
6691 parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp)
6692 char *name;
6693 int var_is_special, quoted, pflags;
6694 arrayind_t *indp;
6695 {
6696 WORD_DESC *ret;
6697 char *temp, *tt;
6698 intmax_t arg_index;
6699 SHELL_VAR *var;
6700 int atype, rflags;
6701 arrayind_t ind;
6702
6703 ret = 0;
6704 temp = 0;
6705 rflags = 0;
6706
6707 if (indp)
6708 *indp = INTMAX_MIN;
6709
6710 /* Handle multiple digit arguments, as in ${11}. */
6711 if (legal_number (name, &arg_index))
6712 {
6713 tt = get_dollar_var_value (arg_index);
6714 if (tt)
6715 temp = (*tt && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
6716 ? quote_string (tt)
6717 : quote_escapes (tt);
6718 else
6719 temp = (char *)NULL;
6720 FREE (tt);
6721 }
6722 else if (var_is_special) /* ${@} */
6723 {
6724 int sindex;
6725 tt = (char *)xmalloc (2 + strlen (name));
6726 tt[sindex = 0] = '$';
6727 strcpy (tt + 1, name);
6728
6729 ret = param_expand (tt, &sindex, quoted, (int *)NULL, (int *)NULL,
6730 (int *)NULL, (int *)NULL, pflags);
6731 free (tt);
6732 }
6733 #if defined (ARRAY_VARS)
6734 else if (valid_array_reference (name, 0))
6735 {
6736 expand_arrayref:
6737 var = array_variable_part (name, 0, &tt, (int *)0);
6738 /* These are the cases where word splitting will not be performed */
6739 if (pflags & PF_ASSIGNRHS)
6740 {
6741 if (ALL_ELEMENT_SUB (tt[0]) && tt[1] == RBRACK)
6742 {
6743 /* Only treat as double quoted if array variable */
6744 if (var && (array_p (var) || assoc_p (var)))
6745 temp = array_value (name, quoted|Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind);
6746 else
6747 temp = array_value (name, quoted, 0, &atype, &ind);
6748 }
6749 else
6750 temp = array_value (name, quoted, 0, &atype, &ind);
6751 }
6752 /* Posix interp 888 */
6753 else if (pflags & PF_NOSPLIT2)
6754 {
6755 /* Special cases, then general case, for each of A[@], A[*], A[n] */
6756 #if defined (HANDLE_MULTIBYTE)
6757 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
6758 #else
6759 if (tt[0] == '@' && tt[1] == RBRACK && var && quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
6760 #endif
6761 temp = array_value (name, Q_DOUBLE_QUOTES, AV_ASSIGNRHS, &atype, &ind);
6762 else if (tt[0] == '@' && tt[1] == RBRACK)
6763 temp = array_value (name, quoted, 0, &atype, &ind);
6764 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
6765 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind);
6766 else if (tt[0] == '*' && tt[1] == RBRACK)
6767 temp = array_value (name, quoted, 0, &atype, &ind);
6768 else
6769 temp = array_value (name, quoted, 0, &atype, &ind);
6770 }
6771 else if (tt[0] == '*' && tt[1] == RBRACK && expand_no_split_dollar_star && ifs_is_null)
6772 temp = array_value (name, Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT, 0, &atype, &ind);
6773 else
6774 temp = array_value (name, quoted, 0, &atype, &ind);
6775 if (atype == 0 && temp)
6776 {
6777 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
6778 ? quote_string (temp)
6779 : quote_escapes (temp);
6780 rflags |= W_ARRAYIND;
6781 if (indp)
6782 *indp = ind;
6783 }
6784 else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
6785 rflags |= W_HASQUOTEDNULL;
6786 }
6787 #endif
6788 else if (var = find_variable (name))
6789 {
6790 if (var_isset (var) && invisible_p (var) == 0)
6791 {
6792 #if defined (ARRAY_VARS)
6793 if (assoc_p (var))
6794 temp = assoc_reference (assoc_cell (var), "0");
6795 else if (array_p (var))
6796 temp = array_reference (array_cell (var), 0);
6797 else
6798 temp = value_cell (var);
6799 #else
6800 temp = value_cell (var);
6801 #endif
6802
6803 if (temp)
6804 temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
6805 ? quote_string (temp)
6806 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
6807 : quote_escapes (temp));
6808 }
6809 else
6810 temp = (char *)NULL;
6811 }
6812 else if (var = find_variable_last_nameref (name, 0))
6813 {
6814 temp = nameref_cell (var);
6815 #if defined (ARRAY_VARS)
6816 /* Handle expanding nameref whose value is x[n] */
6817 if (temp && *temp && valid_array_reference (temp, 0))
6818 {
6819 name = temp;
6820 goto expand_arrayref;
6821 }
6822 else
6823 #endif
6824 /* y=2 ; typeset -n x=y; echo ${x} is not the same as echo ${2} in ksh */
6825 if (temp && *temp && legal_identifier (temp) == 0)
6826 {
6827 set_exit_status (EXECUTION_FAILURE);
6828 report_error (_("%s: invalid variable name for name reference"), temp);
6829 temp = &expand_param_error;
6830 }
6831 else
6832 temp = (char *)NULL;
6833 }
6834 else
6835 temp = (char *)NULL;
6836
6837 if (ret == 0)
6838 {
6839 ret = alloc_word_desc ();
6840 ret->word = temp;
6841 ret->flags |= rflags;
6842 }
6843 return ret;
6844 }
6845
6846 static char *
6847 parameter_brace_find_indir (name, var_is_special, quoted, find_nameref)
6848 char *name;
6849 int var_is_special, quoted, find_nameref;
6850 {
6851 char *temp, *t;
6852 WORD_DESC *w;
6853 SHELL_VAR *v;
6854 int pflags, oldex;
6855
6856 if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) &&
6857 nameref_p (v) && (t = nameref_cell (v)) && *t)
6858 return (savestring (t));
6859
6860 /* If var_is_special == 0, and name is not an array reference, this does
6861 more expansion than necessary. It should really look up the variable's
6862 value and not try to expand it. */
6863 pflags = PF_IGNUNBOUND;
6864 /* Note that we're not going to be doing word splitting here */
6865 if (var_is_special)
6866 {
6867 pflags |= PF_ASSIGNRHS; /* suppresses word splitting */
6868 oldex = expand_no_split_dollar_star;
6869 expand_no_split_dollar_star = 1;
6870 }
6871 w = parameter_brace_expand_word (name, var_is_special, quoted, pflags, 0);
6872 if (var_is_special)
6873 expand_no_split_dollar_star = oldex;
6874
6875 t = w->word;
6876 /* Have to dequote here if necessary */
6877 if (t)
6878 {
6879 temp = ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || var_is_special)
6880 ? dequote_string (t)
6881 : dequote_escapes (t);
6882 free (t);
6883 t = temp;
6884 }
6885 dispose_word_desc (w);
6886
6887 return t;
6888 }
6889
6890 /* Expand an indirect reference to a variable: ${!NAME} expands to the
6891 value of the variable whose name is the value of NAME. */
6892 static WORD_DESC *
6893 parameter_brace_expand_indir (name, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
6894 char *name;
6895 int var_is_special, quoted, pflags;
6896 int *quoted_dollar_atp, *contains_dollar_at;
6897 {
6898 char *t;
6899 WORD_DESC *w;
6900 SHELL_VAR *v;
6901
6902 /* See if it's a nameref first, behave in ksh93-compatible fashion.
6903 There is at least one incompatibility: given ${!foo[0]} where foo=bar,
6904 bash performs an indirect lookup on foo[0] and expands the result;
6905 ksh93 expands bar[0]. We could do that here -- there are enough usable
6906 primitives to do that -- but do not at this point. */
6907 if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0)))
6908 {
6909 if (nameref_p (v) && (t = nameref_cell (v)) && *t)
6910 {
6911 w = alloc_word_desc ();
6912 w->word = savestring (t);
6913 w->flags = 0;
6914 return w;
6915 }
6916 }
6917
6918 /* An indirect reference to a positional parameter or a special parameter
6919 is ok. Indirect references to array references, as explained above, are
6920 ok (currently). Only references to unset variables are errors at this
6921 point. */
6922 if (legal_identifier (name) && v == 0)
6923 {
6924 report_error (_("%s: invalid indirect expansion"), name);
6925 w = alloc_word_desc ();
6926 w->word = &expand_param_error;
6927 w->flags = 0;
6928 return (w);
6929 }
6930
6931 t = parameter_brace_find_indir (name, var_is_special, quoted, 0);
6932
6933 chk_atstar (t, quoted, pflags, quoted_dollar_atp, contains_dollar_at);
6934
6935 #if defined (ARRAY_VARS)
6936 /* Array references to unset variables are also an error */
6937 if (t == 0 && valid_array_reference (name, 0))
6938 {
6939 v = array_variable_part (name, 0, (char **)0, (int *)0);
6940 if (v == 0)
6941 {
6942 report_error (_("%s: invalid indirect expansion"), name);
6943 w = alloc_word_desc ();
6944 w->word = &expand_param_error;
6945 w->flags = 0;
6946 return (w);
6947 }
6948 else
6949 return (WORD_DESC *)NULL;
6950 }
6951 #endif
6952
6953 if (t == 0)
6954 return (WORD_DESC *)NULL;
6955
6956 if (valid_brace_expansion_word (t, SPECIAL_VAR (t, 0)) == 0)
6957 {
6958 report_error (_("%s: invalid variable name"), t);
6959 free (t);
6960 w = alloc_word_desc ();
6961 w->word = &expand_param_error;
6962 w->flags = 0;
6963 return (w);
6964 }
6965
6966 w = parameter_brace_expand_word (t, SPECIAL_VAR(t, 0), quoted, pflags, 0);
6967 free (t);
6968
6969 return w;
6970 }
6971
6972 /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
6973 depending on the value of C, the separating character. C can be one of
6974 "-", "+", or "=". QUOTED is true if the entire brace expression occurs
6975 between double quotes. */
6976 static WORD_DESC *
6977 parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdollarat)
6978 char *name, *value;
6979 int op, quoted, pflags, *qdollaratp, *hasdollarat;
6980 {
6981 WORD_DESC *w;
6982 WORD_LIST *l, *tl;
6983 char *t, *t1, *temp, *vname;
6984 int l_hasdollat, sindex;
6985 SHELL_VAR *v;
6986
6987 /*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/
6988 /* If the entire expression is between double quotes, we want to treat
6989 the value as a double-quoted string, with the exception that we strip
6990 embedded unescaped double quotes (for sh backwards compatibility). */
6991 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && *value)
6992 {
6993 sindex = 0;
6994 temp = string_extract_double_quoted (value, &sindex, SX_STRIPDQ);
6995 }
6996 else
6997 temp = value;
6998
6999 w = alloc_word_desc ();
7000 l_hasdollat = 0;
7001 l = *temp ? expand_string_for_rhs (temp, quoted, op, pflags, &l_hasdollat, (int *)NULL)
7002 : (WORD_LIST *)0;
7003 if (hasdollarat)
7004 *hasdollarat = l_hasdollat || (l && l->next);
7005 if (temp != value)
7006 free (temp);
7007
7008 /* list_string takes multiple CTLNULs and turns them into an empty word
7009 with W_SAWQUOTEDNULL set. Turn it back into a single CTLNUL for the
7010 rest of this function and the caller. */
7011 for (tl = l; tl; tl = tl->next)
7012 {
7013 if (tl->word && (tl->word->word == 0 || tl->word->word[0] == 0) &&
7014 (tl->word->flags | W_SAWQUOTEDNULL))
7015 {
7016 t = make_quoted_char ('\0');
7017 FREE (tl->word->word);
7018 tl->word->word = t;
7019 tl->word->flags |= W_QUOTED|W_HASQUOTEDNULL;
7020 tl->word->flags &= ~W_SAWQUOTEDNULL;
7021 }
7022 }
7023
7024 if (l)
7025 {
7026 /* If l->next is not null, we know that TEMP contained "$@", since that
7027 is the only expansion that creates more than one word. */
7028 if (qdollaratp && ((l_hasdollat && quoted) || l->next))
7029 {
7030 /*itrace("parameter_brace_expand_rhs: %s:%s: l != NULL, set *qdollaratp", name, value);*/
7031 *qdollaratp = 1;
7032 }
7033
7034 /* The expansion of TEMP returned something. We need to treat things
7035 slightly differently if L_HASDOLLAT is non-zero. If we have "$@",
7036 the individual words have already been quoted. We need to turn them
7037 into a string with the words separated by the first character of
7038 $IFS without any additional quoting, so string_list_dollar_at won't
7039 do the right thing. If IFS is null, we want "$@" to split into
7040 separate arguments, not be concatenated, so we use string_list_internal
7041 and mark the word to be split on spaces later. We use
7042 string_list_dollar_star for "$@" otherwise. */
7043 if (l->next && ifs_is_null)
7044 {
7045 temp = string_list_internal (l, " ");
7046 w->flags |= W_SPLITSPACE;
7047 }
7048 else if (l_hasdollat || l->next)
7049 temp = string_list_dollar_star (l, quoted, 0);
7050 else
7051 {
7052 temp = string_list (l);
7053 if (temp && (QUOTED_NULL (temp) == 0) && (l->word->flags & W_SAWQUOTEDNULL))
7054 w->flags |= W_SAWQUOTEDNULL; /* XXX */
7055 }
7056
7057 /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
7058 a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
7059 flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
7060 expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7061 (which is more paranoia than anything else), we need to return the
7062 quoted null string and set the flags to indicate it. */
7063 if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp) && QUOTED_NULL (l->word->word) && (l->word->flags & W_HASQUOTEDNULL))
7064 {
7065 w->flags |= W_HASQUOTEDNULL;
7066 /*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null, turning off qdollaratp", name, value);*/
7067 /* If we return a quoted null with L_HASDOLLARAT, we either have a
7068 construct like "${@-$@}" or "${@-${@-$@}}" with no positional
7069 parameters or a quoted expansion of "$@" with $1 == ''. In either
7070 case, we don't want to enable special handling of $@. */
7071 if (qdollaratp && l_hasdollat)
7072 *qdollaratp = 0;
7073 }
7074 dispose_words (l);
7075 }
7076 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && l_hasdollat)
7077 {
7078 /* Posix interp 221 changed the rules on this. The idea is that
7079 something like "$xxx$@" should expand the same as "${foo-$xxx$@}"
7080 when foo and xxx are unset. The problem is that it's not in any
7081 way backwards compatible and few other shells do it. We're eventually
7082 going to try and split the difference (heh) a little bit here. */
7083 /* l_hasdollat == 1 means we saw a quoted dollar at. */
7084
7085 /* The brace expansion occurred between double quotes and there was
7086 a $@ in TEMP. It does not matter if the $@ is quoted, as long as
7087 it does not expand to anything. In this case, we want to return
7088 a quoted empty string. Posix interp 888 */
7089 temp = make_quoted_char ('\0');
7090 w->flags |= W_HASQUOTEDNULL;
7091 /*itrace("parameter_brace_expand_rhs (%s:%s): returning quoted null", name, value);*/
7092 }
7093 else
7094 temp = (char *)NULL;
7095
7096 if (op == '-' || op == '+')
7097 {
7098 w->word = temp;
7099 return w;
7100 }
7101
7102 /* op == '=' */
7103 t1 = temp ? dequote_string (temp) : savestring ("");
7104 free (temp);
7105
7106 /* bash-4.4/5.0 */
7107 vname = name;
7108 if (*name == '!' &&
7109 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1]) || VALID_INDIR_PARAM (name[1])))
7110 {
7111 vname = parameter_brace_find_indir (name + 1, SPECIAL_VAR (name, 1), quoted, 1);
7112 if (vname == 0 || *vname == 0)
7113 {
7114 report_error (_("%s: invalid indirect expansion"), name);
7115 free (vname);
7116 free (t1);
7117 dispose_word (w);
7118 return &expand_wdesc_error;
7119 }
7120 if (legal_identifier (vname) == 0)
7121 {
7122 report_error (_("%s: invalid variable name"), vname);
7123 free (vname);
7124 free (t1);
7125 dispose_word (w);
7126 return &expand_wdesc_error;
7127 }
7128 }
7129
7130 #if defined (ARRAY_VARS)
7131 if (valid_array_reference (vname, 0))
7132 v = assign_array_element (vname, t1, 0);
7133 else
7134 #endif /* ARRAY_VARS */
7135 v = bind_variable (vname, t1, 0);
7136
7137 if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */
7138 {
7139 if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct)
7140 {
7141 last_command_exit_value = EXECUTION_FAILURE;
7142 exp_jump_to_top_level (FORCE_EOF);
7143 }
7144 else
7145 {
7146 if (vname != name)
7147 free (vname);
7148 last_command_exit_value = EX_BADUSAGE;
7149 exp_jump_to_top_level (DISCARD);
7150 }
7151 }
7152
7153 stupidly_hack_special_variables (vname);
7154
7155 if (vname != name)
7156 free (vname);
7157
7158 /* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
7159
7160 /* If we are double-quoted or if we are not going to be performing word
7161 splitting, we want to quote the value we return appropriately, like
7162 the other expansions this function handles. */
7163 w->word = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (t1) : quote_escapes (t1);
7164 /* If we have something that's non-null, that's not a quoted null string,
7165 and we're not going to be performing word splitting (we know we're not
7166 because the operator is `='), we can forget we saw a quoted null. */
7167 if (w->word && w->word[0] && QUOTED_NULL (w->word) == 0)
7168 w->flags &= ~W_SAWQUOTEDNULL;
7169 free (t1);
7170
7171 /* If we convert a null string into a quoted null, make sure the caller
7172 knows it. */
7173 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && QUOTED_NULL (w->word))
7174 w->flags |= W_HASQUOTEDNULL;
7175
7176 return w;
7177 }
7178
7179 /* Deal with the right hand side of a ${name:?value} expansion in the case
7180 that NAME is null or not set. If VALUE is non-null it is expanded and
7181 used as the error message to print, otherwise a standard message is
7182 printed. */
7183 static void
7184 parameter_brace_expand_error (name, value, check_null)
7185 char *name, *value;
7186 int check_null;
7187 {
7188 WORD_LIST *l;
7189 char *temp;
7190
7191 set_exit_status (EXECUTION_FAILURE); /* ensure it's non-zero */
7192 if (value && *value)
7193 {
7194 l = expand_string (value, 0);
7195 temp = string_list (l);
7196 report_error ("%s: %s", name, temp ? temp : ""); /* XXX was value not "" */
7197 FREE (temp);
7198 dispose_words (l);
7199 }
7200 else if (check_null == 0)
7201 report_error (_("%s: parameter not set"), name);
7202 else
7203 report_error (_("%s: parameter null or not set"), name);
7204
7205 /* Free the data we have allocated during this expansion, since we
7206 are about to longjmp out. */
7207 free (name);
7208 FREE (value);
7209 }
7210
7211 /* Return 1 if NAME is something for which parameter_brace_expand_length is
7212 OK to do. */
7213 static int
7214 valid_length_expression (name)
7215 char *name;
7216 {
7217 return (name[1] == '\0' || /* ${#} */
7218 ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0') || /* special param */
7219 (DIGIT (name[1]) && all_digits (name + 1)) || /* ${#11} */
7220 #if defined (ARRAY_VARS)
7221 valid_array_reference (name + 1, 0) || /* ${#a[7]} */
7222 #endif
7223 legal_identifier (name + 1)); /* ${#PS1} */
7224 }
7225
7226 /* Handle the parameter brace expansion that requires us to return the
7227 length of a parameter. */
7228 static intmax_t
7229 parameter_brace_expand_length (name)
7230 char *name;
7231 {
7232 char *t, *newname;
7233 intmax_t number, arg_index;
7234 WORD_LIST *list;
7235 SHELL_VAR *var;
7236
7237 var = (SHELL_VAR *)NULL;
7238
7239 if (name[1] == '\0') /* ${#} */
7240 number = number_of_args ();
7241 else if (DOLLAR_AT_STAR (name[1]) && name[2] == '\0') /* ${#@}, ${#*} */
7242 number = number_of_args ();
7243 else if ((sh_syntaxtab[(unsigned char) name[1]] & CSPECVAR) && name[2] == '\0')
7244 {
7245 /* Take the lengths of some of the shell's special parameters. */
7246 switch (name[1])
7247 {
7248 case '-':
7249 t = which_set_flags ();
7250 break;
7251 case '?':
7252 t = itos (last_command_exit_value);
7253 break;
7254 case '$':
7255 t = itos (dollar_dollar_pid);
7256 break;
7257 case '!':
7258 if (last_asynchronous_pid == NO_PID)
7259 t = (char *)NULL; /* XXX - error if set -u set? */
7260 else
7261 t = itos (last_asynchronous_pid);
7262 break;
7263 case '#':
7264 t = itos (number_of_args ());
7265 break;
7266 }
7267 number = STRLEN (t);
7268 FREE (t);
7269 }
7270 #if defined (ARRAY_VARS)
7271 else if (valid_array_reference (name + 1, 0))
7272 number = array_length_reference (name + 1);
7273 #endif /* ARRAY_VARS */
7274 else
7275 {
7276 number = 0;
7277
7278 if (legal_number (name + 1, &arg_index)) /* ${#1} */
7279 {
7280 t = get_dollar_var_value (arg_index);
7281 if (t == 0 && unbound_vars_is_error)
7282 return INTMAX_MIN;
7283 number = MB_STRLEN (t);
7284 FREE (t);
7285 }
7286 #if defined (ARRAY_VARS)
7287 else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && (array_p (var) || assoc_p (var)))
7288 {
7289 if (assoc_p (var))
7290 t = assoc_reference (assoc_cell (var), "0");
7291 else
7292 t = array_reference (array_cell (var), 0);
7293 if (t == 0 && unbound_vars_is_error)
7294 return INTMAX_MIN;
7295 number = MB_STRLEN (t);
7296 }
7297 #endif
7298 /* Fast path for the common case of taking the length of a non-dynamic
7299 scalar variable value. */
7300 else if ((var || (var = find_variable (name + 1))) &&
7301 invisible_p (var) == 0 &&
7302 array_p (var) == 0 && assoc_p (var) == 0 &&
7303 var->dynamic_value == 0)
7304 number = value_cell (var) ? MB_STRLEN (value_cell (var)) : 0;
7305 else if (var == 0 && unbound_vars_is_error == 0)
7306 number = 0;
7307 else /* ${#PS1} */
7308 {
7309 newname = savestring (name);
7310 newname[0] = '$';
7311 list = expand_string (newname, Q_DOUBLE_QUOTES);
7312 t = list ? string_list (list) : (char *)NULL;
7313 free (newname);
7314 if (list)
7315 dispose_words (list);
7316
7317 number = t ? MB_STRLEN (t) : 0;
7318 FREE (t);
7319 }
7320 }
7321
7322 return (number);
7323 }
7324
7325 /* Skip characters in SUBSTR until DELIM. SUBSTR is an arithmetic expression,
7326 so we do some ad-hoc parsing of an arithmetic expression to find
7327 the first DELIM, instead of using strchr(3). Two rules:
7328 1. If the substring contains a `(', read until closing `)'.
7329 2. If the substring contains a `?', read past one `:' for each `?'.
7330 The SD_ARITHEXP flag to skip_to_delim takes care of doing this.
7331 */
7332
7333 static char *
7334 skiparith (substr, delim)
7335 char *substr;
7336 int delim;
7337 {
7338 int i;
7339 char delims[2];
7340
7341 delims[0] = delim;
7342 delims[1] = '\0';
7343
7344 i = skip_to_delim (substr, 0, delims, SD_ARITHEXP);
7345 return (substr + i);
7346 }
7347
7348 /* Verify and limit the start and end of the desired substring. If
7349 VTYPE == 0, a regular shell variable is being used; if it is 1,
7350 then the positional parameters are being used; if it is 2, then
7351 VALUE is really a pointer to an array variable that should be used.
7352 Return value is 1 if both values were OK, 0 if there was a problem
7353 with an invalid expression, or -1 if the values were out of range. */
7354 static int
7355 verify_substring_values (v, value, substr, vtype, e1p, e2p)
7356 SHELL_VAR *v;
7357 char *value, *substr;
7358 int vtype;
7359 intmax_t *e1p, *e2p;
7360 {
7361 char *t, *temp1, *temp2;
7362 arrayind_t len;
7363 int expok;
7364 #if defined (ARRAY_VARS)
7365 ARRAY *a;
7366 HASH_TABLE *h;
7367 #endif
7368
7369 /* duplicate behavior of strchr(3) */
7370 t = skiparith (substr, ':');
7371 if (*t && *t == ':')
7372 *t = '\0';
7373 else
7374 t = (char *)0;
7375
7376 temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES);
7377 *e1p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */
7378 free (temp1);
7379 if (expok == 0)
7380 return (0);
7381
7382 len = -1; /* paranoia */
7383 switch (vtype)
7384 {
7385 case VT_VARIABLE:
7386 case VT_ARRAYMEMBER:
7387 len = MB_STRLEN (value);
7388 break;
7389 case VT_POSPARMS:
7390 len = number_of_args () + 1;
7391 if (*e1p == 0)
7392 len++; /* add one arg if counting from $0 */
7393 break;
7394 #if defined (ARRAY_VARS)
7395 case VT_ARRAYVAR:
7396 /* For arrays, the first value deals with array indices. Negative
7397 offsets count from one past the array's maximum index. Associative
7398 arrays treat the number of elements as the maximum index. */
7399 if (assoc_p (v))
7400 {
7401 h = assoc_cell (v);
7402 len = assoc_num_elements (h) + (*e1p < 0);
7403 }
7404 else
7405 {
7406 a = (ARRAY *)value;
7407 len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
7408 }
7409 break;
7410 #endif
7411 }
7412
7413 if (len == -1) /* paranoia */
7414 return -1;
7415
7416 if (*e1p < 0) /* negative offsets count from end */
7417 *e1p += len;
7418
7419 if (*e1p > len || *e1p < 0)
7420 return (-1);
7421
7422 #if defined (ARRAY_VARS)
7423 /* For arrays, the second offset deals with the number of elements. */
7424 if (vtype == VT_ARRAYVAR)
7425 len = assoc_p (v) ? assoc_num_elements (h) : array_num_elements (a);
7426 #endif
7427
7428 if (t)
7429 {
7430 t++;
7431 temp2 = savestring (t);
7432 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES);
7433 free (temp2);
7434 t[-1] = ':';
7435 *e2p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */
7436 free (temp1);
7437 if (expok == 0)
7438 return (0);
7439
7440 /* Should we allow positional parameter length < 0 to count backwards
7441 from end of positional parameters? */
7442 #if 1
7443 if ((vtype == VT_ARRAYVAR || vtype == VT_POSPARMS) && *e2p < 0)
7444 #else /* XXX - TAG: bash-5.1 */
7445 if (vtype == VT_ARRAYVAR && *e2p < 0)
7446 #endif
7447 {
7448 internal_error (_("%s: substring expression < 0"), t);
7449 return (0);
7450 }
7451 #if defined (ARRAY_VARS)
7452 /* In order to deal with sparse arrays, push the intelligence about how
7453 to deal with the number of elements desired down to the array-
7454 specific functions. */
7455 if (vtype != VT_ARRAYVAR)
7456 #endif
7457 {
7458 if (*e2p < 0)
7459 {
7460 *e2p += len;
7461 if (*e2p < 0 || *e2p < *e1p)
7462 {
7463 internal_error (_("%s: substring expression < 0"), t);
7464 return (0);
7465 }
7466 }
7467 else
7468 *e2p += *e1p; /* want E2 chars starting at E1 */
7469 if (*e2p > len)
7470 *e2p = len;
7471 }
7472 }
7473 else
7474 *e2p = len;
7475
7476 return (1);
7477 }
7478
7479 /* Return the type of variable specified by VARNAME (simple variable,
7480 positional param, or array variable). Also return the value specified
7481 by VARNAME (value of a variable or a reference to an array element).
7482 QUOTED is the standard description of quoting state, using Q_* defines.
7483 FLAGS is currently a set of flags to pass to array_value. If IND is
7484 non-null and not INTMAX_MIN, and FLAGS includes AV_USEIND, IND is
7485 passed to array_value so the array index is not computed again.
7486 If this returns VT_VARIABLE, the caller assumes that CTLESC and CTLNUL
7487 characters in the value are quoted with CTLESC and takes appropriate
7488 steps. For convenience, *VALP is set to the dequoted VALUE. */
7489 static int
7490 get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
7491 char *varname, *value;
7492 arrayind_t ind;
7493 int quoted, flags;
7494 SHELL_VAR **varp;
7495 char **valp;
7496 {
7497 int vtype, want_indir;
7498 char *temp, *vname;
7499 SHELL_VAR *v;
7500 arrayind_t lind;
7501
7502 want_indir = *varname == '!' &&
7503 (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1])
7504 || VALID_INDIR_PARAM (varname[1]));
7505 if (want_indir)
7506 vname = parameter_brace_find_indir (varname+1, SPECIAL_VAR (varname, 1), quoted, 1);
7507 /* XXX - what if vname == 0 || *vname == 0 ? */
7508 else
7509 vname = varname;
7510
7511 if (vname == 0)
7512 {
7513 vtype = VT_VARIABLE;
7514 *varp = (SHELL_VAR *)NULL;
7515 *valp = (char *)NULL;
7516 return (vtype);
7517 }
7518
7519 /* This sets vtype to VT_VARIABLE or VT_POSPARMS */
7520 vtype = STR_DOLLAR_AT_STAR (vname);
7521 if (vtype == VT_POSPARMS && vname[0] == '*')
7522 vtype |= VT_STARSUB;
7523 *varp = (SHELL_VAR *)NULL;
7524
7525 #if defined (ARRAY_VARS)
7526 if (valid_array_reference (vname, 0))
7527 {
7528 v = array_variable_part (vname, 0, &temp, (int *)0);
7529 /* If we want to signal array_value to use an already-computed index,
7530 set LIND to that index */
7531 lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0;
7532 if (v && invisible_p (v))
7533 {
7534 vtype = VT_ARRAYMEMBER;
7535 *varp = (SHELL_VAR *)NULL;
7536 *valp = (char *)NULL;
7537 }
7538 if (v && (array_p (v) || assoc_p (v)))
7539 {
7540 if (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK)
7541 {
7542 /* Callers have to differentiate between indexed and associative */
7543 vtype = VT_ARRAYVAR;
7544 if (temp[0] == '*')
7545 vtype |= VT_STARSUB;
7546 *valp = array_p (v) ? (char *)array_cell (v) : (char *)assoc_cell (v);
7547 }
7548 else
7549 {
7550 vtype = VT_ARRAYMEMBER;
7551 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
7552 }
7553 *varp = v;
7554 }
7555 else if (v && (ALL_ELEMENT_SUB (temp[0]) && temp[1] == RBRACK))
7556 {
7557 vtype = VT_VARIABLE;
7558 *varp = v;
7559 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
7560 *valp = value ? dequote_string (value) : (char *)NULL;
7561 else
7562 *valp = value ? dequote_escapes (value) : (char *)NULL;
7563 }
7564 else
7565 {
7566 vtype = VT_ARRAYMEMBER;
7567 *varp = v;
7568 *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, (int *)NULL, &lind);
7569 }
7570 }
7571 else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
7572 {
7573 vtype = VT_ARRAYMEMBER;
7574 *varp = v;
7575 *valp = assoc_p (v) ? assoc_reference (assoc_cell (v), "0") : array_reference (array_cell (v), 0);
7576 }
7577 else
7578 #endif
7579 {
7580 if (value && vtype == VT_VARIABLE)
7581 {
7582 *varp = find_variable (vname);
7583 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
7584 *valp = dequote_string (value);
7585 else
7586 *valp = dequote_escapes (value);
7587 }
7588 else
7589 *valp = value;
7590 }
7591
7592 if (want_indir)
7593 free (vname);
7594
7595 return vtype;
7596 }
7597
7598 /***********************************************************/
7599 /* */
7600 /* Functions to perform transformations on variable values */
7601 /* */
7602 /***********************************************************/
7603
7604 static char *
7605 string_var_assignment (v, s)
7606 SHELL_VAR *v;
7607 char *s;
7608 {
7609 char flags[MAX_ATTRIBUTES], *ret, *val;
7610 int i;
7611
7612 val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0);
7613 i = var_attribute_string (v, 0, flags);
7614 if (i == 0 && val == 0)
7615 return (char *)NULL;
7616
7617 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES);
7618 if (i > 0 && val == 0)
7619 sprintf (ret, "declare -%s %s", flags, v->name);
7620 else if (i > 0)
7621 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
7622 else
7623 sprintf (ret, "%s=%s", v->name, val);
7624 free (val);
7625 return ret;
7626 }
7627
7628 #if defined (ARRAY_VARS)
7629 static char *
7630 array_var_assignment (v, itype, quoted, atype)
7631 SHELL_VAR *v;
7632 int itype, quoted, atype;
7633 {
7634 char *ret, *val, flags[MAX_ATTRIBUTES];
7635 int i;
7636
7637 if (v == 0)
7638 return (char *)NULL;
7639 if (atype == 2)
7640 val = array_p (v) ? array_to_kvpair (array_cell (v), 0)
7641 : assoc_to_kvpair (assoc_cell (v), 0);
7642 else
7643 val = array_p (v) ? array_to_assign (array_cell (v), 0)
7644 : assoc_to_assign (assoc_cell (v), 0);
7645
7646 if (val == 0 && (invisible_p (v) || var_isset (v) == 0))
7647 ; /* placeholder */
7648 else if (val == 0)
7649 {
7650 val = (char *)xmalloc (3);
7651 val[0] = LPAREN;
7652 val[1] = RPAREN;
7653 val[2] = 0;
7654 }
7655 else
7656 {
7657 ret = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) ? quote_string (val) : quote_escapes (val);
7658 free (val);
7659 val = ret;
7660 }
7661
7662 if (atype == 2)
7663 return val;
7664
7665 i = var_attribute_string (v, 0, flags);
7666 ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16);
7667 if (val)
7668 sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
7669 else
7670 sprintf (ret, "declare -%s %s", flags, v->name);
7671 free (val);
7672 return ret;
7673 }
7674 #endif
7675
7676 static char *
7677 pos_params_assignment (list, itype, quoted)
7678 WORD_LIST *list;
7679 int itype;
7680 int quoted;
7681 {
7682 char *temp, *ret;
7683
7684 /* first, we transform the list to quote each word. */
7685 temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted);
7686 ret = (char *)xmalloc (strlen (temp) + 8);
7687 strcpy (ret, "set -- ");
7688 strcpy (ret + 7, temp);
7689 free (temp);
7690 return ret;
7691 }
7692
7693 static char *
7694 string_transform (xc, v, s)
7695 int xc;
7696 SHELL_VAR *v;
7697 char *s;
7698 {
7699 char *ret, flags[MAX_ATTRIBUTES], *t;
7700 int i;
7701
7702 if (((xc == 'A' || xc == 'a') && v == 0))
7703 return (char *)NULL;
7704 else if (xc != 'a' && xc != 'A' && s == 0)
7705 return (char *)NULL;
7706
7707 switch (xc)
7708 {
7709 /* Transformations that interrogate the variable */
7710 case 'a':
7711 i = var_attribute_string (v, 0, flags);
7712 ret = (i > 0) ? savestring (flags) : (char *)NULL;
7713 break;
7714 case 'A':
7715 ret = string_var_assignment (v, s);
7716 break;
7717 case 'K':
7718 ret = sh_quote_reusable (s, 0);
7719 break;
7720 /* Transformations that modify the variable's value */
7721 case 'E':
7722 t = ansiexpand (s, 0, strlen (s), (int *)0);
7723 ret = dequote_escapes (t);
7724 free (t);
7725 break;
7726 case 'P':
7727 ret = decode_prompt_string (s);
7728 break;
7729 case 'Q':
7730 ret = sh_quote_reusable (s, 0);
7731 break;
7732 case 'U':
7733 ret = sh_modcase (s, 0, CASE_UPPER);
7734 break;
7735 case 'u':
7736 ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */
7737 break;
7738 case 'L':
7739 ret = sh_modcase (s, 0, CASE_LOWER);
7740 break;
7741 default:
7742 ret = (char *)NULL;
7743 break;
7744 }
7745 return ret;
7746 }
7747
7748 static char *
7749 list_transform (xc, v, list, itype, quoted)
7750 int xc;
7751 SHELL_VAR *v;
7752 WORD_LIST *list;
7753 int itype, quoted;
7754 {
7755 WORD_LIST *new, *l;
7756 WORD_DESC *w;
7757 char *tword;
7758 int qflags;
7759
7760 for (new = (WORD_LIST *)NULL, l = list; l; l = l->next)
7761 {
7762 tword = string_transform (xc, v, l->word->word);
7763 w = alloc_word_desc ();
7764 w->word = tword ? tword : savestring (""); /* XXX */
7765 new = make_word_list (w, new);
7766 }
7767 l = REVERSE_LIST (new, WORD_LIST *);
7768
7769 qflags = quoted;
7770 /* If we are expanding in a context where word splitting will not be
7771 performed, treat as quoted. This changes how $* will be expanded. */
7772 if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
7773 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
7774
7775 tword = string_list_pos_params (itype, l, qflags, 0);
7776 dispose_words (l);
7777
7778 return (tword);
7779 }
7780
7781 static char *
7782 parameter_list_transform (xc, itype, quoted)
7783 int xc;
7784 int itype;
7785 int quoted;
7786 {
7787 char *ret;
7788 WORD_LIST *list;
7789
7790 list = list_rest_of_args ();
7791 if (list == 0)
7792 return ((char *)NULL);
7793 if (xc == 'A')
7794 ret = pos_params_assignment (list, itype, quoted);
7795 else
7796 ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted);
7797 dispose_words (list);
7798 return (ret);
7799 }
7800
7801 #if defined (ARRAY_VARS)
7802 static char *
7803 array_transform (xc, var, starsub, quoted)
7804 int xc;
7805 SHELL_VAR *var;
7806 int starsub; /* so we can figure out how it's indexed */
7807 int quoted;
7808 {
7809 ARRAY *a;
7810 HASH_TABLE *h;
7811 int itype;
7812 char *ret;
7813 WORD_LIST *list;
7814 SHELL_VAR *v;
7815
7816 v = var; /* XXX - for now */
7817
7818 itype = starsub ? '*' : '@';
7819
7820 if (xc == 'A')
7821 return (array_var_assignment (v, itype, quoted, 1));
7822 else if (xc == 'K')
7823 return (array_var_assignment (v, itype, quoted, 2));
7824
7825 /* special case for unset arrays and attributes */
7826 if (xc == 'a' && (invisible_p (v) || var_isset (v) == 0))
7827 {
7828 char flags[MAX_ATTRIBUTES];
7829 int i;
7830
7831 i = var_attribute_string (v, 0, flags);
7832 return ((i > 0) ? savestring (flags) : (char *)NULL);
7833 }
7834
7835 a = (v && array_p (v)) ? array_cell (v) : 0;
7836 h = (v && assoc_p (v)) ? assoc_cell (v) : 0;
7837
7838 list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
7839 if (list == 0)
7840 return ((char *)NULL);
7841 ret = list_transform (xc, v, list, itype, quoted);
7842 dispose_words (list);
7843
7844 return ret;
7845 }
7846 #endif /* ARRAY_VARS */
7847
7848 static char *
7849 parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, flags)
7850 char *varname, *value;
7851 int ind;
7852 char *xform;
7853 int rtype, quoted, pflags, flags;
7854 {
7855 int vtype, xc, starsub;
7856 char *temp1, *val, *oname;
7857 SHELL_VAR *v;
7858
7859 xc = xform[0];
7860 if (value == 0 && xc != 'A' && xc != 'a')
7861 return ((char *)NULL);
7862
7863 oname = this_command_name;
7864 this_command_name = varname;
7865
7866 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
7867 if (vtype == -1)
7868 {
7869 this_command_name = oname;
7870 return ((char *)NULL);
7871 }
7872
7873 /* check for valid values of xc */
7874 switch (xc)
7875 {
7876 case 'a': /* expand to a string with just attributes */
7877 case 'A': /* expand as an assignment statement with attributes */
7878 case 'K': /* expand assoc array to list of key/value pairs */
7879 case 'E': /* expand like $'...' */
7880 case 'P': /* expand like prompt string */
7881 case 'Q': /* quote reusably */
7882 case 'U': /* transform to uppercase */
7883 case 'u': /* tranform by capitalizing */
7884 case 'L': /* transform to lowercase */
7885 break;
7886 default:
7887 this_command_name = oname;
7888 return &expand_param_error;
7889 }
7890
7891 starsub = vtype & VT_STARSUB;
7892 vtype &= ~VT_STARSUB;
7893
7894 /* If we are asked to display the attributes of an unset variable, V will
7895 be NULL after the call to get_var_and_type. Double-check here. */
7896 if ((xc == 'a' || xc == 'A') && vtype == VT_VARIABLE && varname && v == 0)
7897 v = find_variable (varname);
7898
7899 temp1 = (char *)NULL; /* shut up gcc */
7900 switch (vtype)
7901 {
7902 case VT_VARIABLE:
7903 case VT_ARRAYMEMBER:
7904 temp1 = string_transform (xc, v, val);
7905 if (vtype == VT_VARIABLE)
7906 FREE (val);
7907 if (temp1)
7908 {
7909 val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
7910 ? quote_string (temp1)
7911 : quote_escapes (temp1);
7912 free (temp1);
7913 temp1 = val;
7914 }
7915 break;
7916 #if defined (ARRAY_VARS)
7917 case VT_ARRAYVAR:
7918 temp1 = array_transform (xc, v, starsub, quoted);
7919 if (temp1 && quoted == 0 && ifs_is_null)
7920 {
7921 /* Posix interp 888 */
7922 }
7923 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
7924 {
7925 val = quote_escapes (temp1);
7926 free (temp1);
7927 temp1 = val;
7928 }
7929 break;
7930 #endif
7931 case VT_POSPARMS:
7932 temp1 = parameter_list_transform (xc, varname[0], quoted);
7933 if (temp1 && quoted == 0 && ifs_is_null)
7934 {
7935 /* Posix interp 888 */
7936 }
7937 else if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
7938 {
7939 val = quote_escapes (temp1);
7940 free (temp1);
7941 temp1 = val;
7942 }
7943 break;
7944 }
7945
7946 this_command_name = oname;
7947 return temp1;
7948 }
7949
7950 /******************************************************/
7951 /* */
7952 /* Functions to extract substrings of variable values */
7953 /* */
7954 /******************************************************/
7955
7956 #if defined (HANDLE_MULTIBYTE)
7957 /* Character-oriented rather than strictly byte-oriented substrings. S and
7958 E, rather being strict indices into STRING, indicate character (possibly
7959 multibyte character) positions that require calculation.
7960 Used by the ${param:offset[:length]} expansion. */
7961 static char *
7962 mb_substring (string, s, e)
7963 char *string;
7964 int s, e;
7965 {
7966 char *tt;
7967 int start, stop, i;
7968 size_t slen;
7969 DECLARE_MBSTATE;
7970
7971 start = 0;
7972 /* Don't need string length in ADVANCE_CHAR unless multibyte chars possible. */
7973 slen = (MB_CUR_MAX > 1) ? STRLEN (string) : 0;
7974
7975 i = s;
7976 while (string[start] && i--)
7977 ADVANCE_CHAR (string, slen, start);
7978 stop = start;
7979 i = e - s;
7980 while (string[stop] && i--)
7981 ADVANCE_CHAR (string, slen, stop);
7982 tt = substring (string, start, stop);
7983 return tt;
7984 }
7985 #endif
7986
7987 /* Process a variable substring expansion: ${name:e1[:e2]}. If VARNAME
7988 is `@', use the positional parameters; otherwise, use the value of
7989 VARNAME. If VARNAME is an array variable, use the array elements. */
7990
7991 static char *
7992 parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags)
7993 char *varname, *value;
7994 int ind;
7995 char *substr;
7996 int quoted, pflags, flags;
7997 {
7998 intmax_t e1, e2;
7999 int vtype, r, starsub;
8000 char *temp, *val, *tt, *oname;
8001 SHELL_VAR *v;
8002
8003 if (value == 0 && ((varname[0] != '@' && varname[0] != '*') || varname[1]))
8004 return ((char *)NULL);
8005
8006 oname = this_command_name;
8007 this_command_name = varname;
8008
8009 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
8010 if (vtype == -1)
8011 {
8012 this_command_name = oname;
8013 return ((char *)NULL);
8014 }
8015
8016 starsub = vtype & VT_STARSUB;
8017 vtype &= ~VT_STARSUB;
8018
8019 r = verify_substring_values (v, val, substr, vtype, &e1, &e2);
8020 this_command_name = oname;
8021 if (r <= 0)
8022 {
8023 if (vtype == VT_VARIABLE)
8024 FREE (val);
8025 return ((r == 0) ? &expand_param_error : (char *)NULL);
8026 }
8027
8028 switch (vtype)
8029 {
8030 case VT_VARIABLE:
8031 case VT_ARRAYMEMBER:
8032 #if defined (HANDLE_MULTIBYTE)
8033 if (MB_CUR_MAX > 1)
8034 tt = mb_substring (val, e1, e2);
8035 else
8036 #endif
8037 tt = substring (val, e1, e2);
8038
8039 if (vtype == VT_VARIABLE)
8040 FREE (val);
8041 if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
8042 temp = quote_string (tt);
8043 else
8044 temp = tt ? quote_escapes (tt) : (char *)NULL;
8045 FREE (tt);
8046 break;
8047 case VT_POSPARMS:
8048 case VT_ARRAYVAR:
8049 if (vtype == VT_POSPARMS)
8050 tt = pos_params (varname, e1, e2, quoted, pflags);
8051 #if defined (ARRAY_VARS)
8052 /* assoc_subrange and array_subrange both call string_list_pos_params,
8053 so we can treat this case just like VT_POSPARAMS. */
8054 else if (assoc_p (v))
8055 /* we convert to list and take first e2 elements starting at e1th
8056 element -- officially undefined for now */
8057 tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted, pflags);
8058 else
8059 /* We want E2 to be the number of elements desired (arrays can be
8060 sparse, so verify_substring_values just returns the numbers
8061 specified and we rely on array_subrange to understand how to
8062 deal with them). */
8063 tt = array_subrange (array_cell (v), e1, e2, starsub, quoted, pflags);
8064 #endif
8065 /* We want to leave this alone in every case where pos_params/
8066 string_list_pos_params quotes the list members */
8067 if (tt && quoted == 0 && ifs_is_null)
8068 {
8069 temp = tt; /* Posix interp 888 */
8070 }
8071 else if (tt && quoted == 0 && (pflags & PF_ASSIGNRHS))
8072 {
8073 temp = tt; /* Posix interp 888 */
8074 }
8075 else if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
8076 {
8077 temp = tt ? quote_escapes (tt) : (char *)NULL;
8078 FREE (tt);
8079 }
8080 else
8081 temp = tt;
8082 break;
8083
8084 default:
8085 temp = (char *)NULL;
8086 }
8087
8088 return temp;
8089 }
8090
8091 /****************************************************************/
8092 /* */
8093 /* Functions to perform pattern substitution on variable values */
8094 /* */
8095 /****************************************************************/
8096
8097 #ifdef INCLUDE_UNUSED
8098 static int
8099 shouldexp_replacement (s)
8100 char *s;
8101 {
8102 register char *p;
8103
8104 for (p = s; p && *p; p++)
8105 {
8106 if (*p == '\\')
8107 p++;
8108 else if (*p == '&')
8109 return 1;
8110 }
8111 return 0;
8112 }
8113 #endif
8114
8115 char *
8116 pat_subst (string, pat, rep, mflags)
8117 char *string, *pat, *rep;
8118 int mflags;
8119 {
8120 char *ret, *s, *e, *str, *rstr, *mstr, *send;
8121 int rptr, mtype, rxpand, mlen;
8122 size_t rsize, l, replen, rslen;
8123 DECLARE_MBSTATE;
8124
8125 if (string == 0)
8126 return (savestring (""));
8127
8128 mtype = mflags & MATCH_TYPEMASK;
8129
8130 #if 0 /* TAG: bash-5.2? */
8131 rxpand = (rep && *rep) ? shouldexp_replacement (rep) : 0;
8132 #else
8133 rxpand = 0;
8134 #endif
8135
8136 /* Special cases:
8137 * 1. A null pattern with mtype == MATCH_BEG means to prefix STRING
8138 * with REP and return the result.
8139 * 2. A null pattern with mtype == MATCH_END means to append REP to
8140 * STRING and return the result.
8141 * 3. A null STRING with a matching pattern means to append REP to
8142 * STRING and return the result.
8143 * These don't understand or process `&' in the replacement string.
8144 */
8145 if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
8146 {
8147 replen = STRLEN (rep);
8148 l = STRLEN (string);
8149 ret = (char *)xmalloc (replen + l + 2);
8150 if (replen == 0)
8151 strcpy (ret, string);
8152 else if (mtype == MATCH_BEG)
8153 {
8154 strcpy (ret, rep);
8155 strcpy (ret + replen, string);
8156 }
8157 else
8158 {
8159 strcpy (ret, string);
8160 strcpy (ret + l, rep);
8161 }
8162 return (ret);
8163 }
8164 else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
8165 {
8166 replen = STRLEN (rep);
8167 ret = (char *)xmalloc (replen + 1);
8168 if (replen == 0)
8169 ret[0] = '\0';
8170 else
8171 strcpy (ret, rep);
8172 return (ret);
8173 }
8174
8175 ret = (char *)xmalloc (rsize = 64);
8176 ret[0] = '\0';
8177 send = string + strlen (string);
8178
8179 for (replen = STRLEN (rep), rptr = 0, str = string; *str;)
8180 {
8181 if (match_pattern (str, pat, mtype, &s, &e) == 0)
8182 break;
8183 l = s - str;
8184
8185 if (rep && rxpand)
8186 {
8187 int x;
8188 mlen = e - s;
8189 mstr = xmalloc (mlen + 1);
8190 for (x = 0; x < mlen; x++)
8191 mstr[x] = s[x];
8192 mstr[mlen] = '\0';
8193 rstr = strcreplace (rep, '&', mstr, 0);
8194 free (mstr);
8195 rslen = strlen (rstr);
8196 }
8197 else
8198 {
8199 rstr = rep;
8200 rslen = replen;
8201 }
8202
8203 RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64);
8204
8205 /* OK, now copy the leading unmatched portion of the string (from
8206 str to s) to ret starting at rptr (the current offset). Then copy
8207 the replacement string at ret + rptr + (s - str). Increment
8208 rptr (if necessary) and str and go on. */
8209 if (l)
8210 {
8211 strncpy (ret + rptr, str, l);
8212 rptr += l;
8213 }
8214 if (replen)
8215 {
8216 strncpy (ret + rptr, rstr, rslen);
8217 rptr += rslen;
8218 }
8219 str = e; /* e == end of match */
8220
8221 if (rstr != rep)
8222 free (rstr);
8223
8224 if (((mflags & MATCH_GLOBREP) == 0) || mtype != MATCH_ANY)
8225 break;
8226
8227 if (s == e)
8228 {
8229 /* On a zero-length match, make sure we copy one character, since
8230 we increment one character to avoid infinite recursion. */
8231 char *p, *origp, *origs;
8232 size_t clen;
8233
8234 RESIZE_MALLOCED_BUFFER (ret, rptr, locale_mb_cur_max, rsize, 64);
8235 #if defined (HANDLE_MULTIBYTE)
8236 p = origp = ret + rptr;
8237 origs = str;
8238 COPY_CHAR_P (p, str, send);
8239 rptr += p - origp;
8240 e += str - origs;
8241 #else
8242 ret[rptr++] = *str++;
8243 e++; /* avoid infinite recursion on zero-length match */
8244 #endif
8245 }
8246 }
8247
8248 /* Now copy the unmatched portion of the input string */
8249 if (str && *str)
8250 {
8251 RESIZE_MALLOCED_BUFFER (ret, rptr, STRLEN(str) + 1, rsize, 64);
8252 strcpy (ret + rptr, str);
8253 }
8254 else
8255 ret[rptr] = '\0';
8256
8257 return ret;
8258 }
8259
8260 /* Do pattern match and replacement on the positional parameters. */
8261 static char *
8262 pos_params_pat_subst (string, pat, rep, mflags)
8263 char *string, *pat, *rep;
8264 int mflags;
8265 {
8266 WORD_LIST *save, *params;
8267 WORD_DESC *w;
8268 char *ret;
8269 int pchar, qflags, pflags;
8270
8271 save = params = list_rest_of_args ();
8272 if (save == 0)
8273 return ((char *)NULL);
8274
8275 for ( ; params; params = params->next)
8276 {
8277 ret = pat_subst (params->word->word, pat, rep, mflags);
8278 w = alloc_word_desc ();
8279 w->word = ret ? ret : savestring ("");
8280 dispose_word (params->word);
8281 params->word = w;
8282 }
8283
8284 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
8285 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
8286 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
8287
8288 /* If we are expanding in a context where word splitting will not be
8289 performed, treat as quoted. This changes how $* will be expanded. */
8290 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null)
8291 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8292
8293 ret = string_list_pos_params (pchar, save, qflags, pflags);
8294 dispose_words (save);
8295
8296 return (ret);
8297 }
8298
8299 /* Perform pattern substitution on VALUE, which is the expansion of
8300 VARNAME. PATSUB is an expression supplying the pattern to match
8301 and the string to substitute. QUOTED is a flags word containing
8302 the type of quoting currently in effect. */
8303 static char *
8304 parameter_brace_patsub (varname, value, ind, patsub, quoted, pflags, flags)
8305 char *varname, *value;
8306 int ind;
8307 char *patsub;
8308 int quoted, pflags, flags;
8309 {
8310 int vtype, mflags, starsub, delim;
8311 char *val, *temp, *pat, *rep, *p, *lpatsub, *tt, *oname;
8312 SHELL_VAR *v;
8313
8314 if (value == 0)
8315 return ((char *)NULL);
8316
8317 oname = this_command_name;
8318 this_command_name = varname; /* error messages */
8319
8320 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
8321 if (vtype == -1)
8322 {
8323 this_command_name = oname;
8324 return ((char *)NULL);
8325 }
8326
8327 starsub = vtype & VT_STARSUB;
8328 vtype &= ~VT_STARSUB;
8329
8330 mflags = 0;
8331 /* PATSUB is never NULL when this is called. */
8332 if (*patsub == '/')
8333 {
8334 mflags |= MATCH_GLOBREP;
8335 patsub++;
8336 }
8337
8338 /* Malloc this because expand_string_if_necessary or one of the expansion
8339 functions in its call chain may free it on a substitution error. */
8340 lpatsub = savestring (patsub);
8341
8342 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8343 mflags |= MATCH_QUOTED;
8344
8345 if (starsub)
8346 mflags |= MATCH_STARSUB;
8347
8348 if (pflags & PF_ASSIGNRHS)
8349 mflags |= MATCH_ASSIGNRHS;
8350
8351 /* If the pattern starts with a `/', make sure we skip over it when looking
8352 for the replacement delimiter. */
8353 delim = skip_to_delim (lpatsub, ((*patsub == '/') ? 1 : 0), "/", 0);
8354 if (lpatsub[delim] == '/')
8355 {
8356 lpatsub[delim] = 0;
8357 rep = lpatsub + delim + 1;
8358 }
8359 else
8360 rep = (char *)NULL;
8361
8362 if (rep && *rep == '\0')
8363 rep = (char *)NULL;
8364
8365 /* Perform the same expansions on the pattern as performed by the
8366 pattern removal expansions. */
8367 pat = getpattern (lpatsub, quoted, 1);
8368
8369 if (rep)
8370 {
8371 /* We want to perform quote removal on the expanded replacement even if
8372 the entire expansion is double-quoted because the parser and string
8373 extraction functions treated quotes in the replacement string as
8374 special. THIS IS NOT BACKWARDS COMPATIBLE WITH BASH-4.2. */
8375 if (shell_compatibility_level > 42)
8376 rep = expand_string_if_necessary (rep, quoted & ~(Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT), expand_string_unsplit);
8377 /* This is the bash-4.2 code. */
8378 else if ((mflags & MATCH_QUOTED) == 0)
8379 rep = expand_string_if_necessary (rep, quoted, expand_string_unsplit);
8380 else
8381 rep = expand_string_to_string_internal (rep, quoted, expand_string_unsplit);
8382 }
8383
8384 /* ksh93 doesn't allow the match specifier to be a part of the expanded
8385 pattern. This is an extension. Make sure we don't anchor the pattern
8386 at the beginning or end of the string if we're doing global replacement,
8387 though. */
8388 p = pat;
8389 if (mflags & MATCH_GLOBREP)
8390 mflags |= MATCH_ANY;
8391 else if (pat && pat[0] == '#')
8392 {
8393 mflags |= MATCH_BEG;
8394 p++;
8395 }
8396 else if (pat && pat[0] == '%')
8397 {
8398 mflags |= MATCH_END;
8399 p++;
8400 }
8401 else
8402 mflags |= MATCH_ANY;
8403
8404 /* OK, we now want to substitute REP for PAT in VAL. If
8405 flags & MATCH_GLOBREP is non-zero, the substitution is done
8406 everywhere, otherwise only the first occurrence of PAT is
8407 replaced. The pattern matching code doesn't understand
8408 CTLESC quoting CTLESC and CTLNUL so we use the dequoted variable
8409 values passed in (VT_VARIABLE) so the pattern substitution
8410 code works right. We need to requote special chars after
8411 we're done for VT_VARIABLE and VT_ARRAYMEMBER, and for the
8412 other cases if QUOTED == 0, since the posparams and arrays
8413 indexed by * or @ do special things when QUOTED != 0. */
8414
8415 switch (vtype)
8416 {
8417 case VT_VARIABLE:
8418 case VT_ARRAYMEMBER:
8419 temp = pat_subst (val, p, rep, mflags);
8420 if (vtype == VT_VARIABLE)
8421 FREE (val);
8422 if (temp)
8423 {
8424 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
8425 free (temp);
8426 temp = tt;
8427 }
8428 break;
8429 case VT_POSPARMS:
8430 /* This does the right thing for the case where we are not performing
8431 word splitting. MATCH_STARSUB restricts it to ${* /foo/bar}, and
8432 pos_params_pat_subst/string_list_pos_params will do the right thing
8433 in turn for the case where ifs_is_null. Posix interp 888 */
8434 if ((pflags & PF_NOSPLIT2) && (mflags & MATCH_STARSUB))
8435 mflags |= MATCH_ASSIGNRHS;
8436 temp = pos_params_pat_subst (val, p, rep, mflags);
8437 if (temp && quoted == 0 && ifs_is_null)
8438 {
8439 /* Posix interp 888 */
8440 }
8441 else if (temp && quoted == 0 && (pflags & PF_ASSIGNRHS))
8442 {
8443 /* Posix interp 888 */
8444 }
8445 else if (temp && (mflags & MATCH_QUOTED) == 0)
8446 {
8447 tt = quote_escapes (temp);
8448 free (temp);
8449 temp = tt;
8450 }
8451 break;
8452 #if defined (ARRAY_VARS)
8453 case VT_ARRAYVAR:
8454 /* If we are expanding in a context where word splitting will not be
8455 performed, treat as quoted. This changes how ${A[*]} will be
8456 expanded to make it identical to $*. */
8457 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
8458 mflags |= MATCH_QUOTED; /* Posix interp 888 */
8459
8460 /* these eventually call string_list_pos_params */
8461 if (assoc_p (v))
8462 temp = assoc_patsub (assoc_cell (v), p, rep, mflags);
8463 else
8464 temp = array_patsub (array_cell (v), p, rep, mflags);
8465
8466 if (temp && quoted == 0 && ifs_is_null)
8467 {
8468 /* Posix interp 888 */
8469 }
8470 else if (temp && (mflags & MATCH_QUOTED) == 0)
8471 {
8472 tt = quote_escapes (temp);
8473 free (temp);
8474 temp = tt;
8475 }
8476 break;
8477 #endif
8478 }
8479
8480 FREE (pat);
8481 FREE (rep);
8482 free (lpatsub);
8483
8484 this_command_name = oname;
8485
8486 return temp;
8487 }
8488
8489 /****************************************************************/
8490 /* */
8491 /* Functions to perform case modification on variable values */
8492 /* */
8493 /****************************************************************/
8494
8495 /* Do case modification on the positional parameters. */
8496
8497 static char *
8498 pos_params_modcase (string, pat, modop, mflags)
8499 char *string, *pat;
8500 int modop;
8501 int mflags;
8502 {
8503 WORD_LIST *save, *params;
8504 WORD_DESC *w;
8505 char *ret;
8506 int pchar, qflags, pflags;
8507
8508 save = params = list_rest_of_args ();
8509 if (save == 0)
8510 return ((char *)NULL);
8511
8512 for ( ; params; params = params->next)
8513 {
8514 ret = sh_modcase (params->word->word, pat, modop);
8515 w = alloc_word_desc ();
8516 w->word = ret ? ret : savestring ("");
8517 dispose_word (params->word);
8518 params->word = w;
8519 }
8520
8521 pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
8522 qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
8523 pflags = (mflags & MATCH_ASSIGNRHS) == MATCH_ASSIGNRHS ? PF_ASSIGNRHS : 0;
8524
8525 /* If we are expanding in a context where word splitting will not be
8526 performed, treat as quoted. This changes how $* will be expanded. */
8527 if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
8528 qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */
8529
8530 ret = string_list_pos_params (pchar, save, qflags, pflags);
8531 dispose_words (save);
8532
8533 return (ret);
8534 }
8535
8536 /* Perform case modification on VALUE, which is the expansion of
8537 VARNAME. MODSPEC is an expression supplying the type of modification
8538 to perform. QUOTED is a flags word containing the type of quoting
8539 currently in effect. */
8540 static char *
8541 parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, pflags, flags)
8542 char *varname, *value;
8543 int ind, modspec;
8544 char *patspec;
8545 int quoted, pflags, flags;
8546 {
8547 int vtype, starsub, modop, mflags, x;
8548 char *val, *temp, *pat, *p, *lpat, *tt, *oname;
8549 SHELL_VAR *v;
8550
8551 if (value == 0)
8552 return ((char *)NULL);
8553
8554 oname = this_command_name;
8555 this_command_name = varname;
8556
8557 vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
8558 if (vtype == -1)
8559 {
8560 this_command_name = oname;
8561 return ((char *)NULL);
8562 }
8563
8564 starsub = vtype & VT_STARSUB;
8565 vtype &= ~VT_STARSUB;
8566
8567 modop = 0;
8568 mflags = 0;
8569 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
8570 mflags |= MATCH_QUOTED;
8571 if (starsub)
8572 mflags |= MATCH_STARSUB;
8573 if (pflags & PF_ASSIGNRHS)
8574 mflags |= MATCH_ASSIGNRHS;
8575
8576 p = patspec;
8577 if (modspec == '^')
8578 {
8579 x = p && p[0] == modspec;
8580 modop = x ? CASE_UPPER : CASE_UPFIRST;
8581 p += x;
8582 }
8583 else if (modspec == ',')
8584 {
8585 x = p && p[0] == modspec;
8586 modop = x ? CASE_LOWER : CASE_LOWFIRST;
8587 p += x;
8588 }
8589 else if (modspec == '~')
8590 {
8591 x = p && p[0] == modspec;
8592 modop = x ? CASE_TOGGLEALL : CASE_TOGGLE;
8593 p += x;
8594 }
8595
8596 lpat = p ? savestring (p) : 0;
8597 /* Perform the same expansions on the pattern as performed by the
8598 pattern removal expansions. */
8599 pat = lpat ? getpattern (lpat, quoted, 1) : 0;
8600
8601 /* OK, now we do the case modification. */
8602 switch (vtype)
8603 {
8604 case VT_VARIABLE:
8605 case VT_ARRAYMEMBER:
8606 temp = sh_modcase (val, pat, modop);
8607 if (vtype == VT_VARIABLE)
8608 FREE (val);
8609 if (temp)
8610 {
8611 tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
8612 free (temp);
8613 temp = tt;
8614 }
8615 break;
8616
8617 case VT_POSPARMS:
8618 temp = pos_params_modcase (val, pat, modop, mflags);
8619 if (temp && quoted == 0 && ifs_is_null)
8620 {
8621 /* Posix interp 888 */
8622 }
8623 else if (temp && (mflags & MATCH_QUOTED) == 0)
8624 {
8625 tt = quote_escapes (temp);
8626 free (temp);
8627 temp = tt;
8628 }
8629 break;
8630
8631 #if defined (ARRAY_VARS)
8632 case VT_ARRAYVAR:
8633 /* If we are expanding in a context where word splitting will not be
8634 performed, treat as quoted. This changes how ${A[*]} will be
8635 expanded to make it identical to $*. */
8636 if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null)
8637 mflags |= MATCH_QUOTED; /* Posix interp 888 */
8638
8639 temp = assoc_p (v) ? assoc_modcase (assoc_cell (v), pat, modop, mflags)
8640 : array_modcase (array_cell (v), pat, modop, mflags);
8641
8642 if (temp && quoted == 0 && ifs_is_null)
8643 {
8644 /* Posix interp 888 */
8645 }
8646 else if (temp && (mflags & MATCH_QUOTED) == 0)
8647 {
8648 tt = quote_escapes (temp);
8649 free (temp);
8650 temp = tt;
8651 }
8652
8653 break;
8654 #endif
8655 }
8656
8657 FREE (pat);
8658 free (lpat);
8659
8660 this_command_name = oname;
8661
8662 return temp;
8663 }
8664
8665 /* Check for unbalanced parens in S, which is the contents of $(( ... )). If
8666 any occur, this must be a nested command substitution, so return 0.
8667 Otherwise, return 1. A valid arithmetic expression must always have a
8668 ( before a matching ), so any cases where there are more right parens
8669 means that this must not be an arithmetic expression, though the parser
8670 will not accept it without a balanced total number of parens. */
8671 static int
8672 chk_arithsub (s, len)
8673 const char *s;
8674 int len;
8675 {
8676 int i, count;
8677 DECLARE_MBSTATE;
8678
8679 i = count = 0;
8680 while (i < len)
8681 {
8682 if (s[i] == LPAREN)
8683 count++;
8684 else if (s[i] == RPAREN)
8685 {
8686 count--;
8687 if (count < 0)
8688 return 0;
8689 }
8690
8691 switch (s[i])
8692 {
8693 default:
8694 ADVANCE_CHAR (s, len, i);
8695 break;
8696
8697 case '\\':
8698 i++;
8699 if (s[i])
8700 ADVANCE_CHAR (s, len, i);
8701 break;
8702
8703 case '\'':
8704 i = skip_single_quoted (s, len, ++i, 0);
8705 break;
8706
8707 case '"':
8708 i = skip_double_quoted ((char *)s, len, ++i, 0);
8709 break;
8710 }
8711 }
8712
8713 return (count == 0);
8714 }
8715
8716 /****************************************************************/
8717 /* */
8718 /* Functions to perform parameter expansion on a string */
8719 /* */
8720 /****************************************************************/
8721
8722 /* ${[#][!]name[[:][^[^]][,[,]]#[#]%[%]-=?+[word][:e1[:e2]]]} */
8723 static WORD_DESC *
8724 parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
8725 char *string;
8726 int *indexp, quoted, pflags, *quoted_dollar_atp, *contains_dollar_at;
8727 {
8728 int check_nullness, var_is_set, var_is_null, var_is_special;
8729 int want_substring, want_indir, want_patsub, want_casemod;
8730 char *name, *value, *temp, *temp1;
8731 WORD_DESC *tdesc, *ret;
8732 int t_index, sindex, c, tflag, modspec, all_element_arrayref;
8733 intmax_t number;
8734 arrayind_t ind;
8735
8736 temp = temp1 = value = (char *)NULL;
8737 var_is_set = var_is_null = var_is_special = check_nullness = 0;
8738 want_substring = want_indir = want_patsub = want_casemod = 0;
8739
8740 all_element_arrayref = 0;
8741
8742 sindex = *indexp;
8743 t_index = ++sindex;
8744 /* ${#var} doesn't have any of the other parameter expansions on it. */
8745 if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
8746 name = string_extract (string, &t_index, "}", SX_VARNAME);
8747 else
8748 #if defined (CASEMOD_EXPANSIONS)
8749 /* To enable case-toggling expansions using the `~' operator character
8750 change the 1 to 0. */
8751 # if defined (CASEMOD_CAPCASE)
8752 name = string_extract (string, &t_index, "#%^,~:-=?+/@}", SX_VARNAME);
8753 # else
8754 name = string_extract (string, &t_index, "#%^,:-=?+/@}", SX_VARNAME);
8755 # endif /* CASEMOD_CAPCASE */
8756 #else
8757 name = string_extract (string, &t_index, "#%:-=?+/@}", SX_VARNAME);
8758 #endif /* CASEMOD_EXPANSIONS */
8759
8760 /* Handle ${@[stuff]} now that @ is a word expansion operator. Not exactly
8761 the cleanest code ever. */
8762 if (*name == 0 && sindex == t_index && string[sindex] == '@')
8763 {
8764 name = (char *)xrealloc (name, 2);
8765 name[0] = '@';
8766 name[1] = '\0';
8767 t_index++;
8768 }
8769 else if (*name == '!' && t_index > sindex && string[t_index] == '@' && string[t_index+1] == RBRACE)
8770 {
8771 name = (char *)xrealloc (name, t_index - sindex + 2);
8772 name[t_index - sindex] = '@';
8773 name[t_index - sindex + 1] = '\0';
8774 t_index++;
8775 }
8776
8777 ret = 0;
8778 tflag = 0;
8779
8780 ind = INTMAX_MIN;
8781
8782 /* If the name really consists of a special variable, then make sure
8783 that we have the entire name. We don't allow indirect references
8784 to special variables except `#', `?', `@' and `*'. This clause is
8785 designed to handle ${#SPECIAL} and ${!SPECIAL}, not anything more
8786 general. */
8787 if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
8788 (sindex == t_index && string[sindex] == '#' && VALID_SPECIAL_LENGTH_PARAM (string[sindex + 1])) ||
8789 (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
8790 {
8791 t_index++;
8792 temp1 = string_extract (string, &t_index, "#%:-=?+/@}", 0);
8793 name = (char *)xrealloc (name, 3 + (strlen (temp1)));
8794 *name = string[sindex];
8795 if (string[sindex] == '!')
8796 {
8797 /* indirect reference of $#, $?, $@, or $* */
8798 name[1] = string[sindex + 1];
8799 strcpy (name + 2, temp1);
8800 }
8801 else
8802 strcpy (name + 1, temp1);
8803 free (temp1);
8804 }
8805 sindex = t_index;
8806
8807 /* Find out what character ended the variable name. Then
8808 do the appropriate thing. */
8809 if (c = string[sindex])
8810 sindex++;
8811
8812 /* If c is followed by one of the valid parameter expansion
8813 characters, move past it as normal. If not, assume that
8814 a substring specification is being given, and do not move
8815 past it. */
8816 if (c == ':' && VALID_PARAM_EXPAND_CHAR (string[sindex]))
8817 {
8818 check_nullness++;
8819 if (c = string[sindex])
8820 sindex++;
8821 }
8822 else if (c == ':' && string[sindex] != RBRACE)
8823 want_substring = 1;
8824 else if (c == '/' /* && string[sindex] != RBRACE */) /* XXX */
8825 want_patsub = 1;
8826 #if defined (CASEMOD_EXPANSIONS)
8827 else if (c == '^' || c == ',' || c == '~')
8828 {
8829 modspec = c;
8830 want_casemod = 1;
8831 }
8832 #endif
8833
8834 /* Catch the valid and invalid brace expressions that made it through the
8835 tests above. */
8836 /* ${#-} is a valid expansion and means to take the length of $-.
8837 Similarly for ${#?} and ${##}... */
8838 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
8839 VALID_SPECIAL_LENGTH_PARAM (c) && string[sindex] == RBRACE)
8840 {
8841 name = (char *)xrealloc (name, 3);
8842 name[1] = c;
8843 name[2] = '\0';
8844 c = string[sindex++];
8845 }
8846
8847 /* ...but ${#%}, ${#:}, ${#=}, ${#+}, and ${#/} are errors. */
8848 if (name[0] == '#' && name[1] == '\0' && check_nullness == 0 &&
8849 member (c, "%:=+/") && string[sindex] == RBRACE)
8850 {
8851 temp = (char *)NULL;
8852 goto bad_substitution; /* XXX - substitution error */
8853 }
8854
8855 /* Indirect expansion begins with a `!'. A valid indirect expansion is
8856 either a variable name, one of the positional parameters or a special
8857 variable that expands to one of the positional parameters. */
8858 want_indir = *name == '!' &&
8859 (legal_variable_starter ((unsigned char)name[1]) || DIGIT (name[1])
8860 || VALID_INDIR_PARAM (name[1]));
8861
8862 /* Determine the value of this variable whose name is NAME. */
8863
8864 /* Check for special variables, directly referenced. */
8865 if (SPECIAL_VAR (name, want_indir))
8866 var_is_special++;
8867
8868 /* Check for special expansion things, like the length of a parameter */
8869 if (*name == '#' && name[1])
8870 {
8871 /* If we are not pointing at the character just after the
8872 closing brace, then we haven't gotten all of the name.
8873 Since it begins with a special character, this is a bad
8874 substitution. Also check NAME for validity before trying
8875 to go on. */
8876 if (string[sindex - 1] != RBRACE || (valid_length_expression (name) == 0))
8877 {
8878 temp = (char *)NULL;
8879 goto bad_substitution; /* substitution error */
8880 }
8881
8882 number = parameter_brace_expand_length (name);
8883 if (number == INTMAX_MIN && unbound_vars_is_error)
8884 {
8885 set_exit_status (EXECUTION_FAILURE);
8886 err_unboundvar (name+1);
8887 free (name);
8888 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
8889 }
8890 free (name);
8891
8892 *indexp = sindex;
8893 if (number < 0)
8894 return (&expand_wdesc_error);
8895 else
8896 {
8897 ret = alloc_word_desc ();
8898 ret->word = itos (number);
8899 return ret;
8900 }
8901 }
8902
8903 /* ${@} is identical to $@. */
8904 if (name[0] == '@' && name[1] == '\0')
8905 {
8906 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
8907 *quoted_dollar_atp = 1;
8908
8909 if (contains_dollar_at)
8910 *contains_dollar_at = 1;
8911
8912 tflag |= W_DOLLARAT;
8913 }
8914
8915 /* Process ${!PREFIX*} expansion. */
8916 if (want_indir && string[sindex - 1] == RBRACE &&
8917 (string[sindex - 2] == '*' || string[sindex - 2] == '@') &&
8918 legal_variable_starter ((unsigned char) name[1]))
8919 {
8920 char **x;
8921 WORD_LIST *xlist;
8922
8923 temp1 = savestring (name + 1);
8924 number = strlen (temp1);
8925 temp1[number - 1] = '\0';
8926 x = all_variables_matching_prefix (temp1);
8927 xlist = strvec_to_word_list (x, 0, 0);
8928 if (string[sindex - 2] == '*')
8929 temp = string_list_dollar_star (xlist, quoted, 0);
8930 else
8931 {
8932 temp = string_list_dollar_at (xlist, quoted, 0);
8933 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
8934 *quoted_dollar_atp = 1;
8935 if (contains_dollar_at)
8936 *contains_dollar_at = 1;
8937
8938 tflag |= W_DOLLARAT;
8939 }
8940 free (x);
8941 dispose_words (xlist);
8942 free (temp1);
8943 *indexp = sindex;
8944
8945 free (name);
8946
8947 ret = alloc_word_desc ();
8948 ret->word = temp;
8949 ret->flags = tflag; /* XXX */
8950 return ret;
8951 }
8952
8953 #if defined (ARRAY_VARS)
8954 /* Process ${!ARRAY[@]} and ${!ARRAY[*]} expansion. */
8955 if (want_indir && string[sindex - 1] == RBRACE &&
8956 string[sindex - 2] == RBRACK && valid_array_reference (name+1, 0))
8957 {
8958 char *x, *x1;
8959
8960 temp1 = savestring (name + 1);
8961 x = array_variable_name (temp1, 0, &x1, (int *)0);
8962 FREE (x);
8963 if (ALL_ELEMENT_SUB (x1[0]) && x1[1] == RBRACK)
8964 {
8965 temp = array_keys (temp1, quoted, pflags); /* handles assoc vars too */
8966 if (x1[0] == '@')
8967 {
8968 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
8969 *quoted_dollar_atp = 1;
8970 if (contains_dollar_at)
8971 *contains_dollar_at = 1;
8972
8973 tflag |= W_DOLLARAT;
8974 }
8975
8976 free (name);
8977 free (temp1);
8978 *indexp = sindex;
8979
8980 ret = alloc_word_desc ();
8981 ret->word = temp;
8982 ret->flags = tflag; /* XXX */
8983 return ret;
8984 }
8985
8986 free (temp1);
8987 }
8988 #endif /* ARRAY_VARS */
8989
8990 /* Make sure that NAME is valid before trying to go on. */
8991 if (valid_brace_expansion_word (want_indir ? name + 1 : name,
8992 var_is_special) == 0)
8993 {
8994 temp = (char *)NULL;
8995 goto bad_substitution; /* substitution error */
8996 }
8997
8998 if (want_indir)
8999 {
9000 tdesc = parameter_brace_expand_indir (name + 1, var_is_special, quoted, pflags, quoted_dollar_atp, contains_dollar_at);
9001 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9002 {
9003 temp = (char *)NULL;
9004 goto bad_substitution;
9005 }
9006
9007 /* Turn off the W_ARRAYIND flag because there is no way for this function
9008 to return the index we're supposed to be using. */
9009 if (tdesc && tdesc->flags)
9010 tdesc->flags &= ~W_ARRAYIND;
9011 }
9012 else
9013 tdesc = parameter_brace_expand_word (name, var_is_special, quoted, PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS)), &ind);
9014
9015 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9016 {
9017 tflag = 0;
9018 tdesc = 0;
9019 }
9020
9021 if (tdesc)
9022 {
9023 temp = tdesc->word;
9024 tflag = tdesc->flags;
9025 dispose_word_desc (tdesc);
9026 }
9027 else
9028 temp = (char *)0;
9029
9030 if (temp == &expand_param_error || temp == &expand_param_fatal)
9031 {
9032 FREE (name);
9033 FREE (value);
9034 return (temp == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9035 }
9036
9037 #if defined (ARRAY_VARS)
9038 if (valid_array_reference (name, 0))
9039 {
9040 int qflags;
9041 char *t;
9042
9043 qflags = quoted;
9044 /* If in a context where word splitting will not take place, treat as
9045 if double-quoted. Has effects with $* and ${array[*]} */
9046
9047 if (pflags & PF_ASSIGNRHS)
9048 qflags |= Q_DOUBLE_QUOTES;
9049 /* We duplicate a little code here */
9050 t = mbschr (name, LBRACK);
9051 if (t && ALL_ELEMENT_SUB (t[1]) && t[2] == RBRACK)
9052 {
9053 all_element_arrayref = 1;
9054 if (expand_no_split_dollar_star && t[1] == '*') /* XXX */
9055 qflags |= Q_DOUBLE_QUOTES;
9056 }
9057 chk_atstar (name, qflags, pflags, quoted_dollar_atp, contains_dollar_at);
9058 }
9059 #endif
9060
9061 var_is_set = temp != (char *)0;
9062 var_is_null = check_nullness && (var_is_set == 0 || *temp == 0);
9063 /* XXX - this may not need to be restricted to special variables */
9064 if (check_nullness)
9065 var_is_null |= var_is_set && var_is_special && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL (temp);
9066 #if defined (ARRAY_VARS)
9067 if (check_nullness)
9068 var_is_null |= var_is_set &&
9069 (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) &&
9070 QUOTED_NULL (temp) &&
9071 valid_array_reference (name, 0) &&
9072 chk_atstar (name, 0, 0, (int *)0, (int *)0);
9073 #endif
9074
9075 /* Get the rest of the stuff inside the braces. */
9076 if (c && c != RBRACE)
9077 {
9078 /* Extract the contents of the ${ ... } expansion
9079 according to the Posix.2 rules. */
9080 value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD);
9081 if (string[sindex] == RBRACE)
9082 sindex++;
9083 else
9084 goto bad_substitution; /* substitution error */
9085 }
9086 else
9087 value = (char *)NULL;
9088
9089 *indexp = sindex;
9090
9091 /* All the cases where an expansion can possibly generate an unbound
9092 variable error. */
9093 if (want_substring || want_patsub || want_casemod || c == '@' || c == '#' || c == '%' || c == RBRACE)
9094 {
9095 if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]) && all_element_arrayref == 0)
9096 {
9097 set_exit_status (EXECUTION_FAILURE);
9098 err_unboundvar (name);
9099 FREE (value);
9100 FREE (temp);
9101 free (name);
9102 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9103 }
9104 }
9105
9106 /* If this is a substring spec, process it and add the result. */
9107 if (want_substring)
9108 {
9109 temp1 = parameter_brace_substring (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9110 FREE (value);
9111 FREE (temp);
9112
9113 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9114 {
9115 FREE (name);
9116 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9117 }
9118
9119 ret = alloc_word_desc ();
9120 ret->word = temp1;
9121 /* We test quoted_dollar_atp because we want variants with double-quoted
9122 "$@" to take a different code path. In fact, we make sure at the end
9123 of expand_word_internal that we're only looking at these flags if
9124 quoted_dollar_at == 0. */
9125 if (temp1 &&
9126 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9127 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9128 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9129 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 &&
9130 (pflags & PF_ASSIGNRHS))
9131 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9132 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9133 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9134 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9135
9136 FREE (name);
9137 return ret;
9138 }
9139 else if (want_patsub)
9140 {
9141 temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9142 FREE (value);
9143 FREE (temp);
9144
9145 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9146 {
9147 FREE (name);
9148 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9149 }
9150
9151 ret = alloc_word_desc ();
9152 ret->word = temp1;
9153 if (temp1 &&
9154 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9155 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9156 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9157 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9158 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9159 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9160
9161 FREE (name);
9162 return ret;
9163 }
9164 #if defined (CASEMOD_EXPANSIONS)
9165 else if (want_casemod)
9166 {
9167 temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9168 FREE (value);
9169 FREE (temp);
9170
9171 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9172 {
9173 FREE (name);
9174 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9175 }
9176
9177 ret = alloc_word_desc ();
9178 ret->word = temp1;
9179 if (temp1 &&
9180 (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
9181 QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9182 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9183 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9184 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9185 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9186
9187 FREE (name);
9188 return ret;
9189 }
9190 #endif
9191
9192 /* Do the right thing based on which character ended the variable name. */
9193 switch (c)
9194 {
9195 default:
9196 case '\0':
9197 bad_substitution:
9198 set_exit_status (EXECUTION_FAILURE);
9199 report_error (_("%s: bad substitution"), string ? string : "??");
9200 FREE (value);
9201 FREE (temp);
9202 free (name);
9203 if (shell_compatibility_level <= 43)
9204 return &expand_wdesc_error;
9205 else
9206 return ((posixly_correct && interactive_shell == 0) ? &expand_wdesc_fatal : &expand_wdesc_error);
9207
9208 case RBRACE:
9209 break;
9210
9211 case '@':
9212 temp1 = parameter_brace_transform (name, temp, ind, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9213 free (temp);
9214 free (value);
9215
9216 if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
9217 {
9218 free (name);
9219 set_exit_status (EXECUTION_FAILURE);
9220 report_error (_("%s: bad substitution"), string ? string : "??");
9221 return (temp1 == &expand_param_error ? &expand_wdesc_error : &expand_wdesc_fatal);
9222 }
9223
9224 ret = alloc_word_desc ();
9225 ret->word = temp1;
9226 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9227 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9228 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9229 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9230 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9231
9232 free (name);
9233 return ret;
9234
9235 case '#': /* ${param#[#]pattern} */
9236 case '%': /* ${param%[%]pattern} */
9237 if (value == 0 || *value == '\0' || temp == 0 || *temp == '\0')
9238 {
9239 FREE (value);
9240 break;
9241 }
9242 temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
9243 free (temp);
9244 free (value);
9245
9246 ret = alloc_word_desc ();
9247 ret->word = temp1;
9248 if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9249 ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
9250 /* Special handling for $* when unquoted and $IFS is null. Posix interp 888 */
9251 else if (temp1 && (name[0] == '*' && name[1] == 0) && quoted == 0 && ifs_is_null)
9252 ret->flags |= W_SPLITSPACE; /* Posix interp 888 */
9253
9254 free (name);
9255 return ret;
9256
9257 case '-':
9258 case '=':
9259 case '?':
9260 case '+':
9261 if (var_is_set && var_is_null == 0)
9262 {
9263 /* If the operator is `+', we don't want the value of the named
9264 variable for anything, just the value of the right hand side. */
9265 if (c == '+')
9266 {
9267 /* XXX -- if we're double-quoted and the named variable is "$@",
9268 we want to turn off any special handling of "$@" --
9269 we're not using it, so whatever is on the rhs applies. */
9270 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9271 *quoted_dollar_atp = 0;
9272 if (contains_dollar_at)
9273 *contains_dollar_at = 0;
9274
9275 FREE (temp);
9276 if (value)
9277 {
9278 /* From Posix discussion on austin-group list. Issue 221
9279 requires that backslashes escaping `}' inside
9280 double-quoted ${...} be removed. */
9281 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9282 quoted |= Q_DOLBRACE;
9283 ret = parameter_brace_expand_rhs (name, value, c,
9284 quoted,
9285 pflags,
9286 quoted_dollar_atp,
9287 contains_dollar_at);
9288 /* XXX - fix up later, esp. noting presence of
9289 W_HASQUOTEDNULL in ret->flags */
9290 free (value);
9291 }
9292 else
9293 temp = (char *)NULL;
9294 }
9295 else
9296 {
9297 FREE (value);
9298 }
9299 /* Otherwise do nothing; just use the value in TEMP. */
9300 }
9301 else /* VAR not set or VAR is NULL. */
9302 {
9303 FREE (temp);
9304 temp = (char *)NULL;
9305 if (c == '=' && var_is_special)
9306 {
9307 set_exit_status (EXECUTION_FAILURE);
9308 report_error (_("$%s: cannot assign in this way"), name);
9309 free (name);
9310 free (value);
9311 return &expand_wdesc_error;
9312 }
9313 else if (c == '?')
9314 {
9315 parameter_brace_expand_error (name, value, check_nullness);
9316 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9317 }
9318 else if (c != '+')
9319 {
9320 /* XXX -- if we're double-quoted and the named variable is "$@",
9321 we want to turn off any special handling of "$@" --
9322 we're not using it, so whatever is on the rhs applies. */
9323 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && quoted_dollar_atp)
9324 *quoted_dollar_atp = 0;
9325 if (contains_dollar_at)
9326 *contains_dollar_at = 0;
9327
9328 /* From Posix discussion on austin-group list. Issue 221 requires
9329 that backslashes escaping `}' inside double-quoted ${...} be
9330 removed. */
9331 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
9332 quoted |= Q_DOLBRACE;
9333 ret = parameter_brace_expand_rhs (name, value, c, quoted, pflags,
9334 quoted_dollar_atp,
9335 contains_dollar_at);
9336 /* XXX - fix up later, esp. noting presence of
9337 W_HASQUOTEDNULL in tdesc->flags */
9338 }
9339 free (value);
9340 }
9341
9342 break;
9343 }
9344 free (name);
9345
9346 if (ret == 0)
9347 {
9348 ret = alloc_word_desc ();
9349 ret->flags = tflag;
9350 ret->word = temp;
9351 }
9352 return (ret);
9353 }
9354
9355 /* Expand a single ${xxx} expansion. The braces are optional. When
9356 the braces are used, parameter_brace_expand() does the work,
9357 possibly calling param_expand recursively. */
9358 static WORD_DESC *
9359 param_expand (string, sindex, quoted, expanded_something,
9360 contains_dollar_at, quoted_dollar_at_p, had_quoted_null_p,
9361 pflags)
9362 char *string;
9363 int *sindex, quoted, *expanded_something, *contains_dollar_at;
9364 int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
9365 {
9366 char *temp, *temp1, uerror[3], *savecmd;
9367 int zindex, t_index, expok;
9368 unsigned char c;
9369 intmax_t number;
9370 SHELL_VAR *var;
9371 WORD_LIST *list, *l;
9372 WORD_DESC *tdesc, *ret;
9373 int tflag, nullarg;
9374
9375 /*itrace("param_expand: `%s' pflags = %d", string+*sindex, pflags);*/
9376 zindex = *sindex;
9377 c = string[++zindex];
9378
9379 temp = (char *)NULL;
9380 ret = tdesc = (WORD_DESC *)NULL;
9381 tflag = 0;
9382
9383 /* Do simple cases first. Switch on what follows '$'. */
9384 switch (c)
9385 {
9386 /* $0 .. $9? */
9387 case '0':
9388 case '1':
9389 case '2':
9390 case '3':
9391 case '4':
9392 case '5':
9393 case '6':
9394 case '7':
9395 case '8':
9396 case '9':
9397 temp1 = dollar_vars[TODIGIT (c)];
9398 /* This doesn't get called when (pflags&PF_IGNUNBOUND) != 0 */
9399 if (unbound_vars_is_error && temp1 == (char *)NULL)
9400 {
9401 uerror[0] = '$';
9402 uerror[1] = c;
9403 uerror[2] = '\0';
9404 set_exit_status (EXECUTION_FAILURE);
9405 err_unboundvar (uerror);
9406 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9407 }
9408 if (temp1)
9409 temp = (*temp1 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9410 ? quote_string (temp1)
9411 : quote_escapes (temp1);
9412 else
9413 temp = (char *)NULL;
9414
9415 break;
9416
9417 /* $$ -- pid of the invoking shell. */
9418 case '$':
9419 temp = itos (dollar_dollar_pid);
9420 break;
9421
9422 /* $# -- number of positional parameters. */
9423 case '#':
9424 temp = itos (number_of_args ());
9425 break;
9426
9427 /* $? -- return value of the last synchronous command. */
9428 case '?':
9429 temp = itos (last_command_exit_value);
9430 break;
9431
9432 /* $- -- flags supplied to the shell on invocation or by `set'. */
9433 case '-':
9434 temp = which_set_flags ();
9435 break;
9436
9437 /* $! -- Pid of the last asynchronous command. */
9438 case '!':
9439 /* If no asynchronous pids have been created, expand to nothing.
9440 If `set -u' has been executed, and no async processes have
9441 been created, this is an expansion error. */
9442 if (last_asynchronous_pid == NO_PID)
9443 {
9444 if (expanded_something)
9445 *expanded_something = 0;
9446 temp = (char *)NULL;
9447 if (unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
9448 {
9449 uerror[0] = '$';
9450 uerror[1] = c;
9451 uerror[2] = '\0';
9452 set_exit_status (EXECUTION_FAILURE);
9453 err_unboundvar (uerror);
9454 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9455 }
9456 }
9457 else
9458 temp = itos (last_asynchronous_pid);
9459 break;
9460
9461 /* The only difference between this and $@ is when the arg is quoted. */
9462 case '*': /* `$*' */
9463 list = list_rest_of_args ();
9464
9465 #if 0
9466 /* According to austin-group posix proposal by Geoff Clare in
9467 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
9468
9469 "The shell shall write a message to standard error and
9470 immediately exit when it tries to expand an unset parameter
9471 other than the '@' and '*' special parameters."
9472 */
9473
9474 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
9475 {
9476 uerror[0] = '$';
9477 uerror[1] = '*';
9478 uerror[2] = '\0';
9479 set_exit_status (EXECUTION_FAILURE);
9480 err_unboundvar (uerror);
9481 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9482 }
9483 #endif
9484
9485 /* If there are no command-line arguments, this should just
9486 disappear if there are other characters in the expansion,
9487 even if it's quoted. */
9488 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && list == 0)
9489 temp = (char *)NULL;
9490 else if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES|Q_PATQUOTE))
9491 {
9492 /* If we have "$*" we want to make a string of the positional
9493 parameters, separated by the first character of $IFS, and
9494 quote the whole string, including the separators. If IFS
9495 is unset, the parameters are separated by ' '; if $IFS is
9496 null, the parameters are concatenated. */
9497 temp = (quoted & (Q_DOUBLE_QUOTES|Q_PATQUOTE)) ? string_list_dollar_star (list, quoted, 0) : string_list (list);
9498 if (temp)
9499 {
9500 temp1 = (quoted & Q_DOUBLE_QUOTES) ? quote_string (temp) : temp;
9501 if (*temp == 0)
9502 tflag |= W_HASQUOTEDNULL;
9503 if (temp != temp1)
9504 free (temp);
9505 temp = temp1;
9506 }
9507 }
9508 else
9509 {
9510 /* We check whether or not we're eventually going to split $* here,
9511 for example when IFS is empty and we are processing the rhs of
9512 an assignment statement. In that case, we don't separate the
9513 arguments at all. Otherwise, if the $* is not quoted it is
9514 identical to $@ */
9515 if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set == 0 && (pflags & PF_ASSIGNRHS))
9516 {
9517 /* Posix interp 888: RHS of assignment, IFS unset: no splitting,
9518 separate with space */
9519 temp1 = string_list_dollar_star (list, quoted, pflags);
9520 temp = temp1 ? quote_string (temp1) : temp1;
9521 /* XXX - tentative - note that we saw a quoted null here */
9522 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
9523 tflag |= W_SAWQUOTEDNULL;
9524 FREE (temp1);
9525 }
9526 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_null && (pflags & PF_ASSIGNRHS))
9527 {
9528 /* Posix interp 888: RHS of assignment, IFS set to '' */
9529 temp1 = string_list_dollar_star (list, quoted, pflags);
9530 temp = temp1 ? quote_escapes (temp1) : temp1;
9531 FREE (temp1);
9532 }
9533 else if (expand_no_split_dollar_star && quoted == 0 && ifs_is_set && ifs_is_null == 0 && (pflags & PF_ASSIGNRHS))
9534 {
9535 /* Posix interp 888: RHS of assignment, IFS set to non-null value */
9536 temp1 = string_list_dollar_star (list, quoted, pflags);
9537 temp = temp1 ? quote_string (temp1) : temp1;
9538
9539 /* XXX - tentative - note that we saw a quoted null here */
9540 if (temp1 && *temp1 == 0 && QUOTED_NULL (temp))
9541 tflag |= W_SAWQUOTEDNULL;
9542 FREE (temp1);
9543 }
9544 /* XXX - should we check ifs_is_set here as well? */
9545 # if defined (HANDLE_MULTIBYTE)
9546 else if (expand_no_split_dollar_star && ifs_firstc[0] == 0)
9547 # else
9548 else if (expand_no_split_dollar_star && ifs_firstc == 0)
9549 # endif
9550 /* Posix interp 888: not RHS, no splitting, IFS set to '' */
9551 temp = string_list_dollar_star (list, quoted, 0);
9552 else
9553 {
9554 temp = string_list_dollar_at (list, quoted, 0);
9555 /* Set W_SPLITSPACE to make sure the individual positional
9556 parameters are split into separate arguments */
9557 #if 0
9558 if (quoted == 0 && (ifs_is_set == 0 || ifs_is_null))
9559 #else /* change with bash-5.0 */
9560 if (quoted == 0 && ifs_is_null)
9561 #endif
9562 tflag |= W_SPLITSPACE;
9563 /* If we're not quoted but we still don't want word splitting, make
9564 we quote the IFS characters to protect them from splitting (e.g.,
9565 when $@ is in the string as well). */
9566 else if (temp && quoted == 0 && ifs_is_set && (pflags & PF_ASSIGNRHS))
9567 {
9568 temp1 = quote_string (temp);
9569 free (temp);
9570 temp = temp1;
9571 }
9572 }
9573
9574 if (expand_no_split_dollar_star == 0 && contains_dollar_at)
9575 *contains_dollar_at = 1;
9576 }
9577
9578 dispose_words (list);
9579 break;
9580
9581 /* When we have "$@" what we want is "$1" "$2" "$3" ... This
9582 means that we have to turn quoting off after we split into
9583 the individually quoted arguments so that the final split
9584 on the first character of $IFS is still done. */
9585 case '@': /* `$@' */
9586 list = list_rest_of_args ();
9587
9588 #if 0
9589 /* According to austin-group posix proposal by Geoff Clare in
9590 <20090505091501.GA10097@squonk.masqnet> of 5 May 2009:
9591
9592 "The shell shall write a message to standard error and
9593 immediately exit when it tries to expand an unset parameter
9594 other than the '@' and '*' special parameters."
9595 */
9596
9597 if (list == 0 && unbound_vars_is_error && (pflags & PF_IGNUNBOUND) == 0)
9598 {
9599 uerror[0] = '$';
9600 uerror[1] = '@';
9601 uerror[2] = '\0';
9602 set_exit_status (EXECUTION_FAILURE);
9603 err_unboundvar (uerror);
9604 return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
9605 }
9606 #endif
9607
9608 for (nullarg = 0, l = list; l; l = l->next)
9609 {
9610 if (l->word && (l->word->word == 0 || l->word->word[0] == 0))
9611 nullarg = 1;
9612 }
9613
9614 /* We want to flag the fact that we saw this. We can't turn
9615 off quoting entirely, because other characters in the
9616 string might need it (consider "\"$@\""), but we need some
9617 way to signal that the final split on the first character
9618 of $IFS should be done, even though QUOTED is 1. */
9619 /* XXX - should this test include Q_PATQUOTE? */
9620 if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9621 *quoted_dollar_at_p = 1;
9622 if (contains_dollar_at)
9623 *contains_dollar_at = 1;
9624
9625 /* We want to separate the positional parameters with the first
9626 character of $IFS in case $IFS is something other than a space.
9627 We also want to make sure that splitting is done no matter what --
9628 according to POSIX.2, this expands to a list of the positional
9629 parameters no matter what IFS is set to. */
9630 /* XXX - what to do when in a context where word splitting is not
9631 performed? Even when IFS is not the default, posix seems to imply
9632 that we have to expand $@ to all the positional parameters and
9633 separate them with spaces, which are preserved because word splitting
9634 doesn't take place. See below for how we use PF_NOSPLIT2 here. */
9635
9636 /* These are the cases where word splitting will not be performed. */
9637 if (pflags & PF_ASSIGNRHS)
9638 {
9639 temp = string_list_dollar_at (list, (quoted|Q_DOUBLE_QUOTES), pflags);
9640 if (nullarg)
9641 tflag |= W_HASQUOTEDNULL; /* we know quoting produces quoted nulls */
9642 }
9643
9644 /* This needs to match what expand_word_internal does with non-quoted $@
9645 does with separating with spaces. Passing Q_DOUBLE_QUOTES means that
9646 the characters in LIST will be quoted, and PF_ASSIGNRHS ensures that
9647 they will separated by spaces. After doing this, we need the special
9648 handling for PF_NOSPLIT2 in expand_word_internal to remove the CTLESC
9649 quotes. */
9650 else if (pflags & PF_NOSPLIT2)
9651 {
9652 #if defined (HANDLE_MULTIBYTE)
9653 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc[0] != ' ')
9654 #else
9655 if (quoted == 0 && ifs_is_set && ifs_is_null == 0 && ifs_firstc != ' ')
9656 #endif
9657 /* Posix interp 888 */
9658 temp = string_list_dollar_at (list, Q_DOUBLE_QUOTES, pflags);
9659 else
9660 temp = string_list_dollar_at (list, quoted, pflags);
9661 }
9662 else
9663 temp = string_list_dollar_at (list, quoted, pflags);
9664
9665 tflag |= W_DOLLARAT;
9666 dispose_words (list);
9667 break;
9668
9669 case LBRACE:
9670 tdesc = parameter_brace_expand (string, &zindex, quoted, pflags,
9671 quoted_dollar_at_p,
9672 contains_dollar_at);
9673
9674 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9675 return (tdesc);
9676 temp = tdesc ? tdesc->word : (char *)0;
9677
9678 /* XXX */
9679 /* Quoted nulls should be removed if there is anything else
9680 in the string. */
9681 /* Note that we saw the quoted null so we can add one back at
9682 the end of this function if there are no other characters
9683 in the string, discard TEMP, and go on. The exception to
9684 this is when we have "${@}" and $1 is '', since $@ needs
9685 special handling. */
9686 if (tdesc && tdesc->word && (tdesc->flags & W_HASQUOTEDNULL) && QUOTED_NULL (temp))
9687 {
9688 if (had_quoted_null_p)
9689 *had_quoted_null_p = 1;
9690 if (*quoted_dollar_at_p == 0)
9691 {
9692 free (temp);
9693 tdesc->word = temp = (char *)NULL;
9694 }
9695
9696 }
9697
9698 ret = tdesc;
9699 goto return0;
9700
9701 /* Do command or arithmetic substitution. */
9702 case LPAREN:
9703 /* We have to extract the contents of this paren substitution. */
9704 t_index = zindex + 1;
9705 /* XXX - might want to check for string[t_index+2] == LPAREN and parse
9706 as arithmetic substitution immediately. */
9707 temp = extract_command_subst (string, &t_index, (pflags&PF_COMPLETE) ? SX_COMPLETE : 0);
9708 zindex = t_index;
9709
9710 /* For Posix.2-style `$(( ))' arithmetic substitution,
9711 extract the expression and pass it to the evaluator. */
9712 if (temp && *temp == LPAREN)
9713 {
9714 char *temp2;
9715 temp1 = temp + 1;
9716 temp2 = savestring (temp1);
9717 t_index = strlen (temp2) - 1;
9718
9719 if (temp2[t_index] != RPAREN)
9720 {
9721 free (temp2);
9722 goto comsub;
9723 }
9724
9725 /* Cut off ending `)' */
9726 temp2[t_index] = '\0';
9727
9728 if (chk_arithsub (temp2, t_index) == 0)
9729 {
9730 free (temp2);
9731 #if 0
9732 internal_warning (_("future versions of the shell will force evaluation as an arithmetic substitution"));
9733 #endif
9734 goto comsub;
9735 }
9736
9737 /* Expand variables found inside the expression. */
9738 temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
9739 free (temp2);
9740
9741 arithsub:
9742 /* No error messages. */
9743 savecmd = this_command_name;
9744 this_command_name = (char *)NULL;
9745 number = evalexp (temp1, EXP_EXPANDED, &expok);
9746 this_command_name = savecmd;
9747 free (temp);
9748 free (temp1);
9749 if (expok == 0)
9750 {
9751 if (interactive_shell == 0 && posixly_correct)
9752 {
9753 set_exit_status (EXECUTION_FAILURE);
9754 return (&expand_wdesc_fatal);
9755 }
9756 else
9757 return (&expand_wdesc_error);
9758 }
9759 temp = itos (number);
9760 break;
9761 }
9762
9763 comsub:
9764 if (pflags & PF_NOCOMSUB)
9765 /* we need zindex+1 because string[zindex] == RPAREN */
9766 temp1 = substring (string, *sindex, zindex+1);
9767 else
9768 {
9769 tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS);
9770 temp1 = tdesc ? tdesc->word : (char *)NULL;
9771 if (tdesc)
9772 dispose_word_desc (tdesc);
9773 }
9774 FREE (temp);
9775 temp = temp1;
9776 break;
9777
9778 /* Do POSIX.2d9-style arithmetic substitution. This will probably go
9779 away in a future bash release. */
9780 case '[': /*]*/
9781 /* Extract the contents of this arithmetic substitution. */
9782 t_index = zindex + 1;
9783 temp = extract_arithmetic_subst (string, &t_index);
9784 zindex = t_index;
9785 if (temp == 0)
9786 {
9787 temp = savestring (string);
9788 if (expanded_something)
9789 *expanded_something = 0;
9790 goto return0;
9791 }
9792
9793 /* Do initial variable expansion. */
9794 temp1 = expand_arith_string (temp, Q_DOUBLE_QUOTES|Q_ARITH);
9795
9796 goto arithsub;
9797
9798 default:
9799 /* Find the variable in VARIABLE_LIST. */
9800 temp = (char *)NULL;
9801
9802 for (t_index = zindex; (c = string[zindex]) && legal_variable_char (c); zindex++)
9803 ;
9804 temp1 = (zindex > t_index) ? substring (string, t_index, zindex) : (char *)NULL;
9805
9806 /* If this isn't a variable name, then just output the `$'. */
9807 if (temp1 == 0 || *temp1 == '\0')
9808 {
9809 FREE (temp1);
9810 temp = (char *)xmalloc (2);
9811 temp[0] = '$';
9812 temp[1] = '\0';
9813 if (expanded_something)
9814 *expanded_something = 0;
9815 goto return0;
9816 }
9817
9818 /* If the variable exists, return its value cell. */
9819 var = find_variable (temp1);
9820
9821 if (var && invisible_p (var) == 0 && var_isset (var))
9822 {
9823 #if defined (ARRAY_VARS)
9824 if (assoc_p (var) || array_p (var))
9825 {
9826 temp = array_p (var) ? array_reference (array_cell (var), 0)
9827 : assoc_reference (assoc_cell (var), "0");
9828 if (temp)
9829 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9830 ? quote_string (temp)
9831 : quote_escapes (temp);
9832 else if (unbound_vars_is_error)
9833 goto unbound_variable;
9834 }
9835 else
9836 #endif
9837 {
9838 temp = value_cell (var);
9839
9840 temp = (*temp && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
9841 ? quote_string (temp)
9842 : ((pflags & PF_ASSIGNRHS) ? quote_rhs (temp)
9843 : quote_escapes (temp));
9844 }
9845
9846 free (temp1);
9847
9848 goto return0;
9849 }
9850 else if (var && (invisible_p (var) || var_isset (var) == 0))
9851 temp = (char *)NULL;
9852 else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0)
9853 {
9854 temp = nameref_cell (var);
9855 #if defined (ARRAY_VARS)
9856 if (temp && *temp && valid_array_reference (temp, 0))
9857 {
9858 tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (arrayind_t *)NULL);
9859 if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
9860 return (tdesc);
9861 ret = tdesc;
9862 goto return0;
9863 }
9864 else
9865 #endif
9866 /* y=2 ; typeset -n x=y; echo $x is not the same as echo $2 in ksh */
9867 if (temp && *temp && legal_identifier (temp) == 0)
9868 {
9869 set_exit_status (EXECUTION_FAILURE);
9870 report_error (_("%s: invalid variable name for name reference"), temp);
9871 return (&expand_wdesc_error); /* XXX */
9872 }
9873 else
9874 temp = (char *)NULL;
9875 }
9876
9877 temp = (char *)NULL;
9878
9879 unbound_variable:
9880 if (unbound_vars_is_error)
9881 {
9882 set_exit_status (EXECUTION_FAILURE);
9883 err_unboundvar (temp1);
9884 }
9885 else
9886 {
9887 free (temp1);
9888 goto return0;
9889 }
9890
9891 free (temp1);
9892 set_exit_status (EXECUTION_FAILURE);
9893 return ((unbound_vars_is_error && interactive_shell == 0)
9894 ? &expand_wdesc_fatal
9895 : &expand_wdesc_error);
9896 }
9897
9898 if (string[zindex])
9899 zindex++;
9900
9901 return0:
9902 *sindex = zindex;
9903
9904 if (ret == 0)
9905 {
9906 ret = alloc_word_desc ();
9907 ret->flags = tflag; /* XXX */
9908 ret->word = temp;
9909 }
9910 return ret;
9911 }
9912
9913 void
9914 invalidate_cached_quoted_dollar_at ()
9915 {
9916 dispose_words (cached_quoted_dollar_at);
9917 cached_quoted_dollar_at = 0;
9918 }
9919
9920 /* Make a word list which is the result of parameter and variable
9921 expansion, command substitution, arithmetic substitution, and
9922 quote removal of WORD. Return a pointer to a WORD_LIST which is
9923 the result of the expansion. If WORD contains a null word, the
9924 word list returned is also null.
9925
9926 QUOTED contains flag values defined in shell.h.
9927
9928 ISEXP is used to tell expand_word_internal that the word should be
9929 treated as the result of an expansion. This has implications for
9930 how IFS characters in the word are treated.
9931
9932 CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
9933 they point to an integer value which receives information about expansion.
9934 CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
9935 EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
9936 else zero.
9937
9938 This only does word splitting in the case of $@ expansion. In that
9939 case, we split on ' '. */
9940
9941 /* Values for the local variable quoted_state. */
9942 #define UNQUOTED 0
9943 #define PARTIALLY_QUOTED 1
9944 #define WHOLLY_QUOTED 2
9945
9946 static WORD_LIST *
9947 expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_something)
9948 WORD_DESC *word;
9949 int quoted, isexp;
9950 int *contains_dollar_at;
9951 int *expanded_something;
9952 {
9953 WORD_LIST *list;
9954 WORD_DESC *tword;
9955
9956 /* The intermediate string that we build while expanding. */
9957 char *istring;
9958
9959 /* The current size of the above object. */
9960 size_t istring_size;
9961
9962 /* Index into ISTRING. */
9963 int istring_index;
9964
9965 /* Temporary string storage. */
9966 char *temp, *temp1;
9967
9968 /* The text of WORD. */
9969 register char *string;
9970
9971 /* The size of STRING. */
9972 size_t string_size;
9973
9974 /* The index into STRING. */
9975 int sindex;
9976
9977 /* This gets 1 if we see a $@ while quoted. */
9978 int quoted_dollar_at;
9979
9980 /* One of UNQUOTED, PARTIALLY_QUOTED, or WHOLLY_QUOTED, depending on
9981 whether WORD contains no quoting characters, a partially quoted
9982 string (e.g., "xx"ab), or is fully quoted (e.g., "xxab"). */
9983 int quoted_state;
9984
9985 /* State flags */
9986 int had_quoted_null;
9987 int has_quoted_ifs; /* did we add a quoted $IFS character here? */
9988 int has_dollar_at, temp_has_dollar_at;
9989 int split_on_spaces;
9990 int local_expanded;
9991 int tflag;
9992 int pflags; /* flags passed to param_expand */
9993 int mb_cur_max;
9994
9995 int assignoff; /* If assignment, offset of `=' */
9996
9997 register unsigned char c; /* Current character. */
9998 int t_index; /* For calls to string_extract_xxx. */
9999
10000 char twochars[2];
10001
10002 DECLARE_MBSTATE;
10003
10004 /* OK, let's see if we can optimize a common idiom: "$@" */
10005 if (STREQ (word->word, "\"$@\"") &&
10006 (word->flags == (W_HASDOLLAR|W_QUOTED)) &&
10007 dollar_vars[1]) /* XXX - check IFS here as well? */
10008 {
10009 if (contains_dollar_at)
10010 *contains_dollar_at = 1;
10011 if (expanded_something)
10012 *expanded_something = 1;
10013 if (cached_quoted_dollar_at)
10014 return (copy_word_list (cached_quoted_dollar_at));
10015 list = list_rest_of_args ();
10016 list = quote_list (list);
10017 cached_quoted_dollar_at = copy_word_list (list);
10018 return (list);
10019 }
10020
10021 istring = (char *)xmalloc (istring_size = DEFAULT_INITIAL_ARRAY_SIZE);
10022 istring[istring_index = 0] = '\0';
10023 quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
10024 has_quoted_ifs = 0;
10025 split_on_spaces = 0;
10026 quoted_state = UNQUOTED;
10027
10028 string = word->word;
10029 if (string == 0)
10030 goto finished_with_string;
10031 mb_cur_max = MB_CUR_MAX;
10032
10033 /* Don't need the string length for the SADD... and COPY_ macros unless
10034 multibyte characters are possible, but do need it for bounds checking. */
10035 string_size = (mb_cur_max > 1) ? strlen (string) : 1;
10036
10037 if (contains_dollar_at)
10038 *contains_dollar_at = 0;
10039
10040 assignoff = -1;
10041
10042 /* Begin the expansion. */
10043
10044 for (sindex = 0; ;)
10045 {
10046 c = string[sindex];
10047
10048 /* Case on top-level character. */
10049 switch (c)
10050 {
10051 case '\0':
10052 goto finished_with_string;
10053
10054 case CTLESC:
10055 sindex++;
10056 #if HANDLE_MULTIBYTE
10057 if (mb_cur_max > 1 && string[sindex])
10058 {
10059 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
10060 }
10061 else
10062 #endif
10063 {
10064 temp = (char *)xmalloc (3);
10065 temp[0] = CTLESC;
10066 temp[1] = c = string[sindex];
10067 temp[2] = '\0';
10068 }
10069
10070 dollar_add_string:
10071 if (string[sindex])
10072 sindex++;
10073
10074 add_string:
10075 if (temp)
10076 {
10077 istring = sub_append_string (temp, istring, &istring_index, &istring_size);
10078 temp = (char *)0;
10079 }
10080
10081 break;
10082
10083 #if defined (PROCESS_SUBSTITUTION)
10084 /* Process substitution. */
10085 case '<':
10086 case '>':
10087 {
10088 /* XXX - technically this should only be expanded at the start
10089 of a word */
10090 if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)))
10091 {
10092 sindex--; /* add_character: label increments sindex */
10093 goto add_character;
10094 }
10095 else
10096 t_index = sindex + 1; /* skip past both '<' and LPAREN */
10097
10098 temp1 = extract_process_subst (string, (c == '<') ? "<(" : ">(", &t_index, 0); /*))*/
10099 sindex = t_index;
10100
10101 /* If the process substitution specification is `<()', we want to
10102 open the pipe for writing in the child and produce output; if
10103 it is `>()', we want to open the pipe for reading in the child
10104 and consume input. */
10105 temp = temp1 ? process_substitute (temp1, (c == '>')) : (char *)0;
10106
10107 FREE (temp1);
10108
10109 goto dollar_add_string;
10110 }
10111 #endif /* PROCESS_SUBSTITUTION */
10112
10113 case '=':
10114 /* Posix.2 section 3.6.1 says that tildes following `=' in words
10115 which are not assignment statements are not expanded. If the
10116 shell isn't in posix mode, though, we perform tilde expansion
10117 on `likely candidate' unquoted assignment statements (flags
10118 include W_ASSIGNMENT but not W_QUOTED). A likely candidate
10119 contains an unquoted :~ or =~. Something to think about: we
10120 now have a flag that says to perform tilde expansion on arguments
10121 to `assignment builtins' like declare and export that look like
10122 assignment statements. We now do tilde expansion on such words
10123 even in POSIX mode. */
10124 if (word->flags & (W_ASSIGNRHS|W_NOTILDE))
10125 {
10126 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
10127 goto add_ifs_character;
10128 else
10129 goto add_character;
10130 }
10131 /* If we're not in posix mode or forcing assignment-statement tilde
10132 expansion, note where the `=' appears in the word and prepare to
10133 do tilde expansion following the first `='. */
10134 if ((word->flags & W_ASSIGNMENT) &&
10135 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
10136 assignoff == -1 && sindex > 0)
10137 assignoff = sindex;
10138 if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
10139 word->flags |= W_ITILDE;
10140 #if 0
10141 else if ((word->flags & W_ASSIGNMENT) &&
10142 (posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
10143 string[sindex+1] == '~')
10144 word->flags |= W_ITILDE;
10145 #endif
10146
10147 if (word->flags & W_ASSIGNARG)
10148 word->flags |= W_ASSIGNRHS; /* affects $@ */
10149
10150 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
10151 {
10152 has_quoted_ifs++;
10153 goto add_ifs_character;
10154 }
10155 else
10156 goto add_character;
10157
10158 case ':':
10159 if (word->flags & (W_NOTILDE|W_NOASSNTILDE))
10160 {
10161 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
10162 goto add_ifs_character;
10163 else
10164 goto add_character;
10165 }
10166
10167 if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS|W_TILDEEXP)) &&
10168 string[sindex+1] == '~')
10169 word->flags |= W_ITILDE;
10170
10171 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
10172 goto add_ifs_character;
10173 else
10174 goto add_character;
10175
10176 case '~':
10177 /* If the word isn't supposed to be tilde expanded, or we're not
10178 at the start of a word or after an unquoted : or = in an
10179 assignment statement, we don't do tilde expansion. We don't
10180 do tilde expansion if quoted or in an arithmetic context. */
10181
10182 if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
10183 (sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
10184 (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
10185 {
10186 word->flags &= ~W_ITILDE;
10187 if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
10188 goto add_ifs_character;
10189 else
10190 goto add_character;
10191 }
10192
10193 if (word->flags & W_ASSIGNRHS)
10194 tflag = 2;
10195 else if (word->flags & (W_ASSIGNMENT|W_TILDEEXP))
10196 tflag = 1;
10197 else
10198 tflag = 0;
10199
10200 temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
10201
10202 word->flags &= ~W_ITILDE;
10203
10204 if (temp && *temp && t_index > 0)
10205 {
10206 temp1 = bash_tilde_expand (temp, tflag);
10207 if (temp1 && *temp1 == '~' && STREQ (temp, temp1))
10208 {
10209 FREE (temp);
10210 FREE (temp1);
10211 goto add_character; /* tilde expansion failed */
10212 }
10213 free (temp);
10214 temp = temp1;
10215 sindex += t_index;
10216 goto add_quoted_string; /* XXX was add_string */
10217 }
10218 else
10219 {
10220 FREE (temp);
10221 goto add_character;
10222 }
10223
10224 case '$':
10225 if (expanded_something)
10226 *expanded_something = 1;
10227 local_expanded = 1;
10228
10229 temp_has_dollar_at = 0;
10230 pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
10231 if (word->flags & W_NOSPLIT2)
10232 pflags |= PF_NOSPLIT2;
10233 if (word->flags & W_ASSIGNRHS)
10234 pflags |= PF_ASSIGNRHS;
10235 if (word->flags & W_COMPLETE)
10236 pflags |= PF_COMPLETE;
10237
10238 tword = param_expand (string, &sindex, quoted, expanded_something,
10239 &temp_has_dollar_at, &quoted_dollar_at,
10240 &had_quoted_null, pflags);
10241 has_dollar_at += temp_has_dollar_at;
10242 split_on_spaces += (tword->flags & W_SPLITSPACE);
10243
10244 if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
10245 {
10246 free (string);
10247 free (istring);
10248 return ((tword == &expand_wdesc_error) ? &expand_word_error
10249 : &expand_word_fatal);
10250 }
10251 if (contains_dollar_at && has_dollar_at)
10252 *contains_dollar_at = 1;
10253
10254 if (tword && (tword->flags & W_HASQUOTEDNULL))
10255 had_quoted_null = 1; /* note for later */
10256 if (tword && (tword->flags & W_SAWQUOTEDNULL))
10257 had_quoted_null = 1; /* XXX */
10258
10259 temp = tword ? tword->word : (char *)NULL;
10260 dispose_word_desc (tword);
10261
10262 /* Kill quoted nulls; we will add them back at the end of
10263 expand_word_internal if nothing else in the string */
10264 if (had_quoted_null && temp && QUOTED_NULL (temp))
10265 {
10266 FREE (temp);
10267 temp = (char *)NULL;
10268 }
10269
10270 goto add_string;
10271 break;
10272
10273 case '`': /* Backquoted command substitution. */
10274 {
10275 t_index = sindex++;
10276
10277 temp = string_extract (string, &sindex, "`", SX_REQMATCH);
10278 /* The test of sindex against t_index is to allow bare instances of
10279 ` to pass through, for backwards compatibility. */
10280 if (temp == &extract_string_error || temp == &extract_string_fatal)
10281 {
10282 if (sindex - 1 == t_index)
10283 {
10284 sindex = t_index;
10285 goto add_character;
10286 }
10287 set_exit_status (EXECUTION_FAILURE);
10288 report_error (_("bad substitution: no closing \"`\" in %s") , string+t_index);
10289 free (string);
10290 free (istring);
10291 return ((temp == &extract_string_error) ? &expand_word_error
10292 : &expand_word_fatal);
10293 }
10294
10295 if (expanded_something)
10296 *expanded_something = 1;
10297 local_expanded = 1;
10298
10299 if (word->flags & W_NOCOMSUB)
10300 /* sindex + 1 because string[sindex] == '`' */
10301 temp1 = substring (string, t_index, sindex + 1);
10302 else
10303 {
10304 de_backslash (temp);
10305 tword = command_substitute (temp, quoted, 0);
10306 temp1 = tword ? tword->word : (char *)NULL;
10307 if (tword)
10308 dispose_word_desc (tword);
10309 }
10310 FREE (temp);
10311 temp = temp1;
10312 goto dollar_add_string;
10313 }
10314
10315 case '\\':
10316 if (string[sindex + 1] == '\n')
10317 {
10318 sindex += 2;
10319 continue;
10320 }
10321
10322 c = string[++sindex];
10323
10324 if (quoted & Q_HERE_DOCUMENT)
10325 tflag = CBSHDOC;
10326 else if (quoted & Q_DOUBLE_QUOTES)
10327 tflag = CBSDQUOTE;
10328 else
10329 tflag = 0;
10330
10331 /* From Posix discussion on austin-group list: Backslash escaping
10332 a } in ${...} is removed. Issue 0000221 */
10333 if ((quoted & Q_DOLBRACE) && c == RBRACE)
10334 {
10335 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
10336 }
10337 /* This is the fix for " $@\ " */
10338 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0) && isexp == 0 && isifs (c))
10339 {
10340 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
10341 DEFAULT_ARRAY_SIZE);
10342 istring[istring_index++] = CTLESC;
10343 istring[istring_index++] = '\\';
10344 istring[istring_index] = '\0';
10345
10346 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
10347 }
10348 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && c == 0)
10349 {
10350 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
10351 DEFAULT_ARRAY_SIZE);
10352 istring[istring_index++] = CTLESC;
10353 istring[istring_index++] = '\\';
10354 istring[istring_index] = '\0';
10355 break;
10356 }
10357 else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && ((sh_syntaxtab[c] & tflag) == 0))
10358 {
10359 SCOPY_CHAR_I (twochars, '\\', c, string, sindex, string_size);
10360 }
10361 else if (c == 0)
10362 {
10363 c = CTLNUL;
10364 sindex--; /* add_character: label increments sindex */
10365 goto add_character;
10366 }
10367 else
10368 {
10369 SCOPY_CHAR_I (twochars, CTLESC, c, string, sindex, string_size);
10370 }
10371
10372 sindex++;
10373 add_twochars:
10374 /* BEFORE jumping here, we need to increment sindex if appropriate */
10375 RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size,
10376 DEFAULT_ARRAY_SIZE);
10377 istring[istring_index++] = twochars[0];
10378 istring[istring_index++] = twochars[1];
10379 istring[istring_index] = '\0';
10380
10381 break;
10382
10383 case '"':
10384 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0))
10385 goto add_character;
10386
10387 t_index = ++sindex;
10388 temp = string_extract_double_quoted (string, &sindex, (word->flags & W_COMPLETE) ? SX_COMPLETE : 0);
10389
10390 /* If the quotes surrounded the entire string, then the
10391 whole word was quoted. */
10392 quoted_state = (t_index == 1 && string[sindex] == '\0')
10393 ? WHOLLY_QUOTED
10394 : PARTIALLY_QUOTED;
10395
10396 if (temp && *temp)
10397 {
10398 tword = alloc_word_desc ();
10399 tword->word = temp;
10400
10401 if (word->flags & W_ASSIGNARG)
10402 tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */
10403 if (word->flags & W_COMPLETE)
10404 tword->flags |= W_COMPLETE; /* for command substitutions */
10405 if (word->flags & W_NOCOMSUB)
10406 tword->flags |= W_NOCOMSUB;
10407 if (word->flags & W_NOPROCSUB)
10408 tword->flags |= W_NOPROCSUB;
10409
10410 if (word->flags & W_ASSIGNRHS)
10411 tword->flags |= W_ASSIGNRHS;
10412
10413 temp = (char *)NULL;
10414
10415 temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */
10416 /* Need to get W_HASQUOTEDNULL flag through this function. */
10417 list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL);
10418 has_dollar_at += temp_has_dollar_at;
10419
10420 if (list == &expand_word_error || list == &expand_word_fatal)
10421 {
10422 free (istring);
10423 free (string);
10424 /* expand_word_internal has already freed temp_word->word
10425 for us because of the way it prints error messages. */
10426 tword->word = (char *)NULL;
10427 dispose_word (tword);
10428 return list;
10429 }
10430
10431 dispose_word (tword);
10432
10433 /* "$@" (a double-quoted dollar-at) expands into nothing,
10434 not even a NULL word, when there are no positional
10435 parameters. Posix interp 888 says that other parts of the
10436 word that expand to quoted nulls result in quoted nulls, so
10437 we can't just throw the entire word away if we have "$@"
10438 anywhere in it. We use had_quoted_null to keep track */
10439 if (list == 0 && temp_has_dollar_at) /* XXX - was has_dollar_at */
10440 {
10441 quoted_dollar_at++;
10442 break;
10443 }
10444
10445 /* If this list comes back with a quoted null from expansion,
10446 we have either "$x" or "$@" with $1 == ''. In either case,
10447 we need to make sure we add a quoted null argument and
10448 disable the special handling that "$@" gets. */
10449 if (list && list->word && list->next == 0 && (list->word->flags & W_HASQUOTEDNULL))
10450 {
10451 if (had_quoted_null && temp_has_dollar_at)
10452 quoted_dollar_at++;
10453 had_quoted_null = 1; /* XXX */
10454 }
10455
10456 /* If we get "$@", we know we have expanded something, so we
10457 need to remember it for the final split on $IFS. This is
10458 a special case; it's the only case where a quoted string
10459 can expand into more than one word. It's going to come back
10460 from the above call to expand_word_internal as a list with
10461 multiple words. */
10462 if (list)
10463 dequote_list (list);
10464
10465 if (temp_has_dollar_at) /* XXX - was has_dollar_at */
10466 {
10467 quoted_dollar_at++;
10468 if (contains_dollar_at)
10469 *contains_dollar_at = 1;
10470 if (expanded_something)
10471 *expanded_something = 1;
10472 local_expanded = 1;
10473 }
10474 }
10475 else
10476 {
10477 /* What we have is "". This is a minor optimization. */
10478 FREE (temp);
10479 list = (WORD_LIST *)NULL;
10480 had_quoted_null = 1; /* note for later */
10481 }
10482
10483 /* The code above *might* return a list (consider the case of "$@",
10484 where it returns "$1", "$2", etc.). We can't throw away the
10485 rest of the list, and we have to make sure each word gets added
10486 as quoted. We test on tresult->next: if it is non-NULL, we
10487 quote the whole list, save it to a string with string_list, and
10488 add that string. We don't need to quote the results of this
10489 (and it would be wrong, since that would quote the separators
10490 as well), so we go directly to add_string. */
10491 if (list)
10492 {
10493 if (list->next)
10494 {
10495 /* Testing quoted_dollar_at makes sure that "$@" is
10496 split correctly when $IFS does not contain a space. */
10497 temp = quoted_dollar_at
10498 ? string_list_dollar_at (list, Q_DOUBLE_QUOTES, 0)
10499 : string_list (quote_list (list));
10500 dispose_words (list);
10501 goto add_string;
10502 }
10503 else
10504 {
10505 temp = savestring (list->word->word);
10506 tflag = list->word->flags;
10507 dispose_words (list);
10508
10509 /* If the string is not a quoted null string, we want
10510 to remove any embedded unquoted CTLNUL characters.
10511 We do not want to turn quoted null strings back into
10512 the empty string, though. We do this because we
10513 want to remove any quoted nulls from expansions that
10514 contain other characters. For example, if we have
10515 x"$*"y or "x$*y" and there are no positional parameters,
10516 the $* should expand into nothing. */
10517 /* We use the W_HASQUOTEDNULL flag to differentiate the
10518 cases: a quoted null character as above and when
10519 CTLNUL is contained in the (non-null) expansion
10520 of some variable. We use the had_quoted_null flag to
10521 pass the value through this function to its caller. */
10522 if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
10523 remove_quoted_nulls (temp); /* XXX */
10524 }
10525 }
10526 else
10527 temp = (char *)NULL;
10528
10529 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
10530 had_quoted_null = 1; /* note for later */
10531
10532 /* We do not want to add quoted nulls to strings that are only
10533 partially quoted; we can throw them away. The exception to
10534 this is when we are going to be performing word splitting,
10535 since we have to preserve a null argument if the next character
10536 will cause word splitting. */
10537 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
10538 {
10539 c = CTLNUL;
10540 sindex--;
10541 had_quoted_null = 1;
10542 goto add_character;
10543 }
10544 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
10545 continue;
10546
10547 add_quoted_string:
10548
10549 if (temp)
10550 {
10551 temp1 = temp;
10552 temp = quote_string (temp);
10553 free (temp1);
10554 goto add_string;
10555 }
10556 else
10557 {
10558 /* Add NULL arg. */
10559 c = CTLNUL;
10560 sindex--; /* add_character: label increments sindex */
10561 had_quoted_null = 1; /* note for later */
10562 goto add_character;
10563 }
10564
10565 /* break; */
10566
10567 case '\'':
10568 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
10569 goto add_character;
10570
10571 t_index = ++sindex;
10572 temp = string_extract_single_quoted (string, &sindex);
10573
10574 /* If the entire STRING was surrounded by single quotes,
10575 then the string is wholly quoted. */
10576 quoted_state = (t_index == 1 && string[sindex] == '\0')
10577 ? WHOLLY_QUOTED
10578 : PARTIALLY_QUOTED;
10579
10580 /* If all we had was '', it is a null expansion. */
10581 if (*temp == '\0')
10582 {
10583 free (temp);
10584 temp = (char *)NULL;
10585 }
10586 else
10587 remove_quoted_escapes (temp); /* ??? */
10588
10589 if (temp == 0 && quoted_state == PARTIALLY_QUOTED)
10590 had_quoted_null = 1; /* note for later */
10591
10592 /* We do not want to add quoted nulls to strings that are only
10593 partially quoted; such nulls are discarded. See above for the
10594 exception, which is when the string is going to be split.
10595 Posix interp 888/1129 */
10596 if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & (W_NOSPLIT|W_EXPANDRHS|W_ASSIGNRHS)) == W_EXPANDRHS)
10597 {
10598 c = CTLNUL;
10599 sindex--;
10600 goto add_character;
10601 }
10602
10603 if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
10604 continue;
10605
10606 /* If we have a quoted null expansion, add a quoted NULL to istring. */
10607 if (temp == 0)
10608 {
10609 c = CTLNUL;
10610 sindex--; /* add_character: label increments sindex */
10611 goto add_character;
10612 }
10613 else
10614 goto add_quoted_string;
10615
10616 /* break; */
10617
10618 case ' ':
10619 /* If we are in a context where the word is not going to be split, but
10620 we need to account for $@ and $* producing one word for each
10621 positional parameter, add quoted spaces so the spaces in the
10622 expansion of "$@", if any, behave correctly. We still may need to
10623 split if we are expanding the rhs of a word expansion. */
10624 if (ifs_is_null || split_on_spaces || ((word->flags & (W_NOSPLIT|W_NOSPLIT2|W_ASSIGNRHS)) && (word->flags & W_EXPANDRHS) == 0))
10625 {
10626 if (string[sindex])
10627 sindex++;
10628 twochars[0] = CTLESC;
10629 twochars[1] = c;
10630 goto add_twochars;
10631 }
10632 /* FALLTHROUGH */
10633
10634 default:
10635 /* This is the fix for " $@ " */
10636 add_ifs_character:
10637 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (isexp == 0 && isifs (c) && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0))
10638 {
10639 if ((quoted&(Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)
10640 has_quoted_ifs++;
10641 add_quoted_character:
10642 if (string[sindex]) /* from old goto dollar_add_string */
10643 sindex++;
10644 if (c == 0)
10645 {
10646 c = CTLNUL;
10647 goto add_character;
10648 }
10649 else
10650 {
10651 #if HANDLE_MULTIBYTE
10652 /* XXX - should make sure that c is actually multibyte,
10653 otherwise we can use the twochars branch */
10654 if (mb_cur_max > 1)
10655 sindex--;
10656
10657 if (mb_cur_max > 1)
10658 {
10659 SADD_MBQCHAR_BODY(temp, string, sindex, string_size);
10660 }
10661 else
10662 #endif
10663 {
10664 twochars[0] = CTLESC;
10665 twochars[1] = c;
10666 goto add_twochars;
10667 }
10668 }
10669 }
10670
10671 SADD_MBCHAR (temp, string, sindex, string_size);
10672
10673 add_character:
10674 RESIZE_MALLOCED_BUFFER (istring, istring_index, 1, istring_size,
10675 DEFAULT_ARRAY_SIZE);
10676 istring[istring_index++] = c;
10677 istring[istring_index] = '\0';
10678
10679 /* Next character. */
10680 sindex++;
10681 }
10682 }
10683
10684 finished_with_string:
10685 /* OK, we're ready to return. If we have a quoted string, and
10686 quoted_dollar_at is not set, we do no splitting at all; otherwise
10687 we split on ' '. The routines that call this will handle what to
10688 do if nothing has been expanded. */
10689
10690 /* Partially and wholly quoted strings which expand to the empty
10691 string are retained as an empty arguments. Unquoted strings
10692 which expand to the empty string are discarded. The single
10693 exception is the case of expanding "$@" when there are no
10694 positional parameters. In that case, we discard the expansion. */
10695
10696 /* Because of how the code that handles "" and '' in partially
10697 quoted strings works, we need to make ISTRING into a QUOTED_NULL
10698 if we saw quoting characters, but the expansion was empty.
10699 "" and '' are tossed away before we get to this point when
10700 processing partially quoted strings. This makes "" and $xxx""
10701 equivalent when xxx is unset. We also look to see whether we
10702 saw a quoted null from a ${} expansion and add one back if we
10703 need to. */
10704
10705 /* If we expand to nothing and there were no single or double quotes
10706 in the word, we throw it away. Otherwise, we return a NULL word.
10707 The single exception is for $@ surrounded by double quotes when
10708 there are no positional parameters. In that case, we also throw
10709 the word away. */
10710
10711 if (*istring == '\0')
10712 {
10713 if (quoted_dollar_at == 0 && (had_quoted_null || quoted_state == PARTIALLY_QUOTED))
10714 {
10715 istring[0] = CTLNUL;
10716 istring[1] = '\0';
10717 tword = alloc_word_desc ();
10718 tword->word = istring;
10719 istring = 0; /* avoid later free() */
10720 tword->flags |= W_HASQUOTEDNULL; /* XXX */
10721 list = make_word_list (tword, (WORD_LIST *)NULL);
10722 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10723 tword->flags |= W_QUOTED;
10724 }
10725 /* According to sh, ksh, and Posix.2, if a word expands into nothing
10726 and a double-quoted "$@" appears anywhere in it, then the entire
10727 word is removed. */
10728 /* XXX - exception appears to be that quoted null strings result in
10729 null arguments */
10730 else if (quoted_state == UNQUOTED || quoted_dollar_at)
10731 list = (WORD_LIST *)NULL;
10732 else
10733 list = (WORD_LIST *)NULL;
10734 }
10735 else if (word->flags & W_NOSPLIT)
10736 {
10737 tword = alloc_word_desc ();
10738 tword->word = istring;
10739 if (had_quoted_null && QUOTED_NULL (istring))
10740 tword->flags |= W_HASQUOTEDNULL;
10741 istring = 0; /* avoid later free() */
10742 if (word->flags & W_ASSIGNMENT)
10743 tword->flags |= W_ASSIGNMENT; /* XXX */
10744 if (word->flags & W_COMPASSIGN)
10745 tword->flags |= W_COMPASSIGN; /* XXX */
10746 if (word->flags & W_NOGLOB)
10747 tword->flags |= W_NOGLOB; /* XXX */
10748 if (word->flags & W_NOBRACE)
10749 tword->flags |= W_NOBRACE; /* XXX */
10750 if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
10751 tword->flags |= W_QUOTED;
10752 list = make_word_list (tword, (WORD_LIST *)NULL);
10753 }
10754 else if (word->flags & W_ASSIGNRHS)
10755 {
10756 list = list_string (istring, "", quoted);
10757 tword = list->word;
10758 if (had_quoted_null && QUOTED_NULL (istring))
10759 tword->flags |= W_HASQUOTEDNULL;
10760 free (list);
10761 free (istring);
10762 istring = 0; /* avoid later free() */
10763 goto set_word_flags;
10764 }
10765 else
10766 {
10767 char *ifs_chars;
10768
10769 ifs_chars = (quoted_dollar_at || has_dollar_at) ? ifs_value : (char *)NULL;
10770
10771 /* If we have $@, we need to split the results no matter what. If
10772 IFS is unset or NULL, string_list_dollar_at has separated the
10773 positional parameters with a space, so we split on space (we have
10774 set ifs_chars to " \t\n" above if ifs is unset). If IFS is set,
10775 string_list_dollar_at has separated the positional parameters
10776 with the first character of $IFS, so we split on $IFS. If
10777 SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
10778 unset or null, and we want to make sure that we split on spaces
10779 regardless of what else has happened to IFS since the expansion,
10780 or we expanded "$@" with IFS null and we need to split the positional
10781 parameters into separate words. */
10782 if (split_on_spaces)
10783 {
10784 /* If IFS is not set, and the word is not quoted, we want to split
10785 the individual words on $' \t\n'. We rely on previous steps to
10786 quote the portions of the word that should not be split */
10787 if (ifs_is_set == 0)
10788 list = list_string (istring, " \t\n", 1); /* XXX quoted == 1? */
10789 else
10790 list = list_string (istring, " ", 1); /* XXX quoted == 1? */
10791 }
10792
10793 /* If we have $@ (has_dollar_at != 0) and we are in a context where we
10794 don't want to split the result (W_NOSPLIT2), and we are not quoted,
10795 we have already separated the arguments with the first character of
10796 $IFS. In this case, we want to return a list with a single word
10797 with the separator possibly replaced with a space (it's what other
10798 shells seem to do).
10799 quoted_dollar_at is internal to this function and is set if we are
10800 passed an argument that is unquoted (quoted == 0) but we encounter a
10801 double-quoted $@ while expanding it. */
10802 else if (has_dollar_at && quoted_dollar_at == 0 && ifs_chars && quoted == 0 && (word->flags & W_NOSPLIT2))
10803 {
10804 tword = alloc_word_desc ();
10805 /* Only split and rejoin if we have to */
10806 if (*ifs_chars && *ifs_chars != ' ')
10807 {
10808 /* list_string dequotes CTLESCs in the string it's passed, so we
10809 need it to get the space separation right if space isn't the
10810 first character in IFS (but is present) and to remove the
10811 quoting we added back in param_expand(). */
10812 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
10813 /* This isn't exactly right in the case where we're expanding
10814 the RHS of an expansion like ${var-$@} where IFS=: (for
10815 example). The W_NOSPLIT2 means we do the separation with :;
10816 the list_string removes the quotes and breaks the string into
10817 a list, and the string_list rejoins it on spaces. When we
10818 return, we expect to be able to split the results, but the
10819 space separation means the right split doesn't happen. */
10820 tword->word = string_list (list);
10821 }
10822 else
10823 tword->word = istring;
10824 if (had_quoted_null && QUOTED_NULL (istring))
10825 tword->flags |= W_HASQUOTEDNULL; /* XXX */
10826 if (tword->word != istring)
10827 free (istring);
10828 istring = 0; /* avoid later free() */
10829 goto set_word_flags;
10830 }
10831 else if (has_dollar_at && ifs_chars)
10832 list = list_string (istring, *ifs_chars ? ifs_chars : " ", 1);
10833 else
10834 {
10835 tword = alloc_word_desc ();
10836 if (expanded_something && *expanded_something == 0 && has_quoted_ifs)
10837 tword->word = remove_quoted_ifs (istring);
10838 else
10839 tword->word = istring;
10840 if (had_quoted_null && QUOTED_NULL (istring)) /* should check for more than one */
10841 tword->flags |= W_HASQUOTEDNULL; /* XXX */
10842 else if (had_quoted_null)
10843 tword->flags |= W_SAWQUOTEDNULL; /* XXX */
10844 if (tword->word != istring)
10845 free (istring);
10846 istring = 0; /* avoid later free() */
10847 set_word_flags:
10848 if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || (quoted_state == WHOLLY_QUOTED))
10849 tword->flags |= W_QUOTED;
10850 if (word->flags & W_ASSIGNMENT)
10851 tword->flags |= W_ASSIGNMENT;
10852 if (word->flags & W_COMPASSIGN)
10853 tword->flags |= W_COMPASSIGN;
10854 if (word->flags & W_NOGLOB)
10855 tword->flags |= W_NOGLOB;
10856 if (word->flags & W_NOBRACE)
10857 tword->flags |= W_NOBRACE;
10858 list = make_word_list (tword, (WORD_LIST *)NULL);
10859 }
10860 }
10861
10862 free (istring);
10863 return (list);
10864 }
10865
10866 /* **************************************************************** */
10867 /* */
10868 /* Functions for Quote Removal */
10869 /* */
10870 /* **************************************************************** */
10871
10872 /* Perform quote removal on STRING. If QUOTED > 0, assume we are obeying the
10873 backslash quoting rules for within double quotes or a here document. */
10874 char *
10875 string_quote_removal (string, quoted)
10876 char *string;
10877 int quoted;
10878 {
10879 size_t slen;
10880 char *r, *result_string, *temp, *send;
10881 int sindex, tindex, dquote;
10882 unsigned char c;
10883 DECLARE_MBSTATE;
10884
10885 /* The result can be no longer than the original string. */
10886 slen = strlen (string);
10887 send = string + slen;
10888
10889 r = result_string = (char *)xmalloc (slen + 1);
10890
10891 for (dquote = sindex = 0; c = string[sindex];)
10892 {
10893 switch (c)
10894 {
10895 case '\\':
10896 c = string[++sindex];
10897 if (c == 0)
10898 {
10899 *r++ = '\\';
10900 break;
10901 }
10902 if (((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote) && (sh_syntaxtab[c] & CBSDQUOTE) == 0)
10903 *r++ = '\\';
10904 /* FALLTHROUGH */
10905
10906 default:
10907 SCOPY_CHAR_M (r, string, send, sindex);
10908 break;
10909
10910 case '\'':
10911 if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || dquote)
10912 {
10913 *r++ = c;
10914 sindex++;
10915 break;
10916 }
10917 tindex = sindex + 1;
10918 temp = string_extract_single_quoted (string, &tindex);
10919 if (temp)
10920 {
10921 strcpy (r, temp);
10922 r += strlen (r);
10923 free (temp);
10924 }
10925 sindex = tindex;
10926 break;
10927
10928 case '"':
10929 dquote = 1 - dquote;
10930 sindex++;
10931 break;
10932 }
10933 }
10934 *r = '\0';
10935 return (result_string);
10936 }
10937
10938 #if 0
10939 /* UNUSED */
10940 /* Perform quote removal on word WORD. This allocates and returns a new
10941 WORD_DESC *. */
10942 WORD_DESC *
10943 word_quote_removal (word, quoted)
10944 WORD_DESC *word;
10945 int quoted;
10946 {
10947 WORD_DESC *w;
10948 char *t;
10949
10950 t = string_quote_removal (word->word, quoted);
10951 w = alloc_word_desc ();
10952 w->word = t ? t : savestring ("");
10953 return (w);
10954 }
10955
10956 /* Perform quote removal on all words in LIST. If QUOTED is non-zero,
10957 the members of the list are treated as if they are surrounded by
10958 double quotes. Return a new list, or NULL if LIST is NULL. */
10959 WORD_LIST *
10960 word_list_quote_removal (list, quoted)
10961 WORD_LIST *list;
10962 int quoted;
10963 {
10964 WORD_LIST *result, *t, *tresult, *e;
10965
10966 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
10967 {
10968 tresult = make_word_list (word_quote_removal (t->word, quoted), (WORD_LIST *)NULL);
10969 #if 0
10970 result = (WORD_LIST *) list_append (result, tresult);
10971 #else
10972 if (result == 0)
10973 result = e = tresult;
10974 else
10975 {
10976 e->next = tresult;
10977 while (e->next)
10978 e = e->next;
10979 }
10980 #endif
10981 }
10982 return (result);
10983 }
10984 #endif
10985
10986 /*******************************************
10987 * *
10988 * Functions to perform word splitting *
10989 * *
10990 *******************************************/
10991
10992 void
10993 setifs (v)
10994 SHELL_VAR *v;
10995 {
10996 char *t;
10997 unsigned char uc;
10998
10999 ifs_var = v;
11000 ifs_value = (v && value_cell (v)) ? value_cell (v) : " \t\n";
11001
11002 ifs_is_set = ifs_var != 0;
11003 ifs_is_null = ifs_is_set && (*ifs_value == 0);
11004
11005 /* Should really merge ifs_cmap with sh_syntaxtab. XXX - doesn't yet
11006 handle multibyte chars in IFS */
11007 memset (ifs_cmap, '\0', sizeof (ifs_cmap));
11008 for (t = ifs_value ; t && *t; t++)
11009 {
11010 uc = *t;
11011 ifs_cmap[uc] = 1;
11012 }
11013
11014 #if defined (HANDLE_MULTIBYTE)
11015 if (ifs_value == 0)
11016 {
11017 ifs_firstc[0] = '\0'; /* XXX - ? */
11018 ifs_firstc_len = 1;
11019 }
11020 else
11021 {
11022 if (locale_utf8locale && UTF8_SINGLEBYTE (*ifs_value))
11023 ifs_firstc_len = (*ifs_value != 0) ? 1 : 0;
11024 else
11025 {
11026 size_t ifs_len;
11027 ifs_len = strnlen (ifs_value, MB_CUR_MAX);
11028 ifs_firstc_len = MBLEN (ifs_value, ifs_len);
11029 }
11030 if (ifs_firstc_len == 1 || ifs_firstc_len == 0 || MB_INVALIDCH (ifs_firstc_len))
11031 {
11032 ifs_firstc[0] = ifs_value[0];
11033 ifs_firstc[1] = '\0';
11034 ifs_firstc_len = 1;
11035 }
11036 else
11037 memcpy (ifs_firstc, ifs_value, ifs_firstc_len);
11038 }
11039 #else
11040 ifs_firstc = ifs_value ? *ifs_value : 0;
11041 #endif
11042 }
11043
11044 char *
11045 getifs ()
11046 {
11047 return ifs_value;
11048 }
11049
11050 /* This splits a single word into a WORD LIST on $IFS, but only if the word
11051 is not quoted. list_string () performs quote removal for us, even if we
11052 don't do any splitting. */
11053 WORD_LIST *
11054 word_split (w, ifs_chars)
11055 WORD_DESC *w;
11056 char *ifs_chars;
11057 {
11058 WORD_LIST *result;
11059
11060 if (w)
11061 {
11062 char *xifs;
11063
11064 xifs = ((w->flags & W_QUOTED) || ifs_chars == 0) ? "" : ifs_chars;
11065 result = list_string (w->word, xifs, w->flags & W_QUOTED);
11066 }
11067 else
11068 result = (WORD_LIST *)NULL;
11069
11070 return (result);
11071 }
11072
11073 /* Perform word splitting on LIST and return the RESULT. It is possible
11074 to return (WORD_LIST *)NULL. */
11075 static WORD_LIST *
11076 word_list_split (list)
11077 WORD_LIST *list;
11078 {
11079 WORD_LIST *result, *t, *tresult, *e;
11080 WORD_DESC *w;
11081
11082 for (t = list, result = (WORD_LIST *)NULL; t; t = t->next)
11083 {
11084 tresult = word_split (t->word, ifs_value);
11085 /* POSIX 2.6: "If the complete expansion appropriate for a word results
11086 in an empty field, that empty field shall be deleted from the list
11087 of fields that form the completely expanded command, unless the
11088 original word contained single-quote or double-quote characters."
11089 This is where we handle these words that contain quoted null strings
11090 and other characters that expand to nothing after word splitting. */
11091 if (tresult == 0 && t->word && (t->word->flags & W_SAWQUOTEDNULL)) /* XXX */
11092 {
11093 w = alloc_word_desc ();
11094 w->word = (char *)xmalloc (1);
11095 w->word[0] = '\0';
11096 tresult = make_word_list (w, (WORD_LIST *)NULL);
11097 }
11098 if (result == 0)
11099 result = e = tresult;
11100 else
11101 {
11102 e->next = tresult;
11103 while (e->next)
11104 e = e->next;
11105 }
11106 }
11107 return (result);
11108 }
11109
11110 /**************************************************
11111 * *
11112 * Functions to expand an entire WORD_LIST *
11113 * *
11114 **************************************************/
11115
11116 /* Do any word-expansion-specific cleanup and jump to top_level */
11117 static void
11118 exp_jump_to_top_level (v)
11119 int v;
11120 {
11121 set_pipestatus_from_exit (last_command_exit_value);
11122
11123 /* Cleanup code goes here. */
11124 expand_no_split_dollar_star = 0; /* XXX */
11125 if (expanding_redir)
11126 undo_partial_redirects ();
11127 expanding_redir = 0;
11128 assigning_in_environment = 0;
11129
11130 if (parse_and_execute_level == 0)
11131 top_level_cleanup (); /* from sig.c */
11132
11133 jump_to_top_level (v);
11134 }
11135
11136 /* Put NLIST (which is a WORD_LIST * of only one element) at the front of
11137 ELIST, and set ELIST to the new list. */
11138 #define PREPEND_LIST(nlist, elist) \
11139 do { nlist->next = elist; elist = nlist; } while (0)
11140
11141 /* Separate out any initial variable assignments from TLIST. If set -k has
11142 been executed, remove all assignment statements from TLIST. Initial
11143 variable assignments and other environment assignments are placed
11144 on SUBST_ASSIGN_VARLIST. */
11145 static WORD_LIST *
11146 separate_out_assignments (tlist)
11147 WORD_LIST *tlist;
11148 {
11149 register WORD_LIST *vp, *lp;
11150
11151 if (tlist == 0)
11152 return ((WORD_LIST *)NULL);
11153
11154 if (subst_assign_varlist)
11155 dispose_words (subst_assign_varlist); /* Clean up after previous error */
11156
11157 subst_assign_varlist = (WORD_LIST *)NULL;
11158 vp = lp = tlist;
11159
11160 /* Separate out variable assignments at the start of the command.
11161 Loop invariant: vp->next == lp
11162 Loop postcondition:
11163 lp = list of words left after assignment statements skipped
11164 tlist = original list of words
11165 */
11166 while (lp && (lp->word->flags & W_ASSIGNMENT))
11167 {
11168 vp = lp;
11169 lp = lp->next;
11170 }
11171
11172 /* If lp != tlist, we have some initial assignment statements.
11173 We make SUBST_ASSIGN_VARLIST point to the list of assignment
11174 words and TLIST point to the remaining words. */
11175 if (lp != tlist)
11176 {
11177 subst_assign_varlist = tlist;
11178 /* ASSERT(vp->next == lp); */
11179 vp->next = (WORD_LIST *)NULL; /* terminate variable list */
11180 tlist = lp; /* remainder of word list */
11181 }
11182
11183 /* vp == end of variable list */
11184 /* tlist == remainder of original word list without variable assignments */
11185 if (!tlist)
11186 /* All the words in tlist were assignment statements */
11187 return ((WORD_LIST *)NULL);
11188
11189 /* ASSERT(tlist != NULL); */
11190 /* ASSERT((tlist->word->flags & W_ASSIGNMENT) == 0); */
11191
11192 /* If the -k option is in effect, we need to go through the remaining
11193 words, separate out the assignment words, and place them on
11194 SUBST_ASSIGN_VARLIST. */
11195 if (place_keywords_in_env)
11196 {
11197 WORD_LIST *tp; /* tp == running pointer into tlist */
11198
11199 tp = tlist;
11200 lp = tlist->next;
11201
11202 /* Loop Invariant: tp->next == lp */
11203 /* Loop postcondition: tlist == word list without assignment statements */
11204 while (lp)
11205 {
11206 if (lp->word->flags & W_ASSIGNMENT)
11207 {
11208 /* Found an assignment statement, add this word to end of
11209 subst_assign_varlist (vp). */
11210 if (!subst_assign_varlist)
11211 subst_assign_varlist = vp = lp;
11212 else
11213 {
11214 vp->next = lp;
11215 vp = lp;
11216 }
11217
11218 /* Remove the word pointed to by LP from TLIST. */
11219 tp->next = lp->next;
11220 /* ASSERT(vp == lp); */
11221 lp->next = (WORD_LIST *)NULL;
11222 lp = tp->next;
11223 }
11224 else
11225 {
11226 tp = lp;
11227 lp = lp->next;
11228 }
11229 }
11230 }
11231 return (tlist);
11232 }
11233
11234 #define WEXP_VARASSIGN 0x001
11235 #define WEXP_BRACEEXP 0x002
11236 #define WEXP_TILDEEXP 0x004
11237 #define WEXP_PARAMEXP 0x008
11238 #define WEXP_PATHEXP 0x010
11239
11240 /* All of the expansions, including variable assignments at the start of
11241 the list. */
11242 #define WEXP_ALL (WEXP_VARASSIGN|WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
11243
11244 /* All of the expansions except variable assignments at the start of
11245 the list. */
11246 #define WEXP_NOVARS (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP|WEXP_PATHEXP)
11247
11248 /* All of the `shell expansions': brace expansion, tilde expansion, parameter
11249 expansion, command substitution, arithmetic expansion, word splitting, and
11250 quote removal. */
11251 #define WEXP_SHELLEXP (WEXP_BRACEEXP|WEXP_TILDEEXP|WEXP_PARAMEXP)
11252
11253 /* Take the list of words in LIST and do the various substitutions. Return
11254 a new list of words which is the expanded list, and without things like
11255 variable assignments. */
11256
11257 WORD_LIST *
11258 expand_words (list)
11259 WORD_LIST *list;
11260 {
11261 return (expand_word_list_internal (list, WEXP_ALL));
11262 }
11263
11264 /* Same as expand_words (), but doesn't hack variable or environment
11265 variables. */
11266 WORD_LIST *
11267 expand_words_no_vars (list)
11268 WORD_LIST *list;
11269 {
11270 return (expand_word_list_internal (list, WEXP_NOVARS));
11271 }
11272
11273 WORD_LIST *
11274 expand_words_shellexp (list)
11275 WORD_LIST *list;
11276 {
11277 return (expand_word_list_internal (list, WEXP_SHELLEXP));
11278 }
11279
11280 static WORD_LIST *
11281 glob_expand_word_list (tlist, eflags)
11282 WORD_LIST *tlist;
11283 int eflags;
11284 {
11285 char **glob_array, *temp_string;
11286 register int glob_index;
11287 WORD_LIST *glob_list, *output_list, *disposables, *next;
11288 WORD_DESC *tword;
11289 int x;
11290
11291 output_list = disposables = (WORD_LIST *)NULL;
11292 glob_array = (char **)NULL;
11293 while (tlist)
11294 {
11295 /* For each word, either globbing is attempted or the word is
11296 added to orig_list. If globbing succeeds, the results are
11297 added to orig_list and the word (tlist) is added to the list
11298 of disposable words. If globbing fails and failed glob
11299 expansions are left unchanged (the shell default), the
11300 original word is added to orig_list. If globbing fails and
11301 failed glob expansions are removed, the original word is
11302 added to the list of disposable words. orig_list ends up
11303 in reverse order and requires a call to REVERSE_LIST to
11304 be set right. After all words are examined, the disposable
11305 words are freed. */
11306 next = tlist->next;
11307
11308 /* If the word isn't an assignment and contains an unquoted
11309 pattern matching character, then glob it. */
11310 if ((tlist->word->flags & W_NOGLOB) == 0 &&
11311 unquoted_glob_pattern_p (tlist->word->word))
11312 {
11313 glob_array = shell_glob_filename (tlist->word->word, QGLOB_CTLESC); /* XXX */
11314
11315 /* Handle error cases.
11316 I don't think we should report errors like "No such file
11317 or directory". However, I would like to report errors
11318 like "Read failed". */
11319
11320 if (glob_array == 0 || GLOB_FAILED (glob_array))
11321 {
11322 glob_array = (char **)xmalloc (sizeof (char *));
11323 glob_array[0] = (char *)NULL;
11324 }
11325
11326 /* Dequote the current word in case we have to use it. */
11327 if (glob_array[0] == NULL)
11328 {
11329 temp_string = dequote_string (tlist->word->word);
11330 free (tlist->word->word);
11331 tlist->word->word = temp_string;
11332 }
11333
11334 /* Make the array into a word list. */
11335 glob_list = (WORD_LIST *)NULL;
11336 for (glob_index = 0; glob_array[glob_index]; glob_index++)
11337 {
11338 tword = make_bare_word (glob_array[glob_index]);
11339 glob_list = make_word_list (tword, glob_list);
11340 }
11341
11342 if (glob_list)
11343 {
11344 output_list = (WORD_LIST *)list_append (glob_list, output_list);
11345 PREPEND_LIST (tlist, disposables);
11346 }
11347 else if (fail_glob_expansion != 0)
11348 {
11349 last_command_exit_value = EXECUTION_FAILURE;
11350 report_error (_("no match: %s"), tlist->word->word);
11351 exp_jump_to_top_level (DISCARD);
11352 }
11353 else if (allow_null_glob_expansion == 0)
11354 {
11355 /* Failed glob expressions are left unchanged. */
11356 PREPEND_LIST (tlist, output_list);
11357 }
11358 else
11359 {
11360 /* Failed glob expressions are removed. */
11361 PREPEND_LIST (tlist, disposables);
11362 }
11363 }
11364 else
11365 {
11366 /* Dequote the string. */
11367 temp_string = dequote_string (tlist->word->word);
11368 free (tlist->word->word);
11369 tlist->word->word = temp_string;
11370 PREPEND_LIST (tlist, output_list);
11371 }
11372
11373 strvec_dispose (glob_array);
11374 glob_array = (char **)NULL;
11375
11376 tlist = next;
11377 }
11378
11379 if (disposables)
11380 dispose_words (disposables);
11381
11382 if (output_list)
11383 output_list = REVERSE_LIST (output_list, WORD_LIST *);
11384
11385 return (output_list);
11386 }
11387
11388 #if defined (BRACE_EXPANSION)
11389 static WORD_LIST *
11390 brace_expand_word_list (tlist, eflags)
11391 WORD_LIST *tlist;
11392 int eflags;
11393 {
11394 register char **expansions;
11395 char *temp_string;
11396 WORD_LIST *disposables, *output_list, *next;
11397 WORD_DESC *w;
11398 int eindex;
11399
11400 for (disposables = output_list = (WORD_LIST *)NULL; tlist; tlist = next)
11401 {
11402 next = tlist->next;
11403
11404 if (tlist->word->flags & W_NOBRACE)
11405 {
11406 /*itrace("brace_expand_word_list: %s: W_NOBRACE", tlist->word->word);*/
11407 PREPEND_LIST (tlist, output_list);
11408 continue;
11409 }
11410
11411 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
11412 {
11413 /*itrace("brace_expand_word_list: %s: W_COMPASSIGN|W_ASSIGNARG", tlist->word->word);*/
11414 PREPEND_LIST (tlist, output_list);
11415 continue;
11416 }
11417
11418 /* Only do brace expansion if the word has a brace character. If
11419 not, just add the word list element to BRACES and continue. In
11420 the common case, at least when running shell scripts, this will
11421 degenerate to a bunch of calls to `mbschr', and then what is
11422 basically a reversal of TLIST into BRACES, which is corrected
11423 by a call to REVERSE_LIST () on BRACES when the end of TLIST
11424 is reached. */
11425 if (mbschr (tlist->word->word, LBRACE))
11426 {
11427 expansions = brace_expand (tlist->word->word);
11428
11429 for (eindex = 0; temp_string = expansions[eindex]; eindex++)
11430 {
11431 w = alloc_word_desc ();
11432 w->word = temp_string;
11433
11434 /* If brace expansion didn't change the word, preserve
11435 the flags. We may want to preserve the flags
11436 unconditionally someday -- XXX */
11437 if (STREQ (temp_string, tlist->word->word))
11438 w->flags = tlist->word->flags;
11439 else
11440 w = make_word_flags (w, temp_string);
11441
11442 output_list = make_word_list (w, output_list);
11443 }
11444 free (expansions);
11445
11446 /* Add TLIST to the list of words to be freed after brace
11447 expansion has been performed. */
11448 PREPEND_LIST (tlist, disposables);
11449 }
11450 else
11451 PREPEND_LIST (tlist, output_list);
11452 }
11453
11454 if (disposables)
11455 dispose_words (disposables);
11456
11457 if (output_list)
11458 output_list = REVERSE_LIST (output_list, WORD_LIST *);
11459
11460 return (output_list);
11461 }
11462 #endif
11463
11464 #if defined (ARRAY_VARS)
11465 /* Take WORD, a compound array assignment, and internally run (for example),
11466 'declare -A w', where W is the variable name portion of WORD. OPTION is
11467 the list of options to supply to `declare'. CMD is the declaration command
11468 we are expanding right now; it's unused currently. */
11469 static int
11470 make_internal_declare (word, option, cmd)
11471 char *word;
11472 char *option;
11473 char *cmd;
11474 {
11475 int t, r;
11476 WORD_LIST *wl;
11477 WORD_DESC *w;
11478
11479 w = make_word (word);
11480
11481 t = assignment (w->word, 0);
11482 if (w->word[t] == '=')
11483 {
11484 w->word[t] = '\0';
11485 if (w->word[t - 1] == '+') /* cut off any append op */
11486 w->word[t - 1] = '\0';
11487 }
11488
11489 wl = make_word_list (w, (WORD_LIST *)NULL);
11490 wl = make_word_list (make_word (option), wl);
11491
11492 r = declare_builtin (wl);
11493
11494 dispose_words (wl);
11495 return r;
11496 }
11497
11498 /* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME
11499 is an associative array.
11500
11501 If we are processing an indexed array, expand_compound_array_assignment
11502 will expand all the individual words and quote_compound_array_list will
11503 single-quote them. If we are processing an associative array, we use
11504 parse_string_to_word_list to split VALUE into a list of words instead of
11505 faking up a shell variable and calling expand_compound_array_assignment.
11506 expand_and_quote_assoc_word expands and single-quotes each word in VALUE
11507 together so we don't have problems finding the end of the subscript when
11508 quoting it.
11509
11510 Words in VALUE can be individual words, which are expanded and single-quoted,
11511 or words of the form [IND]=VALUE, which end up as explained below, as
11512 ['expanded-ind']='expanded-value'. */
11513
11514 static WORD_LIST *
11515 expand_oneword (value, flags)
11516 char *value;
11517 int flags;
11518 {
11519 WORD_LIST *l, *nl;
11520 char *t;
11521
11522 if (flags == 0)
11523 {
11524 /* Indexed array */
11525 l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags);
11526 /* Now we quote the results of the expansion above to prevent double
11527 expansion. */
11528 quote_compound_array_list (l, flags);
11529 return l;
11530 }
11531 else
11532 {
11533 /* Associative array */
11534 l = parse_string_to_word_list (value, 1, "array assign");
11535 /* For associative arrays, with their arbitrary subscripts, we have to
11536 expand and quote in one step so we don't have to search for the
11537 closing right bracket more than once. */
11538 for (nl = l; nl; nl = nl->next)
11539 {
11540 if ((nl->word->flags & W_ASSIGNMENT) == 0)
11541 t = sh_single_quote (nl->word->word ? nl->word->word : "");
11542 else
11543 t = expand_and_quote_assoc_word (nl->word->word, flags);
11544 free (nl->word->word);
11545 nl->word->word = t;
11546 }
11547 return l;
11548 }
11549 }
11550
11551 /* Expand a single compound assignment argument to a declaration builtin.
11552 This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through
11553 unchanged. The VALUE is expanded and each word in the result is single-
11554 quoted. Words of the form [key]=value end up as
11555 ['expanded-key']='expanded-value'. Associative arrays have special
11556 handling, see expand_oneword() above. The return value is
11557 NAME[+]=( expanded-and-quoted-VALUE ). */
11558 static void
11559 expand_compound_assignment_word (tlist, flags)
11560 WORD_LIST *tlist;
11561 int flags;
11562 {
11563 WORD_LIST *l;
11564 int wlen, oind, t;
11565 char *value, *temp;
11566
11567 /*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/
11568 t = assignment (tlist->word->word, 0);
11569
11570 /* value doesn't have the open and close parens */
11571 oind = 1;
11572 value = extract_array_assignment_list (tlist->word->word + t + 1, &oind);
11573 /* This performs one round of expansion on the index/key and value and
11574 single-quotes each word in the result. */
11575 l = expand_oneword (value, flags);
11576 free (value);
11577
11578 value = string_list (l);
11579 wlen = STRLEN (value);
11580
11581 /* Now, let's rebuild the string */
11582 temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */
11583 memcpy (temp, tlist->word->word, ++t);
11584 temp[t++] = '(';
11585 if (value)
11586 memcpy (temp + t, value, wlen);
11587 t += wlen;
11588 temp[t++] = ')';
11589 temp[t] = '\0';
11590 /*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/
11591
11592 free (tlist->word->word);
11593 tlist->word->word = temp;
11594
11595 free (value);
11596 }
11597
11598 /* Expand and process an argument to a declaration command. We have already
11599 set flags in TLIST->word->flags depending on the declaration command
11600 (declare, local, etc.) and the options supplied to it (-a, -A, etc.).
11601 TLIST->word->word is of the form NAME[+]=( VALUE ).
11602
11603 This does several things, all using pieces of other functions to get the
11604 evaluation sequence right. It's called for compound array assignments with
11605 the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs).
11606 It parses out which flags need to be set for declare to create the variable
11607 correctly, then calls declare internally (make_internal_declare) to make
11608 sure the variable exists with the correct attributes. Before the variable
11609 is created, it calls expand_compound_assignment_word to expand VALUE to a
11610 list of words, appropriately quoted for further evaluation. This preserves
11611 the semantics of word-expansion-before-calling-builtins. Finally, it calls
11612 do_word_assignment to perform the expansion and assignment with the same
11613 expansion semantics as a standalone assignment statement (no word splitting,
11614 etc.) even though the word is single-quoted so all that needs to happen is
11615 quote removal. */
11616 static WORD_LIST *
11617 expand_declaration_argument (tlist, wcmd)
11618 WORD_LIST *tlist, *wcmd;
11619 {
11620 char opts[16], omap[128];
11621 int t, opti, oind, skip, inheriting;
11622 WORD_LIST *l;
11623
11624 inheriting = localvar_inherit;
11625 opti = 0;
11626 if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY))
11627 opts[opti++] = '-';
11628
11629 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
11630 {
11631 opts[opti++] = 'g';
11632 opts[opti++] = 'A';
11633 }
11634 else if (tlist->word->flags & W_ASSIGNASSOC)
11635 {
11636 opts[opti++] = 'A';
11637 }
11638 else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
11639 {
11640 opts[opti++] = 'g';
11641 opts[opti++] = 'a';
11642 }
11643 else if (tlist->word->flags & W_ASSIGNARRAY)
11644 {
11645 opts[opti++] = 'a';
11646 }
11647 else if (tlist->word->flags & W_ASSNGLOBAL)
11648 opts[opti++] = 'g';
11649
11650 if (tlist->word->flags & W_CHKLOCAL)
11651 opts[opti++] = 'G';
11652
11653 /* If we have special handling note the integer attribute and others
11654 that transform the value upon assignment. What we do is take all
11655 of the option arguments and scan through them looking for options
11656 that cause such transformations, and add them to the `opts' array. */
11657
11658 memset (omap, '\0', sizeof (omap));
11659 for (l = wcmd->next; l != tlist; l = l->next)
11660 {
11661 if (l->word->word[0] != '-')
11662 break; /* non-option argument */
11663 if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0)
11664 break; /* -- signals end of options */
11665 for (oind = 1; l->word->word[oind]; oind++)
11666 switch (l->word->word[oind])
11667 {
11668 case 'I':
11669 inheriting = 1;
11670 case 'i':
11671 case 'l':
11672 case 'u':
11673 case 'c':
11674 omap[l->word->word[oind]] = 1;
11675 if (opti == 0)
11676 opts[opti++] = '-';
11677 break;
11678 default:
11679 break;
11680 }
11681 }
11682
11683 for (oind = 0; oind < sizeof (omap); oind++)
11684 if (omap[oind])
11685 opts[opti++] = oind;
11686
11687 /* If there are no -a/-A options, but we have a compound assignment,
11688 we have a choice: we can set opts[0]='-', opts[1]='a', since the
11689 default is to create an indexed array, and call
11690 make_internal_declare with that, or we can just skip the -a and let
11691 declare_builtin deal with it. Once we're here, we're better set
11692 up for the latter, since we don't want to deal with looking up
11693 any existing variable here -- better to let declare_builtin do it.
11694 We need the variable created, though, especially if it's local, so
11695 we get the scoping right before we call do_word_assignment.
11696 To ensure that make_local_declare gets called, we add `--' if there
11697 aren't any options. */
11698 if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0)
11699 {
11700 if (opti == 0)
11701 {
11702 opts[opti++] = '-';
11703 opts[opti++] = '-';
11704 }
11705 }
11706 opts[opti] = '\0';
11707
11708 /* This isn't perfect, but it's a start. Improvements later. We expand
11709 tlist->word->word and single-quote the results to avoid multiple
11710 expansions by, say, do_assignment_internal(). We have to weigh the
11711 cost of reconstructing the compound assignment string with its single
11712 quoting and letting the declare builtin handle it. The single quotes
11713 will prevent any unwanted additional expansion or word splitting. */
11714 expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0);
11715
11716 skip = 0;
11717 if (opti > 0)
11718 {
11719 t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0);
11720 if (t != EXECUTION_SUCCESS)
11721 {
11722 last_command_exit_value = t;
11723 if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */
11724 skip = 1;
11725 else
11726 exp_jump_to_top_level (DISCARD);
11727 }
11728 }
11729
11730 if (skip == 0)
11731 {
11732 t = do_word_assignment (tlist->word, 0);
11733 if (t == 0)
11734 {
11735 last_command_exit_value = EXECUTION_FAILURE;
11736 exp_jump_to_top_level (DISCARD);
11737 }
11738 }
11739
11740 /* Now transform the word as ksh93 appears to do and go on */
11741 t = assignment (tlist->word->word, 0);
11742 tlist->word->word[t] = '\0';
11743 if (tlist->word->word[t - 1] == '+')
11744 tlist->word->word[t - 1] = '\0'; /* cut off append op */
11745 tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
11746
11747 return (tlist);
11748 }
11749 #endif /* ARRAY_VARS */
11750
11751 static WORD_LIST *
11752 shell_expand_word_list (tlist, eflags)
11753 WORD_LIST *tlist;
11754 int eflags;
11755 {
11756 WORD_LIST *expanded, *orig_list, *new_list, *next, *temp_list, *wcmd;
11757 int expanded_something, has_dollar_at;
11758
11759 /* We do tilde expansion all the time. This is what 1003.2 says. */
11760 wcmd = new_list = (WORD_LIST *)NULL;
11761
11762 for (orig_list = tlist; tlist; tlist = next)
11763 {
11764 if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN))
11765 wcmd = tlist;
11766
11767 next = tlist->next;
11768
11769 #if defined (ARRAY_VARS)
11770 /* If this is a compound array assignment to a builtin that accepts
11771 such assignments (e.g., `declare'), take the assignment and perform
11772 it separately, handling the semantics of declarations inside shell
11773 functions. This avoids the double-evaluation of such arguments,
11774 because `declare' does some evaluation of compound assignments on
11775 its own. */
11776 if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
11777 expand_declaration_argument (tlist, wcmd);
11778 #endif
11779
11780 expanded_something = 0;
11781 expanded = expand_word_internal
11782 (tlist->word, 0, 0, &has_dollar_at, &expanded_something);
11783
11784 if (expanded == &expand_word_error || expanded == &expand_word_fatal)
11785 {
11786 /* By convention, each time this error is returned,
11787 tlist->word->word has already been freed. */
11788 tlist->word->word = (char *)NULL;
11789
11790 /* Dispose our copy of the original list. */
11791 dispose_words (orig_list);
11792 /* Dispose the new list we're building. */
11793 dispose_words (new_list);
11794
11795 last_command_exit_value = EXECUTION_FAILURE;
11796 if (expanded == &expand_word_error)
11797 exp_jump_to_top_level (DISCARD);
11798 else
11799 exp_jump_to_top_level (FORCE_EOF);
11800 }
11801
11802 /* Don't split words marked W_NOSPLIT. */
11803 if (expanded_something && (tlist->word->flags & W_NOSPLIT) == 0)
11804 {
11805 temp_list = word_list_split (expanded);
11806 dispose_words (expanded);
11807 }
11808 else
11809 {
11810 /* If no parameter expansion, command substitution, process
11811 substitution, or arithmetic substitution took place, then
11812 do not do word splitting. We still have to remove quoted
11813 null characters from the result. */
11814 word_list_remove_quoted_nulls (expanded);
11815 temp_list = expanded;
11816 }
11817
11818 expanded = REVERSE_LIST (temp_list, WORD_LIST *);
11819 new_list = (WORD_LIST *)list_append (expanded, new_list);
11820 }
11821
11822 if (orig_list)
11823 dispose_words (orig_list);
11824
11825 if (new_list)
11826 new_list = REVERSE_LIST (new_list, WORD_LIST *);
11827
11828 return (new_list);
11829 }
11830
11831 /* The workhorse for expand_words () and expand_words_no_vars ().
11832 First arg is LIST, a WORD_LIST of words.
11833 Second arg EFLAGS is a flags word controlling which expansions are
11834 performed.
11835
11836 This does all of the substitutions: brace expansion, tilde expansion,
11837 parameter expansion, command substitution, arithmetic expansion,
11838 process substitution, word splitting, and pathname expansion, according
11839 to the bits set in EFLAGS. Words with the W_QUOTED or W_NOSPLIT bits
11840 set, or for which no expansion is done, do not undergo word splitting.
11841 Words with the W_NOGLOB bit set do not undergo pathname expansion; words
11842 with W_NOBRACE set do not undergo brace expansion (see
11843 brace_expand_word_list above). */
11844 static WORD_LIST *
11845 expand_word_list_internal (list, eflags)
11846 WORD_LIST *list;
11847 int eflags;
11848 {
11849 WORD_LIST *new_list, *temp_list;
11850 int tint;
11851 char *savecmd;
11852
11853 tempenv_assign_error = 0;
11854 if (list == 0)
11855 return ((WORD_LIST *)NULL);
11856
11857 garglist = new_list = copy_word_list (list);
11858 if (eflags & WEXP_VARASSIGN)
11859 {
11860 garglist = new_list = separate_out_assignments (new_list);
11861 if (new_list == 0)
11862 {
11863 if (subst_assign_varlist)
11864 {
11865 /* All the words were variable assignments, so they are placed
11866 into the shell's environment. */
11867 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
11868 {
11869 savecmd = this_command_name;
11870 this_command_name = (char *)NULL; /* no arithmetic errors */
11871 tint = do_word_assignment (temp_list->word, 0);
11872 this_command_name = savecmd;
11873 /* Variable assignment errors in non-interactive shells
11874 running in Posix.2 mode cause the shell to exit, unless
11875 they are being run by the `command' builtin. */
11876 if (tint == 0)
11877 {
11878 last_command_exit_value = EXECUTION_FAILURE;
11879 if (interactive_shell == 0 && posixly_correct && executing_command_builtin == 0)
11880 exp_jump_to_top_level (FORCE_EOF);
11881 else
11882 exp_jump_to_top_level (DISCARD);
11883 }
11884 }
11885 dispose_words (subst_assign_varlist);
11886 subst_assign_varlist = (WORD_LIST *)NULL;
11887 }
11888 return ((WORD_LIST *)NULL);
11889 }
11890 }
11891
11892 /* Begin expanding the words that remain. The expansions take place on
11893 things that aren't really variable assignments. */
11894
11895 #if defined (BRACE_EXPANSION)
11896 /* Do brace expansion on this word if there are any brace characters
11897 in the string. */
11898 if ((eflags & WEXP_BRACEEXP) && brace_expansion && new_list)
11899 new_list = brace_expand_word_list (new_list, eflags);
11900 #endif /* BRACE_EXPANSION */
11901
11902 /* Perform the `normal' shell expansions: tilde expansion, parameter and
11903 variable substitution, command substitution, arithmetic expansion,
11904 and word splitting. */
11905 new_list = shell_expand_word_list (new_list, eflags);
11906
11907 /* Okay, we're almost done. Now let's just do some filename
11908 globbing. */
11909 if (new_list)
11910 {
11911 if ((eflags & WEXP_PATHEXP) && disallow_filename_globbing == 0)
11912 /* Glob expand the word list unless globbing has been disabled. */
11913 new_list = glob_expand_word_list (new_list, eflags);
11914 else
11915 /* Dequote the words, because we're not performing globbing. */
11916 new_list = dequote_list (new_list);
11917 }
11918
11919 if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
11920 {
11921 sh_wassign_func_t *assign_func;
11922 int is_special_builtin, is_builtin_or_func;
11923
11924 /* If the remainder of the words expand to nothing, Posix.2 requires
11925 that the variable and environment assignments affect the shell's
11926 environment. */
11927 assign_func = new_list ? assign_in_env : do_word_assignment;
11928 tempenv_assign_error = 0;
11929
11930 is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
11931 /* Posix says that special builtins exit if a variable assignment error
11932 occurs in an assignment preceding it. */
11933 is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
11934
11935 for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
11936 {
11937 savecmd = this_command_name;
11938 this_command_name = (char *)NULL;
11939 assigning_in_environment = (assign_func == assign_in_env);
11940 tint = (*assign_func) (temp_list->word, is_builtin_or_func);
11941 assigning_in_environment = 0;
11942 this_command_name = savecmd;
11943 /* Variable assignment errors in non-interactive shells running
11944 in Posix.2 mode cause the shell to exit. */
11945 if (tint == 0)
11946 {
11947 if (assign_func == do_word_assignment)
11948 {
11949 last_command_exit_value = EXECUTION_FAILURE;
11950 if (interactive_shell == 0 && posixly_correct)
11951 exp_jump_to_top_level (FORCE_EOF);
11952 else
11953 exp_jump_to_top_level (DISCARD);
11954 }
11955 else if (interactive_shell == 0 && is_special_builtin)
11956 {
11957 last_command_exit_value = EXECUTION_FAILURE;
11958 exp_jump_to_top_level (FORCE_EOF);
11959 }
11960 else
11961 tempenv_assign_error++;
11962 }
11963 }
11964
11965 dispose_words (subst_assign_varlist);
11966 subst_assign_varlist = (WORD_LIST *)NULL;
11967 }
11968
11969 return (new_list);
11970 }