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