Use _IO_FILE_complete, not _IO_file_plus.
[kopensolaris-gnu/glibc.git] / posix / wordexp.c
1 /* POSIX.2 wordexp implementation.
2    Copyright (C) 1997 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
40 #include <assert.h>
41
42 /*
43  * This is a recursive-descent-style word expansion routine.
44  */
45
46 /* Some forward declarations */
47 static int parse_dollars (char **word, size_t *word_length, size_t *max_length,
48                           const char *words, size_t *offset, int flags,
49                           wordexp_t *pwordexp)
50      internal_function;
51 static int parse_backtick (char **word, size_t *word_length,
52                            size_t *max_length, const char *words,
53                            size_t *offset, int flags, wordexp_t *pwordexp)
54      internal_function;
55 static int eval_expr (char *expr, int *result) internal_function;
56
57 /* The w_*() functions manipulate word lists. */
58
59 #define W_CHUNK (100)
60
61 static inline char *
62 w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch)
63      /* (lengths exclude trailing zero) */
64 {
65   /* Add a character to the buffer, allocating room for it if needed.
66    */
67
68   if (*actlen == *maxlen)
69     {
70       char *old_buffer = buffer;
71       assert (buffer == NULL || *maxlen != 0);
72       *maxlen += W_CHUNK;
73       buffer = realloc (buffer, 1 + *maxlen);
74
75       if (buffer == NULL)
76         free (old_buffer);
77     }
78
79   if (buffer != NULL)
80     {
81       buffer[*actlen] = ch;
82       buffer[++(*actlen)] = '\0';
83     }
84
85   return buffer;
86 }
87
88 static char *
89 w_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str)
90      /* (lengths exclude trailing zero) */
91 {
92   /* Add a string to the buffer, allocating room for it if needed.
93    */
94   size_t len;
95
96   assert (str != NULL); /* w_addstr only called from this file */
97   len = strlen (str);
98
99   if (*actlen + len > *maxlen)
100     {
101       char *old_buffer = buffer;
102       assert (buffer == NULL || *maxlen != 0);
103       *maxlen += MAX (2 * len, W_CHUNK);
104       buffer = realloc (old_buffer, 1 + *maxlen);
105
106       if (buffer == NULL)
107         free (old_buffer);
108     }
109
110   if (buffer != NULL)
111     {
112       memcpy (&buffer[*actlen], str, len);
113       *actlen += len;
114       buffer[*actlen] = '\0';
115     }
116
117   return buffer;
118 }
119
120 static int
121 w_addword (wordexp_t *pwordexp, char *word)
122 {
123   /* Add a word to the wordlist */
124   size_t num_p;
125
126   num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
127   pwordexp->we_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p);
128   if (pwordexp->we_wordv != NULL)
129     {
130       pwordexp->we_wordv[pwordexp->we_wordc++] = word;
131       pwordexp->we_wordv[pwordexp->we_wordc] = NULL;
132       return 0;
133     }
134
135   return WRDE_NOSPACE;
136 }
137
138 /* The parse_*() functions should leave *offset being the offset in 'words'
139  * to the last character processed.
140  */
141
142 static int
143 internal_function
144 parse_backslash (char **word, size_t *word_length, size_t *max_length,
145                  const char *words, size_t *offset)
146 {
147   /* We are poised _at_ a backslash, not in quotes */
148
149   switch (words[1 + *offset])
150     {
151     case 0:
152       /* Backslash is last character of input words */
153       return WRDE_SYNTAX;
154
155     case '\n':
156       (*offset)++;
157       break;
158
159     default:
160       *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
161       if (*word == NULL)
162         return WRDE_NOSPACE;
163
164       (*offset)++;
165       break;
166     }
167
168   return 0;
169 }
170
171 static int
172 internal_function
173 parse_qtd_backslash (char **word, size_t *word_length, size_t *max_length,
174                      const char *words, size_t *offset)
175 {
176   /* We are poised _at_ a backslash, inside quotes */
177
178   switch (words[1 + *offset])
179     {
180     case 0:
181       /* Backslash is last character of input words */
182       return WRDE_SYNTAX;
183
184     case '\n':
185       ++(*offset);
186       break;
187
188     case '$':
189     case '`':
190     case '"':
191     case '\\':
192       *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
193       if (*word == NULL)
194         return WRDE_NOSPACE;
195
196       ++(*offset);
197       break;
198
199     default:
200       *word = w_addchar (*word, word_length, max_length, words[*offset]);
201       if (*word != NULL)
202         *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
203
204       if (*word == NULL)
205         return WRDE_NOSPACE;
206
207       ++(*offset);
208       break;
209     }
210
211   return 0;
212 }
213
214 static int
215 internal_function
216 parse_tilde (char **word, size_t *word_length, size_t *max_length,
217              const char *words, size_t *offset, size_t wordc)
218 {
219   /* We are poised _at_ a tilde */
220   size_t i;
221
222   if (*word_length != 0)
223     {
224       if (!((*word)[*word_length - 1] == '=' && wordc == 0))
225         {
226           if (!((*word)[*word_length - 1] == ':' &&
227                 strchr (*word, '=') && wordc == 0))
228             {
229               *word = w_addchar (*word, word_length, max_length, '~');
230               return *word ? 0 : WRDE_NOSPACE;
231             }
232         }
233     }
234
235   for (i = 1 + *offset; words[i]; i++)
236     {
237       if (words[i] == ':' || words[i] == '/' || words[i] == ' ' ||
238           words[i] == '\t' || words[i] == 0 )
239         break;
240
241       if (words[i] == '\\')
242         {
243           *word = w_addchar (*word, word_length, max_length, '~');
244           return *word ? 0 : WRDE_NOSPACE;
245         }
246     }
247
248   if (i == 1 + *offset)
249     {
250       /* Tilde appears on its own */
251       uid_t uid;
252       struct passwd pwd, *tpwd;
253       int buflen = 1000;
254       char* buffer = __alloca (buflen);
255       int result;
256
257       uid = getuid ();
258
259       while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
260              && errno == ERANGE)
261         {
262           buflen += 1000;
263           buffer = __alloca (buflen);
264         }
265
266       if (result == 0 && pwd.pw_dir != NULL)
267         {
268           *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
269           if (*word == NULL)
270             return WRDE_NOSPACE;
271         }
272       else
273         {
274           *word = w_addchar (*word, word_length, max_length, '~');
275           if (*word == NULL)
276             return WRDE_NOSPACE;
277         }
278     }
279   else
280     {
281       /* Look up user name in database to get home directory */
282       char *user = __strndup (&words[1 + *offset], i - *offset);
283       struct passwd pwd, *tpwd;
284       int buflen = 1000;
285       char* buffer = __alloca (buflen);
286       int result;
287
288       while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
289              && errno == ERANGE)
290         {
291           buflen += 1000;
292           buffer = __alloca (buflen);
293         }
294
295       if (result == 0 && pwd.pw_dir)
296         *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
297       else
298         {
299           /* (invalid login name) */
300           *word = w_addchar (*word, word_length, max_length, '~');
301           if (*word != NULL)
302             *word = w_addstr (*word, word_length, max_length, user);
303         }
304
305       *offset = i - 1;
306     }
307   return *word ? 0 : WRDE_NOSPACE;
308 }
309
310 static int
311 internal_function
312 parse_glob (char **word, size_t *word_length, size_t *max_length,
313             const char *words, size_t *offset, int flags,
314             wordexp_t *pwordexp, char *ifs)
315 {
316   /* We are poised just after a '*' or a '{'. */
317   int error;
318   glob_t globbuf;
319   int match;
320   char *matching_word;
321
322   for (; words[*offset]; (*offset)++)
323     switch (words[*offset])
324       {
325       case ' ':
326       case '\t':
327         break;
328
329       case '$':
330         error = parse_dollars (word, word_length, max_length, words, offset,
331                                flags, pwordexp);
332         if (error)
333           return error;
334
335         continue;
336
337       default:
338         if (ifs == NULL || strchr (ifs, words[*offset]) == NULL)
339           {
340             *word = w_addchar (*word, word_length, max_length, words[*offset]);
341             if (*word == NULL)
342               return WRDE_NOSPACE;
343
344             continue;
345           }
346
347         break;
348       }
349
350   error = glob (*word, GLOB_NOCHECK, NULL, &globbuf);
351
352   if (error != 0)
353     {
354       /* We can only run into memory problems.  */
355       assert (error == GLOB_NOSPACE);
356
357       return WRDE_NOSPACE;
358     }
359
360   if (ifs && !*ifs)
361     {
362       /* No field splitting allowed */
363       *word_length = strlen (globbuf.gl_pathv[0]);
364       *word = realloc (*word, 1 + *word_length);
365       if (*word == NULL)
366         goto no_space;
367
368       strcpy (*word, globbuf.gl_pathv[0]);
369
370       for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
371         {
372           *word = w_addchar (*word, word_length, max_length, ' ');
373           if (*word != NULL)
374             *word = w_addstr (*word, word_length, max_length,
375                               globbuf.gl_pathv[match]);
376         }
377
378       /* Re-parse white space on return */
379       globfree (&globbuf);
380       --(*offset);
381       return *word ? 0 : WRDE_NOSPACE;
382     }
383
384   /* here ifs != "" */
385   free (*word);
386   *word = NULL;
387   *word_length = 0;
388
389   matching_word = malloc (1 + strlen (globbuf.gl_pathv[0]));
390   if (matching_word == NULL)
391     goto no_space;
392
393   strcpy (matching_word, globbuf.gl_pathv[0]);
394   if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
395     goto no_space;
396
397   for (match = 1; match < globbuf.gl_pathc; ++match)
398     {
399       matching_word = __strdup (globbuf.gl_pathv[match]);
400       if (matching_word == NULL)
401         goto no_space;
402
403       if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
404         goto no_space;
405     }
406
407   globfree (&globbuf);
408
409   /* Re-parse white space on return */
410   --(*offset);
411   return 0;
412
413 no_space:
414   globfree (&globbuf);
415   return WRDE_NOSPACE;
416 }
417
418 static int
419 parse_squote (char **word, size_t *word_length, size_t *max_length,
420               const char *words, size_t *offset)
421 {
422   /* We are poised just after a single quote */
423   for (; words[*offset]; ++(*offset))
424     {
425       if (words[*offset] != '\'')
426         {
427           *word = w_addchar (*word, word_length, max_length, words[*offset]);
428           if (*word == NULL)
429             return WRDE_NOSPACE;
430         }
431       else return 0;
432     }
433
434   /* Unterminated string */
435   return WRDE_SYNTAX;
436 }
437
438 /* Functions to evaluate an arithmetic expression */
439 static int
440 internal_function
441 eval_expr_val (char **expr, int *result)
442 {
443   int sgn = +1;
444   char *digit;
445
446   /* Skip white space */
447   for (digit = *expr; digit && *digit && isspace (*digit); ++digit);
448
449   switch (*digit)
450     {
451     case '(':
452
453       /* Scan for closing paren */
454       for (++digit; **expr && **expr != ')'; ++(*expr));
455
456       /* Is there one? */
457       if (!**expr)
458         return WRDE_SYNTAX;
459
460       *(*expr)++ = 0;
461
462       if (eval_expr (digit, result))
463         return WRDE_SYNTAX;
464
465       return 0;
466
467     case '+':   /* Positive value */
468       ++digit;
469       break;
470
471     case '-':   /* Negative value */
472       ++digit;
473       sgn = -1;
474       break;
475
476     default:
477       if (!isdigit (*digit))
478         return WRDE_SYNTAX;
479     }
480
481   *result = 0;
482   for (; *digit && isdigit (*digit); ++digit)
483     *result = (*result * 10) + (*digit - '0');
484
485   *expr = digit;
486   *result *= sgn;
487   return 0;
488 }
489
490 static int
491 internal_function
492 eval_expr_multdiv (char **expr, int *result)
493 {
494   int arg;
495
496   /* Read a Value */
497   if (eval_expr_val (expr, result))
498     return WRDE_SYNTAX;
499
500   while (**expr)
501     {
502       /* Skip white space */
503       for (; *expr && **expr && isspace (**expr); ++(*expr));
504
505       if (**expr == '*')
506         {
507           (*expr)++;
508           if ((eval_expr_val (expr, &arg)) != 0)
509             return WRDE_SYNTAX;
510
511           *result *= arg;
512         }
513       else if (**expr == '/')
514         {
515           (*expr)++;
516           if ((eval_expr_val (expr, &arg)) != 0)
517             return WRDE_SYNTAX;
518
519           *result /= arg;
520         }
521       else break;
522     }
523
524   return 0;
525 }
526
527 static int
528 internal_function
529 eval_expr (char *expr, int *result)
530 {
531   int arg;
532
533   /* Read a Multdiv */
534   if ((eval_expr_multdiv (&expr, result)) != 0)
535     return WRDE_SYNTAX;
536
537   while (*expr)
538     {
539       /* Skip white space */
540       for (; expr && *expr && isspace (*expr); ++expr);
541
542       if (*expr == '+')
543         {
544           expr++;
545           if ((eval_expr_multdiv (&expr, &arg)) != 0)
546             return WRDE_SYNTAX;
547
548           *result += arg;
549         }
550       else if (*expr == '-')
551         {
552           expr++;
553           if ((eval_expr_multdiv (&expr, &arg)) != 0)
554             return WRDE_SYNTAX;
555
556           *result -= arg;
557         }
558       else break;
559     }
560
561   return 0;
562 }
563
564 static int
565 internal_function
566 parse_arith (char **word, size_t *word_length, size_t *max_length,
567              const char *words, size_t *offset, int flags, int bracket)
568 {
569   /* We are poised just after "$((" or "$[" */
570   int error;
571   int paren_depth = 1;
572   size_t expr_length = 0;
573   size_t expr_maxlen = 0;
574   char *expr = NULL;
575
576   for (; words[*offset]; ++(*offset))
577     {
578       switch (words[*offset])
579         {
580         case '$':
581           error = parse_dollars (&expr, &expr_length, &expr_maxlen,
582                                  words, offset, flags, NULL);
583           /* The NULL here is to tell parse_dollars not to
584            * split the fields.
585            */
586           if (error)
587             {
588               free (expr);
589               return error;
590             }
591           break;
592
593         case '`':
594           (*offset)++;
595           error = parse_backtick (&expr, &expr_length, &expr_maxlen,
596                                   words, offset, flags, NULL);
597           /* The NULL here is to tell parse_backtick not to
598            * split the fields.
599            */
600           if (error)
601             {
602               free (expr);
603               return error;
604             }
605           break;
606
607         case '\\':
608           error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen,
609                                        words, offset);
610           if (error)
611             {
612               free (expr);
613               return error;
614             }
615           /* I think that a backslash within an
616            * arithmetic expansion is bound to
617            * cause an error sooner or later anyway though.
618            */
619           break;
620
621         case ')':
622           if (--paren_depth == 0)
623             {
624               char *result;
625               int numresult = 0;
626
627               if (bracket || words[1 + *offset] != ')')
628                 return WRDE_SYNTAX;
629
630               ++(*offset);
631
632               /* Go - evaluate. */
633               if (*expr &&
634                   eval_expr (expr, &numresult) != 0)
635                 return WRDE_SYNTAX;
636
637               result = __alloca (100);
638               __snprintf (result, 100, "%d", numresult);
639               *word = w_addstr (*word, word_length, max_length, result);
640               free (expr);
641               return *word ? 0 : WRDE_NOSPACE;
642             }
643           expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
644           if (expr == NULL)
645             return WRDE_NOSPACE;
646
647           break;
648
649         case ']':
650           if (bracket && paren_depth == 1)
651             {
652               char *result;
653               int numresult = 0;
654
655               /* Go - evaluate. */
656               if (*expr && eval_expr (expr, &numresult) != 0)
657                 return WRDE_SYNTAX;
658
659               result = __alloca (100);
660               __snprintf (result, 100, "%d", numresult);
661               *word = w_addstr (*word, word_length, max_length, result);
662               free (expr);
663               return *word ? 0 : WRDE_NOSPACE;
664             }
665
666           free (expr);
667           return WRDE_SYNTAX;
668
669         case '\n':
670         case ';':
671         case '{':
672         case '}':
673           free (expr);
674           return WRDE_BADCHAR;
675
676         case '(':
677           ++paren_depth;
678         default:
679           expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
680           if (expr == NULL)
681             return WRDE_NOSPACE;
682         }
683     }
684
685   /* Premature end */
686   free (expr);
687   return WRDE_SYNTAX;
688 }
689
690 /* Function to execute a command and retrieve the results */
691 /* pwordexp contains NULL if field-splitting is forbidden */
692 static int
693 internal_function
694 exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
695            int flags, wordexp_t *pwordexp)
696 {
697   int fildes[2];
698   int bufsize = 128;
699   int buflen;
700   int state = 0;
701   int i;
702   char *buffer;
703   pid_t pid;
704   /* 'state' is:
705    *  0 until first non-(whitespace-ifs)
706    *  1 after a non-ifs
707    *  2 after non-(whitespace-ifs)
708    */
709
710   /* Don't fork() unless necessary */
711   if (!comm || !*comm)
712     return 0;
713
714   if (pipe (fildes))
715     /* Bad */
716     return WRDE_NOSPACE;
717
718   if ((pid = fork ()) < 0)
719     {
720       /* Bad */
721       return WRDE_NOSPACE;
722     }
723
724   if (pid == 0)
725     {
726       /* Child */
727       /* Redirect input and output */
728       dup2 (fildes[1], 1);
729
730       /* Close stderr if we have to */
731       if ((flags & WRDE_SHOWERR) == 0)
732         close (2);
733
734       execl (_PATH_BSHELL, _PATH_BSHELL, "-c", comm, NULL);
735
736       /* Bad. What now? */
737       exit (1);
738     }
739
740   /* Parent */
741
742   close (fildes[1]);
743   buffer = __alloca (bufsize);
744
745   if (!pwordexp)
746     { /* Quoted - no field splitting */
747
748       while (1)
749         {
750           if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
751             {
752               if (waitpid (pid, NULL, WNOHANG) == 0)
753                 continue;
754               if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
755                 break;
756             }
757
758           for (i = 0; i < buflen; ++i)
759             {
760               *word = w_addchar (*word, word_length, max_length, buffer[i]);
761               if (*word == NULL)
762                 {
763                   close (fildes[0]);
764                   return WRDE_NOSPACE;
765                 }
766             }
767         }
768
769       close (fildes[0]);
770       return 0;
771     }
772
773   /* Not quoted - split fields.
774    * NB. This isn't done properly yet.
775    */
776   while (1)
777     {
778       if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
779         {
780           if (waitpid (pid, NULL, WNOHANG) == 0)
781             continue;
782           if ((read (fildes[0], buffer, bufsize)) < 1)
783             break;
784         }
785
786       for (i = 0; i < buflen; ++i)
787         {
788           /* What if these aren't field separators? FIX */
789           if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n')
790             {
791               if (state != 0)
792                 state = 2;
793               continue;
794             }
795
796           if (state == 2)
797             {
798               /* End of word */
799               if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
800                 {
801                   close (fildes[0]);
802                   return WRDE_NOSPACE;
803                 }
804
805               *word = NULL;
806               *word_length = 0;
807             }
808
809           state = 1;
810           *word = w_addchar (*word, word_length, max_length, buffer[i]);
811           if (*word == NULL)
812             {
813               close (fildes[0]);
814               return WRDE_NOSPACE;
815             }
816         }
817     }
818
819   close (fildes[0]);
820   return 0;
821 }
822
823 static int
824 parse_comm (char **word, size_t *word_length, size_t *max_length,
825             const char *words, size_t *offset, int flags, wordexp_t *pwordexp)
826 {
827   /* We are poised just after "$(" */
828   int paren_depth = 1;
829   int error;
830   size_t comm_length = 0;
831   size_t comm_maxlen = 0;
832   char *comm = NULL;
833
834   for (; words[*offset]; ++(*offset))
835     {
836       switch (words[*offset])
837         {
838         case ')':
839           if (--paren_depth == 0)
840             {
841               /* Go -- give script to the shell */
842               error = exec_comm (comm, word, word_length, max_length, flags,
843                                  pwordexp);
844               free (comm);
845               return error;
846             }
847
848           /* This is just part of the script */
849           comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
850           if (comm == NULL)
851             return WRDE_NOSPACE;
852
853           break;
854
855         case '(':
856           paren_depth++;
857         default:
858           comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
859           if (comm == NULL)
860             return WRDE_NOSPACE;
861
862           break;
863         }
864     }
865
866   /* Premature end */
867   free (comm);
868   return WRDE_SYNTAX;
869 }
870
871 static int
872 internal_function
873 parse_param (char **word, size_t *word_length, size_t *max_length,
874              const char *words, size_t *offset, int flags, wordexp_t *pwordexp)
875 {
876   /* We are poised just after "$" */
877   size_t start = *offset;
878   size_t env_length = 0;
879   size_t env_maxlen = 0;
880   size_t pat_length = 0;
881   size_t pat_maxlen = 0;
882   char *env = NULL;
883   char *pattern = NULL;
884   char *value;
885   char action = 0;
886   int prefix = 0;
887   int suffix = 0;
888   int colon_seen = 0;
889   int depth = 0;
890   int error;
891
892   for (; words[*offset]; ++(*offset))
893     {
894       switch (words[*offset])
895         {
896         case '{':
897           if (action || prefix || suffix)
898             {
899               ++depth;
900               pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
901                                    words[*offset]);
902               if (pattern == NULL)
903                 goto no_space;
904
905               break;
906             }
907
908           if (*offset == start)
909             break;
910           /* Otherwise evaluate */
911           /* (and re-parse this character) */
912           --(*offset);
913           goto envsubst;
914
915         case '}':
916           if (words[start] != '{')
917             {
918               --(*offset);
919             }
920
921           if (action || prefix || suffix)
922             {
923               if (--depth)
924                 {
925                   pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
926                                        words[*offset]);
927                   if (pattern == NULL)
928                     goto no_space;
929
930                   break;
931                 }
932             }
933
934           /* Evaluate */
935           goto envsubst;
936
937         case '#':
938         case '%':
939           if (words[start] == '{')
940             {
941               /* At the start?  (ie. 'string length') */
942               if (*offset == start + 1)
943                 break;
944
945               /* Separating variable name from prefix pattern? */
946               if (words[*offset] == '#')
947                 {
948                   if (prefix < 2 && !suffix)
949                     {
950                       ++prefix;
951                       break;
952                     }
953                 }
954               else
955                 {
956                   if (suffix < 2 && !prefix)
957                     {
958                       ++suffix;
959                       break;
960                     }
961                 }
962
963               /* Must be part of prefix/suffix pattern. */
964               pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
965                                    words[*offset]);
966               if (pattern == NULL)
967                 goto no_space;
968
969               break;
970             }
971           /* Otherwise evaluate */
972           /* (and re-parse this character) */
973           --(*offset);
974           goto envsubst;
975
976         case ':':
977           if (!*env)
978             {
979               free (env);
980               free (pattern);
981               return WRDE_SYNTAX;
982             }
983
984           if (action || prefix || suffix)
985             {
986               pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
987                                    words[*offset]);
988               if (pattern == NULL)
989                 goto no_space;
990
991               break;
992             }
993
994           if ((words[1 + *offset] == '-') || (words[1 + *offset] == '=') ||
995               (words[1 + *offset] == '?') || (words[1 + *offset] == '+'))
996             {
997               colon_seen = 1;
998               break;
999             }
1000
1001           free (env);
1002           free (pattern);
1003           return WRDE_SYNTAX;
1004
1005         case '-':
1006         case '=':
1007         case '?':
1008         case '+':
1009           if (!*env)
1010             {
1011               free (env);
1012               free (pattern);
1013               return WRDE_SYNTAX;
1014             }
1015
1016           if (action || prefix || suffix)
1017             {
1018               pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1019                                    words[*offset]);
1020               if (pattern == NULL)
1021                 {
1022                   free (env);
1023                   return WRDE_NOSPACE;
1024                 }
1025
1026               break;
1027             }
1028
1029           action = words[*offset];
1030           break;
1031
1032         case '\\':
1033           if (action || prefix || suffix)
1034             {
1035               error = parse_qtd_backslash (word, word_length, max_length,
1036                                            words, offset);
1037               if (error == 0)
1038                 break;
1039             }
1040           else
1041             {
1042               error = WRDE_SYNTAX;
1043             }
1044
1045           free (env);
1046           free (pattern);
1047           return error;
1048
1049         default:
1050           if (action || prefix || suffix)
1051             {
1052               pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1053                                    words[*offset]);
1054               if (pattern == NULL)
1055                 goto no_space;
1056
1057               break;
1058             }
1059
1060           if ((words[start] == '{') || isalpha (words[*offset]))
1061             {
1062               env = w_addchar (env, &env_length, &env_maxlen, words[*offset]);
1063               if (env == NULL)
1064                 goto no_space;
1065
1066               break;
1067             }
1068
1069           --(*offset);
1070           goto envsubst;
1071         }
1072     }
1073
1074   /* End of input string */
1075   --(*offset);
1076
1077 envsubst:
1078   if (words[start] == '{' && words[*offset] != '}')
1079     {
1080       free (env);
1081       free (pattern);
1082       return WRDE_SYNTAX;
1083     }
1084
1085   if (!env || !*env)
1086     {
1087       *offset = start - 1;
1088       *word = w_addchar (*word, word_length, max_length, '$');
1089       free (env);
1090       free (pattern);
1091       return *word ? 0 : WRDE_NOSPACE;
1092     }
1093
1094   value = getenv (env);
1095
1096   if (action || prefix || suffix)
1097     {
1098       switch (action)
1099         {
1100         case 0:
1101           /* For the time being, pattern is ignored */
1102           printf ("Pattern: %s\nPrefix: %d\nSuffix: %d\n", pattern, prefix, suffix);
1103           break;
1104
1105         case '?':
1106           if (value && *value)
1107             break;
1108
1109           if (!colon_seen && value)
1110             {
1111               /* Substitute NULL */
1112               free (env);
1113               free (pattern);
1114               return 0;
1115             }
1116
1117           /* Error - exit */
1118           fprintf (stderr, "%s: ", env);
1119
1120           if (*pattern)
1121             {
1122               /* Expand 'pattern' and write it to stderr */
1123               wordexp_t we;
1124
1125               error = wordexp (pattern, &we, flags);
1126
1127               if (error == 0)
1128                 {
1129                   int i;
1130
1131                   for (i = 0; i < we.we_wordc; ++i)
1132                     {
1133                       fprintf (stderr, "%s%s", i ? " " : "", we.we_wordv[i]);
1134                     }
1135
1136                   fprintf (stderr, "\n");
1137                   error = WRDE_BADVAL;
1138                 }
1139
1140               wordfree (&we);
1141               free (env);
1142               free (pattern);
1143               return error;
1144             }
1145
1146           fprintf (stderr, "parameter null or not set\n");
1147           free (env);
1148           free (pattern);
1149           return WRDE_BADVAL;
1150
1151         default:
1152           printf ("warning: parameter substitution does not yet support \"%s%c\"\n", colon_seen?":":"", action);
1153         }
1154     }
1155
1156   free (env);
1157   free (pattern);
1158
1159   if (value == NULL)
1160     {
1161       /* Variable not defined */
1162       if (flags & WRDE_UNDEF)
1163         return WRDE_SYNTAX;
1164
1165       return 0;
1166     }
1167
1168   if (pwordexp == NULL)
1169     /* Quoted - no field split */
1170     *word = w_addstr (*word, word_length, max_length, value);
1171   else
1172     /* Should field-split here - FIX */
1173     *word = w_addstr (*word, word_length, max_length, value);
1174
1175   return *word ? 0 : WRDE_NOSPACE;
1176
1177 no_space:
1178   if (env)
1179     free (env);
1180
1181   if (pattern)
1182     free (pattern);
1183
1184   return WRDE_NOSPACE;
1185 }
1186
1187 static int
1188 internal_function
1189 parse_dollars (char **word, size_t *word_length, size_t *max_length,
1190                const char *words, size_t *offset, int flags,
1191                wordexp_t *pwordexp)
1192 {
1193   /* We are poised _at_ "$" */
1194   switch (words[1 + *offset])
1195     {
1196     case '"':
1197     case '\'':
1198     case 0:
1199       *word = w_addchar (*word, word_length, max_length, '$');
1200       return *word ? 0 : WRDE_NOSPACE;
1201
1202     case '(':
1203       if (words[2 + *offset] == '(')
1204         {
1205           (*offset) += 3;
1206           /* Call parse_arith -- 0 is for "no brackets" */
1207           return parse_arith (word, word_length, max_length, words, offset,
1208                               flags, 0);
1209         }
1210
1211       if (flags & WRDE_NOCMD)
1212         return WRDE_CMDSUB;
1213
1214       (*offset) += 2;
1215       return parse_comm (word, word_length, max_length, words, offset, flags,
1216                          pwordexp);
1217
1218     case '[':
1219       (*offset) += 2;
1220       /* Call parse_arith -- 1 is for "brackets" */
1221       return parse_arith (word, word_length, max_length, words, offset, flags,
1222                           1);
1223
1224     case '{':
1225     default:
1226       ++(*offset);      /* parse_param needs to know if "{" is there */
1227       return parse_param (word, word_length, max_length, words, offset, flags,
1228                           pwordexp);
1229     }
1230 }
1231
1232 static int
1233 parse_backtick (char **word, size_t *word_length, size_t *max_length,
1234                 const char *words, size_t *offset, int flags,
1235                 wordexp_t *pwordexp)
1236 {
1237   /* We are poised just after "`" */
1238   int error;
1239   size_t comm_length = 0;
1240   size_t comm_maxlen = 0;
1241   char *comm = NULL;
1242   int squoting = 0;
1243
1244   for (; words[*offset]; ++(*offset))
1245     {
1246       switch (words[*offset])
1247         {
1248         case '`':
1249           /* Go -- give the script to the shell */
1250           error = exec_comm (comm, word, word_length, max_length, flags,
1251                              pwordexp);
1252           free (comm);
1253           return error;
1254
1255         case '\\':
1256           if (squoting)
1257             {
1258               error = parse_qtd_backslash (&comm, &comm_length, &comm_maxlen,
1259                                            words, offset);
1260
1261               if (error)
1262                 {
1263                   free (comm);
1264                   return error;
1265                 }
1266
1267               break;
1268             }
1269
1270           ++(*offset);
1271           error = parse_backslash (&comm, &comm_length, &comm_maxlen, words,
1272                                    offset);
1273
1274           if (error)
1275             {
1276               free (comm);
1277               return error;
1278             }
1279
1280           break;
1281
1282         case '\'':
1283           squoting = 1 - squoting;
1284         default:
1285           comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
1286           if (comm == NULL)
1287             return WRDE_NOSPACE;
1288         }
1289     }
1290
1291   /* Premature end */
1292   free (comm);
1293   return WRDE_SYNTAX;
1294 }
1295
1296 static int
1297 internal_function
1298 parse_dquote (char **word, size_t *word_length, size_t *max_length,
1299               const char *words, size_t *offset, int flags)
1300 {
1301   /* We are poised just after a double-quote */
1302   int error;
1303
1304   for (; words[*offset]; ++(*offset))
1305     {
1306       switch (words[*offset])
1307         {
1308         case '"':
1309           return 0;
1310
1311         case '$':
1312           error = parse_dollars (word, word_length, max_length, words, offset,
1313                                  flags, NULL);
1314           /* The NULL here is to tell parse_dollars not to
1315            * split the fields.
1316            */
1317           if (error)
1318             return error;
1319
1320           break;
1321
1322         case '`':
1323           if (flags & WRDE_NOCMD)
1324             return WRDE_CMDSUB;
1325
1326           ++(*offset);
1327           error = parse_backtick (word, word_length, max_length, words,
1328                                   offset, flags, NULL);
1329           /* The NULL here is to tell parse_backtick not to
1330            * split the fields.
1331            */
1332           if (error)
1333             return error;
1334
1335           break;
1336
1337         case '\\':
1338           error = parse_qtd_backslash (word, word_length, max_length, words,
1339                                        offset);
1340
1341           if (error)
1342             return error;
1343
1344           break;
1345
1346         default:
1347           *word = w_addchar (*word, word_length, max_length, words[*offset]);
1348           if (*word == NULL)
1349             return WRDE_NOSPACE;
1350         }
1351     }
1352
1353   /* Unterminated string */
1354   return WRDE_SYNTAX;
1355 }
1356
1357 /*
1358  * wordfree() is to be called after pwordexp is finished with.
1359  */
1360
1361 void
1362 wordfree (wordexp_t *pwordexp)
1363 {
1364
1365   /* wordexp can set pwordexp to NULL */
1366   if (pwordexp && pwordexp->we_wordv)
1367     {
1368       char **wordv = pwordexp->we_wordv;
1369
1370       for (wordv += pwordexp->we_offs; *wordv; ++wordv)
1371         free (*wordv);
1372
1373       free (pwordexp->we_wordv);
1374       pwordexp->we_wordv = NULL;
1375     }
1376 }
1377
1378 /*
1379  * wordexp()
1380  */
1381
1382 int
1383 wordexp (const char *words, wordexp_t *pwordexp, int flags)
1384 {
1385   size_t wordv_offset;
1386   size_t words_offset;
1387   size_t word_length = 0;
1388   size_t max_length = 0;
1389   char *word = NULL;
1390   int error;
1391   char *ifs;
1392   char ifs_white[4];
1393   char **old_wordv = pwordexp->we_wordv;
1394   size_t old_wordc = pwordexp->we_wordc;
1395
1396   if (flags & WRDE_REUSE)
1397     /* Minimal implementation of WRDE_REUSE for now */
1398     wordfree (pwordexp);
1399
1400   if (flags & WRDE_DOOFFS)
1401     {
1402       pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
1403       if (pwordexp->we_wordv == NULL)
1404         return WRDE_NOSPACE;
1405     }
1406   else
1407     {
1408       pwordexp->we_wordv = calloc (1, sizeof (char *));
1409       if (pwordexp->we_wordv == NULL)
1410         return WRDE_NOSPACE;
1411
1412       pwordexp->we_offs = 0;
1413     }
1414
1415   if ((flags & WRDE_APPEND) == 0)
1416     pwordexp->we_wordc = 0;
1417
1418   wordv_offset = pwordexp->we_offs + pwordexp->we_wordc;
1419
1420   /* Find out what the field separators are.
1421    * There are two types: whitespace and non-whitespace.
1422    */
1423   ifs = getenv ("IFS");
1424
1425   if (!ifs)
1426     ifs = strcpy (ifs_white, " \t\n");
1427   else
1428     {
1429       char *ifsch = ifs;
1430       char *whch = ifs_white;
1431
1432       while (*ifsch != '\0')
1433         if ((*ifsch == ' ') || (*ifsch == '\t') || (*ifsch == '\n'))
1434           {
1435             /* White space IFS.  See first whether it is already in our
1436                collection.  */
1437             char *runp = ifs_white;
1438
1439             while (runp < whch && *runp != '\0' && *runp != *ifsch)
1440               ++runp;
1441
1442             if (runp == whch)
1443               *whch++ = *ifsch;
1444           }
1445       *whch = '\0';
1446     }
1447
1448   for (words_offset = 0 ; words[words_offset] ; ++words_offset)
1449     switch (words[words_offset])
1450       {
1451       case '\n':
1452       case '|':
1453       case '&':
1454       case ';':
1455       case '<':
1456       case '>':
1457       case '(':
1458       case ')':
1459       case '}':
1460         /* Fail */
1461         wordfree (pwordexp);
1462         pwordexp->we_wordc = 0;
1463         pwordexp->we_wordv = old_wordv;
1464         return WRDE_BADCHAR;
1465
1466       case '\\':
1467         error = parse_backslash (&word, &word_length, &max_length, words,
1468                                  &words_offset);
1469
1470         if (error)
1471           goto do_error;
1472
1473         break;
1474
1475       case '$':
1476         error = parse_dollars (&word, &word_length, &max_length, words,
1477                                &words_offset, flags, pwordexp);
1478
1479         if (error)
1480           goto do_error;
1481
1482         break;
1483
1484       case '`':
1485         if (flags & WRDE_NOCMD)
1486           return WRDE_CMDSUB;
1487
1488         ++words_offset;
1489         error = parse_backtick (&word, &word_length, &max_length, words,
1490                                 &words_offset, flags, pwordexp);
1491
1492         if (error)
1493           goto do_error;
1494
1495         break;
1496
1497       case '"':
1498         ++words_offset;
1499         error = parse_dquote (&word, &word_length, &max_length, words,
1500                               &words_offset, flags);
1501
1502         if (error)
1503           goto do_error;
1504
1505         break;
1506
1507       case '\'':
1508         ++words_offset;
1509         error = parse_squote (&word, &word_length, &max_length, words,
1510                               &words_offset);
1511
1512         if (error)
1513           goto do_error;
1514
1515         break;
1516
1517       case '~':
1518         error = parse_tilde (&word, &word_length, &max_length, words,
1519                              &words_offset, pwordexp->we_wordc);
1520
1521         if (error)
1522           goto do_error;
1523
1524         break;
1525
1526       case '*':
1527       case '{':
1528         error = parse_glob (&word, &word_length, &max_length, words,
1529                             &words_offset, flags, pwordexp, ifs);
1530
1531         if (error)
1532           goto do_error;
1533
1534         break;
1535
1536       default:
1537         /* Is it a field separator? */
1538         if (strchr (ifs, words[words_offset]) == NULL)
1539           {
1540             /* "Ordinary" character -- add it to word */
1541
1542             word = w_addchar (word, &word_length, &max_length,
1543                               words[words_offset]);
1544             if (word == NULL)
1545               {
1546                 error = WRDE_NOSPACE;
1547                 goto do_error;
1548               }
1549
1550             break;
1551           }
1552
1553         /* Field separator */
1554         if (strchr (ifs_white, words[words_offset]))
1555           {
1556             /* It's a whitespace IFS char.  Ignore it at the beginning
1557                of a line and ignore multiple instances.  */
1558             if (!word || !*word)
1559               break;
1560
1561             if (w_addword (pwordexp, word) == WRDE_NOSPACE)
1562               {
1563                 error = WRDE_NOSPACE;
1564                 goto do_error;
1565               }
1566
1567             word = NULL;
1568             word_length = 0;
1569             break;
1570           }
1571
1572         /* It's a non-whitespace IFS char */
1573
1574         /* Multiple non-whitespace IFS chars are treated as one;
1575          * IS THIS CORRECT?
1576          */
1577         if (word != NULL)
1578           {
1579             if (w_addword (pwordexp, word) == WRDE_NOSPACE)
1580               {
1581                 error = WRDE_NOSPACE;
1582                 goto do_error;
1583               }
1584           }
1585
1586         word = NULL;
1587         word_length = 0;
1588         max_length = 0;
1589       }
1590
1591   /* End of string */
1592
1593   /* There was a field separator at the end */
1594   if (word == NULL)
1595     return 0;
1596
1597   /* There was no field separator at the end */
1598   return w_addword (pwordexp, word);
1599
1600 do_error:
1601   /* Error:
1602         free memory used, set we_wordc and wd_wordv back to what they were.
1603    */
1604   if (word != NULL)
1605     free (word);
1606
1607   wordfree (pwordexp);
1608   pwordexp->we_wordv = old_wordv;
1609   pwordexp->we_wordc = old_wordc;
1610   return error;
1611 }