1df552a66fe1cead05648fc1281ce85fc949b8d4
[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 /* These variables are defined and initialized in the startup code.  */
52 extern int __libc_argc;
53 extern char **__libc_argv;
54
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;
72
73 /* The w_*() functions manipulate word lists. */
74
75 #define W_CHUNK (100)
76
77 static inline char *
78 w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch)
79      /* (lengths exclude trailing zero) */
80 {
81   /* Add a character to the buffer, allocating room for it if needed.
82    */
83
84   if (*actlen == *maxlen)
85     {
86       char *old_buffer = buffer;
87       assert (buffer == NULL || *maxlen != 0);
88       *maxlen += W_CHUNK;
89       buffer = realloc (buffer, 1 + *maxlen);
90
91       if (buffer == NULL)
92         free (old_buffer);
93     }
94
95   if (buffer != NULL)
96     {
97       buffer[*actlen] = ch;
98       buffer[++(*actlen)] = '\0';
99     }
100
101   return buffer;
102 }
103
104 static char *
105 internal_function
106 w_addmem (char *buffer, size_t *actlen, size_t *maxlen, const char *str,
107           size_t len)
108 {
109   /* Add a string to the buffer, allocating room for it if needed.
110    */
111   if (*actlen + len > *maxlen)
112     {
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);
117
118       if (buffer == NULL)
119         free (old_buffer);
120     }
121
122   if (buffer != NULL)
123     {
124       *((char *) __mempcpy (&buffer[*actlen], str, len)) = '\0';
125       *actlen += len;
126     }
127
128   return buffer;
129 }
130
131
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) */
136 {
137   /* Add a string to the buffer, allocating room for it if needed.
138    */
139   size_t len;
140
141   assert (str != NULL); /* w_addstr only called from this file */
142   len = strlen (str);
143
144   return w_addmem (buffer, actlen, maxlen, str, len);
145 }
146
147 static int
148 internal_function
149 w_addword (wordexp_t *pwordexp, char *word)
150 {
151   /* Add a word to the wordlist */
152   size_t num_p;
153   char **new_wordv;
154
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)
158     {
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;
163     }
164
165   return WRDE_NOSPACE;
166 }
167
168 /* The parse_*() functions should leave *offset being the offset in 'words'
169  * to the last character processed.
170  */
171
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)
176 {
177   /* We are poised _at_ a backslash, not in quotes */
178
179   switch (words[1 + *offset])
180     {
181     case 0:
182       /* Backslash is last character of input words */
183       return WRDE_SYNTAX;
184
185     case '\n':
186       ++(*offset);
187       break;
188
189     default:
190       *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
191       if (*word == NULL)
192         return WRDE_NOSPACE;
193
194       ++(*offset);
195       break;
196     }
197
198   return 0;
199 }
200
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)
205 {
206   /* We are poised _at_ a backslash, inside quotes */
207
208   switch (words[1 + *offset])
209     {
210     case 0:
211       /* Backslash is last character of input words */
212       return WRDE_SYNTAX;
213
214     case '\n':
215       ++(*offset);
216       break;
217
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;
225
226       ++(*offset);
227       break;
228
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]);
233
234       if (*word == NULL)
235         return WRDE_NOSPACE;
236
237       ++(*offset);
238       break;
239     }
240
241   return 0;
242 }
243
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)
248 {
249   /* We are poised _at_ a tilde */
250   size_t i;
251
252   if (*word_length != 0)
253     {
254       if (!((*word)[*word_length - 1] == '=' && wordc == 0))
255         {
256           if (!((*word)[*word_length - 1] == ':'
257                 && strchr (*word, '=') && wordc == 0))
258             {
259               *word = w_addchar (*word, word_length, max_length, '~');
260               return *word ? 0 : WRDE_NOSPACE;
261             }
262         }
263     }
264
265   for (i = 1 + *offset; words[i]; i++)
266     {
267       if (words[i] == ':' || words[i] == '/' || words[i] == ' ' ||
268           words[i] == '\t' || words[i] == 0 )
269         break;
270
271       if (words[i] == '\\')
272         {
273           *word = w_addchar (*word, word_length, max_length, '~');
274           return *word ? 0 : WRDE_NOSPACE;
275         }
276     }
277
278   if (i == 1 + *offset)
279     {
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;
286
287       uid = getuid ();
288
289       while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
290              && errno == ERANGE)
291         {
292           buflen += 1000;
293           buffer = __alloca (buflen);
294         }
295
296       if (result == 0 && pwd.pw_dir != NULL)
297         {
298           *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
299           if (*word == NULL)
300             return WRDE_NOSPACE;
301         }
302       else
303         {
304           *word = w_addchar (*word, word_length, max_length, '~');
305           if (*word == NULL)
306             return WRDE_NOSPACE;
307         }
308     }
309   else
310     {
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;
317
318       while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
319              && errno == ERANGE)
320         {
321           buflen += 1000;
322           buffer = __alloca (buflen);
323         }
324
325       if (result == 0 && pwd.pw_dir)
326         *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
327       else
328         {
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);
333         }
334
335       *offset = i - 1;
336     }
337   return *word ? 0 : WRDE_NOSPACE;
338 }
339
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)
345 {
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 */
352
353   for (; words[*offset]; (*offset)++)
354     {
355       if ((ifs && strchr (ifs, words[*offset])) ||
356           (!ifs && strchr (" \t\n", words[*offset])))
357         /* Reached IFS */
358         break;
359
360       /* Sort out quoting */
361       if (words[*offset] == '\'')
362           if (quoted == 0)
363             {
364               quoted = 1;
365               continue;
366             }
367           else if (quoted == 1)
368             {
369               quoted = 0;
370               continue;
371             }
372       else if (words[*offset] == '"')
373         if (quoted == 0)
374           {
375             quoted = 2;
376             continue;
377           }
378         else if (quoted == 2)
379           {
380             quoted = 0;
381             continue;
382           }
383
384       /* Sort out other special characters */
385       if (quoted != 1 && words[*offset] == '$')
386         {
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;
391
392           continue;
393         }
394       else if (words[*offset] == '\\')
395         {
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);
402
403           if (error)
404             return error;
405
406           continue;
407         }
408
409       *word = w_addchar (*word, word_length, max_length, words[*offset]);
410       if (*word == NULL)
411         return WRDE_NOSPACE;
412     }
413
414   error = glob (*word, GLOB_NOCHECK, NULL, &globbuf);
415
416   if (error != 0)
417     {
418       /* We can only run into memory problems.  */
419       assert (error == GLOB_NOSPACE);
420
421       return WRDE_NOSPACE;
422     }
423
424   if (ifs && !*ifs)
425     {
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)
431         {
432           free (old_word);
433           goto no_space;
434         }
435
436       memcpy (*word, globbuf.gl_pathv[0], length + 1);
437       *word_length = length;
438
439       for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
440         {
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]);
445         }
446
447       /* Re-parse white space on return */
448       globfree (&globbuf);
449       --(*offset);
450       return *word ? 0 : WRDE_NOSPACE;
451     }
452
453   /* here ifs != "" */
454   free (*word);
455   *word = NULL;
456   *word_length = 0;
457
458   matching_word = __strdup (globbuf.gl_pathv[0]);
459   if (matching_word == NULL)
460     goto no_space;
461
462   if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
463     goto no_space;
464
465   for (match = 1; match < globbuf.gl_pathc; ++match)
466     {
467       matching_word = __strdup (globbuf.gl_pathv[match]);
468       if (matching_word == NULL)
469         goto no_space;
470
471       if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
472         goto no_space;
473     }
474
475   globfree (&globbuf);
476
477   /* Re-parse white space on return */
478   --(*offset);
479   return 0;
480
481 no_space:
482   globfree (&globbuf);
483   return WRDE_NOSPACE;
484 }
485
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)
490 {
491   /* We are poised just after a single quote */
492   for (; words[*offset]; ++(*offset))
493     {
494       if (words[*offset] != '\'')
495         {
496           *word = w_addchar (*word, word_length, max_length, words[*offset]);
497           if (*word == NULL)
498             return WRDE_NOSPACE;
499         }
500       else return 0;
501     }
502
503   /* Unterminated string */
504   return WRDE_SYNTAX;
505 }
506
507 /* Functions to evaluate an arithmetic expression */
508 static int
509 internal_function
510 eval_expr_val (char **expr, long int *result)
511 {
512   int sgn = +1;
513   char *digit;
514
515   /* Skip white space */
516   for (digit = *expr; digit && *digit && isspace (*digit); ++digit);
517
518   switch (*digit)
519     {
520     case '(':
521
522       /* Scan for closing paren */
523       for (++digit; **expr && **expr != ')'; ++(*expr));
524
525       /* Is there one? */
526       if (!**expr)
527         return WRDE_SYNTAX;
528
529       *(*expr)++ = 0;
530
531       if (eval_expr (digit, result))
532         return WRDE_SYNTAX;
533
534       return 0;
535
536     case '+':   /* Positive value */
537       ++digit;
538       break;
539
540     case '-':   /* Negative value */
541       ++digit;
542       sgn = -1;
543       break;
544
545     default:
546       if (!isdigit (*digit))
547         return WRDE_SYNTAX;
548     }
549
550   *result = 0;
551   for (; *digit && isdigit (*digit); ++digit)
552     *result = (*result * 10) + (*digit - '0');
553
554   *expr = digit;
555   *result *= sgn;
556   return 0;
557 }
558
559 static int
560 internal_function
561 eval_expr_multdiv (char **expr, long int *result)
562 {
563   long int arg;
564
565   /* Read a Value */
566   if (eval_expr_val (expr, result) != 0)
567     return WRDE_SYNTAX;
568
569   while (**expr)
570     {
571       /* Skip white space */
572       for (; *expr && **expr && isspace (**expr); ++(*expr));
573
574       if (**expr == '*')
575         {
576           ++(*expr);
577           if (eval_expr_val (expr, &arg) != 0)
578             return WRDE_SYNTAX;
579
580           *result *= arg;
581         }
582       else if (**expr == '/')
583         {
584           ++(*expr);
585           if (eval_expr_val (expr, &arg) != 0)
586             return WRDE_SYNTAX;
587
588           *result /= arg;
589         }
590       else break;
591     }
592
593   return 0;
594 }
595
596 static int
597 internal_function
598 eval_expr (char *expr, long int *result)
599 {
600   long int arg;
601
602   /* Read a Multdiv */
603   if (eval_expr_multdiv (&expr, result) != 0)
604     return WRDE_SYNTAX;
605
606   while (*expr)
607     {
608       /* Skip white space */
609       for (; expr && *expr && isspace (*expr); ++expr);
610
611       if (*expr == '+')
612         {
613           ++expr;
614           if (eval_expr_multdiv (&expr, &arg) != 0)
615             return WRDE_SYNTAX;
616
617           *result += arg;
618         }
619       else if (*expr == '-')
620         {
621           ++expr;
622           if (eval_expr_multdiv (&expr, &arg) != 0)
623             return WRDE_SYNTAX;
624
625           *result -= arg;
626         }
627       else break;
628     }
629
630   return 0;
631 }
632
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)
637 {
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;
644
645   for (; words[*offset]; ++(*offset))
646     {
647       switch (words[*offset])
648         {
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.
654            */
655           if (error)
656             {
657               free (expr);
658               return error;
659             }
660           break;
661
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.
668            */
669           if (error)
670             {
671               free (expr);
672               return error;
673             }
674           break;
675
676         case '\\':
677           error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen,
678                                        words, offset);
679           if (error)
680             {
681               free (expr);
682               return error;
683             }
684           /* I think that a backslash within an
685            * arithmetic expansion is bound to
686            * cause an error sooner or later anyway though.
687            */
688           break;
689
690         case ')':
691           if (--paren_depth == 0)
692             {
693               char result[21];  /* 21 = ceil(log10(2^64)) + 1 */
694               long int numresult = 0;
695               long long int convertme;
696
697               if (bracket || words[1 + *offset] != ')')
698                 return WRDE_SYNTAX;
699
700               ++(*offset);
701
702               /* Go - evaluate. */
703               if (*expr && eval_expr (expr, &numresult) != 0)
704                 return WRDE_SYNTAX;
705
706               if (numresult < 0)
707                 {
708                   convertme = -numresult;
709                   *word = w_addchar (*word, word_length, max_length, '-');
710                   if (!*word)
711                     {
712                       free (expr);
713                       return WRDE_NOSPACE;
714                     }
715                 }
716               else
717                 convertme = numresult;
718
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;
724             }
725           expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
726           if (expr == NULL)
727             return WRDE_NOSPACE;
728
729           break;
730
731         case ']':
732           if (bracket && paren_depth == 1)
733             {
734               char result[21];  /* 21 = ceil(log10(2^64)) + 1 */
735               long int numresult = 0;
736
737               /* Go - evaluate. */
738               if (*expr && eval_expr (expr, &numresult) != 0)
739                 return WRDE_SYNTAX;
740
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;
746             }
747
748           free (expr);
749           return WRDE_SYNTAX;
750
751         case '\n':
752         case ';':
753         case '{':
754         case '}':
755           free (expr);
756           return WRDE_BADCHAR;
757
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;
764         }
765     }
766
767   /* Premature end */
768   free (expr);
769   return WRDE_SYNTAX;
770 }
771
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)
779 {
780   int fildes[2];
781   int bufsize = 128;
782   int buflen;
783   int i;
784   char *buffer;
785   pid_t pid;
786
787   /* Don't fork() unless necessary */
788   if (!comm || !*comm)
789     return 0;
790
791   if (pipe (fildes))
792     /* Bad */
793     return WRDE_NOSPACE;
794
795   if ((pid = fork ()) < 0)
796     {
797       /* Bad */
798       return WRDE_NOSPACE;
799     }
800
801   if (pid == 0)
802     {
803       /* Child */
804       const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
805
806       /* Redirect output.  */
807       dup2 (fildes[1], 1);
808       close (fildes[1]);
809
810       /* Redirect stderr to /dev/null if we have to.  */
811       if ((flags & WRDE_SHOWERR) == 0)
812         {
813           int fd;
814           close (2);
815           fd = open (_PATH_DEVNULL, O_WRONLY);
816           if (fd >= 0 && fd != 2)
817             {
818               dup2 (fd, 2);
819               close (fd);
820             }
821         }
822
823       close (fildes[0]);
824       __execve (_PATH_BSHELL, (char *const *) args, __environ);
825
826       /* Bad.  What now?  */
827       abort ();
828     }
829
830   /* Parent */
831
832   close (fildes[1]);
833   buffer = __alloca (bufsize);
834
835   if (!pwordexp)
836     { /* Quoted - no field splitting */
837
838       while (1)
839         {
840           if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
841             {
842               if (__waitpid (pid, NULL, WNOHANG) == 0)
843                 continue;
844               if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
845                 break;
846             }
847
848           *word = w_addmem (*word, word_length, max_length, buffer, buflen);
849           if (*word == NULL)
850             {
851               kill (pid, SIGKILL);
852               __waitpid (pid, NULL, 0);
853               close (fildes[0]);
854               return WRDE_NOSPACE;
855             }
856         }
857     }
858   else
859     /* Not quoted - split fields */
860     {
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
866        */
867
868       while (1)
869         {
870           if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
871             {
872               if (__waitpid (pid, NULL, WNOHANG) == 0)
873                 continue;
874               if ((read (fildes[0], buffer, bufsize)) < 1)
875                 break;
876             }
877
878           for (i = 0; i < buflen; ++i)
879             {
880               if (strchr (ifs, buffer[i]) != NULL)
881                 {
882                   /* Current character is IFS */
883                   if (strchr (ifs_white, buffer[i]) == NULL)
884                     {
885                       /* Current character is IFS but not whitespace */
886                       if (copying == 2)
887                         {
888                           /*            current character
889                            *                   |
890                            *                   V
891                            * eg: text<space><comma><space>moretext
892                            *
893                            * So, strip whitespace IFS (like at the start)
894                            */
895                           copying = 0;
896                           continue;
897                         }
898
899                       copying = 0;
900                       /* fall through and delimit field.. */
901                     }
902                   else
903                     {
904                       /* Current character is IFS white space */
905
906                       /* If not copying a field, ignore it */
907                       if (copying != 1)
908                         continue;
909
910                       /* End of field (search for non-IFS afterwards) */
911                       copying = 2;
912                     }
913
914                   /* First IFS white space, or IFS non-whitespace.
915                    * Delimit the field. */
916                   if (!*word)
917                     {
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)
921                         {
922                           kill (pid, SIGKILL);
923                           __waitpid (pid, NULL, 0);
924                           close (fildes[0]);
925                           return WRDE_NOSPACE;
926                         }
927                     }
928
929                   if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
930                     {
931                       kill (pid, SIGKILL);
932                       __waitpid (pid, NULL, 0);
933                       close (fildes[0]);
934                       return WRDE_NOSPACE;
935                     }
936
937                   *word = NULL;
938                   *word_length = 0;
939                   *max_length = 0;
940                   /* fall back round the loop.. */
941                 }
942               else
943                 {
944                   /* Not IFS character */
945                   copying = 1;
946                   *word = w_addchar (*word, word_length, max_length,
947                                      buffer[i]);
948                   if (*word == NULL)
949                     {
950                       kill (pid, SIGKILL);
951                       __waitpid (pid, NULL, 0);
952                       close (fildes[0]);
953                       return WRDE_NOSPACE;
954                     }
955                 }
956             }
957         }
958     }
959
960   /* Bash chops off trailing newlines, which seems sensible.  */
961   while (*word_length > 0 && (*word)[*word_length - 1] == '\n')
962     (*word)[--*word_length] = '\0';
963
964   close (fildes[0]);
965   return 0;
966 }
967
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)
973 {
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 */
981
982   for (; words[*offset]; ++(*offset))
983     {
984       switch (words[*offset])
985         {
986         case '\'':
987           if (quoted == 0)
988             quoted = 1;
989           else if (quoted == 1)
990             quoted = 0;
991
992           break;
993
994         case '"':
995           if (quoted == 0)
996             quoted = 2;
997           else if (quoted == 2)
998             quoted = 0;
999
1000           break;
1001
1002         case ')':
1003           if (!quoted && --paren_depth == 0)
1004             {
1005               /* Go -- give script to the shell */
1006               if (comm)
1007                 {
1008                   error = exec_comm (comm, word, word_length, max_length,
1009                                      flags, pwordexp, ifs, ifs_white);
1010                   free (comm);
1011                 }
1012
1013               return error;
1014             }
1015
1016           /* This is just part of the script */
1017           break;
1018
1019         case '(':
1020           if (!quoted)
1021             ++paren_depth;
1022         }
1023
1024       comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
1025       if (comm == NULL)
1026         return WRDE_NOSPACE;
1027     }
1028
1029   /* Premature end */
1030   if (comm)
1031     free (comm);
1032
1033   return WRDE_SYNTAX;
1034 }
1035
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)
1041 {
1042   /* We are poised just after "$" */
1043   enum action
1044   {
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 = '='
1054   };
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] == '{';
1071
1072   if (brace)
1073     ++*offset;
1074
1075   for (; words[*offset]; ++(*offset))
1076     {
1077       int special;
1078
1079       if (action != ACT_NONE)
1080         {
1081           switch (words[*offset])
1082             {
1083             case '{':
1084               if (!pattern_is_quoted)
1085                 ++depth;
1086               break;
1087
1088             case '}':
1089               if (!pattern_is_quoted)
1090                 {
1091                   if (depth == 0)
1092                     goto envsubst;
1093                   --depth;
1094                 }
1095               break;
1096
1097             case '\\':
1098               if (!pattern_is_quoted && words[++*offset] == '\0')
1099                 goto syntax;
1100               break;
1101
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;
1107
1108               break;
1109
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;
1115
1116               break;
1117             }
1118
1119           pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1120                                words[*offset]);
1121           if (pattern == NULL)
1122             goto no_space;
1123
1124           continue;
1125         }
1126
1127       switch (words[*offset])
1128         {
1129         case '}':
1130           if (!brace)
1131             goto end_of_word;
1132
1133           if (env == NULL)
1134             goto syntax;
1135
1136           /* Evaluate. */
1137           goto envsubst;
1138
1139         case '#':
1140           /* '#' only has special meaning inside braces or as the very
1141            * first character after $ */
1142           if (*offset == start)
1143             {
1144               seen_hash = 1;
1145               goto envsubst;
1146             }
1147
1148           if (!brace)
1149             /* Evaluate */
1150             /* (and re-parse this character) */
1151             goto end_of_word;
1152
1153           /* At the start? (i.e. 'string length') */
1154           if (env == NULL)
1155             {
1156               seen_hash = 1;
1157               continue;
1158             }
1159           else if (seen_hash)
1160             goto syntax;
1161
1162           action = ACT_RP_SHORT_LEFT;
1163           if (words[1 + *offset] == '#')
1164             {
1165               ++*offset;
1166               action = ACT_RP_LONG_LEFT;
1167             }
1168
1169           continue;
1170
1171         case '%':
1172           if (!brace)
1173             /* Re-parse this character after substitution */
1174             goto end_of_word;
1175
1176           if (!env || !*env)
1177             goto syntax;
1178
1179           if (seen_hash)
1180             goto syntax;
1181
1182           action = ACT_RP_SHORT_RIGHT;
1183           if (words[1 + *offset] == '%')
1184             {
1185               ++*offset;
1186               action = ACT_RP_LONG_RIGHT;
1187             }
1188
1189           continue;
1190
1191         case ':':
1192           if (!brace)
1193             goto end_of_word;
1194
1195           if (!env || !*env)
1196             goto syntax;
1197
1198           if (seen_hash)
1199             goto syntax;
1200
1201           if (words[1 + *offset] != '-' && words[1 + *offset] != '='
1202               && words[1 + *offset] != '?' && words[1 + *offset] != '+')
1203             goto syntax;
1204
1205           colon_seen = 1;
1206           action = words[++*offset];
1207           continue;
1208
1209         case '-':
1210         case '=':
1211         case '?':
1212         case '+':
1213           if (!brace)
1214             goto end_of_word;
1215
1216           if (!env || !*env)
1217             goto syntax;
1218
1219           action = words[*offset];
1220           continue;
1221         }
1222
1223       special = strchr ("*@$", words[*offset]) != NULL;
1224
1225       if (!isalnum (words[*offset]) && !special)
1226         /* Stop and evaluate, remembering char we stopped at */
1227         break;
1228
1229       env = w_addchar (env, &env_length, &env_maxlen,
1230                            words[*offset]);
1231       if (env == NULL)
1232         goto no_space;
1233
1234       if (special)
1235         {
1236           if (brace)
1237             ++*offset;
1238           goto envsubst;
1239         }
1240     }
1241
1242   /* End of input string -- remember to reparse the character that we stopped
1243    * at.  */
1244 end_of_word:
1245   --(*offset);
1246
1247 envsubst:
1248   if (words[start] == '{' && words[*offset] != '}')
1249     goto syntax;
1250
1251   if (!env || !*env)
1252     {
1253       if (seen_hash)
1254         {
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));
1260         }
1261       else
1262         {
1263           /* Just $ on its own */
1264           *offset = start - 1;
1265           *word = w_addchar (*word, word_length, max_length, '$');
1266         }
1267
1268       if (env)
1269         free (env);
1270
1271       return *word ? 0 : WRDE_NOSPACE;
1272     }
1273
1274   /* Is it a special parameter? */
1275   if (strpbrk (env, "*@$") || isdigit (*env))
1276     {
1277       if ((isdigit(*env) && strcspn (env, "1234567890")) ||
1278           (!isdigit(*env) && env[1] != '\0'))
1279         {
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;
1285         }
1286
1287       /* Is it a digit? */
1288       if (isdigit(*env))
1289         {
1290           char *endp;
1291           int n = strtol (env, &endp, 10);
1292
1293           if (*endp != '\0')
1294             goto bad_subst;
1295
1296           free (env);
1297           if (n >= __libc_argc)
1298             /* Substitute NULL */
1299             return 0;
1300
1301           /* Replace with the appropriate positional parameter */
1302           value = __libc_argv[n];
1303           goto maybe_fieldsplit;
1304         }
1305       /* Is it `$$' ? */
1306       else if (*env == '$')
1307         {
1308           char pidstr[21];
1309
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;
1315         }
1316       /* Is it `$*' or `$@' (unquoted) ? */
1317       else if (*env == '*' || (*env == '@' && !quoted))
1318         {
1319           size_t plist_len = 1;
1320           int p;
1321
1322           /* Build up value parameter by parameter (copy them) */
1323           free (env);
1324           for (p = 1; __libc_argv[p]; ++p)
1325             {
1326               char *old_pointer = value;
1327               size_t argv_len = strlen (__libc_argv[p]);
1328               size_t old_plist_len = plist_len;
1329
1330               if (value)
1331                 value[plist_len - 1] = 0;
1332
1333               plist_len += 1 + argv_len;
1334
1335               /* First realloc will act as malloc because value is
1336                * initialised to NULL. */
1337               value = realloc (value, plist_len);
1338               if (value == NULL)
1339                 {
1340                   free (old_pointer);
1341                   return WRDE_NOSPACE;
1342                 }
1343
1344               memcpy (&value[old_plist_len - 1], __libc_argv[p], argv_len + 1);
1345               if (__libc_argv[p + 1])
1346                 {
1347                   value[plist_len - 1] = '\0';
1348                   value[plist_len - 2] = ' ';
1349                 }
1350             }
1351
1352           free_value = 1;
1353           if (value)
1354             goto maybe_fieldsplit;
1355
1356           return 0;
1357         }
1358
1359       /* Must be a quoted `$@' */
1360       assert (*env == '@');
1361       assert (quoted);
1362       free (env);
1363
1364       /* Each parameter is a separate word ("$@") */
1365       if (__libc_argv[0] != NULL && __libc_argv[1] != NULL)
1366         {
1367           /* Append first parameter to current word. */
1368           int p;
1369
1370           *word = w_addstr (*word, word_length, max_length, __libc_argv[1]);
1371           if (*word == NULL)
1372             return WRDE_NOSPACE;
1373
1374           for (p = 2; __libc_argv[p]; p++)
1375             {
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;
1386             }
1387         }
1388
1389       return 0;
1390     }
1391
1392   value = getenv (env);
1393
1394   if (action != ACT_NONE)
1395     {
1396       switch (action)
1397         {
1398         case ACT_RP_SHORT_LEFT:
1399         case ACT_RP_LONG_LEFT:
1400         case ACT_RP_SHORT_RIGHT:
1401         case ACT_RP_LONG_RIGHT:
1402           {
1403             char *p;
1404             char c;
1405             char *end;
1406
1407             if (!pattern || !*pattern)
1408               break;
1409
1410             end = value + strlen (value);
1411
1412             if (value == NULL)
1413               break;
1414
1415             switch (action)
1416               {
1417               case ACT_RP_SHORT_LEFT:
1418                 for (p = value; p <= end; ++p)
1419                   {
1420                     c = *p;
1421                     *p = '\0';
1422                     if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1423                       {
1424                         *p = c;
1425                         value = p;
1426                         break;
1427                       }
1428                     *p = c;
1429                   }
1430
1431                 break;
1432
1433               case ACT_RP_LONG_LEFT:
1434                 for (p = end; p >= value; --p)
1435                   {
1436                     c = *p;
1437                     *p = '\0';
1438                     if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1439                       {
1440                         *p = c;
1441                         value = p;
1442                         break;
1443                       }
1444                     *p = c;
1445                   }
1446
1447                 break;
1448
1449               case ACT_RP_SHORT_RIGHT:
1450                 for (p = end; p >= value; --p)
1451                   {
1452                     if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1453                       {
1454                         *p = '\0';
1455                         break;
1456                       }
1457                   }
1458
1459                 break;
1460
1461               case ACT_RP_LONG_RIGHT:
1462                 for (p = value; p <= end; ++p)
1463                   {
1464                     if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1465                       {
1466                         *p = '\0';
1467                         break;
1468                       }
1469                   }
1470
1471                 break;
1472
1473               default:
1474                 break;
1475               }
1476
1477             break;
1478           }
1479
1480         case ACT_NULL_ERROR:
1481           if (value && *value)
1482             /* Substitute parameter */
1483             break;
1484
1485           if (!colon_seen && value)
1486             {
1487               /* Substitute NULL */
1488               free (env);
1489               free (pattern);
1490               return 0;
1491             }
1492
1493           if (*pattern)
1494             {
1495               /* Expand 'pattern' and write it to stderr */
1496               wordexp_t we;
1497
1498               error = wordexp (pattern, &we, flags);
1499
1500               if (error == 0)
1501                 {
1502                   int i;
1503
1504                   fprintf (stderr, "%s:", env);
1505
1506                   for (i = 0; i < we.we_wordc; ++i)
1507                     {
1508                       fprintf (stderr, " %s", we.we_wordv[i]);
1509                     }
1510
1511                   fprintf (stderr, "\n");
1512                   error = WRDE_BADVAL;
1513                 }
1514
1515               wordfree (&we);
1516               free (env);
1517               free (pattern);
1518               return error;
1519             }
1520
1521           fprintf (stderr, "%s: parameter null or not set\n", env);
1522           free (env);
1523           free (pattern);
1524           return WRDE_BADVAL;
1525
1526         case ACT_NULL_SUBST:
1527           if (value && *value)
1528             /* Substitute parameter */
1529             break;
1530
1531           if (!colon_seen && value)
1532             {
1533               /* Substitute NULL */
1534               free (env);
1535               free (pattern);
1536               return 0;
1537             }
1538
1539         subst_word:
1540           {
1541             /* Substitute word */
1542             wordexp_t we;
1543             int i;
1544
1545             if (quoted)
1546               {
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;
1554               }
1555
1556             if (pattern == NULL && (pattern = __strdup ("")) == NULL)
1557               goto no_space;
1558
1559             error = wordexp (pattern, &we, flags);
1560             if (error)
1561               {
1562                 free (env);
1563                 free (pattern);
1564                 return error;
1565               }
1566
1567             /* Fingers crossed that the quotes worked.. */
1568             assert (!quoted || we.we_wordc == 1);
1569
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;
1575
1576             if (i < we.we_wordc)
1577               {
1578                 /* Ran out of space */
1579                 wordfree (&we);
1580                 goto no_space;
1581               }
1582
1583             if (action == ACT_NULL_ASSIGN)
1584               {
1585                 char *words;
1586                 char *cp;
1587                 size_t words_size = 0;
1588
1589                 for (i = 0; i < we.we_wordc; i++)
1590                   words_size += strlen (we.we_wordv[i]) + 1; /* for <space> */
1591                 words_size++;
1592
1593                 cp = words = __alloca (words_size);
1594                 *words = 0;
1595                 for (i = 0; i < we.we_wordc - 1; i++)
1596                   {
1597                     cp = __stpcpy (cp, we.we_wordv[i]);
1598                     *cp++ = ' ';
1599                   }
1600
1601                 __stpcpy (cp, we.we_wordv[i]);
1602
1603                 /* Also assign */
1604                 setenv (env, words, 1);
1605               }
1606
1607             wordfree (&we);
1608             return 0;
1609           }
1610
1611         case ACT_NONNULL_SUBST:
1612           if (value && *value)
1613             goto subst_word;
1614
1615           if (!colon_seen && value)
1616             goto subst_word;
1617
1618           /* Substitute NULL */
1619           free (env);
1620           free (pattern);
1621           return 0;
1622
1623         case ACT_NULL_ASSIGN:
1624           if (value && *value)
1625             /* Substitute parameter */
1626             break;
1627
1628           if (!colon_seen && value)
1629             {
1630               /* Substitute NULL */
1631               free (env);
1632               free (pattern);
1633               return 0;
1634             }
1635
1636           /* This checks for '=' so it knows to assign */
1637           goto subst_word;
1638
1639         default:
1640           assert (! "Unrecognised action!");
1641         }
1642     }
1643
1644   free (env);
1645   free (pattern);
1646
1647   if (value == NULL)
1648     {
1649       /* Variable not defined */
1650       if (flags & WRDE_UNDEF)
1651         return WRDE_BADVAL;
1652
1653       return 0;
1654     }
1655
1656   if (seen_hash)
1657     {
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;
1663     }
1664
1665  maybe_fieldsplit:
1666   if (quoted || !pwordexp)
1667     {
1668       /* Quoted - no field split */
1669       *word = w_addstr (*word, word_length, max_length, value);
1670       if (free_value)
1671         free (value);
1672
1673       return *word ? 0 : WRDE_NOSPACE;
1674     }
1675   else
1676     {
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;
1681
1682       if (free_value)
1683         free (value);
1684
1685       if (value_copy == NULL)
1686         return WRDE_NOSPACE;
1687
1688       do
1689         {
1690           char *field_end = field_begin;
1691           char *next_field;
1692
1693           /* If this isn't the first field, start a new word */
1694           if (field_begin != value_copy)
1695             {
1696               if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
1697                 {
1698                   free (value_copy);
1699                   return WRDE_NOSPACE;
1700                 }
1701
1702               *word = NULL;
1703               *word_length = *max_length = 0;
1704             }
1705
1706           /* Skip IFS whitespace before the field */
1707           while (*field_begin && strchr (ifs_white, *field_begin) != NULL)
1708             field_begin++;
1709
1710           if (!seen_nonws_ifs && *field_begin == 0)
1711             /* Nothing but whitespace */
1712             break;
1713
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++;
1718
1719           /* Set up pointer to the character after end of field */
1720           next_field = *field_end ? field_end : NULL;
1721
1722           /* Skip whitespace IFS after the field */
1723           while (next_field && *next_field && strchr (ifs_white, *next_field))
1724             next_field++;
1725
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))
1729             {
1730               seen_nonws_ifs = 1;
1731               next_field++;
1732             }
1733
1734           /* Null-terminate it */
1735           *field_end = 0;
1736
1737           /* Tag a copy onto the current word */
1738           *word = w_addstr (*word, word_length, max_length, field_begin);
1739
1740           if (*word == NULL)
1741             {
1742               free (value_copy);
1743               return WRDE_NOSPACE;
1744             }
1745
1746           field_begin = next_field;
1747         }
1748       while (seen_nonws_ifs || (field_begin != NULL && *field_begin));
1749
1750       free (value_copy);
1751     }
1752
1753   return 0;
1754
1755 no_space:
1756   if (env)
1757     free (env);
1758
1759   if (pattern)
1760     free (pattern);
1761
1762   return WRDE_NOSPACE;
1763
1764 syntax:
1765   if (env)
1766     free (env);
1767
1768   if (pattern)
1769     free (pattern);
1770
1771   return WRDE_SYNTAX;
1772 }
1773
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)
1780 {
1781   /* We are poised _at_ "$" */
1782   switch (words[1 + *offset])
1783     {
1784     case '"':
1785     case '\'':
1786     case 0:
1787       *word = w_addchar (*word, word_length, max_length, '$');
1788       return *word ? 0 : WRDE_NOSPACE;
1789
1790     case '(':
1791       if (words[2 + *offset] == '(')
1792         {
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] == ')'))
1797             {
1798               if (words[i] == '(')
1799                 ++depth;
1800               else if (words[i] == ')')
1801                 --depth;
1802
1803               ++i;
1804             }
1805
1806           if (words[i] == ')' && words[i + 1] == ')')
1807             {
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);
1812             }
1813         }
1814
1815       if (flags & WRDE_NOCMD)
1816         return WRDE_CMDSUB;
1817
1818       (*offset) += 2;
1819       return parse_comm (word, word_length, max_length, words, offset, flags,
1820                          quoted? NULL : pwordexp, ifs, ifs_white);
1821
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,
1826                           1);
1827
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);
1833     }
1834 }
1835
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)
1840 {
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;
1847
1848   for (; words[*offset]; ++(*offset))
1849     {
1850       switch (words[*offset])
1851         {
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;
1858
1859         case '\\':
1860           if (squoting)
1861             {
1862               error = parse_qtd_backslash (&comm, &comm_length, &comm_maxlen,
1863                                            words, offset);
1864
1865               if (error)
1866                 {
1867                   free (comm);
1868                   return error;
1869                 }
1870
1871               break;
1872             }
1873
1874           ++(*offset);
1875           error = parse_backslash (&comm, &comm_length, &comm_maxlen, words,
1876                                    offset);
1877
1878           if (error)
1879             {
1880               free (comm);
1881               return error;
1882             }
1883
1884           break;
1885
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;
1892         }
1893     }
1894
1895   /* Premature end */
1896   free (comm);
1897   return WRDE_SYNTAX;
1898 }
1899
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)
1905 {
1906   /* We are poised just after a double-quote */
1907   int error;
1908
1909   for (; words[*offset]; ++(*offset))
1910     {
1911       switch (words[*offset])
1912         {
1913         case '"':
1914           return 0;
1915
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 ("$@").
1921            */
1922           if (error)
1923             return error;
1924
1925           break;
1926
1927         case '`':
1928           if (flags & WRDE_NOCMD)
1929             return WRDE_CMDSUB;
1930
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.
1936            */
1937           if (error)
1938             return error;
1939
1940           break;
1941
1942         case '\\':
1943           error = parse_qtd_backslash (word, word_length, max_length, words,
1944                                        offset);
1945
1946           if (error)
1947             return error;
1948
1949           break;
1950
1951         default:
1952           *word = w_addchar (*word, word_length, max_length, words[*offset]);
1953           if (*word == NULL)
1954             return WRDE_NOSPACE;
1955         }
1956     }
1957
1958   /* Unterminated string */
1959   return WRDE_SYNTAX;
1960 }
1961
1962 /*
1963  * wordfree() is to be called after pwordexp is finished with.
1964  */
1965
1966 void
1967 wordfree (wordexp_t *pwordexp)
1968 {
1969
1970   /* wordexp can set pwordexp to NULL */
1971   if (pwordexp && pwordexp->we_wordv)
1972     {
1973       char **wordv = pwordexp->we_wordv;
1974
1975       for (wordv += pwordexp->we_offs; *wordv; ++wordv)
1976         free (*wordv);
1977
1978       free (pwordexp->we_wordv);
1979       pwordexp->we_wordv = NULL;
1980     }
1981 }
1982
1983 /*
1984  * wordexp()
1985  */
1986
1987 int
1988 wordexp (const char *words, wordexp_t *pwordexp, int flags)
1989 {
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;
2000
2001   if (flags & WRDE_REUSE)
2002     {
2003       /* Minimal implementation of WRDE_REUSE for now */
2004       wordfree (pwordexp);
2005       old_wordv = NULL;
2006     }
2007
2008   if (flags & WRDE_DOOFFS)
2009     {
2010       pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
2011       if (pwordexp->we_wordv == NULL)
2012         return WRDE_NOSPACE;
2013     }
2014   else
2015     {
2016       pwordexp->we_wordv = calloc (1, sizeof (char *));
2017       if (pwordexp->we_wordv == NULL)
2018         return WRDE_NOSPACE;
2019
2020       pwordexp->we_offs = 0;
2021     }
2022
2023   if ((flags & WRDE_APPEND) == 0)
2024     pwordexp->we_wordc = 0;
2025
2026   wordv_offset = pwordexp->we_offs + pwordexp->we_wordc;
2027
2028   /* Find out what the field separators are.
2029    * There are two types: whitespace and non-whitespace.
2030    */
2031   ifs = getenv ("IFS");
2032
2033   if (!ifs)
2034     /* NULL IFS means no field-splitting is to be performed */
2035     ifs = strcpy (ifs_white, "");
2036   else
2037     {
2038       char *ifsch = ifs;
2039       char *whch = ifs_white;
2040
2041       /* Start off with no whitespace IFS characters */
2042       ifs_white[0] = '\0';
2043
2044       while (*ifsch != '\0')
2045         {
2046           if ((*ifsch == ' ') || (*ifsch == '\t') || (*ifsch == '\n'))
2047             {
2048               /* Whitespace IFS.  See first whether it is already in our
2049                  collection.  */
2050               char *runp = ifs_white;
2051
2052               while (runp < whch && *runp != '\0' && *runp != *ifsch)
2053                 ++runp;
2054
2055               if (runp == whch)
2056                 *whch++ = *ifsch;
2057             }
2058
2059           ++ifsch;
2060         }
2061       *whch = '\0';
2062     }
2063
2064   for (words_offset = 0 ; words[words_offset] ; ++words_offset)
2065     switch (words[words_offset])
2066       {
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;
2082
2083       case '\\':
2084         error = parse_backslash (&word, &word_length, &max_length, words,
2085                                  &words_offset);
2086
2087         if (error)
2088           goto do_error;
2089
2090         break;
2091
2092       case '$':
2093         error = parse_dollars (&word, &word_length, &max_length, words,
2094                                &words_offset, flags, pwordexp, ifs, ifs_white,
2095                                0);
2096
2097         if (error)
2098           goto do_error;
2099
2100         break;
2101
2102       case '`':
2103         if (flags & WRDE_NOCMD)
2104           return WRDE_CMDSUB;
2105
2106         ++words_offset;
2107         error = parse_backtick (&word, &word_length, &max_length, words,
2108                                 &words_offset, flags, pwordexp, ifs,
2109                                 ifs_white);
2110
2111         if (error)
2112           goto do_error;
2113
2114         break;
2115
2116       case '"':
2117         ++words_offset;
2118         error = parse_dquote (&word, &word_length, &max_length, words,
2119                               &words_offset, flags, pwordexp, ifs, ifs_white);
2120
2121         if (error)
2122           goto do_error;
2123
2124         break;
2125
2126       case '\'':
2127         ++words_offset;
2128         error = parse_squote (&word, &word_length, &max_length, words,
2129                               &words_offset);
2130
2131         if (error)
2132           goto do_error;
2133
2134         break;
2135
2136       case '~':
2137         error = parse_tilde (&word, &word_length, &max_length, words,
2138                              &words_offset, pwordexp->we_wordc);
2139
2140         if (error)
2141           goto do_error;
2142
2143         break;
2144
2145       case '*':
2146       case '[':
2147       case '?':
2148         error = parse_glob (&word, &word_length, &max_length, words,
2149                             &words_offset, flags, pwordexp, ifs, ifs_white);
2150
2151         if (error)
2152           goto do_error;
2153
2154         break;
2155
2156       default:
2157         /* Is it a field separator? */
2158         if (strchr (ifs, words[words_offset]) == NULL)
2159           {
2160             /* "Ordinary" character -- add it to word */
2161
2162             word = w_addchar (word, &word_length, &max_length,
2163                               words[words_offset]);
2164             if (word == NULL)
2165               {
2166                 error = WRDE_NOSPACE;
2167                 goto do_error;
2168               }
2169
2170             break;
2171           }
2172
2173         /* Field separator */
2174         if (strchr (ifs_white, words[words_offset]))
2175           {
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;
2180
2181             if (w_addword (pwordexp, word) == WRDE_NOSPACE)
2182               {
2183                 error = WRDE_NOSPACE;
2184                 goto do_error;
2185               }
2186
2187             word = NULL;
2188             word_length = 0;
2189             max_length = 0;
2190             break;
2191           }
2192
2193         /* It's a non-whitespace IFS char */
2194
2195         /* Multiple non-whitespace IFS chars are treated as one;
2196          * IS THIS CORRECT?
2197          */
2198         if (word != NULL)
2199           {
2200             if (w_addword (pwordexp, word) == WRDE_NOSPACE)
2201               {
2202                 error = WRDE_NOSPACE;
2203                 goto do_error;
2204               }
2205           }
2206
2207         word = NULL;
2208         word_length = 0;
2209         max_length = 0;
2210       }
2211
2212   /* End of string */
2213
2214   /* There was a field separator at the end */
2215   if (word == NULL)
2216     return 0;
2217
2218   /* There was no field separator at the end */
2219   return w_addword (pwordexp, word);
2220
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.
2225    */
2226
2227   if (error == WRDE_NOSPACE)
2228     return WRDE_NOSPACE;
2229
2230   if (word != NULL)
2231     free (word);
2232
2233   wordfree (pwordexp);
2234   pwordexp->we_wordv = old_wordv;
2235   pwordexp->we_wordc = old_wordc;
2236   return error;
2237 }