OSDN Git Service

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