More tests.
[kopensolaris-gnu/glibc.git] / posix / wordexp.c
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>.
5
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.
10
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.
15
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.  */
20
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>
40
41 #include <stdio-common/_itoa.h>
42
43 /* Undefine the following line for the production version.  */
44 /* #define NDEBUG 1 */
45 #include <assert.h>
46
47 /*
48  * This is a recursive-descent-style word expansion routine.
49  */
50
51 /* This variable is defined and initialized in the startup code.  */
52 extern char **__libc_argv;
53
54 /* Some forward declarations */
55 static int parse_dollars (char **word, size_t *word_length, size_t *max_length,
56                           const char *words, size_t *offset, int flags,
57                           wordexp_t *pwordexp, const char *ifs,
58                           const char *ifs_white, int quoted)
59      internal_function;
60 static int parse_backtick (char **word, size_t *word_length,
61                            size_t *max_length, const char *words,
62                            size_t *offset, int flags, wordexp_t *pwordexp,
63                            const char *ifs, const char *ifs_white)
64      internal_function;
65 static int eval_expr (char *expr, long int *result) internal_function;
66
67 /* The w_*() functions manipulate word lists. */
68
69 #define W_CHUNK (100)
70
71 static inline char *
72 w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch)
73      /* (lengths exclude trailing zero) */
74 {
75   /* Add a character to the buffer, allocating room for it if needed.
76    */
77
78   if (*actlen == *maxlen)
79     {
80       char *old_buffer = buffer;
81       assert (buffer == NULL || *maxlen != 0);
82       *maxlen += W_CHUNK;
83       buffer = realloc (buffer, 1 + *maxlen);
84
85       if (buffer == NULL)
86         free (old_buffer);
87     }
88
89   if (buffer != NULL)
90     {
91       buffer[*actlen] = ch;
92       buffer[++(*actlen)] = '\0';
93     }
94
95   return buffer;
96 }
97
98 static char *
99 internal_function
100 w_addmem (char *buffer, size_t *actlen, size_t *maxlen, const char *str,
101           size_t len)
102 {
103   /* Add a string to the buffer, allocating room for it if needed.
104    */
105   if (*actlen + len > *maxlen)
106     {
107       char *old_buffer = buffer;
108       assert (buffer == NULL || *maxlen != 0);
109       *maxlen += MAX (2 * len, W_CHUNK);
110       buffer = realloc (old_buffer, 1 + *maxlen);
111
112       if (buffer == NULL)
113         free (old_buffer);
114     }
115
116   if (buffer != NULL)
117     {
118       *((char *) __mempcpy (&buffer[*actlen], str, len)) = '\0';
119       *actlen += len;
120     }
121
122   return buffer;
123 }
124
125
126 static char *
127 internal_function
128 w_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str)
129      /* (lengths exclude trailing zero) */
130 {
131   /* Add a string to the buffer, allocating room for it if needed.
132    */
133   size_t len;
134
135   assert (str != NULL); /* w_addstr only called from this file */
136   len = strlen (str);
137
138   return w_addmem (buffer, actlen, maxlen, str, len);
139 }
140
141 static int
142 internal_function
143 w_addword (wordexp_t *pwordexp, char *word)
144 {
145   /* Add a word to the wordlist */
146   size_t num_p;
147
148   num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
149   pwordexp->we_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p);
150   if (pwordexp->we_wordv != NULL)
151     {
152       pwordexp->we_wordv[pwordexp->we_wordc++] = word;
153       pwordexp->we_wordv[pwordexp->we_wordc] = NULL;
154       return 0;
155     }
156
157   return WRDE_NOSPACE;
158 }
159
160 /* The parse_*() functions should leave *offset being the offset in 'words'
161  * to the last character processed.
162  */
163
164 static int
165 internal_function
166 parse_backslash (char **word, size_t *word_length, size_t *max_length,
167                  const char *words, size_t *offset)
168 {
169   /* We are poised _at_ a backslash, not in quotes */
170
171   switch (words[1 + *offset])
172     {
173     case 0:
174       /* Backslash is last character of input words */
175       return WRDE_SYNTAX;
176
177     case '\n':
178       ++(*offset);
179       break;
180
181     default:
182       *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
183       if (*word == NULL)
184         return WRDE_NOSPACE;
185
186       ++(*offset);
187       break;
188     }
189
190   return 0;
191 }
192
193 static int
194 internal_function
195 parse_qtd_backslash (char **word, size_t *word_length, size_t *max_length,
196                      const char *words, size_t *offset)
197 {
198   /* We are poised _at_ a backslash, inside quotes */
199
200   switch (words[1 + *offset])
201     {
202     case 0:
203       /* Backslash is last character of input words */
204       return WRDE_SYNTAX;
205
206     case '\n':
207       ++(*offset);
208       break;
209
210     case '$':
211     case '`':
212     case '"':
213     case '\\':
214       *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
215       if (*word == NULL)
216         return WRDE_NOSPACE;
217
218       ++(*offset);
219       break;
220
221     default:
222       *word = w_addchar (*word, word_length, max_length, words[*offset]);
223       if (*word != NULL)
224         *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
225
226       if (*word == NULL)
227         return WRDE_NOSPACE;
228
229       ++(*offset);
230       break;
231     }
232
233   return 0;
234 }
235
236 static int
237 internal_function
238 parse_tilde (char **word, size_t *word_length, size_t *max_length,
239              const char *words, size_t *offset, size_t wordc)
240 {
241   /* We are poised _at_ a tilde */
242   size_t i;
243
244   if (*word_length != 0)
245     {
246       if (!((*word)[*word_length - 1] == '=' && wordc == 0))
247         {
248           if (!((*word)[*word_length - 1] == ':'
249                 && strchr (*word, '=') && wordc == 0))
250             {
251               *word = w_addchar (*word, word_length, max_length, '~');
252               return *word ? 0 : WRDE_NOSPACE;
253             }
254         }
255     }
256
257   for (i = 1 + *offset; words[i]; i++)
258     {
259       if (words[i] == ':' || words[i] == '/' || words[i] == ' ' ||
260           words[i] == '\t' || words[i] == 0 )
261         break;
262
263       if (words[i] == '\\')
264         {
265           *word = w_addchar (*word, word_length, max_length, '~');
266           return *word ? 0 : WRDE_NOSPACE;
267         }
268     }
269
270   if (i == 1 + *offset)
271     {
272       /* Tilde appears on its own */
273       uid_t uid;
274       struct passwd pwd, *tpwd;
275       int buflen = 1000;
276       char* buffer = __alloca (buflen);
277       int result;
278
279       uid = getuid ();
280
281       while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
282              && errno == ERANGE)
283         {
284           buflen += 1000;
285           buffer = __alloca (buflen);
286         }
287
288       if (result == 0 && pwd.pw_dir != NULL)
289         {
290           *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
291           if (*word == NULL)
292             return WRDE_NOSPACE;
293         }
294       else
295         {
296           *word = w_addchar (*word, word_length, max_length, '~');
297           if (*word == NULL)
298             return WRDE_NOSPACE;
299         }
300     }
301   else
302     {
303       /* Look up user name in database to get home directory */
304       char *user = __strndup (&words[1 + *offset], i - *offset);
305       struct passwd pwd, *tpwd;
306       int buflen = 1000;
307       char* buffer = __alloca (buflen);
308       int result;
309
310       while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
311              && errno == ERANGE)
312         {
313           buflen += 1000;
314           buffer = __alloca (buflen);
315         }
316
317       if (result == 0 && pwd.pw_dir)
318         *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
319       else
320         {
321           /* (invalid login name) */
322           *word = w_addchar (*word, word_length, max_length, '~');
323           if (*word != NULL)
324             *word = w_addstr (*word, word_length, max_length, user);
325         }
326
327       *offset = i - 1;
328     }
329   return *word ? 0 : WRDE_NOSPACE;
330 }
331
332 static int
333 internal_function
334 parse_glob (char **word, size_t *word_length, size_t *max_length,
335             const char *words, size_t *offset, int flags,
336             wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
337 {
338   /* We are poised just after a '*', a '[' or a '?'. */
339   int error;
340   glob_t globbuf;
341   int match;
342   char *matching_word;
343   int quoted = 0; /* 1 if singly-quoted, 2 if doubly */
344
345   for (; words[*offset]; (*offset)++)
346     {
347       if ((ifs && strchr (ifs, words[*offset])) ||
348           (!ifs && strchr (" \t\n", words[*offset])))
349         /* Reached IFS */
350         break;
351
352       /* Sort out quoting */
353       if (words[*offset] == '\'')
354           if (quoted == 0)
355             {
356               quoted = 1;
357               continue;
358             }
359           else if (quoted == 1)
360             {
361               quoted = 0;
362               continue;
363             }
364       else if (words[*offset] == '"')
365         if (quoted == 0)
366           {
367             quoted = 2;
368             continue;
369           }
370         else if (quoted == 2)
371           {
372             quoted = 0;
373             continue;
374           }
375
376       /* Sort out other special characters */
377       if (quoted != 1 && words[*offset] == '$')
378         {
379           error = parse_dollars (word, word_length, max_length, words, offset,
380                                  flags, pwordexp, ifs, ifs_white, quoted == 2);
381           if (error)
382             return error;
383
384           continue;
385         }
386       else if (words[*offset] == '\\')
387         {
388           if (quoted)
389             error = parse_qtd_backslash (word, word_length, max_length, words,
390                                          offset);
391           else
392             error = parse_backslash (word, word_length, max_length, words,
393                                      offset);
394
395           if (error)
396             return error;
397
398           continue;
399         }
400
401       *word = w_addchar (*word, word_length, max_length, words[*offset]);
402       if (*word == NULL)
403         return WRDE_NOSPACE;
404     }
405
406   error = glob (*word, GLOB_NOCHECK, NULL, &globbuf);
407
408   if (error != 0)
409     {
410       /* We can only run into memory problems.  */
411       assert (error == GLOB_NOSPACE);
412
413       return WRDE_NOSPACE;
414     }
415
416   if (ifs && !*ifs)
417     {
418       /* No field splitting allowed */
419       size_t length = strlen (globbuf.gl_pathv[0]);
420       *word = realloc (*word, length + 1);
421       if (*word == NULL)
422         goto no_space;
423
424       memcpy (*word, globbuf.gl_pathv[0], length + 1);
425       *word_length = length;
426
427       for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
428         {
429           *word = w_addchar (*word, word_length, max_length, ' ');
430           if (*word != NULL)
431             *word = w_addstr (*word, word_length, max_length,
432                               globbuf.gl_pathv[match]);
433         }
434
435       /* Re-parse white space on return */
436       globfree (&globbuf);
437       --(*offset);
438       return *word ? 0 : WRDE_NOSPACE;
439     }
440
441   /* here ifs != "" */
442   free (*word);
443   *word = NULL;
444   *word_length = 0;
445
446   matching_word = __strdup (globbuf.gl_pathv[0]);
447   if (matching_word == NULL)
448     goto no_space;
449
450   if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
451     goto no_space;
452
453   for (match = 1; match < globbuf.gl_pathc; ++match)
454     {
455       matching_word = __strdup (globbuf.gl_pathv[match]);
456       if (matching_word == NULL)
457         goto no_space;
458
459       if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
460         goto no_space;
461     }
462
463   globfree (&globbuf);
464
465   /* Re-parse white space on return */
466   --(*offset);
467   return 0;
468
469 no_space:
470   globfree (&globbuf);
471   return WRDE_NOSPACE;
472 }
473
474 static int
475 internal_function
476 parse_squote (char **word, size_t *word_length, size_t *max_length,
477               const char *words, size_t *offset)
478 {
479   /* We are poised just after a single quote */
480   for (; words[*offset]; ++(*offset))
481     {
482       if (words[*offset] != '\'')
483         {
484           *word = w_addchar (*word, word_length, max_length, words[*offset]);
485           if (*word == NULL)
486             return WRDE_NOSPACE;
487         }
488       else return 0;
489     }
490
491   /* Unterminated string */
492   return WRDE_SYNTAX;
493 }
494
495 /* Functions to evaluate an arithmetic expression */
496 static int
497 internal_function
498 eval_expr_val (char **expr, long int *result)
499 {
500   int sgn = +1;
501   char *digit;
502
503   /* Skip white space */
504   for (digit = *expr; digit && *digit && isspace (*digit); ++digit);
505
506   switch (*digit)
507     {
508     case '(':
509
510       /* Scan for closing paren */
511       for (++digit; **expr && **expr != ')'; ++(*expr));
512
513       /* Is there one? */
514       if (!**expr)
515         return WRDE_SYNTAX;
516
517       *(*expr)++ = 0;
518
519       if (eval_expr (digit, result))
520         return WRDE_SYNTAX;
521
522       return 0;
523
524     case '+':   /* Positive value */
525       ++digit;
526       break;
527
528     case '-':   /* Negative value */
529       ++digit;
530       sgn = -1;
531       break;
532
533     default:
534       if (!isdigit (*digit))
535         return WRDE_SYNTAX;
536     }
537
538   *result = 0;
539   for (; *digit && isdigit (*digit); ++digit)
540     *result = (*result * 10) + (*digit - '0');
541
542   *expr = digit;
543   *result *= sgn;
544   return 0;
545 }
546
547 static int
548 internal_function
549 eval_expr_multdiv (char **expr, long int *result)
550 {
551   long int arg;
552
553   /* Read a Value */
554   if (eval_expr_val (expr, result) != 0)
555     return WRDE_SYNTAX;
556
557   while (**expr)
558     {
559       /* Skip white space */
560       for (; *expr && **expr && isspace (**expr); ++(*expr));
561
562       if (**expr == '*')
563         {
564           ++(*expr);
565           if (eval_expr_val (expr, &arg) != 0)
566             return WRDE_SYNTAX;
567
568           *result *= arg;
569         }
570       else if (**expr == '/')
571         {
572           ++(*expr);
573           if (eval_expr_val (expr, &arg) != 0)
574             return WRDE_SYNTAX;
575
576           *result /= arg;
577         }
578       else break;
579     }
580
581   return 0;
582 }
583
584 static int
585 internal_function
586 eval_expr (char *expr, long int *result)
587 {
588   long int arg;
589
590   /* Read a Multdiv */
591   if (eval_expr_multdiv (&expr, result) != 0)
592     return WRDE_SYNTAX;
593
594   while (*expr)
595     {
596       /* Skip white space */
597       for (; expr && *expr && isspace (*expr); ++expr);
598
599       if (*expr == '+')
600         {
601           ++expr;
602           if (eval_expr_multdiv (&expr, &arg) != 0)
603             return WRDE_SYNTAX;
604
605           *result += arg;
606         }
607       else if (*expr == '-')
608         {
609           ++expr;
610           if (eval_expr_multdiv (&expr, &arg) != 0)
611             return WRDE_SYNTAX;
612
613           *result -= arg;
614         }
615       else break;
616     }
617
618   return 0;
619 }
620
621 static int
622 internal_function
623 parse_arith (char **word, size_t *word_length, size_t *max_length,
624              const char *words, size_t *offset, int flags, int bracket)
625 {
626   /* We are poised just after "$((" or "$[" */
627   int error;
628   int paren_depth = 1;
629   size_t expr_length = 0;
630   size_t expr_maxlen = 0;
631   char *expr = NULL;
632
633   for (; words[*offset]; ++(*offset))
634     {
635       switch (words[*offset])
636         {
637         case '$':
638           error = parse_dollars (&expr, &expr_length, &expr_maxlen,
639                                  words, offset, flags, NULL, NULL, NULL, 1);
640           /* The ``1'' here is to tell parse_dollars not to
641            * split the fields.
642            */
643           if (error)
644             {
645               free (expr);
646               return error;
647             }
648           break;
649
650         case '`':
651           (*offset)++;
652           error = parse_backtick (&expr, &expr_length, &expr_maxlen,
653                                   words, offset, flags, NULL, NULL, NULL);
654           /* The first NULL here is to tell parse_backtick not to
655            * split the fields.
656            */
657           if (error)
658             {
659               free (expr);
660               return error;
661             }
662           break;
663
664         case '\\':
665           error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen,
666                                        words, offset);
667           if (error)
668             {
669               free (expr);
670               return error;
671             }
672           /* I think that a backslash within an
673            * arithmetic expansion is bound to
674            * cause an error sooner or later anyway though.
675            */
676           break;
677
678         case ')':
679           if (--paren_depth == 0)
680             {
681               char result[21];  /* 21 = ceil(log10(2^64)) + 1 */
682               long int numresult = 0;
683               long long int convertme;
684
685               if (bracket || words[1 + *offset] != ')')
686                 return WRDE_SYNTAX;
687
688               ++(*offset);
689
690               /* Go - evaluate. */
691               if (*expr && eval_expr (expr, &numresult) != 0)
692                 return WRDE_SYNTAX;
693
694               if (numresult < 0)
695                 {
696                   convertme = -numresult;
697                   *word = w_addchar (*word, word_length, max_length, '-');
698                   if (!*word)
699                     {
700                       free (expr);
701                       return WRDE_NOSPACE;
702                     }
703                 }
704               else
705                 convertme = numresult;
706
707               result[20] = '\0';
708               *word = w_addstr (*word, word_length, max_length,
709                                 _itoa (convertme, &result[20], 10, 0));
710               free (expr);
711               return *word ? 0 : WRDE_NOSPACE;
712             }
713           expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
714           if (expr == NULL)
715             return WRDE_NOSPACE;
716
717           break;
718
719         case ']':
720           if (bracket && paren_depth == 1)
721             {
722               char result[21];  /* 21 = ceil(log10(2^64)) + 1 */
723               long int numresult = 0;
724
725               /* Go - evaluate. */
726               if (*expr && eval_expr (expr, &numresult) != 0)
727                 return WRDE_SYNTAX;
728
729               result[20] = '\0';
730               *word = w_addstr (*word, word_length, max_length,
731                                 _itoa_word (numresult, &result[20], 10, 0));
732               free (expr);
733               return *word ? 0 : WRDE_NOSPACE;
734             }
735
736           free (expr);
737           return WRDE_SYNTAX;
738
739         case '\n':
740         case ';':
741         case '{':
742         case '}':
743           free (expr);
744           return WRDE_BADCHAR;
745
746         case '(':
747           ++paren_depth;
748         default:
749           expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
750           if (expr == NULL)
751             return WRDE_NOSPACE;
752         }
753     }
754
755   /* Premature end */
756   free (expr);
757   return WRDE_SYNTAX;
758 }
759
760 /* Function to execute a command and retrieve the results */
761 /* pwordexp contains NULL if field-splitting is forbidden */
762 static int
763 internal_function
764 exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
765            int flags, wordexp_t *pwordexp, const char *ifs,
766            const char *ifs_white)
767 {
768   int fildes[2];
769   int bufsize = 128;
770   int buflen;
771   int i;
772   char *buffer;
773   pid_t pid;
774
775   /* Don't fork() unless necessary */
776   if (!comm || !*comm)
777     return 0;
778
779   if (pipe (fildes))
780     /* Bad */
781     return WRDE_NOSPACE;
782
783   if ((pid = fork ()) < 0)
784     {
785       /* Bad */
786       return WRDE_NOSPACE;
787     }
788
789   if (pid == 0)
790     {
791       /* Child */
792       const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
793
794       /* Redirect input and output */
795       dup2 (fildes[1], 1);
796
797       /* Close stderr if we have to */
798       if ((flags & WRDE_SHOWERR) == 0)
799         close (2);
800
801       __execve (_PATH_BSHELL, (char *const *) args, __environ);
802
803       /* Bad.  What now?  */
804       abort ();
805     }
806
807   /* Parent */
808
809   close (fildes[1]);
810   buffer = __alloca (bufsize);
811
812   if (!pwordexp)
813     { /* Quoted - no field splitting */
814
815       while (1)
816         {
817           if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
818             {
819               if (__waitpid (pid, NULL, WNOHANG) == 0)
820                 continue;
821               if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
822                 break;
823             }
824
825           *word = w_addmem (*word, word_length, max_length, buffer, buflen);
826           if (*word == NULL)
827             {
828               close (fildes[0]);
829               return WRDE_NOSPACE;
830             }
831         }
832
833       close (fildes[0]);
834
835       /* bash chops off a terminating linefeed, which seems sensible */
836       if ((*word)[*word_length - 1] == '\n')
837         (*word)[--*word_length] = '\0';
838
839       return 0;
840     }
841   else
842     /* Not quoted - split fields */
843     {
844       int copying = 0;
845       /* 'copying' is:
846        *  0 when searching for first character in a field not IFS white space
847        *  1 when copying the text of a field
848        *  2 when searching for possible non-whitespace IFS
849        */
850
851       while (1)
852         {
853           if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
854             {
855               if (__waitpid (pid, NULL, WNOHANG) == 0)
856                 continue;
857               if ((read (fildes[0], buffer, bufsize)) < 1)
858                 break;
859             }
860
861           for (i = 0; i < buflen; ++i)
862             {
863               if (strchr (ifs, buffer[i]) != NULL)
864                 {
865                   /* Current character is IFS */
866                   if (strchr (ifs_white, buffer[i]) == NULL)
867                     {
868                       /* Current character is IFS but not whitespace */
869                       if (copying == 2)
870                         {
871                           /*            current character
872                            *                   |
873                            *                   V
874                            * eg: text<space><comma><space>moretext
875                            *
876                            * So, strip whitespace IFS (like at the start)
877                            */
878                           copying = 0;
879                           continue;
880                         }
881
882                       copying = 0;
883                       /* fall through and delimit field.. */
884                     }
885                   else
886                     {
887                       /* Current character is IFS white space */
888
889                       /* If not copying a field, ignore it */
890                       if (copying != 1)
891                         continue;
892
893                       /* End of field (search for non-IFS afterwards) */
894                       copying = 2;
895                     }
896
897                   /* First IFS white space, or IFS non-whitespace.
898                    * Delimit the field. */
899                   if (!*word)
900                     {
901                       /* This field is null, so make it an empty string */
902                       *word = w_addchar (*word, word_length, max_length, 0);
903                       if (*word == NULL)
904                         {
905                           close (fildes[0]);
906                           return WRDE_NOSPACE;
907                         }
908                     }
909
910                   if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
911                     {
912                       /* Should do __waitpid? */
913                       close (fildes[0]);
914                       return WRDE_NOSPACE;
915                     }
916
917                   *word = NULL;
918                   *word_length = 0;
919                   *max_length = 0;
920                   /* fall back round the loop.. */
921                 }
922               else
923                 {
924                   /* Not IFS character */
925                   copying = 1;
926                   *word = w_addchar (*word, word_length, max_length,
927                                      buffer[i]);
928                   if (*word == NULL)
929                     {
930                       close (fildes[0]);
931                       return WRDE_NOSPACE;
932                     }
933                 }
934             }
935         }
936     }
937
938   close (fildes[0]);
939   return 0;
940 }
941
942 static int
943 internal_function
944 parse_comm (char **word, size_t *word_length, size_t *max_length,
945             const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
946             const char *ifs, const char *ifs_white)
947 {
948   /* We are poised just after "$(" */
949   int paren_depth = 1;
950   int error;
951   size_t comm_length = 0;
952   size_t comm_maxlen = 0;
953   char *comm = NULL;
954
955   for (; words[*offset]; ++(*offset))
956     {
957       switch (words[*offset])
958         {
959         case ')':
960           if (--paren_depth == 0)
961             {
962               /* Go -- give script to the shell */
963               error = exec_comm (comm, word, word_length, max_length, flags,
964                                  pwordexp, ifs, ifs_white);
965               free (comm);
966               return error;
967             }
968
969           /* This is just part of the script */
970           comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
971           if (comm == NULL)
972             return WRDE_NOSPACE;
973
974           break;
975
976         case '(':
977           ++paren_depth;
978         default:
979           comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
980           if (comm == NULL)
981             return WRDE_NOSPACE;
982
983           break;
984         }
985     }
986
987   /* Premature end */
988   free (comm);
989   return WRDE_SYNTAX;
990 }
991
992 static int
993 internal_function
994 parse_param (char **word, size_t *word_length, size_t *max_length,
995              const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
996              const char *ifs, const char *ifs_white, int quoted)
997 {
998   /* We are poised just after "$" */
999   enum remove_pattern_enum
1000   {
1001     RP_NONE = 0,
1002     RP_SHORT_LEFT,
1003     RP_LONG_LEFT,
1004     RP_SHORT_RIGHT,
1005     RP_LONG_RIGHT
1006   };
1007   size_t start = *offset;
1008   size_t env_length = 0;
1009   size_t env_maxlen = 0;
1010   size_t pat_length = 0;
1011   size_t pat_maxlen = 0;
1012   char *env = NULL;
1013   char *pattern = NULL;
1014   char *value = NULL;
1015   char action = '\0';
1016   enum remove_pattern_enum remove = RP_NONE;
1017   int colon_seen = 0;
1018   int depth = 0;
1019   int substitute_length = 0;
1020   int error;
1021   int star = 0;
1022
1023   for (; words[*offset]; ++(*offset))
1024     {
1025       switch (words[*offset])
1026         {
1027         case '{':
1028           ++depth;
1029
1030           if (action != '\0' || remove != RP_NONE)
1031             {
1032               pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1033                                    words[*offset]);
1034               if (pattern == NULL)
1035                 goto no_space;
1036
1037               break;
1038             }
1039
1040           if (*offset == start)
1041             break;
1042
1043           /* Otherwise evaluate */
1044           /* (and re-parse this character) */
1045           --(*offset);
1046           goto envsubst;
1047
1048         case '}':
1049           if (words[start] != '{')
1050               --(*offset);
1051
1052           if (action != '\0' || remove != RP_NONE)
1053             {
1054               if (--depth)
1055                 {
1056                   pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1057                                        words[*offset]);
1058                   if (pattern == NULL)
1059                     goto no_space;
1060
1061                   break;
1062                 }
1063             }
1064
1065           /* Evaluate */
1066           goto envsubst;
1067
1068         case '#':
1069           /* '#' only has special meaning inside braces */
1070           if (words[start] != '{')
1071             {
1072               /* Evaluate */
1073               /* (and re-parse this character) */
1074               --(*offset);
1075               goto envsubst;
1076             }
1077
1078           /* At the start? (i.e. 'string length') */
1079           if (*offset == start + 1)
1080             {
1081               substitute_length = 1;
1082               break;
1083             }
1084           else if (substitute_length)
1085             goto syntax;
1086
1087           /* Separating variable name from prefix pattern? */
1088           if (remove == RP_NONE)
1089             {
1090               remove = RP_SHORT_LEFT;
1091               break;
1092             }
1093           else if (remove == RP_SHORT_LEFT)
1094             {
1095               remove = RP_LONG_LEFT;
1096               break;
1097             }
1098
1099           /* Must be part of prefix/suffix pattern. */
1100           pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1101                                words[*offset]);
1102           if (pattern == NULL)
1103             goto no_space;
1104
1105           break;
1106
1107         case '%':
1108           if (!env || !*env)
1109             goto syntax;
1110
1111           /* Separating variable name from suffix pattern? */
1112           if (remove == RP_NONE)
1113             {
1114               remove = RP_SHORT_RIGHT;
1115               break;
1116             }
1117           else if (remove == RP_SHORT_RIGHT)
1118             {
1119               remove = RP_LONG_RIGHT;
1120               break;
1121             }
1122
1123           /* Must be part of prefix/suffix pattern. */
1124           pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1125                                words[*offset]);
1126           if (pattern == NULL)
1127             goto no_space;
1128
1129           break;
1130
1131         case ':':
1132           if (!env || !*env)
1133             goto syntax;
1134
1135           if (action != '\0' || remove != RP_NONE)
1136             {
1137               pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1138                                    words[*offset]);
1139               if (pattern == NULL)
1140                 goto no_space;
1141
1142               break;
1143             }
1144
1145           if ((words[1 + *offset] == '-') || (words[1 + *offset] == '=')
1146               || (words[1 + *offset] == '?') || (words[1 + *offset] == '+'))
1147             {
1148               colon_seen = 1;
1149               break;
1150             }
1151
1152           goto syntax;
1153
1154         case '-':
1155         case '=':
1156         case '?':
1157         case '+':
1158           if (!env || !*env)
1159             goto syntax;
1160
1161           if (substitute_length)
1162             goto syntax;
1163
1164           if (action != '\0' || remove != RP_NONE)
1165             {
1166               pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1167                                    words[*offset]);
1168               if (pattern == NULL)
1169                 goto no_space;
1170
1171               break;
1172             }
1173
1174           action = words[*offset];
1175           break;
1176
1177         case '\\':
1178           if (action != '\0' || remove != RP_NONE)
1179             {
1180               /* Um. Is this right? */
1181               error = parse_qtd_backslash (word, word_length, max_length,
1182                                            words, offset);
1183               if (error == 0)
1184                 break;
1185             }
1186           else
1187             {
1188               error = WRDE_SYNTAX;
1189             }
1190
1191           if (env)
1192             free (env);
1193
1194           if (pattern != NULL)
1195             free (pattern);
1196
1197           return error;
1198
1199         default:
1200           if (action != '\0' || remove != RP_NONE)
1201             {
1202               pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1203                                    words[*offset]);
1204               if (pattern == NULL)
1205                 goto no_space;
1206
1207               break;
1208             }
1209
1210           star = strchr ("*@", words[*offset]) != NULL;
1211           if (isalnum (words[*offset]) || star)
1212             {
1213               env = w_addchar (env, &env_length, &env_maxlen, words[*offset]);
1214               if (env == NULL)
1215                 goto no_space;
1216
1217               if (star)
1218                 goto envsubst;
1219
1220               break;
1221             }
1222
1223           --(*offset);
1224           goto envsubst;
1225         }
1226     }
1227
1228   /* End of input string -- remember to reparse the character that we stopped
1229    * at.  */
1230   --(*offset);
1231
1232 envsubst:
1233   if (words[start] == '{' && words[*offset] != '}')
1234     goto syntax;
1235
1236   if (!env || !*env)
1237     {
1238       *offset = start - 1;
1239       *word = w_addchar (*word, word_length, max_length, '$');
1240       free (env);
1241       return *word ? 0 : WRDE_NOSPACE;
1242     }
1243
1244   /* Is it `$*' or `$@' ? */
1245   if (strpbrk (env, "*@") != NULL)
1246     {
1247       size_t plist_len = 1;
1248       int p;
1249
1250       if (env[1] != '\0')
1251         {
1252           /* Bad substitution if there is more than one character */
1253           fprintf (stderr, "${%s}: bad substitution\n", env);
1254           return WRDE_SYNTAX;
1255         }
1256
1257       if (!quoted || *env == '*')
1258         {
1259           /* Build up value parameter by parameter (copy them) */
1260           for (p = 1; __libc_argv[p]; ++p)
1261             {
1262               char *old_pointer = value;
1263               size_t argv_len = strlen (__libc_argv[p]);
1264               size_t old_plist_len = plist_len;
1265
1266               if (value)
1267                 value[plist_len - 1] = 0;
1268
1269               plist_len += 1 + argv_len;
1270
1271               /* First realloc will act as malloc because value is
1272                * initialised to NULL. */
1273               value = realloc (value, plist_len);
1274               if (value == NULL)
1275                 {
1276                   free (old_pointer);
1277                   return WRDE_NOSPACE;
1278                 }
1279
1280               memcpy (&value[old_plist_len - 1], __libc_argv[p], argv_len + 1);
1281               if (__libc_argv[p + 1])
1282                 {
1283                   value[plist_len - 1] = '\0';
1284                   value[plist_len - 2] = ' ';
1285                 }
1286             }
1287
1288           if (value)
1289             goto maybe_fieldsplit;
1290         }
1291
1292       /* Each parameter is a separate word ("$@") */
1293       if (__libc_argv[0] == NULL)
1294         {
1295           /* This can happen if the application is started without any
1296              parameter, not even a name.  This is legal according to
1297              POSIX since the giving parameters is only a "should" rule.  */
1298           *word = __strdup ("");
1299           *max_length = *word_length = 0;
1300         }
1301       else
1302         {
1303           for (p = 1; __libc_argv[p + 1]; p++)
1304             {
1305               char *copy = __strdup (__libc_argv[p]);
1306               if (copy == NULL)
1307                 return WRDE_NOSPACE;
1308
1309               strcpy (copy, __libc_argv[p]);
1310               error = w_addword (pwordexp, copy);
1311               if (error)
1312                 {
1313                   free (copy);
1314                   return error;
1315                 }
1316             }
1317
1318           /* Last parameter becomes current word */
1319           if (__libc_argv[p])
1320             {
1321               *word = __strdup (__libc_argv[p]);
1322               *max_length = *word_length = strlen (*word);
1323             }
1324         }
1325
1326       return 0;
1327     }
1328
1329   value = getenv (env);
1330
1331   if (action != '\0' || remove != RP_NONE)
1332     {
1333       switch (action)
1334         {
1335         case 0:
1336           {
1337             char *p;
1338             char c;
1339             char *end;
1340
1341             if (!pattern || !*pattern)
1342               break;
1343
1344             end = value + strlen (value);
1345
1346             if (value == NULL)
1347               break;
1348
1349             switch (remove)
1350               {
1351               case RP_SHORT_LEFT:
1352                 for (p = value; p <= end; ++p)
1353                   {
1354                     c = *p;
1355                     *p = '\0';
1356                     if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1357                       {
1358                         *p = c;
1359                         value = p;
1360                         break;
1361                       }
1362                     *p = c;
1363                   }
1364
1365                 break;
1366
1367               case RP_LONG_LEFT:
1368                 for (p = end; p >= value; --p)
1369                   {
1370                     c = *p;
1371                     *p = '\0';
1372                     if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1373                       {
1374                         *p = c;
1375                         value = p;
1376                         break;
1377                       }
1378                     *p = c;
1379                   }
1380
1381                 break;
1382
1383               case RP_SHORT_RIGHT:
1384                 for (p = end; p >= value; --p)
1385                   {
1386                     if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1387                       {
1388                         *p = '\0';
1389                         break;
1390                       }
1391                   }
1392
1393                 break;
1394
1395               case RP_LONG_RIGHT:
1396                 for (p = value; p <= end; ++p)
1397                   {
1398                     if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1399                       {
1400                         *p = '\0';
1401                         break;
1402                       }
1403                   }
1404
1405                 break;
1406
1407               default:
1408                 assert (! "Unexpected `remove' value\n");
1409               }
1410
1411             break;
1412           }
1413
1414         case '?':
1415           if (value && *value)
1416             /* Substitute parameter */
1417             break;
1418
1419           if (!colon_seen && value)
1420             {
1421               /* Substitute NULL */
1422               free (env);
1423               free (pattern);
1424               return 0;
1425             }
1426
1427           /* Error - exit */
1428           fprintf (stderr, "%s: ", env);
1429
1430           if (*pattern)
1431             {
1432               /* Expand 'pattern' and write it to stderr */
1433               wordexp_t we;
1434
1435               error = wordexp (pattern, &we, flags);
1436
1437               if (error == 0)
1438                 {
1439                   int i;
1440
1441                   for (i = 0; i < we.we_wordc; ++i)
1442                     {
1443                       fprintf (stderr, "%s%s", i ? " " : "", we.we_wordv[i]);
1444                     }
1445
1446                   fprintf (stderr, "\n");
1447                   error = WRDE_BADVAL;
1448                 }
1449
1450               wordfree (&we);
1451               free (env);
1452               free (pattern);
1453               return error;
1454             }
1455
1456           fprintf (stderr, "parameter null or not set\n");
1457           free (env);
1458           free (pattern);
1459           return WRDE_BADVAL;
1460
1461         case '-':
1462           if (value && *value)
1463             /* Substitute parameter */
1464             break;
1465
1466           if (!colon_seen && value)
1467             {
1468               /* Substitute NULL */
1469               free (env);
1470               free (pattern);
1471               return 0;
1472             }
1473
1474         subst_word:
1475           {
1476             /* Substitute word */
1477             wordexp_t we;
1478             int i;
1479
1480             if (quoted)
1481               {
1482                 /* No field-splitting is allowed, so imagine
1483                    quotes around the word.  */
1484                 char *qtd_pattern = malloc (3 + strlen (pattern));
1485                 sprintf (qtd_pattern, "\"%s\"", pattern);
1486                 free (pattern);
1487                 pattern = qtd_pattern;
1488               }
1489
1490             error = wordexp (pattern, &we, flags);
1491             if (error)
1492               {
1493                 free (env);
1494                 free (pattern);
1495                 return error;
1496               }
1497
1498             /* Fingers crossed that the quotes worked.. */
1499             assert (!quoted || we.we_wordc == 1);
1500
1501             /* Substitute */
1502             for (i = 0; i < we.we_wordc; i++)
1503               if (w_addword (pwordexp, __strdup(we.we_wordv[i]))
1504                   == WRDE_NOSPACE)
1505                 break;
1506
1507             if (i < we.we_wordc)
1508               {
1509                 /* Ran out of space */
1510                 wordfree (&we);
1511                 goto no_space;
1512               }
1513
1514             if (action == '=')
1515               {
1516                 char *words;
1517                 char *cp;
1518                 size_t words_size = 0;
1519
1520                 for (i = 0; i < we.we_wordc; i++)
1521                   words_size += strlen (we.we_wordv[i]) + 1; /* for <space> */
1522                 words_size++;
1523
1524                 cp = words = __alloca (words_size);
1525                 *words = 0;
1526                 for (i = 0; i < we.we_wordc - 1; i++)
1527                   {
1528                     cp = __stpcpy (cp, we.we_wordv[i]);
1529                     *cp++ = ' ';
1530                   }
1531
1532                 __stpcpy (cp, we.we_wordv[i]);
1533
1534                 /* Also assign */
1535                 setenv (env, words, 1);
1536               }
1537
1538             wordfree (&we);
1539             return 0;
1540           }
1541
1542         case '+':
1543           if (value && *value)
1544             goto subst_word;
1545
1546           if (!colon_seen && value)
1547             goto subst_word;
1548
1549           /* Substitute NULL */
1550           free (env);
1551           free (pattern);
1552           return 0;
1553
1554         case '=':
1555           if (value && *value)
1556             /* Substitute parameter */
1557             break;
1558
1559           if (!colon_seen && value)
1560             {
1561               /* Substitute NULL */
1562               free (env);
1563               free (pattern);
1564               return 0;
1565             }
1566
1567           /* This checks for '=' so it knows to assign */
1568           goto subst_word;
1569
1570         default:
1571           assert (! "Unrecognised action!");
1572         }
1573     }
1574
1575   free (env);
1576   free (pattern);
1577
1578   if (value == NULL)
1579     {
1580       /* Variable not defined */
1581       if (flags & WRDE_UNDEF)
1582         return WRDE_BADVAL;
1583
1584       return 0;
1585     }
1586
1587   if (substitute_length)
1588     {
1589       char param_length[21];
1590       param_length[20] = '\0';
1591       *word = w_addstr (*word, word_length, max_length,
1592                         _itoa_word (strlen (value), &param_length[20], 10, 0));
1593       return *word ? 0 : WRDE_NOSPACE;
1594     }
1595
1596
1597  maybe_fieldsplit:
1598   if (quoted || !pwordexp)
1599     {
1600       /* Quoted - no field split */
1601       *word = w_addstr (*word, word_length, max_length, value);
1602       return *word ? 0 : WRDE_NOSPACE;
1603     }
1604   else
1605     {
1606       /* Need to field-split */
1607       char *field_begin = value;
1608       int seen_nonws_ifs = 0;
1609
1610       do
1611         {
1612           char *field_end = field_begin;
1613           char *next_field;
1614           char ch;
1615
1616           /* If this isn't the first field, start a new word */
1617           if (field_begin != value)
1618             {
1619               if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
1620                 return WRDE_NOSPACE;
1621
1622               *word = NULL;
1623               *word_length = *max_length = 0;
1624             }
1625
1626           /* Skip IFS whitespace before the field */
1627           while (*field_begin && strchr (ifs_white, *field_begin) != NULL)
1628             field_begin++;
1629
1630           if (!seen_nonws_ifs && *field_begin == 0)
1631             /* Nothing but whitespace */
1632             break;
1633
1634           /* Search for the end of the field */
1635           field_end = field_begin;
1636           while (*field_end && strchr (ifs, *field_end) == NULL)
1637             field_end++;
1638
1639           /* Set up pointer to the character after end of field */
1640           ch = *field_end;
1641           next_field = ch ? field_end : NULL;
1642
1643           /* Skip whitespace IFS after the field */
1644           while (next_field && *next_field && strchr (ifs_white, *next_field))
1645             next_field++;
1646
1647           /* Skip at most one non-whitespace IFS character after the field */
1648           seen_nonws_ifs = 0;
1649           if (next_field && *next_field && strchr (ifs, *next_field))
1650             {
1651               seen_nonws_ifs = 1;
1652               next_field++;
1653             }
1654
1655           /* Null-terminate it */
1656           *field_end = 0;
1657
1658           /* Tag a copy onto the current word */
1659           *word = w_addstr (*word, word_length, max_length,
1660                             __strdup (field_begin));
1661           if (*word == NULL)
1662             return WRDE_NOSPACE;
1663
1664           field_begin = next_field;
1665         } while (seen_nonws_ifs || (field_begin && *field_begin));
1666     }
1667
1668   return 0;
1669
1670 no_space:
1671   if (env)
1672     free (env);
1673
1674   if (pattern)
1675     free (pattern);
1676
1677   return WRDE_NOSPACE;
1678
1679 syntax:
1680   if (env)
1681     free (env);
1682
1683   if (pattern)
1684     free (pattern);
1685
1686   return WRDE_SYNTAX;
1687 }
1688
1689 static int
1690 internal_function
1691 parse_dollars (char **word, size_t *word_length, size_t *max_length,
1692                const char *words, size_t *offset, int flags,
1693                wordexp_t *pwordexp, const char *ifs, const char *ifs_white,
1694                int quoted)
1695 {
1696   /* We are poised _at_ "$" */
1697   switch (words[1 + *offset])
1698     {
1699     case '"':
1700     case '\'':
1701     case 0:
1702       *word = w_addchar (*word, word_length, max_length, '$');
1703       return *word ? 0 : WRDE_NOSPACE;
1704
1705     case '(':
1706       if (words[2 + *offset] == '(')
1707         {
1708           /* Differentiate between $((1+3)) and $((echo);(ls)) */
1709           int i = 3 + *offset;
1710           while (words[i] && words[i] != ')')
1711             ++i;
1712           if (words[i] == ')' && words[i + 1] == ')')
1713             {
1714               (*offset) += 3;
1715               /* Call parse_arith -- 0 is for "no brackets" */
1716               return parse_arith (word, word_length, max_length, words, offset,
1717                                   flags, 0);
1718             }
1719         }
1720
1721       if (flags & WRDE_NOCMD)
1722         return WRDE_CMDSUB;
1723
1724       (*offset) += 2;
1725       return parse_comm (word, word_length, max_length, words, offset, flags,
1726                          quoted? NULL : pwordexp, ifs, ifs_white);
1727
1728     case '[':
1729       (*offset) += 2;
1730       /* Call parse_arith -- 1 is for "brackets" */
1731       return parse_arith (word, word_length, max_length, words, offset, flags,
1732                           1);
1733
1734     case '{':
1735     default:
1736       ++(*offset);      /* parse_param needs to know if "{" is there */
1737       return parse_param (word, word_length, max_length, words, offset, flags,
1738                            pwordexp, ifs, ifs_white, quoted);
1739     }
1740 }
1741
1742 static int
1743 parse_backtick (char **word, size_t *word_length, size_t *max_length,
1744                 const char *words, size_t *offset, int flags,
1745                 wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
1746 {
1747   /* We are poised just after "`" */
1748   int error;
1749   size_t comm_length = 0;
1750   size_t comm_maxlen = 0;
1751   char *comm = NULL;
1752   int squoting = 0;
1753
1754   for (; words[*offset]; ++(*offset))
1755     {
1756       switch (words[*offset])
1757         {
1758         case '`':
1759           /* Go -- give the script to the shell */
1760           error = exec_comm (comm, word, word_length, max_length, flags,
1761                              pwordexp, ifs, ifs_white);
1762           free (comm);
1763           return error;
1764
1765         case '\\':
1766           if (squoting)
1767             {
1768               error = parse_qtd_backslash (&comm, &comm_length, &comm_maxlen,
1769                                            words, offset);
1770
1771               if (error)
1772                 {
1773                   free (comm);
1774                   return error;
1775                 }
1776
1777               break;
1778             }
1779
1780           ++(*offset);
1781           error = parse_backslash (&comm, &comm_length, &comm_maxlen, words,
1782                                    offset);
1783
1784           if (error)
1785             {
1786               free (comm);
1787               return error;
1788             }
1789
1790           break;
1791
1792         case '\'':
1793           squoting = 1 - squoting;
1794         default:
1795           comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
1796           if (comm == NULL)
1797             return WRDE_NOSPACE;
1798         }
1799     }
1800
1801   /* Premature end */
1802   free (comm);
1803   return WRDE_SYNTAX;
1804 }
1805
1806 static int
1807 internal_function
1808 parse_dquote (char **word, size_t *word_length, size_t *max_length,
1809               const char *words, size_t *offset, int flags,
1810               wordexp_t *pwordexp, const char * ifs, const char * ifs_white)
1811 {
1812   /* We are poised just after a double-quote */
1813   int error;
1814
1815   for (; words[*offset]; ++(*offset))
1816     {
1817       switch (words[*offset])
1818         {
1819         case '"':
1820           return 0;
1821
1822         case '$':
1823           error = parse_dollars (word, word_length, max_length, words, offset,
1824                                  flags, pwordexp, ifs, ifs_white, 1);
1825           /* The ``1'' here is to tell parse_dollars not to
1826            * split the fields.  It may need to, however ("$@").
1827            */
1828           if (error)
1829             return error;
1830
1831           break;
1832
1833         case '`':
1834           if (flags & WRDE_NOCMD)
1835             return WRDE_CMDSUB;
1836
1837           ++(*offset);
1838           error = parse_backtick (word, word_length, max_length, words,
1839                                   offset, flags, NULL, NULL, NULL);
1840           /* The first NULL here is to tell parse_backtick not to
1841            * split the fields.
1842            */
1843           if (error)
1844             return error;
1845
1846           break;
1847
1848         case '\\':
1849           error = parse_qtd_backslash (word, word_length, max_length, words,
1850                                        offset);
1851
1852           if (error)
1853             return error;
1854
1855           break;
1856
1857         default:
1858           *word = w_addchar (*word, word_length, max_length, words[*offset]);
1859           if (*word == NULL)
1860             return WRDE_NOSPACE;
1861         }
1862     }
1863
1864   /* Unterminated string */
1865   return WRDE_SYNTAX;
1866 }
1867
1868 /*
1869  * wordfree() is to be called after pwordexp is finished with.
1870  */
1871
1872 void
1873 wordfree (wordexp_t *pwordexp)
1874 {
1875
1876   /* wordexp can set pwordexp to NULL */
1877   if (pwordexp && pwordexp->we_wordv)
1878     {
1879       char **wordv = pwordexp->we_wordv;
1880
1881       for (wordv += pwordexp->we_offs; *wordv; ++wordv)
1882         free (*wordv);
1883
1884       free (pwordexp->we_wordv);
1885       pwordexp->we_wordv = NULL;
1886     }
1887 }
1888
1889 /*
1890  * wordexp()
1891  */
1892
1893 int
1894 wordexp (const char *words, wordexp_t *pwordexp, int flags)
1895 {
1896   size_t wordv_offset;
1897   size_t words_offset;
1898   size_t word_length = 0;
1899   size_t max_length = 0;
1900   char *word = NULL;
1901   int error;
1902   char *ifs;
1903   char ifs_white[4];
1904   char **old_wordv = pwordexp->we_wordv;
1905   size_t old_wordc = (flags & WRDE_REUSE) ? pwordexp->we_wordc : 0;
1906
1907   if (flags & WRDE_REUSE)
1908     /* Minimal implementation of WRDE_REUSE for now */
1909     wordfree (pwordexp);
1910
1911   if (flags & WRDE_DOOFFS)
1912     {
1913       pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
1914       if (pwordexp->we_wordv == NULL)
1915         return WRDE_NOSPACE;
1916     }
1917   else
1918     {
1919       pwordexp->we_wordv = calloc (1, sizeof (char *));
1920       if (pwordexp->we_wordv == NULL)
1921         return WRDE_NOSPACE;
1922
1923       pwordexp->we_offs = 0;
1924     }
1925
1926   if ((flags & WRDE_APPEND) == 0)
1927     pwordexp->we_wordc = 0;
1928
1929   wordv_offset = pwordexp->we_offs + pwordexp->we_wordc;
1930
1931   /* Find out what the field separators are.
1932    * There are two types: whitespace and non-whitespace.
1933    */
1934   ifs = getenv ("IFS");
1935
1936   if (!ifs)
1937     /* NULL IFS means no field-splitting is to be performed */
1938     ifs = strcpy (ifs_white, "");
1939   else
1940     {
1941       char *ifsch = ifs;
1942       char *whch = ifs_white;
1943
1944       /* Start off with no whitespace IFS characters */
1945       ifs_white[0] = '\0';
1946
1947       while (*ifsch != '\0')
1948         {
1949           if ((*ifsch == ' ') || (*ifsch == '\t') || (*ifsch == '\n'))
1950             {
1951               /* Whitespace IFS.  See first whether it is already in our
1952                  collection.  */
1953               char *runp = ifs_white;
1954
1955               while (runp < whch && *runp != '\0' && *runp != *ifsch)
1956                 ++runp;
1957
1958               if (runp == whch)
1959                 *whch++ = *ifsch;
1960             }
1961
1962           ++ifsch;
1963         }
1964       *whch = '\0';
1965     }
1966
1967   for (words_offset = 0 ; words[words_offset] ; ++words_offset)
1968     switch (words[words_offset])
1969       {
1970       case '\n':
1971       case '|':
1972       case '&':
1973       case ';':
1974       case '<':
1975       case '>':
1976       case '(':
1977       case ')':
1978         case '{':
1979       case '}':
1980         /* Fail */
1981         wordfree (pwordexp);
1982         pwordexp->we_wordc = 0;
1983         pwordexp->we_wordv = old_wordv;
1984         return WRDE_BADCHAR;
1985
1986       case '\\':
1987         error = parse_backslash (&word, &word_length, &max_length, words,
1988                                  &words_offset);
1989
1990         if (error)
1991           goto do_error;
1992
1993         break;
1994
1995       case '$':
1996         error = parse_dollars (&word, &word_length, &max_length, words,
1997                                &words_offset, flags, pwordexp, ifs, ifs_white,
1998                                0);
1999
2000         if (error)
2001           goto do_error;
2002
2003         break;
2004
2005       case '`':
2006         if (flags & WRDE_NOCMD)
2007           return WRDE_CMDSUB;
2008
2009         ++words_offset;
2010         error = parse_backtick (&word, &word_length, &max_length, words,
2011                                 &words_offset, flags, pwordexp, ifs,
2012                                 ifs_white);
2013
2014         if (error)
2015           goto do_error;
2016
2017         break;
2018
2019       case '"':
2020         ++words_offset;
2021         error = parse_dquote (&word, &word_length, &max_length, words,
2022                               &words_offset, flags, pwordexp, ifs, ifs_white);
2023
2024         if (error)
2025           goto do_error;
2026
2027         break;
2028
2029       case '\'':
2030         ++words_offset;
2031         error = parse_squote (&word, &word_length, &max_length, words,
2032                               &words_offset);
2033
2034         if (error)
2035           goto do_error;
2036
2037         break;
2038
2039       case '~':
2040         error = parse_tilde (&word, &word_length, &max_length, words,
2041                              &words_offset, pwordexp->we_wordc);
2042
2043         if (error)
2044           goto do_error;
2045
2046         break;
2047
2048       case '*':
2049       case '[':
2050       case '?':
2051         error = parse_glob (&word, &word_length, &max_length, words,
2052                             &words_offset, flags, pwordexp, ifs, ifs_white);
2053
2054         if (error)
2055           goto do_error;
2056
2057         break;
2058
2059       default:
2060         /* Is it a field separator? */
2061         if (strchr (ifs, words[words_offset]) == NULL)
2062           {
2063             /* "Ordinary" character -- add it to word */
2064
2065             word = w_addchar (word, &word_length, &max_length,
2066                               words[words_offset]);
2067             if (word == NULL)
2068               {
2069                 error = WRDE_NOSPACE;
2070                 goto do_error;
2071               }
2072
2073             break;
2074           }
2075
2076         /* Field separator */
2077         if (strchr (ifs_white, words[words_offset]))
2078           {
2079             /* It's a whitespace IFS char.  Ignore it at the beginning
2080                of a line and ignore multiple instances.  */
2081             if (!word || !*word)
2082               break;
2083
2084             if (w_addword (pwordexp, word) == WRDE_NOSPACE)
2085               {
2086                 error = WRDE_NOSPACE;
2087                 goto do_error;
2088               }
2089
2090             word = NULL;
2091             word_length = 0;
2092             max_length = 0;
2093             break;
2094           }
2095
2096         /* It's a non-whitespace IFS char */
2097
2098         /* Multiple non-whitespace IFS chars are treated as one;
2099          * IS THIS CORRECT?
2100          */
2101         if (word != NULL)
2102           {
2103             if (w_addword (pwordexp, word) == WRDE_NOSPACE)
2104               {
2105                 error = WRDE_NOSPACE;
2106                 goto do_error;
2107               }
2108           }
2109
2110         word = NULL;
2111         word_length = 0;
2112         max_length = 0;
2113       }
2114
2115   /* End of string */
2116
2117   /* There was a field separator at the end */
2118   if (word == NULL)
2119     return 0;
2120
2121   /* There was no field separator at the end */
2122   return w_addword (pwordexp, word);
2123
2124 do_error:
2125   /* Error:
2126    *    free memory used (unless error is WRDE_NOSPACE), and
2127    *    set we_wordc and wd_wordv back to what they were.
2128    */
2129
2130   if (error == WRDE_NOSPACE)
2131     return WRDE_NOSPACE;
2132
2133   if (word != NULL)
2134     free (word);
2135
2136   wordfree (pwordexp);
2137   pwordexp->we_wordv = old_wordv;
2138   pwordexp->we_wordc = old_wordc;
2139   return error;
2140 }