OSDN Git Service

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