powerpc: Remove powerpc64 strncmp variants
[glibc.git] / posix / wordexp.c
blob0da98f5b083139629dda47ba554817d0551b6b69
1 /* POSIX.2 wordexp implementation.
2 Copyright (C) 1997-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <ctype.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <fnmatch.h>
23 #include <glob.h>
24 #include <libintl.h>
25 #include <paths.h>
26 #include <pwd.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/param.h>
31 #include <sys/wait.h>
32 #include <unistd.h>
33 #include <wordexp.h>
34 #include <spawn.h>
35 #include <scratch_buffer.h>
36 #include <_itoa.h>
37 #include <assert.h>
40 * This is a recursive-descent-style word expansion routine.
43 /* These variables are defined and initialized in the startup code. */
44 extern int __libc_argc attribute_hidden;
45 extern char **__libc_argv attribute_hidden;
47 /* Some forward declarations */
48 static int parse_dollars (char **word, size_t *word_length, size_t *max_length,
49 const char *words, size_t *offset, int flags,
50 wordexp_t *pwordexp, const char *ifs,
51 const char *ifs_white, int quoted);
52 static int parse_backtick (char **word, size_t *word_length,
53 size_t *max_length, const char *words,
54 size_t *offset, int flags, wordexp_t *pwordexp,
55 const char *ifs, const char *ifs_white);
56 static int parse_dquote (char **word, size_t *word_length, size_t *max_length,
57 const char *words, size_t *offset, int flags,
58 wordexp_t *pwordexp, const char *ifs,
59 const char *ifs_white);
60 static int eval_expr (char *expr, long int *result);
62 /* The w_*() functions manipulate word lists. */
64 #define W_CHUNK (100)
66 /* Result of w_newword will be ignored if it's the last word. */
67 static inline char *
68 w_newword (size_t *actlen, size_t *maxlen)
70 *actlen = *maxlen = 0;
71 return NULL;
74 static char *
75 w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch)
76 /* (lengths exclude trailing zero) */
78 /* Add a character to the buffer, allocating room for it if needed. */
80 if (*actlen == *maxlen)
82 char *old_buffer = buffer;
83 assert (buffer == NULL || *maxlen != 0);
84 *maxlen += W_CHUNK;
85 buffer = (char *) realloc (buffer, 1 + *maxlen);
87 if (buffer == NULL)
88 free (old_buffer);
91 if (buffer != NULL)
93 buffer[*actlen] = ch;
94 buffer[++(*actlen)] = '\0';
97 return buffer;
100 static char *
101 w_addmem (char *buffer, size_t *actlen, size_t *maxlen, const char *str,
102 size_t len)
104 /* Add a string to the buffer, allocating room for it if needed.
106 if (*actlen + len > *maxlen)
108 char *old_buffer = buffer;
109 assert (buffer == NULL || *maxlen != 0);
110 *maxlen += MAX (2 * len, W_CHUNK);
111 buffer = realloc (old_buffer, 1 + *maxlen);
113 if (buffer == NULL)
114 free (old_buffer);
117 if (buffer != NULL)
119 *((char *) __mempcpy (&buffer[*actlen], str, len)) = '\0';
120 *actlen += len;
123 return buffer;
126 static char *
127 w_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str)
128 /* (lengths exclude trailing zero) */
130 /* Add a string to the buffer, allocating room for it if needed.
132 size_t len;
134 assert (str != NULL); /* w_addstr only called from this file */
135 len = strlen (str);
137 return w_addmem (buffer, actlen, maxlen, str, len);
140 static int
141 w_addword (wordexp_t *pwordexp, char *word)
143 /* Add a word to the wordlist */
144 size_t num_p;
145 char **new_wordv;
146 bool allocated = false;
148 /* Internally, NULL acts like "". Convert NULLs to "" before
149 * the caller sees them.
151 if (word == NULL)
153 word = __strdup ("");
154 if (word == NULL)
155 goto no_space;
156 allocated = true;
159 num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
160 new_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p);
161 if (new_wordv != NULL)
163 pwordexp->we_wordv = new_wordv;
164 pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc++] = word;
165 pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc] = NULL;
166 return 0;
169 if (allocated)
170 free (word);
172 no_space:
173 return WRDE_NOSPACE;
176 /* The parse_*() functions should leave *offset being the offset in 'words'
177 * to the last character processed.
180 static int
181 parse_backslash (char **word, size_t *word_length, size_t *max_length,
182 const char *words, size_t *offset)
184 /* We are poised _at_ a backslash, not in quotes */
186 switch (words[1 + *offset])
188 case 0:
189 /* Backslash is last character of input words */
190 return WRDE_SYNTAX;
192 case '\n':
193 ++(*offset);
194 break;
196 default:
197 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
198 if (*word == NULL)
199 return WRDE_NOSPACE;
201 ++(*offset);
202 break;
205 return 0;
208 static int
209 parse_qtd_backslash (char **word, size_t *word_length, size_t *max_length,
210 const char *words, size_t *offset)
212 /* We are poised _at_ a backslash, inside quotes */
214 switch (words[1 + *offset])
216 case 0:
217 /* Backslash is last character of input words */
218 return WRDE_SYNTAX;
220 case '\n':
221 ++(*offset);
222 break;
224 case '$':
225 case '`':
226 case '"':
227 case '\\':
228 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
229 if (*word == NULL)
230 return WRDE_NOSPACE;
232 ++(*offset);
233 break;
235 default:
236 *word = w_addchar (*word, word_length, max_length, words[*offset]);
237 if (*word != NULL)
238 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
240 if (*word == NULL)
241 return WRDE_NOSPACE;
243 ++(*offset);
244 break;
247 return 0;
250 static int
251 parse_tilde (char **word, size_t *word_length, size_t *max_length,
252 const char *words, size_t *offset, size_t wordc)
254 /* We are poised _at_ a tilde */
255 size_t i;
257 if (*word_length != 0)
259 if (!((*word)[*word_length - 1] == '=' && wordc == 0))
261 if (!((*word)[*word_length - 1] == ':'
262 && strchr (*word, '=') && wordc == 0))
264 *word = w_addchar (*word, word_length, max_length, '~');
265 return *word ? 0 : WRDE_NOSPACE;
270 for (i = 1 + *offset; words[i]; i++)
272 if (words[i] == ':' || words[i] == '/' || words[i] == ' '
273 || words[i] == '\t' || words[i] == 0 )
274 break;
276 if (words[i] == '\\')
278 *word = w_addchar (*word, word_length, max_length, '~');
279 return *word ? 0 : WRDE_NOSPACE;
283 if (i == 1 + *offset)
285 /* Tilde appears on its own */
286 char* home;
288 /* POSIX.2 says ~ expands to $HOME and if HOME is unset the
289 results are unspecified. We do a lookup on the uid if
290 HOME is unset. */
292 home = getenv ("HOME");
293 if (home != NULL)
295 *word = w_addstr (*word, word_length, max_length, home);
296 if (*word == NULL)
297 return WRDE_NOSPACE;
299 else
301 struct passwd pwd, *tpwd;
302 uid_t uid = __getuid ();
303 int result;
304 struct scratch_buffer tmpbuf;
305 scratch_buffer_init (&tmpbuf);
307 while ((result = __getpwuid_r (uid, &pwd,
308 tmpbuf.data, tmpbuf.length,
309 &tpwd)) != 0
310 && errno == ERANGE)
311 if (!scratch_buffer_grow (&tmpbuf))
312 return WRDE_NOSPACE;
314 if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL)
316 *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
317 if (*word == NULL)
319 scratch_buffer_free (&tmpbuf);
320 return WRDE_NOSPACE;
323 else
325 *word = w_addchar (*word, word_length, max_length, '~');
326 if (*word == NULL)
328 scratch_buffer_free (&tmpbuf);
329 return WRDE_NOSPACE;
332 scratch_buffer_free (&tmpbuf);
335 else
337 /* Look up user name in database to get home directory */
338 char *user = strndupa (&words[1 + *offset], i - (1 + *offset));
339 struct passwd pwd, *tpwd;
340 int result;
341 struct scratch_buffer tmpbuf;
342 scratch_buffer_init (&tmpbuf);
344 while ((result = __getpwnam_r (user, &pwd, tmpbuf.data, tmpbuf.length,
345 &tpwd)) != 0
346 && errno == ERANGE)
347 if (!scratch_buffer_grow (&tmpbuf))
348 return WRDE_NOSPACE;
350 if (result == 0 && tpwd != NULL && pwd.pw_dir)
351 *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
352 else
354 /* (invalid login name) */
355 *word = w_addchar (*word, word_length, max_length, '~');
356 if (*word != NULL)
357 *word = w_addstr (*word, word_length, max_length, user);
360 scratch_buffer_free (&tmpbuf);
362 *offset = i - 1;
364 return *word ? 0 : WRDE_NOSPACE;
368 static int
369 do_parse_glob (const char *glob_word, char **word, size_t *word_length,
370 size_t *max_length, wordexp_t *pwordexp, const char *ifs,
371 const char *ifs_white)
373 int error;
374 unsigned int match;
375 glob_t globbuf;
377 error = glob (glob_word, GLOB_NOCHECK, NULL, &globbuf);
379 if (error != 0)
381 /* We can only run into memory problems. */
382 assert (error == GLOB_NOSPACE);
383 return WRDE_NOSPACE;
386 if (ifs && !*ifs)
388 /* No field splitting allowed. */
389 assert (globbuf.gl_pathv[0] != NULL);
390 *word = w_addstr (*word, word_length, max_length, globbuf.gl_pathv[0]);
391 for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
393 *word = w_addchar (*word, word_length, max_length, ' ');
394 if (*word != NULL)
395 *word = w_addstr (*word, word_length, max_length,
396 globbuf.gl_pathv[match]);
399 globfree (&globbuf);
400 return *word ? 0 : WRDE_NOSPACE;
403 assert (ifs == NULL || *ifs != '\0');
404 if (*word != NULL)
406 free (*word);
407 *word = w_newword (word_length, max_length);
410 for (match = 0; match < globbuf.gl_pathc; ++match)
412 char *matching_word = __strdup (globbuf.gl_pathv[match]);
413 if (matching_word == NULL || w_addword (pwordexp, matching_word))
415 globfree (&globbuf);
416 return WRDE_NOSPACE;
420 globfree (&globbuf);
421 return 0;
424 static int
425 parse_glob (char **word, size_t *word_length, size_t *max_length,
426 const char *words, size_t *offset, int flags,
427 wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
429 /* We are poised just after a '*', a '[' or a '?'. */
430 int error = WRDE_NOSPACE;
431 int quoted = 0; /* 1 if singly-quoted, 2 if doubly */
432 size_t i;
433 wordexp_t glob_list; /* List of words to glob */
435 glob_list.we_wordc = 0;
436 glob_list.we_wordv = NULL;
437 glob_list.we_offs = 0;
438 for (; words[*offset] != '\0'; ++*offset)
440 if (strchr (ifs, words[*offset]) != NULL)
441 /* Reached IFS */
442 break;
444 /* Sort out quoting */
445 if (words[*offset] == '\'')
447 if (quoted == 0)
449 quoted = 1;
450 continue;
452 else if (quoted == 1)
454 quoted = 0;
455 continue;
458 else if (words[*offset] == '"')
460 if (quoted == 0)
462 quoted = 2;
463 continue;
465 else if (quoted == 2)
467 quoted = 0;
468 continue;
472 /* Sort out other special characters */
473 if (quoted != 1 && words[*offset] == '$')
475 error = parse_dollars (word, word_length, max_length, words,
476 offset, flags, &glob_list, ifs, ifs_white,
477 quoted == 2);
478 if (error)
479 goto tidy_up;
481 continue;
483 else if (words[*offset] == '\\')
485 if (quoted)
486 error = parse_qtd_backslash (word, word_length, max_length,
487 words, offset);
488 else
489 error = parse_backslash (word, word_length, max_length,
490 words, offset);
492 if (error)
493 goto tidy_up;
495 continue;
498 *word = w_addchar (*word, word_length, max_length, words[*offset]);
499 if (*word == NULL)
500 goto tidy_up;
503 /* Don't forget to re-parse the character we stopped at. */
504 --*offset;
506 /* Glob the words */
507 error = w_addword (&glob_list, *word);
508 *word = w_newword (word_length, max_length);
509 for (i = 0; error == 0 && i < glob_list.we_wordc; i++)
510 error = do_parse_glob (glob_list.we_wordv[i], word, word_length,
511 max_length, pwordexp, ifs, ifs_white);
513 /* Now tidy up */
514 tidy_up:
515 wordfree (&glob_list);
516 return error;
519 static int
520 parse_squote (char **word, size_t *word_length, size_t *max_length,
521 const char *words, size_t *offset)
523 /* We are poised just after a single quote */
524 for (; words[*offset]; ++(*offset))
526 if (words[*offset] != '\'')
528 *word = w_addchar (*word, word_length, max_length, words[*offset]);
529 if (*word == NULL)
530 return WRDE_NOSPACE;
532 else return 0;
535 /* Unterminated string */
536 return WRDE_SYNTAX;
539 /* Functions to evaluate an arithmetic expression */
540 static int
541 eval_expr_val (char **expr, long int *result)
543 char *digit;
545 /* Skip white space */
546 for (digit = *expr; digit && *digit && isspace (*digit); ++digit);
548 if (*digit == '(')
550 /* Scan for closing paren */
551 for (++digit; **expr && **expr != ')'; ++(*expr));
553 /* Is there one? */
554 if (!**expr)
555 return WRDE_SYNTAX;
557 *(*expr)++ = 0;
559 if (eval_expr (digit, result))
560 return WRDE_SYNTAX;
562 return 0;
565 /* POSIX requires that decimal, octal, and hexadecimal constants are
566 recognized. Therefore we pass 0 as the third parameter to strtol. */
567 *result = strtol (digit, expr, 0);
568 if (digit == *expr)
569 return WRDE_SYNTAX;
571 return 0;
574 static int
575 eval_expr_multdiv (char **expr, long int *result)
577 long int arg;
579 /* Read a Value */
580 if (eval_expr_val (expr, result) != 0)
581 return WRDE_SYNTAX;
583 while (**expr)
585 /* Skip white space */
586 for (; *expr && **expr && isspace (**expr); ++(*expr));
588 if (**expr == '*')
590 ++(*expr);
591 if (eval_expr_val (expr, &arg) != 0)
592 return WRDE_SYNTAX;
594 *result *= arg;
596 else if (**expr == '/')
598 ++(*expr);
599 if (eval_expr_val (expr, &arg) != 0)
600 return WRDE_SYNTAX;
602 /* Division by zero or integer overflow. */
603 if (arg == 0 || (arg == -1 && *result == LONG_MIN))
604 return WRDE_SYNTAX;
606 *result /= arg;
608 else break;
611 return 0;
614 static int
615 eval_expr (char *expr, long int *result)
617 long int arg;
619 /* Read a Multdiv */
620 if (eval_expr_multdiv (&expr, result) != 0)
621 return WRDE_SYNTAX;
623 while (*expr)
625 /* Skip white space */
626 for (; expr && *expr && isspace (*expr); ++expr);
628 if (*expr == '+')
630 ++expr;
631 if (eval_expr_multdiv (&expr, &arg) != 0)
632 return WRDE_SYNTAX;
634 *result += arg;
636 else if (*expr == '-')
638 ++expr;
639 if (eval_expr_multdiv (&expr, &arg) != 0)
640 return WRDE_SYNTAX;
642 *result -= arg;
644 else break;
647 return 0;
650 static int
651 parse_arith (char **word, size_t *word_length, size_t *max_length,
652 const char *words, size_t *offset, int flags, int bracket)
654 /* We are poised just after "$((" or "$[" */
655 int error;
656 int paren_depth = 1;
657 size_t expr_length;
658 size_t expr_maxlen;
659 char *expr;
661 expr = w_newword (&expr_length, &expr_maxlen);
662 for (; words[*offset]; ++(*offset))
664 switch (words[*offset])
666 case '$':
667 error = parse_dollars (&expr, &expr_length, &expr_maxlen,
668 words, offset, flags, NULL, NULL, NULL, 1);
669 /* The ``1'' here is to tell parse_dollars not to
670 * split the fields.
672 if (error)
674 free (expr);
675 return error;
677 break;
679 case '`':
680 (*offset)++;
681 error = parse_backtick (&expr, &expr_length, &expr_maxlen,
682 words, offset, flags, NULL, NULL, NULL);
683 /* The first NULL here is to tell parse_backtick not to
684 * split the fields.
686 if (error)
688 free (expr);
689 return error;
691 break;
693 case '\\':
694 error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen,
695 words, offset);
696 if (error)
698 free (expr);
699 return error;
701 /* I think that a backslash within an
702 * arithmetic expansion is bound to
703 * cause an error sooner or later anyway though.
705 break;
707 case ')':
708 if (--paren_depth == 0)
710 char result[21]; /* 21 = ceil(log10(2^64)) + 1 */
711 long int numresult = 0;
712 long long int convertme;
714 if (bracket || words[1 + *offset] != ')')
716 free (expr);
717 return WRDE_SYNTAX;
720 ++(*offset);
722 /* Go - evaluate. */
723 if (*expr && eval_expr (expr, &numresult) != 0)
725 free (expr);
726 return WRDE_SYNTAX;
729 if (numresult < 0)
731 convertme = -numresult;
732 *word = w_addchar (*word, word_length, max_length, '-');
733 if (!*word)
735 free (expr);
736 return WRDE_NOSPACE;
739 else
740 convertme = numresult;
742 result[20] = '\0';
743 *word = w_addstr (*word, word_length, max_length,
744 _itoa (convertme, &result[20], 10, 0));
745 free (expr);
746 return *word ? 0 : WRDE_NOSPACE;
748 expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
749 if (expr == NULL)
750 return WRDE_NOSPACE;
752 break;
754 case ']':
755 if (bracket && paren_depth == 1)
757 char result[21]; /* 21 = ceil(log10(2^64)) + 1 */
758 long int numresult = 0;
760 /* Go - evaluate. */
761 if (*expr && eval_expr (expr, &numresult) != 0)
763 free (expr);
764 return WRDE_SYNTAX;
767 result[20] = '\0';
768 *word = w_addstr (*word, word_length, max_length,
769 _itoa_word (numresult, &result[20], 10, 0));
770 free (expr);
771 return *word ? 0 : WRDE_NOSPACE;
774 free (expr);
775 return WRDE_SYNTAX;
777 case '\n':
778 case ';':
779 case '{':
780 case '}':
781 free (expr);
782 return WRDE_BADCHAR;
784 case '(':
785 ++paren_depth;
786 /* Fall through. */
787 default:
788 expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
789 if (expr == NULL)
790 return WRDE_NOSPACE;
794 /* Premature end */
795 free (expr);
796 return WRDE_SYNTAX;
799 #define DYNARRAY_STRUCT strlist
800 #define DYNARRAY_ELEMENT char *
801 #define DYNARRAY_PREFIX strlist_
802 /* Allocates about 512/1024 (32/64 bit) on stack. */
803 #define DYNARRAY_INITIAL_SIZE 128
804 #include <malloc/dynarray-skeleton.c>
806 /* Function called by child process in exec_comm() */
807 static pid_t
808 exec_comm_child (char *comm, int *fildes, bool showerr, bool noexec)
810 pid_t pid = -1;
812 /* Execute the command, or just check syntax? */
813 const char *args[] = { _PATH_BSHELL, noexec ? "-nc" : "-c", comm, NULL };
815 posix_spawn_file_actions_t fa;
816 /* posix_spawn_file_actions_init does not fail. */
817 __posix_spawn_file_actions_init (&fa);
819 /* Redirect output. For check syntax only (noexec being true), exec_comm
820 explicits sets fildes[1] to -1, so check its value to avoid a failure in
821 __posix_spawn_file_actions_adddup2. */
822 if (fildes[1] != -1)
824 if (__glibc_likely (fildes[1] != STDOUT_FILENO))
826 if (__posix_spawn_file_actions_adddup2 (&fa, fildes[1],
827 STDOUT_FILENO) != 0
828 || __posix_spawn_file_actions_addclose (&fa, fildes[1]) != 0)
829 goto out;
831 else
832 /* Reset the close-on-exec flag (if necessary). */
833 if (__posix_spawn_file_actions_adddup2 (&fa, fildes[1], fildes[1])
834 != 0)
835 goto out;
838 /* Redirect stderr to /dev/null if we have to. */
839 if (!showerr)
840 if (__posix_spawn_file_actions_addopen (&fa, STDERR_FILENO, _PATH_DEVNULL,
841 O_WRONLY, 0) != 0)
842 goto out;
844 struct strlist newenv;
845 strlist_init (&newenv);
847 bool recreate_env = getenv ("IFS") != NULL;
848 if (recreate_env)
850 for (char **ep = __environ; *ep != NULL; ep++)
851 if (strncmp (*ep, "IFS=", strlen ("IFS=")) != 0)
852 strlist_add (&newenv, *ep);
853 strlist_add (&newenv, NULL);
854 if (strlist_has_failed (&newenv))
855 goto out;
858 /* pid is not set if posix_spawn fails, so it keep the original value
859 of -1. */
860 __posix_spawn (&pid, _PATH_BSHELL, &fa, NULL, (char *const *) args,
861 recreate_env ? strlist_begin (&newenv) : __environ);
863 strlist_free (&newenv);
865 out:
866 __posix_spawn_file_actions_destroy (&fa);
868 return pid;
871 /* Function to execute a command and retrieve the results */
872 /* pwordexp contains NULL if field-splitting is forbidden */
873 static int
874 exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
875 int flags, wordexp_t *pwordexp, const char *ifs,
876 const char *ifs_white)
878 int fildes[2];
879 #define bufsize 128
880 int buflen;
881 int i;
882 int status = 0;
883 size_t maxnewlines = 0;
884 char buffer[bufsize];
885 pid_t pid;
886 bool noexec = false;
888 /* Do nothing if command substitution should not succeed. */
889 if (flags & WRDE_NOCMD)
890 return WRDE_CMDSUB;
892 /* Don't posix_spawn unless necessary */
893 if (!comm || !*comm)
894 return 0;
896 if (__pipe2 (fildes, O_CLOEXEC) < 0)
897 return WRDE_NOSPACE;
899 again:
900 pid = exec_comm_child (comm, fildes, noexec ? false : flags & WRDE_SHOWERR,
901 noexec);
902 if (pid < 0)
904 __close (fildes[0]);
905 __close (fildes[1]);
906 return WRDE_NOSPACE;
909 /* If we are just testing the syntax, only wait. */
910 if (noexec)
911 return (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) == pid
912 && status != 0) ? WRDE_SYNTAX : 0;
914 __close (fildes[1]);
915 fildes[1] = -1;
917 if (!pwordexp)
918 /* Quoted - no field splitting */
920 while (1)
922 if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
923 bufsize))) < 1)
925 /* If read returned 0 then the process has closed its
926 stdout. Don't use WNOHANG in that case to avoid busy
927 looping until the process eventually exits. */
928 if (TEMP_FAILURE_RETRY (__waitpid (pid, &status,
929 buflen == 0 ? 0 : WNOHANG))
930 == 0)
931 continue;
932 if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
933 bufsize))) < 1)
934 break;
937 maxnewlines += buflen;
939 *word = w_addmem (*word, word_length, max_length, buffer, buflen);
940 if (*word == NULL)
941 goto no_space;
944 else
945 /* Not quoted - split fields */
947 int copying = 0;
948 /* 'copying' is:
949 * 0 when searching for first character in a field not IFS white space
950 * 1 when copying the text of a field
951 * 2 when searching for possible non-whitespace IFS
952 * 3 when searching for non-newline after copying field
955 while (1)
957 if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
958 bufsize))) < 1)
960 /* If read returned 0 then the process has closed its
961 stdout. Don't use WNOHANG in that case to avoid busy
962 looping until the process eventually exits. */
963 if (TEMP_FAILURE_RETRY (__waitpid (pid, &status,
964 buflen == 0 ? 0 : WNOHANG))
965 == 0)
966 continue;
967 if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
968 bufsize))) < 1)
969 break;
972 for (i = 0; i < buflen; ++i)
974 if (strchr (ifs, buffer[i]) != NULL)
976 /* Current character is IFS */
977 if (strchr (ifs_white, buffer[i]) == NULL)
979 /* Current character is IFS but not whitespace */
980 if (copying == 2)
982 /* current character
985 * eg: text<space><comma><space>moretext
987 * So, strip whitespace IFS (like at the start)
989 copying = 0;
990 continue;
993 copying = 0;
994 /* fall through and delimit field.. */
996 else
998 if (buffer[i] == '\n')
1000 /* Current character is (IFS) newline */
1002 /* If copying a field, this is the end of it,
1003 but maybe all that's left is trailing newlines.
1004 So start searching for a non-newline. */
1005 if (copying == 1)
1006 copying = 3;
1008 continue;
1010 else
1012 /* Current character is IFS white space, but
1013 not a newline */
1015 /* If not either copying a field or searching
1016 for non-newline after a field, ignore it */
1017 if (copying != 1 && copying != 3)
1018 continue;
1020 /* End of field (search for non-ws IFS afterwards) */
1021 copying = 2;
1025 /* First IFS white space (non-newline), or IFS non-whitespace.
1026 * Delimit the field. Nulls are converted by w_addword. */
1027 if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
1028 goto no_space;
1030 *word = w_newword (word_length, max_length);
1032 maxnewlines = 0;
1033 /* fall back round the loop.. */
1035 else
1037 /* Not IFS character */
1039 if (copying == 3)
1041 /* Nothing but (IFS) newlines since the last field,
1042 so delimit it here before starting new word */
1043 if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
1044 goto no_space;
1046 *word = w_newword (word_length, max_length);
1049 copying = 1;
1051 if (buffer[i] == '\n') /* happens if newline not in IFS */
1052 maxnewlines++;
1053 else
1054 maxnewlines = 0;
1056 *word = w_addchar (*word, word_length, max_length,
1057 buffer[i]);
1058 if (*word == NULL)
1059 goto no_space;
1065 /* Chop off trailing newlines (required by POSIX.2) */
1066 /* Ensure we don't go back further than the beginning of the
1067 substitution (i.e. remove maxnewlines bytes at most) */
1068 while (maxnewlines-- != 0
1069 && *word_length > 0 && (*word)[*word_length - 1] == '\n')
1071 (*word)[--*word_length] = '\0';
1073 /* If the last word was entirely newlines, turn it into a new word
1074 * which can be ignored if there's nothing following it. */
1075 if (*word_length == 0)
1077 free (*word);
1078 *word = w_newword (word_length, max_length);
1079 break;
1083 __close (fildes[0]);
1084 fildes[0] = -1;
1086 /* Check for syntax error (re-execute but with "-n" flag) */
1087 if (buflen < 1 && status != 0)
1089 noexec = true;
1090 goto again;
1093 return 0;
1095 no_space:
1096 __kill (pid, SIGKILL);
1097 TEMP_FAILURE_RETRY (__waitpid (pid, NULL, 0));
1098 __close (fildes[0]);
1099 return WRDE_NOSPACE;
1102 static int
1103 parse_comm (char **word, size_t *word_length, size_t *max_length,
1104 const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
1105 const char *ifs, const char *ifs_white)
1107 /* We are poised just after "$(" */
1108 int paren_depth = 1;
1109 int error = 0;
1110 int quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
1111 size_t comm_length;
1112 size_t comm_maxlen;
1113 char *comm = w_newword (&comm_length, &comm_maxlen);
1115 for (; words[*offset]; ++(*offset))
1117 switch (words[*offset])
1119 case '\'':
1120 if (quoted == 0)
1121 quoted = 1;
1122 else if (quoted == 1)
1123 quoted = 0;
1125 break;
1127 case '"':
1128 if (quoted == 0)
1129 quoted = 2;
1130 else if (quoted == 2)
1131 quoted = 0;
1133 break;
1135 case ')':
1136 if (!quoted && --paren_depth == 0)
1138 /* Go -- give script to the shell */
1139 if (comm)
1141 /* posix_spawn already handles thread cancellation. */
1142 error = exec_comm (comm, word, word_length, max_length,
1143 flags, pwordexp, ifs, ifs_white);
1144 free (comm);
1147 return error;
1150 /* This is just part of the script */
1151 break;
1153 case '(':
1154 if (!quoted)
1155 ++paren_depth;
1158 comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
1159 if (comm == NULL)
1160 return WRDE_NOSPACE;
1163 /* Premature end. */
1164 free (comm);
1166 return WRDE_SYNTAX;
1169 #define CHAR_IN_SET(ch, char_set) \
1170 (memchr (char_set "", ch, sizeof (char_set) - 1) != NULL)
1172 static int
1173 parse_param (char **word, size_t *word_length, size_t *max_length,
1174 const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
1175 const char *ifs, const char *ifs_white, int quoted)
1177 /* We are poised just after "$" */
1178 enum action
1180 ACT_NONE,
1181 ACT_RP_SHORT_LEFT = '#',
1182 ACT_RP_LONG_LEFT = 'L',
1183 ACT_RP_SHORT_RIGHT = '%',
1184 ACT_RP_LONG_RIGHT = 'R',
1185 ACT_NULL_ERROR = '?',
1186 ACT_NULL_SUBST = '-',
1187 ACT_NONNULL_SUBST = '+',
1188 ACT_NULL_ASSIGN = '='
1190 size_t env_length;
1191 size_t env_maxlen;
1192 size_t pat_length;
1193 size_t pat_maxlen;
1194 size_t start = *offset;
1195 char *env;
1196 char *pattern;
1197 char *value = NULL;
1198 enum action action = ACT_NONE;
1199 int depth = 0;
1200 int colon_seen = 0;
1201 int seen_hash = 0;
1202 int free_value = 0;
1203 int pattern_is_quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
1204 int error;
1205 int special = 0;
1206 char buffer[21];
1207 int brace = words[*offset] == '{';
1209 env = w_newword (&env_length, &env_maxlen);
1210 pattern = w_newword (&pat_length, &pat_maxlen);
1212 if (brace)
1213 ++*offset;
1215 /* First collect the parameter name. */
1217 if (words[*offset] == '#')
1219 seen_hash = 1;
1220 if (!brace)
1221 goto envsubst;
1222 ++*offset;
1225 if (isalpha (words[*offset]) || words[*offset] == '_')
1227 /* Normal parameter name. */
1230 env = w_addchar (env, &env_length, &env_maxlen,
1231 words[*offset]);
1232 if (env == NULL)
1233 goto no_space;
1235 while (isalnum (words[++*offset]) || words[*offset] == '_');
1237 else if (isdigit (words[*offset]))
1239 /* Numeric parameter name. */
1240 special = 1;
1243 env = w_addchar (env, &env_length, &env_maxlen,
1244 words[*offset]);
1245 if (env == NULL)
1246 goto no_space;
1247 if (!brace)
1248 goto envsubst;
1250 while (isdigit(words[++*offset]));
1252 else if (CHAR_IN_SET (words[*offset], "*@$"))
1254 /* Special parameter. */
1255 special = 1;
1256 env = w_addchar (env, &env_length, &env_maxlen,
1257 words[*offset]);
1258 if (env == NULL)
1259 goto no_space;
1260 ++*offset;
1262 else
1264 if (brace)
1265 goto syntax;
1268 if (brace)
1270 /* Check for special action to be applied to the value. */
1271 switch (words[*offset])
1273 case '}':
1274 /* Evaluate. */
1275 goto envsubst;
1277 case '#':
1278 action = ACT_RP_SHORT_LEFT;
1279 if (words[1 + *offset] == '#')
1281 ++*offset;
1282 action = ACT_RP_LONG_LEFT;
1284 break;
1286 case '%':
1287 action = ACT_RP_SHORT_RIGHT;
1288 if (words[1 + *offset] == '%')
1290 ++*offset;
1291 action = ACT_RP_LONG_RIGHT;
1293 break;
1295 case ':':
1296 if (!CHAR_IN_SET (words[1 + *offset], "-=?+"))
1297 goto syntax;
1299 colon_seen = 1;
1300 action = words[++*offset];
1301 break;
1303 case '-':
1304 case '=':
1305 case '?':
1306 case '+':
1307 action = words[*offset];
1308 break;
1310 default:
1311 goto syntax;
1314 /* Now collect the pattern, but don't expand it yet. */
1315 ++*offset;
1316 for (; words[*offset]; ++(*offset))
1318 switch (words[*offset])
1320 case '{':
1321 if (!pattern_is_quoted)
1322 ++depth;
1323 break;
1325 case '}':
1326 if (!pattern_is_quoted)
1328 if (depth == 0)
1329 goto envsubst;
1330 --depth;
1332 break;
1334 case '\\':
1335 if (pattern_is_quoted)
1336 /* Quoted; treat as normal character. */
1337 break;
1339 /* Otherwise, it's an escape: next character is literal. */
1340 if (words[++*offset] == '\0')
1341 goto syntax;
1343 pattern = w_addchar (pattern, &pat_length, &pat_maxlen, '\\');
1344 if (pattern == NULL)
1345 goto no_space;
1347 break;
1349 case '\'':
1350 if (pattern_is_quoted == 0)
1351 pattern_is_quoted = 1;
1352 else if (pattern_is_quoted == 1)
1353 pattern_is_quoted = 0;
1355 break;
1357 case '"':
1358 if (pattern_is_quoted == 0)
1359 pattern_is_quoted = 2;
1360 else if (pattern_is_quoted == 2)
1361 pattern_is_quoted = 0;
1363 break;
1366 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1367 words[*offset]);
1368 if (pattern == NULL)
1369 goto no_space;
1373 /* End of input string -- remember to reparse the character that we
1374 * stopped at. */
1375 --(*offset);
1377 envsubst:
1378 if (words[start] == '{' && words[*offset] != '}')
1379 goto syntax;
1381 if (env == NULL)
1383 if (seen_hash)
1385 /* $# expands to the number of positional parameters */
1386 buffer[20] = '\0';
1387 value = _itoa_word (__libc_argc - 1, &buffer[20], 10, 0);
1388 seen_hash = 0;
1390 else
1392 /* Just $ on its own */
1393 *offset = start - 1;
1394 *word = w_addchar (*word, word_length, max_length, '$');
1395 return *word ? 0 : WRDE_NOSPACE;
1398 /* Is it a numeric parameter? */
1399 else if (isdigit (env[0]))
1401 unsigned long n = strtoul (env, NULL, 10);
1403 if (n >= __libc_argc)
1404 /* Substitute NULL. */
1405 value = NULL;
1406 else
1407 /* Replace with appropriate positional parameter. */
1408 value = __libc_argv[n];
1410 /* Is it a special parameter? */
1411 else if (special)
1413 /* Is it `$$'? */
1414 if (*env == '$')
1416 buffer[20] = '\0';
1417 value = _itoa_word (__getpid (), &buffer[20], 10, 0);
1419 /* Is it `${#*}' or `${#@}'? */
1420 else if ((*env == '*' || *env == '@') && seen_hash)
1422 buffer[20] = '\0';
1423 value = _itoa_word (__libc_argc > 0 ? __libc_argc - 1 : 0,
1424 &buffer[20], 10, 0);
1425 *word = w_addstr (*word, word_length, max_length, value);
1426 free (env);
1427 free (pattern);
1428 return *word ? 0 : WRDE_NOSPACE;
1430 /* Is it `$*' or `$@' (unquoted) ? */
1431 else if (*env == '*' || (*env == '@' && !quoted))
1433 size_t plist_len = 0;
1434 int p;
1435 char *end;
1437 /* Build up value parameter by parameter (copy them) */
1438 for (p = 1; __libc_argv[p]; ++p)
1439 plist_len += strlen (__libc_argv[p]) + 1; /* for space */
1440 value = malloc (plist_len);
1441 if (value == NULL)
1442 goto no_space;
1443 end = value;
1444 *end = 0;
1445 for (p = 1; __libc_argv[p]; ++p)
1447 if (p > 1)
1448 *end++ = ' ';
1449 end = __stpcpy (end, __libc_argv[p]);
1452 free_value = 1;
1454 else
1456 /* Must be a quoted `$@' */
1457 assert (*env == '@' && quoted);
1459 /* Each parameter is a separate word ("$@") */
1460 if (__libc_argc == 2)
1461 value = __libc_argv[1];
1462 else if (__libc_argc > 2)
1464 int p;
1466 /* Append first parameter to current word. */
1467 value = w_addstr (*word, word_length, max_length,
1468 __libc_argv[1]);
1469 if (value == NULL || w_addword (pwordexp, value))
1470 goto no_space;
1472 for (p = 2; __libc_argv[p + 1]; p++)
1474 char *newword = __strdup (__libc_argv[p]);
1475 if (newword == NULL || w_addword (pwordexp, newword))
1476 goto no_space;
1479 /* Start a new word with the last parameter. */
1480 *word = w_newword (word_length, max_length);
1481 value = __libc_argv[p];
1483 else
1485 free (env);
1486 free (pattern);
1487 return 0;
1491 else
1492 value = getenv (env);
1494 if (value == NULL && (flags & WRDE_UNDEF))
1496 /* Variable not defined. */
1497 error = WRDE_BADVAL;
1498 goto do_error;
1501 if (action != ACT_NONE)
1503 int expand_pattern = 0;
1505 /* First, find out if we need to expand pattern (i.e. if we will
1506 * use it). */
1507 switch (action)
1509 case ACT_RP_SHORT_LEFT:
1510 case ACT_RP_LONG_LEFT:
1511 case ACT_RP_SHORT_RIGHT:
1512 case ACT_RP_LONG_RIGHT:
1513 /* Always expand for these. */
1514 expand_pattern = 1;
1515 break;
1517 case ACT_NULL_ERROR:
1518 case ACT_NULL_SUBST:
1519 case ACT_NULL_ASSIGN:
1520 if (!value || (!*value && colon_seen))
1521 /* If param is unset, or set but null and a colon has been seen,
1522 the expansion of the pattern will be needed. */
1523 expand_pattern = 1;
1525 break;
1527 case ACT_NONNULL_SUBST:
1528 /* Expansion of word will be needed if parameter is set and not null,
1529 or set null but no colon has been seen. */
1530 if (value && (*value || !colon_seen))
1531 expand_pattern = 1;
1533 break;
1535 default:
1536 assert (! "Unrecognised action!");
1539 if (expand_pattern)
1541 /* We need to perform tilde expansion, parameter expansion,
1542 command substitution, and arithmetic expansion. We also
1543 have to be a bit careful with wildcard characters, as
1544 pattern might be given to fnmatch soon. To do this, we
1545 convert quotes to escapes. */
1547 char *expanded;
1548 size_t exp_len;
1549 size_t exp_maxl;
1550 char *p;
1551 int quoted = 0; /* 1: single quotes; 2: double */
1553 expanded = w_newword (&exp_len, &exp_maxl);
1554 for (p = pattern; p && *p; p++)
1556 size_t offset;
1558 switch (*p)
1560 case '"':
1561 if (quoted == 2)
1562 quoted = 0;
1563 else if (quoted == 0)
1564 quoted = 2;
1565 else break;
1567 continue;
1569 case '\'':
1570 if (quoted == 1)
1571 quoted = 0;
1572 else if (quoted == 0)
1573 quoted = 1;
1574 else break;
1576 continue;
1578 case '*':
1579 case '?':
1580 if (quoted)
1582 /* Convert quoted wildchar to escaped wildchar. */
1583 expanded = w_addchar (expanded, &exp_len,
1584 &exp_maxl, '\\');
1586 if (expanded == NULL)
1587 goto no_space;
1589 break;
1591 case '$':
1592 offset = 0;
1593 error = parse_dollars (&expanded, &exp_len, &exp_maxl, p,
1594 &offset, flags, NULL, NULL, NULL, 1);
1595 if (error)
1597 if (free_value)
1598 free (value);
1600 free (expanded);
1602 goto do_error;
1605 p += offset;
1606 continue;
1608 case '~':
1609 if (quoted || exp_len)
1610 break;
1612 offset = 0;
1613 error = parse_tilde (&expanded, &exp_len, &exp_maxl, p,
1614 &offset, 0);
1615 if (error)
1617 if (free_value)
1618 free (value);
1620 free (expanded);
1622 goto do_error;
1625 p += offset;
1626 continue;
1628 case '\\':
1629 expanded = w_addchar (expanded, &exp_len, &exp_maxl, '\\');
1630 ++p;
1631 assert (*p); /* checked when extracted initially */
1632 if (expanded == NULL)
1633 goto no_space;
1636 expanded = w_addchar (expanded, &exp_len, &exp_maxl, *p);
1638 if (expanded == NULL)
1639 goto no_space;
1642 free (pattern);
1644 pattern = expanded;
1647 switch (action)
1649 case ACT_RP_SHORT_LEFT:
1650 case ACT_RP_LONG_LEFT:
1651 case ACT_RP_SHORT_RIGHT:
1652 case ACT_RP_LONG_RIGHT:
1654 char *p;
1655 char c;
1656 char *end;
1658 if (value == NULL || pattern == NULL || *pattern == '\0')
1659 break;
1661 end = value + strlen (value);
1663 switch (action)
1665 case ACT_RP_SHORT_LEFT:
1666 for (p = value; p <= end; ++p)
1668 c = *p;
1669 *p = '\0';
1670 if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1672 *p = c;
1673 if (free_value)
1675 char *newval = __strdup (p);
1676 if (newval == NULL)
1678 free (value);
1679 goto no_space;
1681 free (value);
1682 value = newval;
1684 else
1685 value = p;
1686 break;
1688 *p = c;
1691 break;
1693 case ACT_RP_LONG_LEFT:
1694 for (p = end; p >= value; --p)
1696 c = *p;
1697 *p = '\0';
1698 if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1700 *p = c;
1701 if (free_value)
1703 char *newval = __strdup (p);
1704 if (newval == NULL)
1706 free (value);
1707 goto no_space;
1709 free (value);
1710 value = newval;
1712 else
1713 value = p;
1714 break;
1716 *p = c;
1719 break;
1721 case ACT_RP_SHORT_RIGHT:
1722 for (p = end; p >= value; --p)
1724 if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1726 char *newval;
1727 newval = malloc (p - value + 1);
1729 if (newval == NULL)
1731 if (free_value)
1732 free (value);
1733 goto no_space;
1736 *(char *) __mempcpy (newval, value, p - value) = '\0';
1737 if (free_value)
1738 free (value);
1739 value = newval;
1740 free_value = 1;
1741 break;
1745 break;
1747 case ACT_RP_LONG_RIGHT:
1748 for (p = value; p <= end; ++p)
1750 if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1752 char *newval;
1753 newval = malloc (p - value + 1);
1755 if (newval == NULL)
1757 if (free_value)
1758 free (value);
1759 goto no_space;
1762 *(char *) __mempcpy (newval, value, p - value) = '\0';
1763 if (free_value)
1764 free (value);
1765 value = newval;
1766 free_value = 1;
1767 break;
1771 break;
1773 default:
1774 break;
1777 break;
1780 case ACT_NULL_ERROR:
1781 if (value && *value)
1782 /* Substitute parameter */
1783 break;
1785 error = 0;
1786 if (!colon_seen && value)
1787 /* Substitute NULL */
1789 else
1791 const char *str = pattern;
1793 if (str[0] == '\0')
1794 str = _("parameter null or not set");
1796 __fxprintf (NULL, "%s: %s\n", env, str);
1799 if (free_value)
1800 free (value);
1801 goto do_error;
1803 case ACT_NULL_SUBST:
1804 if (value && *value)
1805 /* Substitute parameter */
1806 break;
1808 if (free_value)
1809 free (value);
1811 if (!colon_seen && value)
1812 /* Substitute NULL */
1813 goto success;
1815 value = pattern ? __strdup (pattern) : pattern;
1816 free_value = 1;
1818 if (pattern && !value)
1819 goto no_space;
1821 break;
1823 case ACT_NONNULL_SUBST:
1824 if (value && (*value || !colon_seen))
1826 if (free_value)
1827 free (value);
1829 value = pattern ? __strdup (pattern) : pattern;
1830 free_value = 1;
1832 if (pattern && !value)
1833 goto no_space;
1835 break;
1838 /* Substitute NULL */
1839 if (free_value)
1840 free (value);
1841 goto success;
1843 case ACT_NULL_ASSIGN:
1844 if (value && *value)
1845 /* Substitute parameter */
1846 break;
1848 if (!colon_seen && value)
1850 /* Substitute NULL */
1851 if (free_value)
1852 free (value);
1853 goto success;
1856 if (free_value)
1857 free (value);
1859 value = pattern ? __strdup (pattern) : pattern;
1860 free_value = 1;
1862 if (pattern && !value)
1863 goto no_space;
1865 __setenv (env, value ?: "", 1);
1866 break;
1868 default:
1869 assert (! "Unrecognised action!");
1873 free (env);
1874 env = NULL;
1875 free (pattern);
1876 pattern = NULL;
1878 if (seen_hash)
1880 char param_length[21];
1881 param_length[20] = '\0';
1882 *word = w_addstr (*word, word_length, max_length,
1883 _itoa_word (value ? strlen (value) : 0,
1884 &param_length[20], 10, 0));
1885 if (free_value)
1887 assert (value != NULL);
1888 free (value);
1891 return *word ? 0 : WRDE_NOSPACE;
1894 if (value == NULL)
1895 return 0;
1897 if (quoted || !pwordexp)
1899 /* Quoted - no field split */
1900 *word = w_addstr (*word, word_length, max_length, value);
1901 if (free_value)
1902 free (value);
1904 return *word ? 0 : WRDE_NOSPACE;
1906 else
1908 /* Need to field-split */
1909 char *value_copy = __strdup (value); /* Don't modify value */
1910 char *field_begin = value_copy;
1911 int seen_nonws_ifs = 0;
1913 if (free_value)
1914 free (value);
1916 if (value_copy == NULL)
1917 goto no_space;
1921 char *field_end = field_begin;
1922 char *next_field;
1924 /* If this isn't the first field, start a new word */
1925 if (field_begin != value_copy)
1927 if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
1929 free (value_copy);
1930 goto no_space;
1933 *word = w_newword (word_length, max_length);
1936 /* Skip IFS whitespace before the field */
1937 field_begin += strspn (field_begin, ifs_white);
1939 if (!seen_nonws_ifs && *field_begin == 0)
1940 /* Nothing but whitespace */
1941 break;
1943 /* Search for the end of the field */
1944 field_end = field_begin + strcspn (field_begin, ifs);
1946 /* Set up pointer to the character after end of field and
1947 skip whitespace IFS after it. */
1948 next_field = field_end + strspn (field_end, ifs_white);
1950 /* Skip at most one non-whitespace IFS character after the field */
1951 seen_nonws_ifs = 0;
1952 if (*next_field && strchr (ifs, *next_field))
1954 seen_nonws_ifs = 1;
1955 next_field++;
1958 /* Null-terminate it */
1959 *field_end = 0;
1961 /* Tag a copy onto the current word */
1962 *word = w_addstr (*word, word_length, max_length, field_begin);
1964 if (*word == NULL && *field_begin != '\0')
1966 free (value_copy);
1967 goto no_space;
1970 field_begin = next_field;
1972 while (seen_nonws_ifs || *field_begin);
1974 free (value_copy);
1977 return 0;
1979 success:
1980 error = 0;
1981 goto do_error;
1983 no_space:
1984 error = WRDE_NOSPACE;
1985 goto do_error;
1987 syntax:
1988 error = WRDE_SYNTAX;
1990 do_error:
1991 free (env);
1993 free (pattern);
1995 return error;
1998 #undef CHAR_IN_SET
2000 static int
2001 parse_dollars (char **word, size_t *word_length, size_t *max_length,
2002 const char *words, size_t *offset, int flags,
2003 wordexp_t *pwordexp, const char *ifs, const char *ifs_white,
2004 int quoted)
2006 /* We are poised _at_ "$" */
2007 switch (words[1 + *offset])
2009 case '"':
2010 case '\'':
2011 case 0:
2012 *word = w_addchar (*word, word_length, max_length, '$');
2013 return *word ? 0 : WRDE_NOSPACE;
2015 case '(':
2016 if (words[2 + *offset] == '(')
2018 /* Differentiate between $((1+3)) and $((echo);(ls)) */
2019 int i = 3 + *offset;
2020 int depth = 0;
2021 while (words[i] && !(depth == 0 && words[i] == ')'))
2023 if (words[i] == '(')
2024 ++depth;
2025 else if (words[i] == ')')
2026 --depth;
2028 ++i;
2031 if (words[i] == ')' && words[i + 1] == ')')
2033 (*offset) += 3;
2034 /* Call parse_arith -- 0 is for "no brackets" */
2035 return parse_arith (word, word_length, max_length, words, offset,
2036 flags, 0);
2040 (*offset) += 2;
2041 return parse_comm (word, word_length, max_length, words, offset, flags,
2042 quoted? NULL : pwordexp, ifs, ifs_white);
2044 case '[':
2045 (*offset) += 2;
2046 /* Call parse_arith -- 1 is for "brackets" */
2047 return parse_arith (word, word_length, max_length, words, offset, flags,
2050 case '{':
2051 default:
2052 ++(*offset); /* parse_param needs to know if "{" is there */
2053 return parse_param (word, word_length, max_length, words, offset, flags,
2054 pwordexp, ifs, ifs_white, quoted);
2058 static int
2059 parse_backtick (char **word, size_t *word_length, size_t *max_length,
2060 const char *words, size_t *offset, int flags,
2061 wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
2063 /* We are poised just after "`" */
2064 int error;
2065 int squoting = 0;
2066 size_t comm_length;
2067 size_t comm_maxlen;
2068 char *comm = w_newword (&comm_length, &comm_maxlen);
2070 for (; words[*offset]; ++(*offset))
2072 switch (words[*offset])
2074 case '`':
2075 /* Go -- give the script to the shell */
2076 error = exec_comm (comm, word, word_length, max_length, flags,
2077 pwordexp, ifs, ifs_white);
2078 free (comm);
2079 return error;
2081 case '\\':
2082 if (squoting)
2084 error = parse_qtd_backslash (&comm, &comm_length, &comm_maxlen,
2085 words, offset);
2087 if (error)
2089 free (comm);
2090 return error;
2093 break;
2096 error = parse_backslash (&comm, &comm_length, &comm_maxlen, words,
2097 offset);
2099 if (error)
2101 free (comm);
2102 return error;
2105 break;
2107 case '\'':
2108 squoting = 1 - squoting;
2109 /* Fall through. */
2110 default:
2111 comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
2112 if (comm == NULL)
2113 return WRDE_NOSPACE;
2117 /* Premature end */
2118 free (comm);
2119 return WRDE_SYNTAX;
2122 static int
2123 parse_dquote (char **word, size_t *word_length, size_t *max_length,
2124 const char *words, size_t *offset, int flags,
2125 wordexp_t *pwordexp, const char * ifs, const char * ifs_white)
2127 /* We are poised just after a double-quote */
2128 int error;
2130 for (; words[*offset]; ++(*offset))
2132 switch (words[*offset])
2134 case '"':
2135 return 0;
2137 case '$':
2138 error = parse_dollars (word, word_length, max_length, words, offset,
2139 flags, pwordexp, ifs, ifs_white, 1);
2140 /* The ``1'' here is to tell parse_dollars not to
2141 * split the fields. It may need to, however ("$@").
2143 if (error)
2144 return error;
2146 break;
2148 case '`':
2149 ++(*offset);
2150 error = parse_backtick (word, word_length, max_length, words,
2151 offset, flags, NULL, NULL, NULL);
2152 /* The first NULL here is to tell parse_backtick not to
2153 * split the fields.
2155 if (error)
2156 return error;
2158 break;
2160 case '\\':
2161 error = parse_qtd_backslash (word, word_length, max_length, words,
2162 offset);
2164 if (error)
2165 return error;
2167 break;
2169 default:
2170 *word = w_addchar (*word, word_length, max_length, words[*offset]);
2171 if (*word == NULL)
2172 return WRDE_NOSPACE;
2176 /* Unterminated string */
2177 return WRDE_SYNTAX;
2181 * wordfree() is to be called after pwordexp is finished with.
2184 void
2185 wordfree (wordexp_t *pwordexp)
2188 /* wordexp can set pwordexp to NULL */
2189 if (pwordexp && pwordexp->we_wordv)
2191 char **wordv = pwordexp->we_wordv;
2193 for (wordv += pwordexp->we_offs; *wordv; ++wordv)
2194 free (*wordv);
2196 free (pwordexp->we_wordv);
2197 pwordexp->we_wordv = NULL;
2200 libc_hidden_def (wordfree)
2203 * wordexp()
2207 wordexp (const char *words, wordexp_t *pwordexp, int flags)
2209 size_t words_offset;
2210 size_t word_length;
2211 size_t max_length;
2212 char *word = w_newword (&word_length, &max_length);
2213 int error;
2214 char *ifs;
2215 char ifs_white[4];
2216 wordexp_t old_word = *pwordexp;
2218 if (flags & WRDE_REUSE)
2220 /* Minimal implementation of WRDE_REUSE for now */
2221 wordfree (pwordexp);
2222 old_word.we_wordv = NULL;
2225 if ((flags & WRDE_APPEND) == 0)
2227 pwordexp->we_wordc = 0;
2229 if (flags & WRDE_DOOFFS)
2231 pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
2232 if (pwordexp->we_wordv == NULL)
2234 error = WRDE_NOSPACE;
2235 goto do_error;
2238 else
2240 pwordexp->we_wordv = calloc (1, sizeof (char *));
2241 if (pwordexp->we_wordv == NULL)
2243 error = WRDE_NOSPACE;
2244 goto do_error;
2247 pwordexp->we_offs = 0;
2251 /* Find out what the field separators are.
2252 * There are two types: whitespace and non-whitespace.
2254 ifs = getenv ("IFS");
2256 if (ifs == NULL)
2257 /* IFS unset - use <space><tab><newline>. */
2258 ifs = strcpy (ifs_white, " \t\n");
2259 else
2261 char *ifsch = ifs;
2262 char *whch = ifs_white;
2264 while (*ifsch != '\0')
2266 if (*ifsch == ' ' || *ifsch == '\t' || *ifsch == '\n')
2268 /* Whitespace IFS. See first whether it is already in our
2269 collection. */
2270 char *runp = ifs_white;
2272 while (runp < whch && *runp != *ifsch)
2273 ++runp;
2275 if (runp == whch)
2276 *whch++ = *ifsch;
2279 ++ifsch;
2281 *whch = '\0';
2284 for (words_offset = 0 ; words[words_offset] ; ++words_offset)
2285 switch (words[words_offset])
2287 case '\\':
2288 error = parse_backslash (&word, &word_length, &max_length, words,
2289 &words_offset);
2291 if (error)
2292 goto do_error;
2294 break;
2296 case '$':
2297 error = parse_dollars (&word, &word_length, &max_length, words,
2298 &words_offset, flags, pwordexp, ifs, ifs_white,
2301 if (error)
2302 goto do_error;
2304 break;
2306 case '`':
2307 ++words_offset;
2308 error = parse_backtick (&word, &word_length, &max_length, words,
2309 &words_offset, flags, pwordexp, ifs,
2310 ifs_white);
2312 if (error)
2313 goto do_error;
2315 break;
2317 case '"':
2318 ++words_offset;
2319 error = parse_dquote (&word, &word_length, &max_length, words,
2320 &words_offset, flags, pwordexp, ifs, ifs_white);
2322 if (error)
2323 goto do_error;
2325 if (!word_length)
2327 error = w_addword (pwordexp, NULL);
2329 if (error)
2330 return error;
2333 break;
2335 case '\'':
2336 ++words_offset;
2337 error = parse_squote (&word, &word_length, &max_length, words,
2338 &words_offset);
2340 if (error)
2341 goto do_error;
2343 if (!word_length)
2345 error = w_addword (pwordexp, NULL);
2347 if (error)
2348 return error;
2351 break;
2353 case '~':
2354 error = parse_tilde (&word, &word_length, &max_length, words,
2355 &words_offset, pwordexp->we_wordc);
2357 if (error)
2358 goto do_error;
2360 break;
2362 case '*':
2363 case '[':
2364 case '?':
2365 error = parse_glob (&word, &word_length, &max_length, words,
2366 &words_offset, flags, pwordexp, ifs, ifs_white);
2368 if (error)
2369 goto do_error;
2371 break;
2373 default:
2374 /* Is it a word separator? */
2375 if (strchr (" \t", words[words_offset]) == NULL)
2377 char ch = words[words_offset];
2379 /* Not a word separator -- but is it a valid word char? */
2380 if (strchr ("\n|&;<>(){}", ch))
2382 /* Fail */
2383 error = WRDE_BADCHAR;
2384 goto do_error;
2387 /* "Ordinary" character -- add it to word */
2388 word = w_addchar (word, &word_length, &max_length,
2389 ch);
2390 if (word == NULL)
2392 error = WRDE_NOSPACE;
2393 goto do_error;
2396 break;
2399 /* If a word has been delimited, add it to the list. */
2400 if (word != NULL)
2402 error = w_addword (pwordexp, word);
2403 if (error)
2404 goto do_error;
2407 word = w_newword (&word_length, &max_length);
2410 /* End of string */
2412 /* There was a word separator at the end */
2413 if (word == NULL) /* i.e. w_newword */
2414 return 0;
2416 /* There was no field separator at the end */
2417 return w_addword (pwordexp, word);
2419 do_error:
2420 /* Error:
2421 * free memory used (unless error is WRDE_NOSPACE), and
2422 * set pwordexp members back to what they were.
2425 free (word);
2427 if (error == WRDE_NOSPACE)
2428 return WRDE_NOSPACE;
2430 if ((flags & WRDE_APPEND) == 0)
2431 wordfree (pwordexp);
2433 *pwordexp = old_word;
2434 return error;