Update.
[glibc.git] / posix / wordexp.c
blob1df552a66fe1cead05648fc1281ce85fc949b8d4
1 /* POSIX.2 wordexp implementation.
2 Copyright (C) 1997, 1998 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Tim Waugh <tim@cyberelk.demon.co.uk>.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #include <wordexp.h>
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <pwd.h>
25 #include <sys/types.h>
26 #include <string.h>
27 #include <glob.h>
28 #include <ctype.h>
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <sys/stat.h>
35 #include <paths.h>
36 #include <errno.h>
37 #include <sys/param.h>
38 #include <stdio.h>
39 #include <fnmatch.h>
41 #include <stdio-common/_itoa.h>
43 /* Undefine the following line for the production version. */
44 /* #define NDEBUG 1 */
45 #include <assert.h>
48 * This is a recursive-descent-style word expansion routine.
51 /* These variables are defined and initialized in the startup code. */
52 extern int __libc_argc;
53 extern char **__libc_argv;
55 /* Some forward declarations */
56 static int parse_dollars (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, int quoted)
60 internal_function;
61 static int parse_backtick (char **word, size_t *word_length,
62 size_t *max_length, const char *words,
63 size_t *offset, int flags, wordexp_t *pwordexp,
64 const char *ifs, const char *ifs_white)
65 internal_function;
66 static int parse_dquote (char **word, size_t *word_length, size_t *max_length,
67 const char *words, size_t *offset, int flags,
68 wordexp_t *pwordexp, const char *ifs,
69 const char *ifs_white)
70 internal_function;
71 static int eval_expr (char *expr, long int *result) internal_function;
73 /* The w_*() functions manipulate word lists. */
75 #define W_CHUNK (100)
77 static inline char *
78 w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch)
79 /* (lengths exclude trailing zero) */
81 /* Add a character to the buffer, allocating room for it if needed.
84 if (*actlen == *maxlen)
86 char *old_buffer = buffer;
87 assert (buffer == NULL || *maxlen != 0);
88 *maxlen += W_CHUNK;
89 buffer = realloc (buffer, 1 + *maxlen);
91 if (buffer == NULL)
92 free (old_buffer);
95 if (buffer != NULL)
97 buffer[*actlen] = ch;
98 buffer[++(*actlen)] = '\0';
101 return buffer;
104 static char *
105 internal_function
106 w_addmem (char *buffer, size_t *actlen, size_t *maxlen, const char *str,
107 size_t len)
109 /* Add a string to the buffer, allocating room for it if needed.
111 if (*actlen + len > *maxlen)
113 char *old_buffer = buffer;
114 assert (buffer == NULL || *maxlen != 0);
115 *maxlen += MAX (2 * len, W_CHUNK);
116 buffer = realloc (old_buffer, 1 + *maxlen);
118 if (buffer == NULL)
119 free (old_buffer);
122 if (buffer != NULL)
124 *((char *) __mempcpy (&buffer[*actlen], str, len)) = '\0';
125 *actlen += len;
128 return buffer;
132 static char *
133 internal_function
134 w_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str)
135 /* (lengths exclude trailing zero) */
137 /* Add a string to the buffer, allocating room for it if needed.
139 size_t len;
141 assert (str != NULL); /* w_addstr only called from this file */
142 len = strlen (str);
144 return w_addmem (buffer, actlen, maxlen, str, len);
147 static int
148 internal_function
149 w_addword (wordexp_t *pwordexp, char *word)
151 /* Add a word to the wordlist */
152 size_t num_p;
153 char **new_wordv;
155 num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
156 new_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p);
157 if (new_wordv != NULL)
159 pwordexp->we_wordv = new_wordv;
160 pwordexp->we_wordv[pwordexp->we_wordc++] = word;
161 pwordexp->we_wordv[pwordexp->we_wordc] = NULL;
162 return 0;
165 return WRDE_NOSPACE;
168 /* The parse_*() functions should leave *offset being the offset in 'words'
169 * to the last character processed.
172 static int
173 internal_function
174 parse_backslash (char **word, size_t *word_length, size_t *max_length,
175 const char *words, size_t *offset)
177 /* We are poised _at_ a backslash, not in quotes */
179 switch (words[1 + *offset])
181 case 0:
182 /* Backslash is last character of input words */
183 return WRDE_SYNTAX;
185 case '\n':
186 ++(*offset);
187 break;
189 default:
190 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
191 if (*word == NULL)
192 return WRDE_NOSPACE;
194 ++(*offset);
195 break;
198 return 0;
201 static int
202 internal_function
203 parse_qtd_backslash (char **word, size_t *word_length, size_t *max_length,
204 const char *words, size_t *offset)
206 /* We are poised _at_ a backslash, inside quotes */
208 switch (words[1 + *offset])
210 case 0:
211 /* Backslash is last character of input words */
212 return WRDE_SYNTAX;
214 case '\n':
215 ++(*offset);
216 break;
218 case '$':
219 case '`':
220 case '"':
221 case '\\':
222 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
223 if (*word == NULL)
224 return WRDE_NOSPACE;
226 ++(*offset);
227 break;
229 default:
230 *word = w_addchar (*word, word_length, max_length, words[*offset]);
231 if (*word != NULL)
232 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
234 if (*word == NULL)
235 return WRDE_NOSPACE;
237 ++(*offset);
238 break;
241 return 0;
244 static int
245 internal_function
246 parse_tilde (char **word, size_t *word_length, size_t *max_length,
247 const char *words, size_t *offset, size_t wordc)
249 /* We are poised _at_ a tilde */
250 size_t i;
252 if (*word_length != 0)
254 if (!((*word)[*word_length - 1] == '=' && wordc == 0))
256 if (!((*word)[*word_length - 1] == ':'
257 && strchr (*word, '=') && wordc == 0))
259 *word = w_addchar (*word, word_length, max_length, '~');
260 return *word ? 0 : WRDE_NOSPACE;
265 for (i = 1 + *offset; words[i]; i++)
267 if (words[i] == ':' || words[i] == '/' || words[i] == ' ' ||
268 words[i] == '\t' || words[i] == 0 )
269 break;
271 if (words[i] == '\\')
273 *word = w_addchar (*word, word_length, max_length, '~');
274 return *word ? 0 : WRDE_NOSPACE;
278 if (i == 1 + *offset)
280 /* Tilde appears on its own */
281 uid_t uid;
282 struct passwd pwd, *tpwd;
283 int buflen = 1000;
284 char* buffer = __alloca (buflen);
285 int result;
287 uid = getuid ();
289 while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
290 && errno == ERANGE)
292 buflen += 1000;
293 buffer = __alloca (buflen);
296 if (result == 0 && pwd.pw_dir != NULL)
298 *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
299 if (*word == NULL)
300 return WRDE_NOSPACE;
302 else
304 *word = w_addchar (*word, word_length, max_length, '~');
305 if (*word == NULL)
306 return WRDE_NOSPACE;
309 else
311 /* Look up user name in database to get home directory */
312 char *user = __strndup (&words[1 + *offset], i - *offset);
313 struct passwd pwd, *tpwd;
314 int buflen = 1000;
315 char* buffer = __alloca (buflen);
316 int result;
318 while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
319 && errno == ERANGE)
321 buflen += 1000;
322 buffer = __alloca (buflen);
325 if (result == 0 && pwd.pw_dir)
326 *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
327 else
329 /* (invalid login name) */
330 *word = w_addchar (*word, word_length, max_length, '~');
331 if (*word != NULL)
332 *word = w_addstr (*word, word_length, max_length, user);
335 *offset = i - 1;
337 return *word ? 0 : WRDE_NOSPACE;
340 static int
341 internal_function
342 parse_glob (char **word, size_t *word_length, size_t *max_length,
343 const char *words, size_t *offset, int flags,
344 wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
346 /* We are poised just after a '*', a '[' or a '?'. */
347 int error;
348 glob_t globbuf;
349 int match;
350 char *matching_word;
351 int quoted = 0; /* 1 if singly-quoted, 2 if doubly */
353 for (; words[*offset]; (*offset)++)
355 if ((ifs && strchr (ifs, words[*offset])) ||
356 (!ifs && strchr (" \t\n", words[*offset])))
357 /* Reached IFS */
358 break;
360 /* Sort out quoting */
361 if (words[*offset] == '\'')
362 if (quoted == 0)
364 quoted = 1;
365 continue;
367 else if (quoted == 1)
369 quoted = 0;
370 continue;
372 else if (words[*offset] == '"')
373 if (quoted == 0)
375 quoted = 2;
376 continue;
378 else if (quoted == 2)
380 quoted = 0;
381 continue;
384 /* Sort out other special characters */
385 if (quoted != 1 && words[*offset] == '$')
387 error = parse_dollars (word, word_length, max_length, words, offset,
388 flags, pwordexp, ifs, ifs_white, quoted == 2);
389 if (error)
390 return error;
392 continue;
394 else if (words[*offset] == '\\')
396 if (quoted)
397 error = parse_qtd_backslash (word, word_length, max_length, words,
398 offset);
399 else
400 error = parse_backslash (word, word_length, max_length, words,
401 offset);
403 if (error)
404 return error;
406 continue;
409 *word = w_addchar (*word, word_length, max_length, words[*offset]);
410 if (*word == NULL)
411 return WRDE_NOSPACE;
414 error = glob (*word, GLOB_NOCHECK, NULL, &globbuf);
416 if (error != 0)
418 /* We can only run into memory problems. */
419 assert (error == GLOB_NOSPACE);
421 return WRDE_NOSPACE;
424 if (ifs && !*ifs)
426 /* No field splitting allowed */
427 size_t length = strlen (globbuf.gl_pathv[0]);
428 char *old_word = *word;
429 *word = realloc (*word, length + 1);
430 if (*word == NULL)
432 free (old_word);
433 goto no_space;
436 memcpy (*word, globbuf.gl_pathv[0], length + 1);
437 *word_length = length;
439 for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
441 *word = w_addchar (*word, word_length, max_length, ' ');
442 if (*word != NULL)
443 *word = w_addstr (*word, word_length, max_length,
444 globbuf.gl_pathv[match]);
447 /* Re-parse white space on return */
448 globfree (&globbuf);
449 --(*offset);
450 return *word ? 0 : WRDE_NOSPACE;
453 /* here ifs != "" */
454 free (*word);
455 *word = NULL;
456 *word_length = 0;
458 matching_word = __strdup (globbuf.gl_pathv[0]);
459 if (matching_word == NULL)
460 goto no_space;
462 if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
463 goto no_space;
465 for (match = 1; match < globbuf.gl_pathc; ++match)
467 matching_word = __strdup (globbuf.gl_pathv[match]);
468 if (matching_word == NULL)
469 goto no_space;
471 if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
472 goto no_space;
475 globfree (&globbuf);
477 /* Re-parse white space on return */
478 --(*offset);
479 return 0;
481 no_space:
482 globfree (&globbuf);
483 return WRDE_NOSPACE;
486 static int
487 internal_function
488 parse_squote (char **word, size_t *word_length, size_t *max_length,
489 const char *words, size_t *offset)
491 /* We are poised just after a single quote */
492 for (; words[*offset]; ++(*offset))
494 if (words[*offset] != '\'')
496 *word = w_addchar (*word, word_length, max_length, words[*offset]);
497 if (*word == NULL)
498 return WRDE_NOSPACE;
500 else return 0;
503 /* Unterminated string */
504 return WRDE_SYNTAX;
507 /* Functions to evaluate an arithmetic expression */
508 static int
509 internal_function
510 eval_expr_val (char **expr, long int *result)
512 int sgn = +1;
513 char *digit;
515 /* Skip white space */
516 for (digit = *expr; digit && *digit && isspace (*digit); ++digit);
518 switch (*digit)
520 case '(':
522 /* Scan for closing paren */
523 for (++digit; **expr && **expr != ')'; ++(*expr));
525 /* Is there one? */
526 if (!**expr)
527 return WRDE_SYNTAX;
529 *(*expr)++ = 0;
531 if (eval_expr (digit, result))
532 return WRDE_SYNTAX;
534 return 0;
536 case '+': /* Positive value */
537 ++digit;
538 break;
540 case '-': /* Negative value */
541 ++digit;
542 sgn = -1;
543 break;
545 default:
546 if (!isdigit (*digit))
547 return WRDE_SYNTAX;
550 *result = 0;
551 for (; *digit && isdigit (*digit); ++digit)
552 *result = (*result * 10) + (*digit - '0');
554 *expr = digit;
555 *result *= sgn;
556 return 0;
559 static int
560 internal_function
561 eval_expr_multdiv (char **expr, long int *result)
563 long int arg;
565 /* Read a Value */
566 if (eval_expr_val (expr, result) != 0)
567 return WRDE_SYNTAX;
569 while (**expr)
571 /* Skip white space */
572 for (; *expr && **expr && isspace (**expr); ++(*expr));
574 if (**expr == '*')
576 ++(*expr);
577 if (eval_expr_val (expr, &arg) != 0)
578 return WRDE_SYNTAX;
580 *result *= arg;
582 else if (**expr == '/')
584 ++(*expr);
585 if (eval_expr_val (expr, &arg) != 0)
586 return WRDE_SYNTAX;
588 *result /= arg;
590 else break;
593 return 0;
596 static int
597 internal_function
598 eval_expr (char *expr, long int *result)
600 long int arg;
602 /* Read a Multdiv */
603 if (eval_expr_multdiv (&expr, result) != 0)
604 return WRDE_SYNTAX;
606 while (*expr)
608 /* Skip white space */
609 for (; expr && *expr && isspace (*expr); ++expr);
611 if (*expr == '+')
613 ++expr;
614 if (eval_expr_multdiv (&expr, &arg) != 0)
615 return WRDE_SYNTAX;
617 *result += arg;
619 else if (*expr == '-')
621 ++expr;
622 if (eval_expr_multdiv (&expr, &arg) != 0)
623 return WRDE_SYNTAX;
625 *result -= arg;
627 else break;
630 return 0;
633 static int
634 internal_function
635 parse_arith (char **word, size_t *word_length, size_t *max_length,
636 const char *words, size_t *offset, int flags, int bracket)
638 /* We are poised just after "$((" or "$[" */
639 int error;
640 int paren_depth = 1;
641 size_t expr_length = 0;
642 size_t expr_maxlen = 0;
643 char *expr = NULL;
645 for (; words[*offset]; ++(*offset))
647 switch (words[*offset])
649 case '$':
650 error = parse_dollars (&expr, &expr_length, &expr_maxlen,
651 words, offset, flags, NULL, NULL, NULL, 1);
652 /* The ``1'' here is to tell parse_dollars not to
653 * split the fields.
655 if (error)
657 free (expr);
658 return error;
660 break;
662 case '`':
663 (*offset)++;
664 error = parse_backtick (&expr, &expr_length, &expr_maxlen,
665 words, offset, flags, NULL, NULL, NULL);
666 /* The first NULL here is to tell parse_backtick not to
667 * split the fields.
669 if (error)
671 free (expr);
672 return error;
674 break;
676 case '\\':
677 error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen,
678 words, offset);
679 if (error)
681 free (expr);
682 return error;
684 /* I think that a backslash within an
685 * arithmetic expansion is bound to
686 * cause an error sooner or later anyway though.
688 break;
690 case ')':
691 if (--paren_depth == 0)
693 char result[21]; /* 21 = ceil(log10(2^64)) + 1 */
694 long int numresult = 0;
695 long long int convertme;
697 if (bracket || words[1 + *offset] != ')')
698 return WRDE_SYNTAX;
700 ++(*offset);
702 /* Go - evaluate. */
703 if (*expr && eval_expr (expr, &numresult) != 0)
704 return WRDE_SYNTAX;
706 if (numresult < 0)
708 convertme = -numresult;
709 *word = w_addchar (*word, word_length, max_length, '-');
710 if (!*word)
712 free (expr);
713 return WRDE_NOSPACE;
716 else
717 convertme = numresult;
719 result[20] = '\0';
720 *word = w_addstr (*word, word_length, max_length,
721 _itoa (convertme, &result[20], 10, 0));
722 free (expr);
723 return *word ? 0 : WRDE_NOSPACE;
725 expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
726 if (expr == NULL)
727 return WRDE_NOSPACE;
729 break;
731 case ']':
732 if (bracket && paren_depth == 1)
734 char result[21]; /* 21 = ceil(log10(2^64)) + 1 */
735 long int numresult = 0;
737 /* Go - evaluate. */
738 if (*expr && eval_expr (expr, &numresult) != 0)
739 return WRDE_SYNTAX;
741 result[20] = '\0';
742 *word = w_addstr (*word, word_length, max_length,
743 _itoa_word (numresult, &result[20], 10, 0));
744 free (expr);
745 return *word ? 0 : WRDE_NOSPACE;
748 free (expr);
749 return WRDE_SYNTAX;
751 case '\n':
752 case ';':
753 case '{':
754 case '}':
755 free (expr);
756 return WRDE_BADCHAR;
758 case '(':
759 ++paren_depth;
760 default:
761 expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
762 if (expr == NULL)
763 return WRDE_NOSPACE;
767 /* Premature end */
768 free (expr);
769 return WRDE_SYNTAX;
772 /* Function to execute a command and retrieve the results */
773 /* pwordexp contains NULL if field-splitting is forbidden */
774 static int
775 internal_function
776 exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
777 int flags, wordexp_t *pwordexp, const char *ifs,
778 const char *ifs_white)
780 int fildes[2];
781 int bufsize = 128;
782 int buflen;
783 int i;
784 char *buffer;
785 pid_t pid;
787 /* Don't fork() unless necessary */
788 if (!comm || !*comm)
789 return 0;
791 if (pipe (fildes))
792 /* Bad */
793 return WRDE_NOSPACE;
795 if ((pid = fork ()) < 0)
797 /* Bad */
798 return WRDE_NOSPACE;
801 if (pid == 0)
803 /* Child */
804 const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
806 /* Redirect output. */
807 dup2 (fildes[1], 1);
808 close (fildes[1]);
810 /* Redirect stderr to /dev/null if we have to. */
811 if ((flags & WRDE_SHOWERR) == 0)
813 int fd;
814 close (2);
815 fd = open (_PATH_DEVNULL, O_WRONLY);
816 if (fd >= 0 && fd != 2)
818 dup2 (fd, 2);
819 close (fd);
823 close (fildes[0]);
824 __execve (_PATH_BSHELL, (char *const *) args, __environ);
826 /* Bad. What now? */
827 abort ();
830 /* Parent */
832 close (fildes[1]);
833 buffer = __alloca (bufsize);
835 if (!pwordexp)
836 { /* Quoted - no field splitting */
838 while (1)
840 if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
842 if (__waitpid (pid, NULL, WNOHANG) == 0)
843 continue;
844 if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
845 break;
848 *word = w_addmem (*word, word_length, max_length, buffer, buflen);
849 if (*word == NULL)
851 kill (pid, SIGKILL);
852 __waitpid (pid, NULL, 0);
853 close (fildes[0]);
854 return WRDE_NOSPACE;
858 else
859 /* Not quoted - split fields */
861 int copying = 0;
862 /* 'copying' is:
863 * 0 when searching for first character in a field not IFS white space
864 * 1 when copying the text of a field
865 * 2 when searching for possible non-whitespace IFS
868 while (1)
870 if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
872 if (__waitpid (pid, NULL, WNOHANG) == 0)
873 continue;
874 if ((read (fildes[0], buffer, bufsize)) < 1)
875 break;
878 for (i = 0; i < buflen; ++i)
880 if (strchr (ifs, buffer[i]) != NULL)
882 /* Current character is IFS */
883 if (strchr (ifs_white, buffer[i]) == NULL)
885 /* Current character is IFS but not whitespace */
886 if (copying == 2)
888 /* current character
891 * eg: text<space><comma><space>moretext
893 * So, strip whitespace IFS (like at the start)
895 copying = 0;
896 continue;
899 copying = 0;
900 /* fall through and delimit field.. */
902 else
904 /* Current character is IFS white space */
906 /* If not copying a field, ignore it */
907 if (copying != 1)
908 continue;
910 /* End of field (search for non-IFS afterwards) */
911 copying = 2;
914 /* First IFS white space, or IFS non-whitespace.
915 * Delimit the field. */
916 if (!*word)
918 /* This field is null, so make it an empty string */
919 *word = w_addchar (*word, word_length, max_length, 0);
920 if (*word == NULL)
922 kill (pid, SIGKILL);
923 __waitpid (pid, NULL, 0);
924 close (fildes[0]);
925 return WRDE_NOSPACE;
929 if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
931 kill (pid, SIGKILL);
932 __waitpid (pid, NULL, 0);
933 close (fildes[0]);
934 return WRDE_NOSPACE;
937 *word = NULL;
938 *word_length = 0;
939 *max_length = 0;
940 /* fall back round the loop.. */
942 else
944 /* Not IFS character */
945 copying = 1;
946 *word = w_addchar (*word, word_length, max_length,
947 buffer[i]);
948 if (*word == NULL)
950 kill (pid, SIGKILL);
951 __waitpid (pid, NULL, 0);
952 close (fildes[0]);
953 return WRDE_NOSPACE;
960 /* Bash chops off trailing newlines, which seems sensible. */
961 while (*word_length > 0 && (*word)[*word_length - 1] == '\n')
962 (*word)[--*word_length] = '\0';
964 close (fildes[0]);
965 return 0;
968 static int
969 internal_function
970 parse_comm (char **word, size_t *word_length, size_t *max_length,
971 const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
972 const char *ifs, const char *ifs_white)
974 /* We are poised just after "$(" */
975 int paren_depth = 1;
976 int error = 0;
977 size_t comm_length = 0;
978 size_t comm_maxlen = 0;
979 char *comm = NULL;
980 int quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
982 for (; words[*offset]; ++(*offset))
984 switch (words[*offset])
986 case '\'':
987 if (quoted == 0)
988 quoted = 1;
989 else if (quoted == 1)
990 quoted = 0;
992 break;
994 case '"':
995 if (quoted == 0)
996 quoted = 2;
997 else if (quoted == 2)
998 quoted = 0;
1000 break;
1002 case ')':
1003 if (!quoted && --paren_depth == 0)
1005 /* Go -- give script to the shell */
1006 if (comm)
1008 error = exec_comm (comm, word, word_length, max_length,
1009 flags, pwordexp, ifs, ifs_white);
1010 free (comm);
1013 return error;
1016 /* This is just part of the script */
1017 break;
1019 case '(':
1020 if (!quoted)
1021 ++paren_depth;
1024 comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
1025 if (comm == NULL)
1026 return WRDE_NOSPACE;
1029 /* Premature end */
1030 if (comm)
1031 free (comm);
1033 return WRDE_SYNTAX;
1036 static int
1037 internal_function
1038 parse_param (char **word, size_t *word_length, size_t *max_length,
1039 const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
1040 const char *ifs, const char *ifs_white, int quoted)
1042 /* We are poised just after "$" */
1043 enum action
1045 ACT_NONE,
1046 ACT_RP_SHORT_LEFT = '#',
1047 ACT_RP_LONG_LEFT = 'L',
1048 ACT_RP_SHORT_RIGHT = '%',
1049 ACT_RP_LONG_RIGHT = 'R',
1050 ACT_NULL_ERROR = '?',
1051 ACT_NULL_SUBST = '-',
1052 ACT_NONNULL_SUBST = '+',
1053 ACT_NULL_ASSIGN = '='
1055 size_t env_length = 0;
1056 size_t env_maxlen = 0;
1057 size_t pat_length = 0;
1058 size_t pat_maxlen = 0;
1059 size_t start = *offset;
1060 char *env = NULL;
1061 char *pattern = NULL;
1062 char *value = NULL;
1063 enum action action = ACT_NONE;
1064 int depth = 0;
1065 int colon_seen = 0;
1066 int seen_hash = 0;
1067 int free_value = 0;
1068 int pattern_is_quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
1069 int error;
1070 int brace = words[*offset] == '{';
1072 if (brace)
1073 ++*offset;
1075 for (; words[*offset]; ++(*offset))
1077 int special;
1079 if (action != ACT_NONE)
1081 switch (words[*offset])
1083 case '{':
1084 if (!pattern_is_quoted)
1085 ++depth;
1086 break;
1088 case '}':
1089 if (!pattern_is_quoted)
1091 if (depth == 0)
1092 goto envsubst;
1093 --depth;
1095 break;
1097 case '\\':
1098 if (!pattern_is_quoted && words[++*offset] == '\0')
1099 goto syntax;
1100 break;
1102 case '\'':
1103 if (pattern_is_quoted == 0)
1104 pattern_is_quoted = 1;
1105 else if (pattern_is_quoted == 1)
1106 pattern_is_quoted = 0;
1108 break;
1110 case '"':
1111 if (pattern_is_quoted == 0)
1112 pattern_is_quoted = 2;
1113 else if (pattern_is_quoted == 2)
1114 pattern_is_quoted = 0;
1116 break;
1119 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1120 words[*offset]);
1121 if (pattern == NULL)
1122 goto no_space;
1124 continue;
1127 switch (words[*offset])
1129 case '}':
1130 if (!brace)
1131 goto end_of_word;
1133 if (env == NULL)
1134 goto syntax;
1136 /* Evaluate. */
1137 goto envsubst;
1139 case '#':
1140 /* '#' only has special meaning inside braces or as the very
1141 * first character after $ */
1142 if (*offset == start)
1144 seen_hash = 1;
1145 goto envsubst;
1148 if (!brace)
1149 /* Evaluate */
1150 /* (and re-parse this character) */
1151 goto end_of_word;
1153 /* At the start? (i.e. 'string length') */
1154 if (env == NULL)
1156 seen_hash = 1;
1157 continue;
1159 else if (seen_hash)
1160 goto syntax;
1162 action = ACT_RP_SHORT_LEFT;
1163 if (words[1 + *offset] == '#')
1165 ++*offset;
1166 action = ACT_RP_LONG_LEFT;
1169 continue;
1171 case '%':
1172 if (!brace)
1173 /* Re-parse this character after substitution */
1174 goto end_of_word;
1176 if (!env || !*env)
1177 goto syntax;
1179 if (seen_hash)
1180 goto syntax;
1182 action = ACT_RP_SHORT_RIGHT;
1183 if (words[1 + *offset] == '%')
1185 ++*offset;
1186 action = ACT_RP_LONG_RIGHT;
1189 continue;
1191 case ':':
1192 if (!brace)
1193 goto end_of_word;
1195 if (!env || !*env)
1196 goto syntax;
1198 if (seen_hash)
1199 goto syntax;
1201 if (words[1 + *offset] != '-' && words[1 + *offset] != '='
1202 && words[1 + *offset] != '?' && words[1 + *offset] != '+')
1203 goto syntax;
1205 colon_seen = 1;
1206 action = words[++*offset];
1207 continue;
1209 case '-':
1210 case '=':
1211 case '?':
1212 case '+':
1213 if (!brace)
1214 goto end_of_word;
1216 if (!env || !*env)
1217 goto syntax;
1219 action = words[*offset];
1220 continue;
1223 special = strchr ("*@$", words[*offset]) != NULL;
1225 if (!isalnum (words[*offset]) && !special)
1226 /* Stop and evaluate, remembering char we stopped at */
1227 break;
1229 env = w_addchar (env, &env_length, &env_maxlen,
1230 words[*offset]);
1231 if (env == NULL)
1232 goto no_space;
1234 if (special)
1236 if (brace)
1237 ++*offset;
1238 goto envsubst;
1242 /* End of input string -- remember to reparse the character that we stopped
1243 * at. */
1244 end_of_word:
1245 --(*offset);
1247 envsubst:
1248 if (words[start] == '{' && words[*offset] != '}')
1249 goto syntax;
1251 if (!env || !*env)
1253 if (seen_hash)
1255 /* $# expands to the number of positional parameters */
1256 char buffer[21];
1257 buffer[20] = '\0';
1258 *word = w_addstr (*word, word_length, max_length,
1259 _itoa_word (__libc_argc - 1, &buffer[20], 10, 0));
1261 else
1263 /* Just $ on its own */
1264 *offset = start - 1;
1265 *word = w_addchar (*word, word_length, max_length, '$');
1268 if (env)
1269 free (env);
1271 return *word ? 0 : WRDE_NOSPACE;
1274 /* Is it a special parameter? */
1275 if (strpbrk (env, "*@$") || isdigit (*env))
1277 if ((isdigit(*env) && strcspn (env, "1234567890")) ||
1278 (!isdigit(*env) && env[1] != '\0'))
1280 /* Bad substitution if it isn't "*", "@", "$", or just a number. */
1281 bad_subst:
1282 free (env);
1283 fprintf (stderr, "${%s}: bad substitution\n", env);
1284 return WRDE_SYNTAX;
1287 /* Is it a digit? */
1288 if (isdigit(*env))
1290 char *endp;
1291 int n = strtol (env, &endp, 10);
1293 if (*endp != '\0')
1294 goto bad_subst;
1296 free (env);
1297 if (n >= __libc_argc)
1298 /* Substitute NULL */
1299 return 0;
1301 /* Replace with the appropriate positional parameter */
1302 value = __libc_argv[n];
1303 goto maybe_fieldsplit;
1305 /* Is it `$$' ? */
1306 else if (*env == '$')
1308 char pidstr[21];
1310 free (env);
1311 pidstr[20] = '\0';
1312 *word = w_addstr (*word, word_length, max_length,
1313 _itoa_word (getpid(), &pidstr[20], 10, 0));
1314 return *word ? 0 : WRDE_NOSPACE;
1316 /* Is it `$*' or `$@' (unquoted) ? */
1317 else if (*env == '*' || (*env == '@' && !quoted))
1319 size_t plist_len = 1;
1320 int p;
1322 /* Build up value parameter by parameter (copy them) */
1323 free (env);
1324 for (p = 1; __libc_argv[p]; ++p)
1326 char *old_pointer = value;
1327 size_t argv_len = strlen (__libc_argv[p]);
1328 size_t old_plist_len = plist_len;
1330 if (value)
1331 value[plist_len - 1] = 0;
1333 plist_len += 1 + argv_len;
1335 /* First realloc will act as malloc because value is
1336 * initialised to NULL. */
1337 value = realloc (value, plist_len);
1338 if (value == NULL)
1340 free (old_pointer);
1341 return WRDE_NOSPACE;
1344 memcpy (&value[old_plist_len - 1], __libc_argv[p], argv_len + 1);
1345 if (__libc_argv[p + 1])
1347 value[plist_len - 1] = '\0';
1348 value[plist_len - 2] = ' ';
1352 free_value = 1;
1353 if (value)
1354 goto maybe_fieldsplit;
1356 return 0;
1359 /* Must be a quoted `$@' */
1360 assert (*env == '@');
1361 assert (quoted);
1362 free (env);
1364 /* Each parameter is a separate word ("$@") */
1365 if (__libc_argv[0] != NULL && __libc_argv[1] != NULL)
1367 /* Append first parameter to current word. */
1368 int p;
1370 *word = w_addstr (*word, word_length, max_length, __libc_argv[1]);
1371 if (*word == NULL)
1372 return WRDE_NOSPACE;
1374 for (p = 2; __libc_argv[p]; p++)
1376 size_t len;
1377 char *s;
1378 if (w_addword (pwordexp, *word))
1379 return WRDE_NOSPACE;
1380 len = strlen (__libc_argv[p]) + 1;
1381 s = malloc (len);
1382 if (s == NULL)
1383 return WRDE_NOSPACE;
1384 *word = memcpy (s, __libc_argv[p], len);
1385 *max_length = *word_length = len - 1;
1389 return 0;
1392 value = getenv (env);
1394 if (action != ACT_NONE)
1396 switch (action)
1398 case ACT_RP_SHORT_LEFT:
1399 case ACT_RP_LONG_LEFT:
1400 case ACT_RP_SHORT_RIGHT:
1401 case ACT_RP_LONG_RIGHT:
1403 char *p;
1404 char c;
1405 char *end;
1407 if (!pattern || !*pattern)
1408 break;
1410 end = value + strlen (value);
1412 if (value == NULL)
1413 break;
1415 switch (action)
1417 case ACT_RP_SHORT_LEFT:
1418 for (p = value; p <= end; ++p)
1420 c = *p;
1421 *p = '\0';
1422 if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1424 *p = c;
1425 value = p;
1426 break;
1428 *p = c;
1431 break;
1433 case ACT_RP_LONG_LEFT:
1434 for (p = end; p >= value; --p)
1436 c = *p;
1437 *p = '\0';
1438 if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1440 *p = c;
1441 value = p;
1442 break;
1444 *p = c;
1447 break;
1449 case ACT_RP_SHORT_RIGHT:
1450 for (p = end; p >= value; --p)
1452 if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1454 *p = '\0';
1455 break;
1459 break;
1461 case ACT_RP_LONG_RIGHT:
1462 for (p = value; p <= end; ++p)
1464 if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1466 *p = '\0';
1467 break;
1471 break;
1473 default:
1474 break;
1477 break;
1480 case ACT_NULL_ERROR:
1481 if (value && *value)
1482 /* Substitute parameter */
1483 break;
1485 if (!colon_seen && value)
1487 /* Substitute NULL */
1488 free (env);
1489 free (pattern);
1490 return 0;
1493 if (*pattern)
1495 /* Expand 'pattern' and write it to stderr */
1496 wordexp_t we;
1498 error = wordexp (pattern, &we, flags);
1500 if (error == 0)
1502 int i;
1504 fprintf (stderr, "%s:", env);
1506 for (i = 0; i < we.we_wordc; ++i)
1508 fprintf (stderr, " %s", we.we_wordv[i]);
1511 fprintf (stderr, "\n");
1512 error = WRDE_BADVAL;
1515 wordfree (&we);
1516 free (env);
1517 free (pattern);
1518 return error;
1521 fprintf (stderr, "%s: parameter null or not set\n", env);
1522 free (env);
1523 free (pattern);
1524 return WRDE_BADVAL;
1526 case ACT_NULL_SUBST:
1527 if (value && *value)
1528 /* Substitute parameter */
1529 break;
1531 if (!colon_seen && value)
1533 /* Substitute NULL */
1534 free (env);
1535 free (pattern);
1536 return 0;
1539 subst_word:
1541 /* Substitute word */
1542 wordexp_t we;
1543 int i;
1545 if (quoted)
1547 /* No field-splitting is allowed, so imagine
1548 quotes around the word. */
1549 char *qtd_pattern = malloc (3 + strlen (pattern));
1550 if (qtd_pattern)
1551 sprintf (qtd_pattern, "\"%s\"", pattern);
1552 free (pattern);
1553 pattern = qtd_pattern;
1556 if (pattern == NULL && (pattern = __strdup ("")) == NULL)
1557 goto no_space;
1559 error = wordexp (pattern, &we, flags);
1560 if (error)
1562 free (env);
1563 free (pattern);
1564 return error;
1567 /* Fingers crossed that the quotes worked.. */
1568 assert (!quoted || we.we_wordc == 1);
1570 /* Substitute */
1571 for (i = 0; i < we.we_wordc; ++i)
1572 if (w_addword (pwordexp, __strdup (we.we_wordv[i]))
1573 == WRDE_NOSPACE)
1574 break;
1576 if (i < we.we_wordc)
1578 /* Ran out of space */
1579 wordfree (&we);
1580 goto no_space;
1583 if (action == ACT_NULL_ASSIGN)
1585 char *words;
1586 char *cp;
1587 size_t words_size = 0;
1589 for (i = 0; i < we.we_wordc; i++)
1590 words_size += strlen (we.we_wordv[i]) + 1; /* for <space> */
1591 words_size++;
1593 cp = words = __alloca (words_size);
1594 *words = 0;
1595 for (i = 0; i < we.we_wordc - 1; i++)
1597 cp = __stpcpy (cp, we.we_wordv[i]);
1598 *cp++ = ' ';
1601 __stpcpy (cp, we.we_wordv[i]);
1603 /* Also assign */
1604 setenv (env, words, 1);
1607 wordfree (&we);
1608 return 0;
1611 case ACT_NONNULL_SUBST:
1612 if (value && *value)
1613 goto subst_word;
1615 if (!colon_seen && value)
1616 goto subst_word;
1618 /* Substitute NULL */
1619 free (env);
1620 free (pattern);
1621 return 0;
1623 case ACT_NULL_ASSIGN:
1624 if (value && *value)
1625 /* Substitute parameter */
1626 break;
1628 if (!colon_seen && value)
1630 /* Substitute NULL */
1631 free (env);
1632 free (pattern);
1633 return 0;
1636 /* This checks for '=' so it knows to assign */
1637 goto subst_word;
1639 default:
1640 assert (! "Unrecognised action!");
1644 free (env);
1645 free (pattern);
1647 if (value == NULL)
1649 /* Variable not defined */
1650 if (flags & WRDE_UNDEF)
1651 return WRDE_BADVAL;
1653 return 0;
1656 if (seen_hash)
1658 char param_length[21];
1659 param_length[20] = '\0';
1660 *word = w_addstr (*word, word_length, max_length,
1661 _itoa_word (strlen (value), &param_length[20], 10, 0));
1662 return *word ? 0 : WRDE_NOSPACE;
1665 maybe_fieldsplit:
1666 if (quoted || !pwordexp)
1668 /* Quoted - no field split */
1669 *word = w_addstr (*word, word_length, max_length, value);
1670 if (free_value)
1671 free (value);
1673 return *word ? 0 : WRDE_NOSPACE;
1675 else
1677 /* Need to field-split */
1678 char *value_copy = __strdup (value); /* Don't modify value */
1679 char *field_begin = value_copy;
1680 int seen_nonws_ifs = 0;
1682 if (free_value)
1683 free (value);
1685 if (value_copy == NULL)
1686 return WRDE_NOSPACE;
1690 char *field_end = field_begin;
1691 char *next_field;
1693 /* If this isn't the first field, start a new word */
1694 if (field_begin != value_copy)
1696 if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
1698 free (value_copy);
1699 return WRDE_NOSPACE;
1702 *word = NULL;
1703 *word_length = *max_length = 0;
1706 /* Skip IFS whitespace before the field */
1707 while (*field_begin && strchr (ifs_white, *field_begin) != NULL)
1708 field_begin++;
1710 if (!seen_nonws_ifs && *field_begin == 0)
1711 /* Nothing but whitespace */
1712 break;
1714 /* Search for the end of the field */
1715 field_end = field_begin;
1716 while (*field_end && strchr (ifs, *field_end) == NULL)
1717 field_end++;
1719 /* Set up pointer to the character after end of field */
1720 next_field = *field_end ? field_end : NULL;
1722 /* Skip whitespace IFS after the field */
1723 while (next_field && *next_field && strchr (ifs_white, *next_field))
1724 next_field++;
1726 /* Skip at most one non-whitespace IFS character after the field */
1727 seen_nonws_ifs = 0;
1728 if (next_field && *next_field && strchr (ifs, *next_field))
1730 seen_nonws_ifs = 1;
1731 next_field++;
1734 /* Null-terminate it */
1735 *field_end = 0;
1737 /* Tag a copy onto the current word */
1738 *word = w_addstr (*word, word_length, max_length, field_begin);
1740 if (*word == NULL)
1742 free (value_copy);
1743 return WRDE_NOSPACE;
1746 field_begin = next_field;
1748 while (seen_nonws_ifs || (field_begin != NULL && *field_begin));
1750 free (value_copy);
1753 return 0;
1755 no_space:
1756 if (env)
1757 free (env);
1759 if (pattern)
1760 free (pattern);
1762 return WRDE_NOSPACE;
1764 syntax:
1765 if (env)
1766 free (env);
1768 if (pattern)
1769 free (pattern);
1771 return WRDE_SYNTAX;
1774 static int
1775 internal_function
1776 parse_dollars (char **word, size_t *word_length, size_t *max_length,
1777 const char *words, size_t *offset, int flags,
1778 wordexp_t *pwordexp, const char *ifs, const char *ifs_white,
1779 int quoted)
1781 /* We are poised _at_ "$" */
1782 switch (words[1 + *offset])
1784 case '"':
1785 case '\'':
1786 case 0:
1787 *word = w_addchar (*word, word_length, max_length, '$');
1788 return *word ? 0 : WRDE_NOSPACE;
1790 case '(':
1791 if (words[2 + *offset] == '(')
1793 /* Differentiate between $((1+3)) and $((echo);(ls)) */
1794 int i = 3 + *offset;
1795 int depth = 0;
1796 while (words[i] && !(depth == 0 && words[i] == ')'))
1798 if (words[i] == '(')
1799 ++depth;
1800 else if (words[i] == ')')
1801 --depth;
1803 ++i;
1806 if (words[i] == ')' && words[i + 1] == ')')
1808 (*offset) += 3;
1809 /* Call parse_arith -- 0 is for "no brackets" */
1810 return parse_arith (word, word_length, max_length, words, offset,
1811 flags, 0);
1815 if (flags & WRDE_NOCMD)
1816 return WRDE_CMDSUB;
1818 (*offset) += 2;
1819 return parse_comm (word, word_length, max_length, words, offset, flags,
1820 quoted? NULL : pwordexp, ifs, ifs_white);
1822 case '[':
1823 (*offset) += 2;
1824 /* Call parse_arith -- 1 is for "brackets" */
1825 return parse_arith (word, word_length, max_length, words, offset, flags,
1828 case '{':
1829 default:
1830 ++(*offset); /* parse_param needs to know if "{" is there */
1831 return parse_param (word, word_length, max_length, words, offset, flags,
1832 pwordexp, ifs, ifs_white, quoted);
1836 static int
1837 parse_backtick (char **word, size_t *word_length, size_t *max_length,
1838 const char *words, size_t *offset, int flags,
1839 wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
1841 /* We are poised just after "`" */
1842 int error;
1843 size_t comm_length = 0;
1844 size_t comm_maxlen = 0;
1845 char *comm = NULL;
1846 int squoting = 0;
1848 for (; words[*offset]; ++(*offset))
1850 switch (words[*offset])
1852 case '`':
1853 /* Go -- give the script to the shell */
1854 error = exec_comm (comm, word, word_length, max_length, flags,
1855 pwordexp, ifs, ifs_white);
1856 free (comm);
1857 return error;
1859 case '\\':
1860 if (squoting)
1862 error = parse_qtd_backslash (&comm, &comm_length, &comm_maxlen,
1863 words, offset);
1865 if (error)
1867 free (comm);
1868 return error;
1871 break;
1874 ++(*offset);
1875 error = parse_backslash (&comm, &comm_length, &comm_maxlen, words,
1876 offset);
1878 if (error)
1880 free (comm);
1881 return error;
1884 break;
1886 case '\'':
1887 squoting = 1 - squoting;
1888 default:
1889 comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
1890 if (comm == NULL)
1891 return WRDE_NOSPACE;
1895 /* Premature end */
1896 free (comm);
1897 return WRDE_SYNTAX;
1900 static int
1901 internal_function
1902 parse_dquote (char **word, size_t *word_length, size_t *max_length,
1903 const char *words, size_t *offset, int flags,
1904 wordexp_t *pwordexp, const char * ifs, const char * ifs_white)
1906 /* We are poised just after a double-quote */
1907 int error;
1909 for (; words[*offset]; ++(*offset))
1911 switch (words[*offset])
1913 case '"':
1914 return 0;
1916 case '$':
1917 error = parse_dollars (word, word_length, max_length, words, offset,
1918 flags, pwordexp, ifs, ifs_white, 1);
1919 /* The ``1'' here is to tell parse_dollars not to
1920 * split the fields. It may need to, however ("$@").
1922 if (error)
1923 return error;
1925 break;
1927 case '`':
1928 if (flags & WRDE_NOCMD)
1929 return WRDE_CMDSUB;
1931 ++(*offset);
1932 error = parse_backtick (word, word_length, max_length, words,
1933 offset, flags, NULL, NULL, NULL);
1934 /* The first NULL here is to tell parse_backtick not to
1935 * split the fields.
1937 if (error)
1938 return error;
1940 break;
1942 case '\\':
1943 error = parse_qtd_backslash (word, word_length, max_length, words,
1944 offset);
1946 if (error)
1947 return error;
1949 break;
1951 default:
1952 *word = w_addchar (*word, word_length, max_length, words[*offset]);
1953 if (*word == NULL)
1954 return WRDE_NOSPACE;
1958 /* Unterminated string */
1959 return WRDE_SYNTAX;
1963 * wordfree() is to be called after pwordexp is finished with.
1966 void
1967 wordfree (wordexp_t *pwordexp)
1970 /* wordexp can set pwordexp to NULL */
1971 if (pwordexp && pwordexp->we_wordv)
1973 char **wordv = pwordexp->we_wordv;
1975 for (wordv += pwordexp->we_offs; *wordv; ++wordv)
1976 free (*wordv);
1978 free (pwordexp->we_wordv);
1979 pwordexp->we_wordv = NULL;
1984 * wordexp()
1988 wordexp (const char *words, wordexp_t *pwordexp, int flags)
1990 size_t wordv_offset;
1991 size_t words_offset;
1992 size_t word_length = 0;
1993 size_t max_length = 0;
1994 char *word = NULL;
1995 int error;
1996 char *ifs;
1997 char ifs_white[4];
1998 char **old_wordv = pwordexp->we_wordv;
1999 size_t old_wordc = (flags & WRDE_REUSE) ? pwordexp->we_wordc : 0;
2001 if (flags & WRDE_REUSE)
2003 /* Minimal implementation of WRDE_REUSE for now */
2004 wordfree (pwordexp);
2005 old_wordv = NULL;
2008 if (flags & WRDE_DOOFFS)
2010 pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
2011 if (pwordexp->we_wordv == NULL)
2012 return WRDE_NOSPACE;
2014 else
2016 pwordexp->we_wordv = calloc (1, sizeof (char *));
2017 if (pwordexp->we_wordv == NULL)
2018 return WRDE_NOSPACE;
2020 pwordexp->we_offs = 0;
2023 if ((flags & WRDE_APPEND) == 0)
2024 pwordexp->we_wordc = 0;
2026 wordv_offset = pwordexp->we_offs + pwordexp->we_wordc;
2028 /* Find out what the field separators are.
2029 * There are two types: whitespace and non-whitespace.
2031 ifs = getenv ("IFS");
2033 if (!ifs)
2034 /* NULL IFS means no field-splitting is to be performed */
2035 ifs = strcpy (ifs_white, "");
2036 else
2038 char *ifsch = ifs;
2039 char *whch = ifs_white;
2041 /* Start off with no whitespace IFS characters */
2042 ifs_white[0] = '\0';
2044 while (*ifsch != '\0')
2046 if ((*ifsch == ' ') || (*ifsch == '\t') || (*ifsch == '\n'))
2048 /* Whitespace IFS. See first whether it is already in our
2049 collection. */
2050 char *runp = ifs_white;
2052 while (runp < whch && *runp != '\0' && *runp != *ifsch)
2053 ++runp;
2055 if (runp == whch)
2056 *whch++ = *ifsch;
2059 ++ifsch;
2061 *whch = '\0';
2064 for (words_offset = 0 ; words[words_offset] ; ++words_offset)
2065 switch (words[words_offset])
2067 case '\n':
2068 case '|':
2069 case '&':
2070 case ';':
2071 case '<':
2072 case '>':
2073 case '(':
2074 case ')':
2075 case '{':
2076 case '}':
2077 /* Fail */
2078 wordfree (pwordexp);
2079 pwordexp->we_wordc = 0;
2080 pwordexp->we_wordv = old_wordv;
2081 return WRDE_BADCHAR;
2083 case '\\':
2084 error = parse_backslash (&word, &word_length, &max_length, words,
2085 &words_offset);
2087 if (error)
2088 goto do_error;
2090 break;
2092 case '$':
2093 error = parse_dollars (&word, &word_length, &max_length, words,
2094 &words_offset, flags, pwordexp, ifs, ifs_white,
2097 if (error)
2098 goto do_error;
2100 break;
2102 case '`':
2103 if (flags & WRDE_NOCMD)
2104 return WRDE_CMDSUB;
2106 ++words_offset;
2107 error = parse_backtick (&word, &word_length, &max_length, words,
2108 &words_offset, flags, pwordexp, ifs,
2109 ifs_white);
2111 if (error)
2112 goto do_error;
2114 break;
2116 case '"':
2117 ++words_offset;
2118 error = parse_dquote (&word, &word_length, &max_length, words,
2119 &words_offset, flags, pwordexp, ifs, ifs_white);
2121 if (error)
2122 goto do_error;
2124 break;
2126 case '\'':
2127 ++words_offset;
2128 error = parse_squote (&word, &word_length, &max_length, words,
2129 &words_offset);
2131 if (error)
2132 goto do_error;
2134 break;
2136 case '~':
2137 error = parse_tilde (&word, &word_length, &max_length, words,
2138 &words_offset, pwordexp->we_wordc);
2140 if (error)
2141 goto do_error;
2143 break;
2145 case '*':
2146 case '[':
2147 case '?':
2148 error = parse_glob (&word, &word_length, &max_length, words,
2149 &words_offset, flags, pwordexp, ifs, ifs_white);
2151 if (error)
2152 goto do_error;
2154 break;
2156 default:
2157 /* Is it a field separator? */
2158 if (strchr (ifs, words[words_offset]) == NULL)
2160 /* "Ordinary" character -- add it to word */
2162 word = w_addchar (word, &word_length, &max_length,
2163 words[words_offset]);
2164 if (word == NULL)
2166 error = WRDE_NOSPACE;
2167 goto do_error;
2170 break;
2173 /* Field separator */
2174 if (strchr (ifs_white, words[words_offset]))
2176 /* It's a whitespace IFS char. Ignore it at the beginning
2177 of a line and ignore multiple instances. */
2178 if (!word || !*word)
2179 break;
2181 if (w_addword (pwordexp, word) == WRDE_NOSPACE)
2183 error = WRDE_NOSPACE;
2184 goto do_error;
2187 word = NULL;
2188 word_length = 0;
2189 max_length = 0;
2190 break;
2193 /* It's a non-whitespace IFS char */
2195 /* Multiple non-whitespace IFS chars are treated as one;
2196 * IS THIS CORRECT?
2198 if (word != NULL)
2200 if (w_addword (pwordexp, word) == WRDE_NOSPACE)
2202 error = WRDE_NOSPACE;
2203 goto do_error;
2207 word = NULL;
2208 word_length = 0;
2209 max_length = 0;
2212 /* End of string */
2214 /* There was a field separator at the end */
2215 if (word == NULL)
2216 return 0;
2218 /* There was no field separator at the end */
2219 return w_addword (pwordexp, word);
2221 do_error:
2222 /* Error:
2223 * free memory used (unless error is WRDE_NOSPACE), and
2224 * set we_wordc and wd_wordv back to what they were.
2227 if (error == WRDE_NOSPACE)
2228 return WRDE_NOSPACE;
2230 if (word != NULL)
2231 free (word);
2233 wordfree (pwordexp);
2234 pwordexp->we_wordv = old_wordv;
2235 pwordexp->we_wordc = old_wordc;
2236 return error;