Back to index

glibc  2.9
wordexp.c
Go to the documentation of this file.
00001 /* POSIX.2 wordexp implementation.
00002    Copyright (C) 1997-2003, 2005, 2006, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Tim Waugh <tim@cyberelk.demon.co.uk>.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <alloca.h>
00022 #include <ctype.h>
00023 #include <errno.h>
00024 #include <fcntl.h>
00025 #include <fnmatch.h>
00026 #include <glob.h>
00027 #include <libintl.h>
00028 #include <paths.h>
00029 #include <pwd.h>
00030 #include <signal.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <sys/param.h>
00035 #include <sys/stat.h>
00036 #include <sys/time.h>
00037 #include <sys/types.h>
00038 #include <sys/types.h>
00039 #include <sys/wait.h>
00040 #include <unistd.h>
00041 #ifdef USE_IN_LIBIO
00042 # include <wchar.h>
00043 #endif
00044 #include <wordexp.h>
00045 #include <kernel-features.h>
00046 
00047 #include <bits/libc-lock.h>
00048 #include <stdio-common/_itoa.h>
00049 
00050 /* Undefine the following line for the production version.  */
00051 /* #define NDEBUG 1 */
00052 #include <assert.h>
00053 
00054 /* Get some device information.  */
00055 #include <device-nrs.h>
00056 
00057 /*
00058  * This is a recursive-descent-style word expansion routine.
00059  */
00060 
00061 /* These variables are defined and initialized in the startup code.  */
00062 extern int __libc_argc attribute_hidden;
00063 extern char **__libc_argv attribute_hidden;
00064 
00065 /* Some forward declarations */
00066 static int parse_dollars (char **word, size_t *word_length, size_t *max_length,
00067                        const char *words, size_t *offset, int flags,
00068                        wordexp_t *pwordexp, const char *ifs,
00069                        const char *ifs_white, int quoted)
00070      internal_function;
00071 static int parse_backtick (char **word, size_t *word_length,
00072                         size_t *max_length, const char *words,
00073                         size_t *offset, int flags, wordexp_t *pwordexp,
00074                         const char *ifs, const char *ifs_white)
00075      internal_function;
00076 static int parse_dquote (char **word, size_t *word_length, size_t *max_length,
00077                       const char *words, size_t *offset, int flags,
00078                       wordexp_t *pwordexp, const char *ifs,
00079                       const char *ifs_white)
00080      internal_function;
00081 static int eval_expr (char *expr, long int *result) internal_function;
00082 
00083 /* The w_*() functions manipulate word lists. */
00084 
00085 #define W_CHUNK      (100)
00086 
00087 /* Result of w_newword will be ignored if it's the last word. */
00088 static inline char *
00089 w_newword (size_t *actlen, size_t *maxlen)
00090 {
00091   *actlen = *maxlen = 0;
00092   return NULL;
00093 }
00094 
00095 static char *
00096 w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch)
00097      /* (lengths exclude trailing zero) */
00098 {
00099   /* Add a character to the buffer, allocating room for it if needed.  */
00100 
00101   if (*actlen == *maxlen)
00102     {
00103       char *old_buffer = buffer;
00104       assert (buffer == NULL || *maxlen != 0);
00105       *maxlen += W_CHUNK;
00106       buffer = (char *) realloc (buffer, 1 + *maxlen);
00107 
00108       if (buffer == NULL)
00109        free (old_buffer);
00110     }
00111 
00112   if (buffer != NULL)
00113     {
00114       buffer[*actlen] = ch;
00115       buffer[++(*actlen)] = '\0';
00116     }
00117 
00118   return buffer;
00119 }
00120 
00121 static char *
00122 internal_function
00123 w_addmem (char *buffer, size_t *actlen, size_t *maxlen, const char *str,
00124          size_t len)
00125 {
00126   /* Add a string to the buffer, allocating room for it if needed.
00127    */
00128   if (*actlen + len > *maxlen)
00129     {
00130       char *old_buffer = buffer;
00131       assert (buffer == NULL || *maxlen != 0);
00132       *maxlen += MAX (2 * len, W_CHUNK);
00133       buffer = realloc (old_buffer, 1 + *maxlen);
00134 
00135       if (buffer == NULL)
00136        free (old_buffer);
00137     }
00138 
00139   if (buffer != NULL)
00140     {
00141       *((char *) __mempcpy (&buffer[*actlen], str, len)) = '\0';
00142       *actlen += len;
00143     }
00144 
00145   return buffer;
00146 }
00147 
00148 static char *
00149 internal_function
00150 w_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str)
00151      /* (lengths exclude trailing zero) */
00152 {
00153   /* Add a string to the buffer, allocating room for it if needed.
00154    */
00155   size_t len;
00156 
00157   assert (str != NULL); /* w_addstr only called from this file */
00158   len = strlen (str);
00159 
00160   return w_addmem (buffer, actlen, maxlen, str, len);
00161 }
00162 
00163 static int
00164 internal_function
00165 w_addword (wordexp_t *pwordexp, char *word)
00166 {
00167   /* Add a word to the wordlist */
00168   size_t num_p;
00169   char **new_wordv;
00170   bool allocated = false;
00171 
00172   /* Internally, NULL acts like "".  Convert NULLs to "" before
00173    * the caller sees them.
00174    */
00175   if (word == NULL)
00176     {
00177       word = __strdup ("");
00178       if (word == NULL)
00179        goto no_space;
00180       allocated = true;
00181     }
00182 
00183   num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
00184   new_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p);
00185   if (new_wordv != NULL)
00186     {
00187       pwordexp->we_wordv = new_wordv;
00188       pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc++] = word;
00189       pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc] = NULL;
00190       return 0;
00191     }
00192 
00193   if (allocated)
00194     free (word);
00195 
00196 no_space:
00197   return WRDE_NOSPACE;
00198 }
00199 
00200 /* The parse_*() functions should leave *offset being the offset in 'words'
00201  * to the last character processed.
00202  */
00203 
00204 static int
00205 internal_function
00206 parse_backslash (char **word, size_t *word_length, size_t *max_length,
00207                const char *words, size_t *offset)
00208 {
00209   /* We are poised _at_ a backslash, not in quotes */
00210 
00211   switch (words[1 + *offset])
00212     {
00213     case 0:
00214       /* Backslash is last character of input words */
00215       return WRDE_SYNTAX;
00216 
00217     case '\n':
00218       ++(*offset);
00219       break;
00220 
00221     default:
00222       *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
00223       if (*word == NULL)
00224        return WRDE_NOSPACE;
00225 
00226       ++(*offset);
00227       break;
00228     }
00229 
00230   return 0;
00231 }
00232 
00233 static int
00234 internal_function
00235 parse_qtd_backslash (char **word, size_t *word_length, size_t *max_length,
00236                    const char *words, size_t *offset)
00237 {
00238   /* We are poised _at_ a backslash, inside quotes */
00239 
00240   switch (words[1 + *offset])
00241     {
00242     case 0:
00243       /* Backslash is last character of input words */
00244       return WRDE_SYNTAX;
00245 
00246     case '\n':
00247       ++(*offset);
00248       break;
00249 
00250     case '$':
00251     case '`':
00252     case '"':
00253     case '\\':
00254       *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
00255       if (*word == NULL)
00256        return WRDE_NOSPACE;
00257 
00258       ++(*offset);
00259       break;
00260 
00261     default:
00262       *word = w_addchar (*word, word_length, max_length, words[*offset]);
00263       if (*word != NULL)
00264        *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
00265 
00266       if (*word == NULL)
00267        return WRDE_NOSPACE;
00268 
00269       ++(*offset);
00270       break;
00271     }
00272 
00273   return 0;
00274 }
00275 
00276 static int
00277 internal_function
00278 parse_tilde (char **word, size_t *word_length, size_t *max_length,
00279             const char *words, size_t *offset, size_t wordc)
00280 {
00281   /* We are poised _at_ a tilde */
00282   size_t i;
00283 
00284   if (*word_length != 0)
00285     {
00286       if (!((*word)[*word_length - 1] == '=' && wordc == 0))
00287        {
00288          if (!((*word)[*word_length - 1] == ':'
00289               && strchr (*word, '=') && wordc == 0))
00290            {
00291              *word = w_addchar (*word, word_length, max_length, '~');
00292              return *word ? 0 : WRDE_NOSPACE;
00293            }
00294        }
00295     }
00296 
00297   for (i = 1 + *offset; words[i]; i++)
00298     {
00299       if (words[i] == ':' || words[i] == '/' || words[i] == ' ' ||
00300          words[i] == '\t' || words[i] == 0 )
00301        break;
00302 
00303       if (words[i] == '\\')
00304        {
00305          *word = w_addchar (*word, word_length, max_length, '~');
00306          return *word ? 0 : WRDE_NOSPACE;
00307        }
00308     }
00309 
00310   if (i == 1 + *offset)
00311     {
00312       /* Tilde appears on its own */
00313       uid_t uid;
00314       struct passwd pwd, *tpwd;
00315       int buflen = 1000;
00316       char* home;
00317       char* buffer;
00318       int result;
00319 
00320       /* POSIX.2 says ~ expands to $HOME and if HOME is unset the
00321         results are unspecified.  We do a lookup on the uid if
00322         HOME is unset. */
00323 
00324       home = getenv ("HOME");
00325       if (home != NULL)
00326        {
00327          *word = w_addstr (*word, word_length, max_length, home);
00328          if (*word == NULL)
00329            return WRDE_NOSPACE;
00330        }
00331       else
00332        {
00333          uid = __getuid ();
00334          buffer = __alloca (buflen);
00335 
00336          while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
00337                && errno == ERANGE)
00338            buffer = extend_alloca (buffer, buflen, buflen + 1000);
00339 
00340          if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL)
00341            {
00342              *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
00343              if (*word == NULL)
00344               return WRDE_NOSPACE;
00345            }
00346          else
00347            {
00348              *word = w_addchar (*word, word_length, max_length, '~');
00349              if (*word == NULL)
00350               return WRDE_NOSPACE;
00351            }
00352        }
00353     }
00354   else
00355     {
00356       /* Look up user name in database to get home directory */
00357       char *user = strndupa (&words[1 + *offset], i - (1 + *offset));
00358       struct passwd pwd, *tpwd;
00359       int buflen = 1000;
00360       char* buffer = __alloca (buflen);
00361       int result;
00362 
00363       while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
00364             && errno == ERANGE)
00365        buffer = extend_alloca (buffer, buflen, buflen + 1000);
00366 
00367       if (result == 0 && tpwd != NULL && pwd.pw_dir)
00368        *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
00369       else
00370        {
00371          /* (invalid login name) */
00372          *word = w_addchar (*word, word_length, max_length, '~');
00373          if (*word != NULL)
00374            *word = w_addstr (*word, word_length, max_length, user);
00375        }
00376 
00377       *offset = i - 1;
00378     }
00379   return *word ? 0 : WRDE_NOSPACE;
00380 }
00381 
00382 
00383 static int
00384 internal_function
00385 do_parse_glob (const char *glob_word, char **word, size_t *word_length,
00386               size_t *max_length, wordexp_t *pwordexp, const char *ifs,
00387               const char *ifs_white)
00388 {
00389   int error;
00390   unsigned int match;
00391   glob_t globbuf;
00392 
00393   error = glob (glob_word, GLOB_NOCHECK, NULL, &globbuf);
00394 
00395   if (error != 0)
00396     {
00397       /* We can only run into memory problems.  */
00398       assert (error == GLOB_NOSPACE);
00399       return WRDE_NOSPACE;
00400     }
00401 
00402   if (ifs && !*ifs)
00403     {
00404       /* No field splitting allowed. */
00405       assert (globbuf.gl_pathv[0] != NULL);
00406       *word = w_addstr (*word, word_length, max_length, globbuf.gl_pathv[0]);
00407       for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
00408        {
00409          *word = w_addchar (*word, word_length, max_length, ' ');
00410          if (*word != NULL)
00411            *word = w_addstr (*word, word_length, max_length,
00412                            globbuf.gl_pathv[match]);
00413        }
00414 
00415       globfree (&globbuf);
00416       return *word ? 0 : WRDE_NOSPACE;
00417     }
00418 
00419   assert (ifs == NULL || *ifs != '\0');
00420   if (*word != NULL)
00421     {
00422       free (*word);
00423       *word = w_newword (word_length, max_length);
00424     }
00425 
00426   for (match = 0; match < globbuf.gl_pathc; ++match)
00427     {
00428       char *matching_word = __strdup (globbuf.gl_pathv[match]);
00429       if (matching_word == NULL || w_addword (pwordexp, matching_word))
00430        {
00431          globfree (&globbuf);
00432          return WRDE_NOSPACE;
00433        }
00434     }
00435 
00436   globfree (&globbuf);
00437   return 0;
00438 }
00439 
00440 static int
00441 internal_function
00442 parse_glob (char **word, size_t *word_length, size_t *max_length,
00443            const char *words, size_t *offset, int flags,
00444            wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
00445 {
00446   /* We are poised just after a '*', a '[' or a '?'. */
00447   int error = WRDE_NOSPACE;
00448   int quoted = 0; /* 1 if singly-quoted, 2 if doubly */
00449   size_t i;
00450   wordexp_t glob_list; /* List of words to glob */
00451 
00452   glob_list.we_wordc = 0;
00453   glob_list.we_wordv = NULL;
00454   glob_list.we_offs = 0;
00455   for (; words[*offset] != '\0'; ++*offset)
00456     {
00457       if (strchr (ifs, words[*offset]) != NULL)
00458        /* Reached IFS */
00459        break;
00460 
00461       /* Sort out quoting */
00462       if (words[*offset] == '\'')
00463        {
00464          if (quoted == 0)
00465            {
00466              quoted = 1;
00467              continue;
00468            }
00469          else if (quoted == 1)
00470            {
00471              quoted = 0;
00472              continue;
00473            }
00474        }
00475       else if (words[*offset] == '"')
00476        {
00477          if (quoted == 0)
00478            {
00479              quoted = 2;
00480              continue;
00481            }
00482          else if (quoted == 2)
00483            {
00484              quoted = 0;
00485              continue;
00486            }
00487        }
00488 
00489       /* Sort out other special characters */
00490       if (quoted != 1 && words[*offset] == '$')
00491        {
00492          error = parse_dollars (word, word_length, max_length, words,
00493                              offset, flags, &glob_list, ifs, ifs_white,
00494                              quoted == 2);
00495          if (error)
00496            goto tidy_up;
00497 
00498          continue;
00499        }
00500       else if (words[*offset] == '\\')
00501        {
00502          if (quoted)
00503            error = parse_qtd_backslash (word, word_length, max_length,
00504                                     words, offset);
00505          else
00506            error = parse_backslash (word, word_length, max_length,
00507                                  words, offset);
00508 
00509          if (error)
00510            goto tidy_up;
00511 
00512          continue;
00513        }
00514 
00515       *word = w_addchar (*word, word_length, max_length, words[*offset]);
00516       if (*word == NULL)
00517        goto tidy_up;
00518     }
00519 
00520   /* Don't forget to re-parse the character we stopped at. */
00521   --*offset;
00522 
00523   /* Glob the words */
00524   error = w_addword (&glob_list, *word);
00525   *word = w_newword (word_length, max_length);
00526   for (i = 0; error == 0 && i < glob_list.we_wordc; i++)
00527     error = do_parse_glob (glob_list.we_wordv[i], word, word_length,
00528                         max_length, pwordexp, ifs, ifs_white);
00529 
00530   /* Now tidy up */
00531 tidy_up:
00532   wordfree (&glob_list);
00533   return error;
00534 }
00535 
00536 static int
00537 internal_function
00538 parse_squote (char **word, size_t *word_length, size_t *max_length,
00539              const char *words, size_t *offset)
00540 {
00541   /* We are poised just after a single quote */
00542   for (; words[*offset]; ++(*offset))
00543     {
00544       if (words[*offset] != '\'')
00545        {
00546          *word = w_addchar (*word, word_length, max_length, words[*offset]);
00547          if (*word == NULL)
00548            return WRDE_NOSPACE;
00549        }
00550       else return 0;
00551     }
00552 
00553   /* Unterminated string */
00554   return WRDE_SYNTAX;
00555 }
00556 
00557 /* Functions to evaluate an arithmetic expression */
00558 static int
00559 internal_function
00560 eval_expr_val (char **expr, long int *result)
00561 {
00562   char *digit;
00563 
00564   /* Skip white space */
00565   for (digit = *expr; digit && *digit && isspace (*digit); ++digit);
00566 
00567   if (*digit == '(')
00568     {
00569       /* Scan for closing paren */
00570       for (++digit; **expr && **expr != ')'; ++(*expr));
00571 
00572       /* Is there one? */
00573       if (!**expr)
00574        return WRDE_SYNTAX;
00575 
00576       *(*expr)++ = 0;
00577 
00578       if (eval_expr (digit, result))
00579        return WRDE_SYNTAX;
00580 
00581       return 0;
00582     }
00583 
00584   /* POSIX requires that decimal, octal, and hexadecimal constants are
00585      recognized.  Therefore we pass 0 as the third parameter to strtol.  */
00586   *result = strtol (digit, expr, 0);
00587   if (digit == *expr)
00588     return WRDE_SYNTAX;
00589 
00590   return 0;
00591 }
00592 
00593 static int
00594 internal_function
00595 eval_expr_multdiv (char **expr, long int *result)
00596 {
00597   long int arg;
00598 
00599   /* Read a Value */
00600   if (eval_expr_val (expr, result) != 0)
00601     return WRDE_SYNTAX;
00602 
00603   while (**expr)
00604     {
00605       /* Skip white space */
00606       for (; *expr && **expr && isspace (**expr); ++(*expr));
00607 
00608       if (**expr == '*')
00609        {
00610          ++(*expr);
00611          if (eval_expr_val (expr, &arg) != 0)
00612            return WRDE_SYNTAX;
00613 
00614          *result *= arg;
00615        }
00616       else if (**expr == '/')
00617        {
00618          ++(*expr);
00619          if (eval_expr_val (expr, &arg) != 0)
00620            return WRDE_SYNTAX;
00621 
00622          *result /= arg;
00623        }
00624       else break;
00625     }
00626 
00627   return 0;
00628 }
00629 
00630 static int
00631 internal_function
00632 eval_expr (char *expr, long int *result)
00633 {
00634   long int arg;
00635 
00636   /* Read a Multdiv */
00637   if (eval_expr_multdiv (&expr, result) != 0)
00638     return WRDE_SYNTAX;
00639 
00640   while (*expr)
00641     {
00642       /* Skip white space */
00643       for (; expr && *expr && isspace (*expr); ++expr);
00644 
00645       if (*expr == '+')
00646        {
00647          ++expr;
00648          if (eval_expr_multdiv (&expr, &arg) != 0)
00649            return WRDE_SYNTAX;
00650 
00651          *result += arg;
00652        }
00653       else if (*expr == '-')
00654        {
00655          ++expr;
00656          if (eval_expr_multdiv (&expr, &arg) != 0)
00657            return WRDE_SYNTAX;
00658 
00659          *result -= arg;
00660        }
00661       else break;
00662     }
00663 
00664   return 0;
00665 }
00666 
00667 static int
00668 internal_function
00669 parse_arith (char **word, size_t *word_length, size_t *max_length,
00670             const char *words, size_t *offset, int flags, int bracket)
00671 {
00672   /* We are poised just after "$((" or "$[" */
00673   int error;
00674   int paren_depth = 1;
00675   size_t expr_length;
00676   size_t expr_maxlen;
00677   char *expr;
00678 
00679   expr = w_newword (&expr_length, &expr_maxlen);
00680   for (; words[*offset]; ++(*offset))
00681     {
00682       switch (words[*offset])
00683        {
00684        case '$':
00685          error = parse_dollars (&expr, &expr_length, &expr_maxlen,
00686                              words, offset, flags, NULL, NULL, NULL, 1);
00687          /* The ``1'' here is to tell parse_dollars not to
00688           * split the fields.
00689           */
00690          if (error)
00691            {
00692              free (expr);
00693              return error;
00694            }
00695          break;
00696 
00697        case '`':
00698          (*offset)++;
00699          error = parse_backtick (&expr, &expr_length, &expr_maxlen,
00700                               words, offset, flags, NULL, NULL, NULL);
00701          /* The first NULL here is to tell parse_backtick not to
00702           * split the fields.
00703           */
00704          if (error)
00705            {
00706              free (expr);
00707              return error;
00708            }
00709          break;
00710 
00711        case '\\':
00712          error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen,
00713                                    words, offset);
00714          if (error)
00715            {
00716              free (expr);
00717              return error;
00718            }
00719          /* I think that a backslash within an
00720           * arithmetic expansion is bound to
00721           * cause an error sooner or later anyway though.
00722           */
00723          break;
00724 
00725        case ')':
00726          if (--paren_depth == 0)
00727            {
00728              char result[21];      /* 21 = ceil(log10(2^64)) + 1 */
00729              long int numresult = 0;
00730              long long int convertme;
00731 
00732              if (bracket || words[1 + *offset] != ')')
00733               {
00734                 free (expr);
00735                 return WRDE_SYNTAX;
00736               }
00737 
00738              ++(*offset);
00739 
00740              /* Go - evaluate. */
00741              if (*expr && eval_expr (expr, &numresult) != 0)
00742               {
00743                 free (expr);
00744                 return WRDE_SYNTAX;
00745               }
00746 
00747              if (numresult < 0)
00748               {
00749                 convertme = -numresult;
00750                 *word = w_addchar (*word, word_length, max_length, '-');
00751                 if (!*word)
00752                   {
00753                     free (expr);
00754                     return WRDE_NOSPACE;
00755                   }
00756               }
00757              else
00758               convertme = numresult;
00759 
00760              result[20] = '\0';
00761              *word = w_addstr (*word, word_length, max_length,
00762                             _itoa (convertme, &result[20], 10, 0));
00763              free (expr);
00764              return *word ? 0 : WRDE_NOSPACE;
00765            }
00766          expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
00767          if (expr == NULL)
00768            return WRDE_NOSPACE;
00769 
00770          break;
00771 
00772        case ']':
00773          if (bracket && paren_depth == 1)
00774            {
00775              char result[21];      /* 21 = ceil(log10(2^64)) + 1 */
00776              long int numresult = 0;
00777 
00778              /* Go - evaluate. */
00779              if (*expr && eval_expr (expr, &numresult) != 0)
00780               {
00781                 free (expr);
00782                 return WRDE_SYNTAX;
00783               }
00784 
00785              result[20] = '\0';
00786              *word = w_addstr (*word, word_length, max_length,
00787                             _itoa_word (numresult, &result[20], 10, 0));
00788              free (expr);
00789              return *word ? 0 : WRDE_NOSPACE;
00790            }
00791 
00792          free (expr);
00793          return WRDE_SYNTAX;
00794 
00795        case '\n':
00796        case ';':
00797        case '{':
00798        case '}':
00799          free (expr);
00800          return WRDE_BADCHAR;
00801 
00802        case '(':
00803          ++paren_depth;
00804        default:
00805          expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
00806          if (expr == NULL)
00807            return WRDE_NOSPACE;
00808        }
00809     }
00810 
00811   /* Premature end */
00812   free (expr);
00813   return WRDE_SYNTAX;
00814 }
00815 
00816 /* Function called by child process in exec_comm() */
00817 static inline void
00818 internal_function __attribute__ ((always_inline))
00819 exec_comm_child (char *comm, int *fildes, int showerr, int noexec)
00820 {
00821   const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
00822 
00823   /* Execute the command, or just check syntax? */
00824   if (noexec)
00825     args[1] = "-nc";
00826 
00827   /* Redirect output.  */
00828   if (__builtin_expect (fildes[1] != STDOUT_FILENO, 1))
00829     {
00830       __dup2 (fildes[1], STDOUT_FILENO);
00831       __close (fildes[1]);
00832     }
00833   else
00834     {
00835 #ifdef O_CLOEXEC
00836       /* Reset the close-on-exec flag (if necessary).  */
00837 # ifndef __ASSUME_PIPE2
00838       if (__have_pipe2 > 0)
00839 # endif
00840        __fcntl (fildes[1], F_SETFD, 0);
00841 #endif
00842     }
00843 
00844   /* Redirect stderr to /dev/null if we have to.  */
00845   if (showerr == 0)
00846     {
00847       struct stat64 st;
00848       int fd;
00849       __close (STDERR_FILENO);
00850       fd = __open (_PATH_DEVNULL, O_WRONLY);
00851       if (fd >= 0 && fd != STDERR_FILENO)
00852        {
00853          __dup2 (fd, STDERR_FILENO);
00854          __close (fd);
00855        }
00856       /* Be paranoid.  Check that we actually opened the /dev/null
00857          device.  */
00858       if (__builtin_expect (__fxstat64 (_STAT_VER, STDERR_FILENO, &st), 0) != 0
00859          || __builtin_expect (S_ISCHR (st.st_mode), 1) == 0
00860 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
00861          || st.st_rdev != makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
00862 #endif
00863          )
00864        /* It's not the /dev/null device.  Stop right here.  The
00865            problem is: how do we stop?  We use _exit() with an
00866            hopefully unusual exit code.  */
00867        _exit (90);
00868     }
00869 
00870   /* Make sure the subshell doesn't field-split on our behalf. */
00871   __unsetenv ("IFS");
00872 
00873   __close (fildes[0]);
00874   __execve (_PATH_BSHELL, (char *const *) args, __environ);
00875 
00876   /* Bad.  What now?  */
00877   abort ();
00878 }
00879 
00880 /* Function to execute a command and retrieve the results */
00881 /* pwordexp contains NULL if field-splitting is forbidden */
00882 static int
00883 internal_function
00884 exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
00885           int flags, wordexp_t *pwordexp, const char *ifs,
00886           const char *ifs_white)
00887 {
00888   int fildes[2];
00889 #define bufsize 128
00890   int buflen;
00891   int i;
00892   int status = 0;
00893   size_t maxnewlines = 0;
00894   char buffer[bufsize];
00895   pid_t pid;
00896   int noexec = 0;
00897 
00898   /* Don't fork() unless necessary */
00899   if (!comm || !*comm)
00900     return 0;
00901 
00902 #ifdef O_CLOEXEC
00903 # ifndef __ASSUME_PIPE2
00904   if (__have_pipe2 >= 0)
00905 # endif
00906     {
00907       int r = __pipe2 (fildes, O_CLOEXEC);
00908 # ifndef __ASSUME_PIPE2
00909       if (__have_pipe2 == 0)
00910        __have_pipe2 = r != -1 || errno != ENOSYS ? 1 : -1;
00911 
00912       if (__have_pipe2 > 0)
00913 # endif
00914        if (r < 0)
00915          /* Bad */
00916          return WRDE_NOSPACE;
00917     }
00918 #endif
00919 #ifndef __ASSUME_PIPE2
00920 # ifdef O_CLOEXEC
00921   if (__have_pipe2 < 0)
00922 # endif
00923     if (__pipe (fildes) < 0)
00924       /* Bad */
00925       return WRDE_NOSPACE;
00926 #endif
00927 
00928  again:
00929   if ((pid = __fork ()) < 0)
00930     {
00931       /* Bad */
00932       __close (fildes[0]);
00933       __close (fildes[1]);
00934       return WRDE_NOSPACE;
00935     }
00936 
00937   if (pid == 0)
00938     exec_comm_child (comm, fildes, noexec ? 0 : flags & WRDE_SHOWERR, noexec);
00939 
00940   /* Parent */
00941 
00942   /* If we are just testing the syntax, only wait.  */
00943   if (noexec)
00944     return (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) == pid
00945            && status != 0) ? WRDE_SYNTAX : 0;
00946 
00947   __close (fildes[1]);
00948   fildes[1] = -1;
00949 
00950   if (!pwordexp)
00951     /* Quoted - no field splitting */
00952     {
00953       while (1)
00954        {
00955          if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
00956                                               bufsize))) < 1)
00957            {
00958              if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, WNOHANG)) == 0)
00959               continue;
00960              if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
00961                                                  bufsize))) < 1)
00962               break;
00963            }
00964 
00965          maxnewlines += buflen;
00966 
00967          *word = w_addmem (*word, word_length, max_length, buffer, buflen);
00968          if (*word == NULL)
00969            goto no_space;
00970        }
00971     }
00972   else
00973     /* Not quoted - split fields */
00974     {
00975       int copying = 0;
00976       /* 'copying' is:
00977        *  0 when searching for first character in a field not IFS white space
00978        *  1 when copying the text of a field
00979        *  2 when searching for possible non-whitespace IFS
00980        *  3 when searching for non-newline after copying field
00981        */
00982 
00983       while (1)
00984        {
00985          if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
00986                                               bufsize))) < 1)
00987            {
00988              if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, WNOHANG)) == 0)
00989               continue;
00990              if ((buflen = TEMP_FAILURE_RETRY (__read (fildes[0], buffer,
00991                                                  bufsize))) < 1)
00992               break;
00993            }
00994 
00995          for (i = 0; i < buflen; ++i)
00996            {
00997              if (strchr (ifs, buffer[i]) != NULL)
00998               {
00999                 /* Current character is IFS */
01000                 if (strchr (ifs_white, buffer[i]) == NULL)
01001                   {
01002                     /* Current character is IFS but not whitespace */
01003                     if (copying == 2)
01004                      {
01005                        /*            current character
01006                         *                   |
01007                         *                   V
01008                         * eg: text<space><comma><space>moretext
01009                         *
01010                         * So, strip whitespace IFS (like at the start)
01011                         */
01012                        copying = 0;
01013                        continue;
01014                      }
01015 
01016                     copying = 0;
01017                     /* fall through and delimit field.. */
01018                   }
01019                 else
01020                   {
01021                     if (buffer[i] == '\n')
01022                      {
01023                        /* Current character is (IFS) newline */
01024 
01025                        /* If copying a field, this is the end of it,
01026                           but maybe all that's left is trailing newlines.
01027                           So start searching for a non-newline. */
01028                        if (copying == 1)
01029                          copying = 3;
01030 
01031                        continue;
01032                      }
01033                     else
01034                      {
01035                        /* Current character is IFS white space, but
01036                           not a newline */
01037 
01038                        /* If not either copying a field or searching
01039                           for non-newline after a field, ignore it */
01040                        if (copying != 1 && copying != 3)
01041                          continue;
01042 
01043                        /* End of field (search for non-ws IFS afterwards) */
01044                        copying = 2;
01045                      }
01046                   }
01047 
01048                 /* First IFS white space (non-newline), or IFS non-whitespace.
01049                  * Delimit the field.  Nulls are converted by w_addword. */
01050                 if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
01051                   goto no_space;
01052 
01053                 *word = w_newword (word_length, max_length);
01054 
01055                 maxnewlines = 0;
01056                 /* fall back round the loop.. */
01057               }
01058              else
01059               {
01060                 /* Not IFS character */
01061 
01062                 if (copying == 3)
01063                   {
01064                     /* Nothing but (IFS) newlines since the last field,
01065                        so delimit it here before starting new word */
01066                     if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
01067                      goto no_space;
01068 
01069                     *word = w_newword (word_length, max_length);
01070                   }
01071 
01072                 copying = 1;
01073 
01074                 if (buffer[i] == '\n') /* happens if newline not in IFS */
01075                   maxnewlines++;
01076                 else
01077                   maxnewlines = 0;
01078 
01079                 *word = w_addchar (*word, word_length, max_length,
01080                                  buffer[i]);
01081                 if (*word == NULL)
01082                   goto no_space;
01083               }
01084            }
01085        }
01086     }
01087 
01088   /* Chop off trailing newlines (required by POSIX.2)  */
01089   /* Ensure we don't go back further than the beginning of the
01090      substitution (i.e. remove maxnewlines bytes at most) */
01091   while (maxnewlines-- != 0 &&
01092          *word_length > 0 && (*word)[*word_length - 1] == '\n')
01093     {
01094       (*word)[--*word_length] = '\0';
01095 
01096       /* If the last word was entirely newlines, turn it into a new word
01097        * which can be ignored if there's nothing following it. */
01098       if (*word_length == 0)
01099        {
01100          free (*word);
01101          *word = w_newword (word_length, max_length);
01102          break;
01103        }
01104     }
01105 
01106   __close (fildes[0]);
01107   fildes[0] = -1;
01108 
01109   /* Check for syntax error (re-execute but with "-n" flag) */
01110   if (buflen < 1 && status != 0)
01111     {
01112       noexec = 1;
01113       goto again;
01114     }
01115 
01116   return 0;
01117 
01118 no_space:
01119   __kill (pid, SIGKILL);
01120   TEMP_FAILURE_RETRY (__waitpid (pid, NULL, 0));
01121   __close (fildes[0]);
01122   return WRDE_NOSPACE;
01123 }
01124 
01125 static int
01126 internal_function
01127 parse_comm (char **word, size_t *word_length, size_t *max_length,
01128            const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
01129            const char *ifs, const char *ifs_white)
01130 {
01131   /* We are poised just after "$(" */
01132   int paren_depth = 1;
01133   int error = 0;
01134   int quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
01135   size_t comm_length;
01136   size_t comm_maxlen;
01137   char *comm = w_newword (&comm_length, &comm_maxlen);
01138 
01139   for (; words[*offset]; ++(*offset))
01140     {
01141       switch (words[*offset])
01142        {
01143        case '\'':
01144          if (quoted == 0)
01145            quoted = 1;
01146          else if (quoted == 1)
01147            quoted = 0;
01148 
01149          break;
01150 
01151        case '"':
01152          if (quoted == 0)
01153            quoted = 2;
01154          else if (quoted == 2)
01155            quoted = 0;
01156 
01157          break;
01158 
01159        case ')':
01160          if (!quoted && --paren_depth == 0)
01161            {
01162              /* Go -- give script to the shell */
01163              if (comm)
01164               {
01165 #ifdef __libc_ptf_call
01166                 /* We do not want the exec_comm call to be cut short
01167                    by a thread cancellation since cleanup is very
01168                    ugly.  Therefore disable cancellation for
01169                    now.  */
01170                 // XXX Ideally we do want the thread being cancelable.
01171                 // XXX If demand is there we'll change it.
01172                 int state = PTHREAD_CANCEL_ENABLE;
01173                 __libc_ptf_call (pthread_setcancelstate,
01174                                (PTHREAD_CANCEL_DISABLE, &state), 0);
01175 #endif
01176 
01177                 error = exec_comm (comm, word, word_length, max_length,
01178                                  flags, pwordexp, ifs, ifs_white);
01179 
01180 #ifdef __libc_ptf_call
01181                 __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
01182 #endif
01183 
01184                 free (comm);
01185               }
01186 
01187              return error;
01188            }
01189 
01190          /* This is just part of the script */
01191          break;
01192 
01193        case '(':
01194          if (!quoted)
01195            ++paren_depth;
01196        }
01197 
01198       comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
01199       if (comm == NULL)
01200        return WRDE_NOSPACE;
01201     }
01202 
01203   /* Premature end.  */
01204   free (comm);
01205 
01206   return WRDE_SYNTAX;
01207 }
01208 
01209 static int
01210 internal_function
01211 parse_param (char **word, size_t *word_length, size_t *max_length,
01212             const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
01213             const char *ifs, const char *ifs_white, int quoted)
01214 {
01215   /* We are poised just after "$" */
01216   enum action
01217   {
01218     ACT_NONE,
01219     ACT_RP_SHORT_LEFT = '#',
01220     ACT_RP_LONG_LEFT = 'L',
01221     ACT_RP_SHORT_RIGHT = '%',
01222     ACT_RP_LONG_RIGHT = 'R',
01223     ACT_NULL_ERROR = '?',
01224     ACT_NULL_SUBST = '-',
01225     ACT_NONNULL_SUBST = '+',
01226     ACT_NULL_ASSIGN = '='
01227   };
01228   size_t env_length;
01229   size_t env_maxlen;
01230   size_t pat_length;
01231   size_t pat_maxlen;
01232   size_t start = *offset;
01233   char *env;
01234   char *pattern;
01235   char *value = NULL;
01236   enum action action = ACT_NONE;
01237   int depth = 0;
01238   int colon_seen = 0;
01239   int seen_hash = 0;
01240   int free_value = 0;
01241   int pattern_is_quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
01242   int error;
01243   int special = 0;
01244   char buffer[21];
01245   int brace = words[*offset] == '{';
01246 
01247   env = w_newword (&env_length, &env_maxlen);
01248   pattern = w_newword (&pat_length, &pat_maxlen);
01249 
01250   if (brace)
01251     ++*offset;
01252 
01253   /* First collect the parameter name. */
01254 
01255   if (words[*offset] == '#')
01256     {
01257       seen_hash = 1;
01258       if (!brace)
01259        goto envsubst;
01260       ++*offset;
01261     }
01262 
01263   if (isalpha (words[*offset]) || words[*offset] == '_')
01264     {
01265       /* Normal parameter name. */
01266       do
01267        {
01268          env = w_addchar (env, &env_length, &env_maxlen,
01269                         words[*offset]);
01270          if (env == NULL)
01271            goto no_space;
01272        }
01273       while (isalnum (words[++*offset]) || words[*offset] == '_');
01274     }
01275   else if (isdigit (words[*offset]))
01276     {
01277       /* Numeric parameter name. */
01278       special = 1;
01279       do
01280        {
01281          env = w_addchar (env, &env_length, &env_maxlen,
01282                         words[*offset]);
01283          if (env == NULL)
01284            goto no_space;
01285          if (!brace)
01286            goto envsubst;
01287        }
01288       while (isdigit(words[++*offset]));
01289     }
01290   else if (strchr ("*@$", words[*offset]) != NULL)
01291     {
01292       /* Special parameter. */
01293       special = 1;
01294       env = w_addchar (env, &env_length, &env_maxlen,
01295                      words[*offset]);
01296       if (env == NULL)
01297        goto no_space;
01298       ++*offset;
01299     }
01300   else
01301     {
01302       if (brace)
01303        goto syntax;
01304     }
01305 
01306   if (brace)
01307     {
01308       /* Check for special action to be applied to the value. */
01309       switch (words[*offset])
01310        {
01311        case '}':
01312          /* Evaluate. */
01313          goto envsubst;
01314 
01315        case '#':
01316          action = ACT_RP_SHORT_LEFT;
01317          if (words[1 + *offset] == '#')
01318            {
01319              ++*offset;
01320              action = ACT_RP_LONG_LEFT;
01321            }
01322          break;
01323 
01324        case '%':
01325          action = ACT_RP_SHORT_RIGHT;
01326          if (words[1 + *offset] == '%')
01327            {
01328              ++*offset;
01329              action = ACT_RP_LONG_RIGHT;
01330            }
01331          break;
01332 
01333        case ':':
01334          if (strchr ("-=?+", words[1 + *offset]) == NULL)
01335            goto syntax;
01336 
01337          colon_seen = 1;
01338          action = words[++*offset];
01339          break;
01340 
01341        case '-':
01342        case '=':
01343        case '?':
01344        case '+':
01345          action = words[*offset];
01346          break;
01347 
01348        default:
01349          goto syntax;
01350        }
01351 
01352       /* Now collect the pattern, but don't expand it yet. */
01353       ++*offset;
01354       for (; words[*offset]; ++(*offset))
01355        {
01356          switch (words[*offset])
01357            {
01358            case '{':
01359              if (!pattern_is_quoted)
01360               ++depth;
01361              break;
01362 
01363            case '}':
01364              if (!pattern_is_quoted)
01365               {
01366                 if (depth == 0)
01367                   goto envsubst;
01368                 --depth;
01369               }
01370              break;
01371 
01372            case '\\':
01373              if (pattern_is_quoted)
01374               /* Quoted; treat as normal character. */
01375               break;
01376 
01377              /* Otherwise, it's an escape: next character is literal. */
01378              if (words[++*offset] == '\0')
01379               goto syntax;
01380 
01381              pattern = w_addchar (pattern, &pat_length, &pat_maxlen, '\\');
01382              if (pattern == NULL)
01383               goto no_space;
01384 
01385              break;
01386 
01387            case '\'':
01388              if (pattern_is_quoted == 0)
01389               pattern_is_quoted = 1;
01390              else if (pattern_is_quoted == 1)
01391               pattern_is_quoted = 0;
01392 
01393              break;
01394 
01395            case '"':
01396              if (pattern_is_quoted == 0)
01397               pattern_is_quoted = 2;
01398              else if (pattern_is_quoted == 2)
01399               pattern_is_quoted = 0;
01400 
01401              break;
01402            }
01403 
01404          pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
01405                             words[*offset]);
01406          if (pattern == NULL)
01407            goto no_space;
01408        }
01409     }
01410 
01411   /* End of input string -- remember to reparse the character that we
01412    * stopped at.  */
01413   --(*offset);
01414 
01415 envsubst:
01416   if (words[start] == '{' && words[*offset] != '}')
01417     goto syntax;
01418 
01419   if (env == NULL)
01420     {
01421       if (seen_hash)
01422        {
01423          /* $# expands to the number of positional parameters */
01424          buffer[20] = '\0';
01425          value = _itoa_word (__libc_argc - 1, &buffer[20], 10, 0);
01426          seen_hash = 0;
01427        }
01428       else
01429        {
01430          /* Just $ on its own */
01431          *offset = start - 1;
01432          *word = w_addchar (*word, word_length, max_length, '$');
01433          return *word ? 0 : WRDE_NOSPACE;
01434        }
01435     }
01436   /* Is it a numeric parameter? */
01437   else if (isdigit (env[0]))
01438     {
01439       int n = atoi (env);
01440 
01441       if (n >= __libc_argc)
01442        /* Substitute NULL. */
01443        value = NULL;
01444       else
01445        /* Replace with appropriate positional parameter. */
01446        value = __libc_argv[n];
01447     }
01448   /* Is it a special parameter? */
01449   else if (special)
01450     {
01451       /* Is it `$$'? */
01452       if (*env == '$')
01453        {
01454          buffer[20] = '\0';
01455          value = _itoa_word (__getpid (), &buffer[20], 10, 0);
01456        }
01457       /* Is it `${#*}' or `${#@}'? */
01458       else if ((*env == '*' || *env == '@') && seen_hash)
01459        {
01460          buffer[20] = '\0';
01461          value = _itoa_word (__libc_argc > 0 ? __libc_argc - 1 : 0,
01462                            &buffer[20], 10, 0);
01463          *word = w_addstr (*word, word_length, max_length, value);
01464          free (env);
01465          free (pattern);
01466          return *word ? 0 : WRDE_NOSPACE;
01467        }
01468       /* Is it `$*' or `$@' (unquoted) ? */
01469       else if (*env == '*' || (*env == '@' && !quoted))
01470        {
01471          size_t plist_len = 0;
01472          int p;
01473          char *end;
01474 
01475          /* Build up value parameter by parameter (copy them) */
01476          for (p = 1; __libc_argv[p]; ++p)
01477            plist_len += strlen (__libc_argv[p]) + 1; /* for space */
01478          value = malloc (plist_len);
01479          if (value == NULL)
01480            goto no_space;
01481          end = value;
01482          *end = 0;
01483          for (p = 1; __libc_argv[p]; ++p)
01484            {
01485              if (p > 1)
01486               *end++ = ' ';
01487              end = __stpcpy (end, __libc_argv[p]);
01488            }
01489 
01490          free_value = 1;
01491        }
01492       else
01493        {
01494          /* Must be a quoted `$@' */
01495          assert (*env == '@' && quoted);
01496 
01497          /* Each parameter is a separate word ("$@") */
01498          if (__libc_argc == 2)
01499            value = __libc_argv[1];
01500          else if (__libc_argc > 2)
01501            {
01502              int p;
01503 
01504              /* Append first parameter to current word. */
01505              value = w_addstr (*word, word_length, max_length,
01506                             __libc_argv[1]);
01507              if (value == NULL || w_addword (pwordexp, value))
01508               goto no_space;
01509 
01510              for (p = 2; __libc_argv[p + 1]; p++)
01511               {
01512                 char *newword = __strdup (__libc_argv[p]);
01513                 if (newword == NULL || w_addword (pwordexp, newword))
01514                   goto no_space;
01515               }
01516 
01517              /* Start a new word with the last parameter. */
01518              *word = w_newword (word_length, max_length);
01519              value = __libc_argv[p];
01520            }
01521          else
01522            {
01523              free (env);
01524              free (pattern);
01525              return 0;
01526            }
01527        }
01528     }
01529   else
01530     value = getenv (env);
01531 
01532   if (value == NULL && (flags & WRDE_UNDEF))
01533     {
01534       /* Variable not defined. */
01535       error = WRDE_BADVAL;
01536       goto do_error;
01537     }
01538 
01539   if (action != ACT_NONE)
01540     {
01541       int expand_pattern = 0;
01542 
01543       /* First, find out if we need to expand pattern (i.e. if we will
01544        * use it). */
01545       switch (action)
01546        {
01547        case ACT_RP_SHORT_LEFT:
01548        case ACT_RP_LONG_LEFT:
01549        case ACT_RP_SHORT_RIGHT:
01550        case ACT_RP_LONG_RIGHT:
01551          /* Always expand for these. */
01552          expand_pattern = 1;
01553          break;
01554 
01555        case ACT_NULL_ERROR:
01556        case ACT_NULL_SUBST:
01557        case ACT_NULL_ASSIGN:
01558          if (!value || (!*value && colon_seen))
01559            /* If param is unset, or set but null and a colon has been seen,
01560               the expansion of the pattern will be needed. */
01561            expand_pattern = 1;
01562 
01563          break;
01564 
01565        case ACT_NONNULL_SUBST:
01566          /* Expansion of word will be needed if parameter is set and not null,
01567             or set null but no colon has been seen. */
01568          if (value && (*value || !colon_seen))
01569            expand_pattern = 1;
01570 
01571          break;
01572 
01573        default:
01574          assert (! "Unrecognised action!");
01575        }
01576 
01577       if (expand_pattern)
01578        {
01579          /* We need to perform tilde expansion, parameter expansion,
01580              command substitution, and arithmetic expansion.  We also
01581             have to be a bit careful with wildcard characters, as
01582             pattern might be given to fnmatch soon.  To do this, we
01583             convert quotes to escapes. */
01584 
01585          char *expanded;
01586          size_t exp_len;
01587          size_t exp_maxl;
01588          char *p;
01589          int quoted = 0; /* 1: single quotes; 2: double */
01590 
01591          expanded = w_newword (&exp_len, &exp_maxl);
01592          for (p = pattern; p && *p; p++)
01593            {
01594              size_t offset;
01595 
01596              switch (*p)
01597               {
01598               case '"':
01599                 if (quoted == 2)
01600                   quoted = 0;
01601                 else if (quoted == 0)
01602                   quoted = 2;
01603                 else break;
01604 
01605                 continue;
01606 
01607               case '\'':
01608                 if (quoted == 1)
01609                   quoted = 0;
01610                 else if (quoted == 0)
01611                   quoted = 1;
01612                 else break;
01613 
01614                 continue;
01615 
01616               case '*':
01617               case '?':
01618                 if (quoted)
01619                   {
01620                     /* Convert quoted wildchar to escaped wildchar. */
01621                     expanded = w_addchar (expanded, &exp_len,
01622                                        &exp_maxl, '\\');
01623 
01624                     if (expanded == NULL)
01625                      goto no_space;
01626                   }
01627                 break;
01628 
01629               case '$':
01630                 offset = 0;
01631                 error = parse_dollars (&expanded, &exp_len, &exp_maxl, p,
01632                                     &offset, flags, NULL, NULL, NULL, 1);
01633                 if (error)
01634                   {
01635                     if (free_value)
01636                      free (value);
01637 
01638                     free (expanded);
01639 
01640                     goto do_error;
01641                   }
01642 
01643                 p += offset;
01644                 continue;
01645 
01646               case '~':
01647                 if (quoted || exp_len)
01648                   break;
01649 
01650                 offset = 0;
01651                 error = parse_tilde (&expanded, &exp_len, &exp_maxl, p,
01652                                    &offset, 0);
01653                 if (error)
01654                   {
01655                     if (free_value)
01656                      free (value);
01657 
01658                     free (expanded);
01659 
01660                     goto do_error;
01661                   }
01662 
01663                 p += offset;
01664                 continue;
01665 
01666               case '\\':
01667                 expanded = w_addchar (expanded, &exp_len, &exp_maxl, '\\');
01668                 ++p;
01669                 assert (*p); /* checked when extracted initially */
01670                 if (expanded == NULL)
01671                   goto no_space;
01672               }
01673 
01674              expanded = w_addchar (expanded, &exp_len, &exp_maxl, *p);
01675 
01676              if (expanded == NULL)
01677               goto no_space;
01678            }
01679 
01680          free (pattern);
01681 
01682          pattern = expanded;
01683        }
01684 
01685       switch (action)
01686        {
01687        case ACT_RP_SHORT_LEFT:
01688        case ACT_RP_LONG_LEFT:
01689        case ACT_RP_SHORT_RIGHT:
01690        case ACT_RP_LONG_RIGHT:
01691          {
01692            char *p;
01693            char c;
01694            char *end;
01695 
01696            if (value == NULL || pattern == NULL || *pattern == '\0')
01697              break;
01698 
01699            end = value + strlen (value);
01700 
01701            switch (action)
01702              {
01703              case ACT_RP_SHORT_LEFT:
01704               for (p = value; p <= end; ++p)
01705                 {
01706                   c = *p;
01707                   *p = '\0';
01708                   if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
01709                     {
01710                      *p = c;
01711                      if (free_value)
01712                        {
01713                          char *newval = __strdup (p);
01714                          if (newval == NULL)
01715                            {
01716                             free (value);
01717                             goto no_space;
01718                            }
01719                          free (value);
01720                          value = newval;
01721                        }
01722                      else
01723                        value = p;
01724                      break;
01725                     }
01726                   *p = c;
01727                 }
01728 
01729               break;
01730 
01731              case ACT_RP_LONG_LEFT:
01732               for (p = end; p >= value; --p)
01733                 {
01734                   c = *p;
01735                   *p = '\0';
01736                   if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
01737                     {
01738                      *p = c;
01739                      if (free_value)
01740                        {
01741                          char *newval = __strdup (p);
01742                          if (newval == NULL)
01743                            {
01744                             free (value);
01745                             goto no_space;
01746                            }
01747                          free (value);
01748                          value = newval;
01749                        }
01750                      else
01751                        value = p;
01752                      break;
01753                     }
01754                   *p = c;
01755                 }
01756 
01757               break;
01758 
01759              case ACT_RP_SHORT_RIGHT:
01760               for (p = end; p >= value; --p)
01761                 {
01762                   if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
01763                     {
01764                      char *newval;
01765                      newval = malloc (p - value + 1);
01766 
01767                      if (newval == NULL)
01768                        {
01769                          if (free_value)
01770                            free (value);
01771                          goto no_space;
01772                        }
01773 
01774                      *(char *) __mempcpy (newval, value, p - value) = '\0';
01775                      if (free_value)
01776                        free (value);
01777                      value = newval;
01778                      free_value = 1;
01779                      break;
01780                     }
01781                 }
01782 
01783               break;
01784 
01785              case ACT_RP_LONG_RIGHT:
01786               for (p = value; p <= end; ++p)
01787                 {
01788                   if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
01789                     {
01790                      char *newval;
01791                      newval = malloc (p - value + 1);
01792 
01793                      if (newval == NULL)
01794                        {
01795                          if (free_value)
01796                            free (value);
01797                          goto no_space;
01798                        }
01799 
01800                      *(char *) __mempcpy (newval, value, p - value) = '\0';
01801                      if (free_value)
01802                        free (value);
01803                      value = newval;
01804                      free_value = 1;
01805                      break;
01806                     }
01807                 }
01808 
01809               break;
01810 
01811              default:
01812               break;
01813              }
01814 
01815            break;
01816          }
01817 
01818        case ACT_NULL_ERROR:
01819          if (value && *value)
01820            /* Substitute parameter */
01821            break;
01822 
01823          error = 0;
01824          if (!colon_seen && value)
01825            /* Substitute NULL */
01826            ;
01827          else
01828            {
01829              const char *str = pattern;
01830 
01831              if (str[0] == '\0')
01832               str = _("parameter null or not set");
01833 
01834              __fxprintf (NULL, "%s: %s\n", env, str);
01835            }
01836 
01837          if (free_value)
01838            free (value);
01839          goto do_error;
01840 
01841        case ACT_NULL_SUBST:
01842          if (value && *value)
01843            /* Substitute parameter */
01844            break;
01845 
01846          if (free_value)
01847            free (value);
01848 
01849          if (!colon_seen && value)
01850            /* Substitute NULL */
01851            goto success;
01852 
01853          value = pattern ? __strdup (pattern) : pattern;
01854          free_value = 1;
01855 
01856          if (pattern && !value)
01857            goto no_space;
01858 
01859          break;
01860 
01861        case ACT_NONNULL_SUBST:
01862          if (value && (*value || !colon_seen))
01863            {
01864              if (free_value)
01865               free (value);
01866 
01867              value = pattern ? __strdup (pattern) : pattern;
01868              free_value = 1;
01869 
01870              if (pattern && !value)
01871               goto no_space;
01872 
01873              break;
01874            }
01875 
01876          /* Substitute NULL */
01877          if (free_value)
01878            free (value);
01879          goto success;
01880 
01881        case ACT_NULL_ASSIGN:
01882          if (value && *value)
01883            /* Substitute parameter */
01884            break;
01885 
01886          if (!colon_seen && value)
01887            {
01888              /* Substitute NULL */
01889              if (free_value)
01890               free (value);
01891              goto success;
01892            }
01893 
01894          if (free_value)
01895            free (value);
01896 
01897          value = pattern ? __strdup (pattern) : pattern;
01898          free_value = 1;
01899 
01900          if (pattern && !value)
01901            goto no_space;
01902 
01903          __setenv (env, value, 1);
01904          break;
01905 
01906        default:
01907          assert (! "Unrecognised action!");
01908        }
01909     }
01910 
01911   free (env);
01912   env = NULL;
01913   free (pattern);
01914   pattern = NULL;
01915 
01916   if (seen_hash)
01917     {
01918       char param_length[21];
01919       param_length[20] = '\0';
01920       *word = w_addstr (*word, word_length, max_length,
01921                      _itoa_word (value ? strlen (value) : 0,
01922                                 &param_length[20], 10, 0));
01923       if (free_value)
01924        {
01925          assert (value != NULL);
01926          free (value);
01927        }
01928 
01929       return *word ? 0 : WRDE_NOSPACE;
01930     }
01931 
01932   if (value == NULL)
01933     return 0;
01934 
01935   if (quoted || !pwordexp)
01936     {
01937       /* Quoted - no field split */
01938       *word = w_addstr (*word, word_length, max_length, value);
01939       if (free_value)
01940        free (value);
01941 
01942       return *word ? 0 : WRDE_NOSPACE;
01943     }
01944   else
01945     {
01946       /* Need to field-split */
01947       char *value_copy = __strdup (value); /* Don't modify value */
01948       char *field_begin = value_copy;
01949       int seen_nonws_ifs = 0;
01950 
01951       if (free_value)
01952        free (value);
01953 
01954       if (value_copy == NULL)
01955        goto no_space;
01956 
01957       do
01958        {
01959          char *field_end = field_begin;
01960          char *next_field;
01961 
01962          /* If this isn't the first field, start a new word */
01963          if (field_begin != value_copy)
01964            {
01965              if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
01966               {
01967                 free (value_copy);
01968                 goto no_space;
01969               }
01970 
01971              *word = w_newword (word_length, max_length);
01972            }
01973 
01974          /* Skip IFS whitespace before the field */
01975          field_begin += strspn (field_begin, ifs_white);
01976 
01977          if (!seen_nonws_ifs && *field_begin == 0)
01978            /* Nothing but whitespace */
01979            break;
01980 
01981          /* Search for the end of the field */
01982          field_end = field_begin + strcspn (field_begin, ifs);
01983 
01984          /* Set up pointer to the character after end of field and
01985              skip whitespace IFS after it. */
01986          next_field = field_end + strspn (field_end, ifs_white);
01987 
01988          /* Skip at most one non-whitespace IFS character after the field */
01989          seen_nonws_ifs = 0;
01990          if (*next_field && strchr (ifs, *next_field))
01991            {
01992              seen_nonws_ifs = 1;
01993              next_field++;
01994            }
01995 
01996          /* Null-terminate it */
01997          *field_end = 0;
01998 
01999          /* Tag a copy onto the current word */
02000          *word = w_addstr (*word, word_length, max_length, field_begin);
02001 
02002          if (*word == NULL && *field_begin != '\0')
02003            {
02004              free (value_copy);
02005              goto no_space;
02006            }
02007 
02008          field_begin = next_field;
02009        }
02010       while (seen_nonws_ifs || *field_begin);
02011 
02012       free (value_copy);
02013     }
02014 
02015   return 0;
02016 
02017 success:
02018   error = 0;
02019   goto do_error;
02020 
02021 no_space:
02022   error = WRDE_NOSPACE;
02023   goto do_error;
02024 
02025 syntax:
02026   error = WRDE_SYNTAX;
02027 
02028 do_error:
02029   free (env);
02030 
02031   free (pattern);
02032 
02033   return error;
02034 }
02035 
02036 static int
02037 internal_function
02038 parse_dollars (char **word, size_t *word_length, size_t *max_length,
02039               const char *words, size_t *offset, int flags,
02040               wordexp_t *pwordexp, const char *ifs, const char *ifs_white,
02041               int quoted)
02042 {
02043   /* We are poised _at_ "$" */
02044   switch (words[1 + *offset])
02045     {
02046     case '"':
02047     case '\'':
02048     case 0:
02049       *word = w_addchar (*word, word_length, max_length, '$');
02050       return *word ? 0 : WRDE_NOSPACE;
02051 
02052     case '(':
02053       if (words[2 + *offset] == '(')
02054        {
02055          /* Differentiate between $((1+3)) and $((echo);(ls)) */
02056          int i = 3 + *offset;
02057          int depth = 0;
02058          while (words[i] && !(depth == 0 && words[i] == ')'))
02059            {
02060              if (words[i] == '(')
02061               ++depth;
02062              else if (words[i] == ')')
02063               --depth;
02064 
02065              ++i;
02066            }
02067 
02068          if (words[i] == ')' && words[i + 1] == ')')
02069            {
02070              (*offset) += 3;
02071              /* Call parse_arith -- 0 is for "no brackets" */
02072              return parse_arith (word, word_length, max_length, words, offset,
02073                               flags, 0);
02074            }
02075        }
02076 
02077       if (flags & WRDE_NOCMD)
02078        return WRDE_CMDSUB;
02079 
02080       (*offset) += 2;
02081       return parse_comm (word, word_length, max_length, words, offset, flags,
02082                       quoted? NULL : pwordexp, ifs, ifs_white);
02083 
02084     case '[':
02085       (*offset) += 2;
02086       /* Call parse_arith -- 1 is for "brackets" */
02087       return parse_arith (word, word_length, max_length, words, offset, flags,
02088                        1);
02089 
02090     case '{':
02091     default:
02092       ++(*offset);   /* parse_param needs to know if "{" is there */
02093       return parse_param (word, word_length, max_length, words, offset, flags,
02094                         pwordexp, ifs, ifs_white, quoted);
02095     }
02096 }
02097 
02098 static int
02099 internal_function
02100 parse_backtick (char **word, size_t *word_length, size_t *max_length,
02101               const char *words, size_t *offset, int flags,
02102               wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
02103 {
02104   /* We are poised just after "`" */
02105   int error;
02106   int squoting = 0;
02107   size_t comm_length;
02108   size_t comm_maxlen;
02109   char *comm = w_newword (&comm_length, &comm_maxlen);
02110 
02111   for (; words[*offset]; ++(*offset))
02112     {
02113       switch (words[*offset])
02114        {
02115        case '`':
02116          /* Go -- give the script to the shell */
02117          error = exec_comm (comm, word, word_length, max_length, flags,
02118                           pwordexp, ifs, ifs_white);
02119          free (comm);
02120          return error;
02121 
02122        case '\\':
02123          if (squoting)
02124            {
02125              error = parse_qtd_backslash (&comm, &comm_length, &comm_maxlen,
02126                                       words, offset);
02127 
02128              if (error)
02129               {
02130                 free (comm);
02131                 return error;
02132               }
02133 
02134              break;
02135            }
02136 
02137          ++(*offset);
02138          error = parse_backslash (&comm, &comm_length, &comm_maxlen, words,
02139                                offset);
02140 
02141          if (error)
02142            {
02143              free (comm);
02144              return error;
02145            }
02146 
02147          break;
02148 
02149        case '\'':
02150          squoting = 1 - squoting;
02151        default:
02152          comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
02153          if (comm == NULL)
02154            return WRDE_NOSPACE;
02155        }
02156     }
02157 
02158   /* Premature end */
02159   free (comm);
02160   return WRDE_SYNTAX;
02161 }
02162 
02163 static int
02164 internal_function
02165 parse_dquote (char **word, size_t *word_length, size_t *max_length,
02166              const char *words, size_t *offset, int flags,
02167              wordexp_t *pwordexp, const char * ifs, const char * ifs_white)
02168 {
02169   /* We are poised just after a double-quote */
02170   int error;
02171 
02172   for (; words[*offset]; ++(*offset))
02173     {
02174       switch (words[*offset])
02175        {
02176        case '"':
02177          return 0;
02178 
02179        case '$':
02180          error = parse_dollars (word, word_length, max_length, words, offset,
02181                              flags, pwordexp, ifs, ifs_white, 1);
02182          /* The ``1'' here is to tell parse_dollars not to
02183           * split the fields.  It may need to, however ("$@").
02184           */
02185          if (error)
02186            return error;
02187 
02188          break;
02189 
02190        case '`':
02191          if (flags & WRDE_NOCMD)
02192            return WRDE_CMDSUB;
02193 
02194          ++(*offset);
02195          error = parse_backtick (word, word_length, max_length, words,
02196                               offset, flags, NULL, NULL, NULL);
02197          /* The first NULL here is to tell parse_backtick not to
02198           * split the fields.
02199           */
02200          if (error)
02201            return error;
02202 
02203          break;
02204 
02205        case '\\':
02206          error = parse_qtd_backslash (word, word_length, max_length, words,
02207                                    offset);
02208 
02209          if (error)
02210            return error;
02211 
02212          break;
02213 
02214        default:
02215          *word = w_addchar (*word, word_length, max_length, words[*offset]);
02216          if (*word == NULL)
02217            return WRDE_NOSPACE;
02218        }
02219     }
02220 
02221   /* Unterminated string */
02222   return WRDE_SYNTAX;
02223 }
02224 
02225 /*
02226  * wordfree() is to be called after pwordexp is finished with.
02227  */
02228 
02229 void
02230 wordfree (wordexp_t *pwordexp)
02231 {
02232 
02233   /* wordexp can set pwordexp to NULL */
02234   if (pwordexp && pwordexp->we_wordv)
02235     {
02236       char **wordv = pwordexp->we_wordv;
02237 
02238       for (wordv += pwordexp->we_offs; *wordv; ++wordv)
02239        free (*wordv);
02240 
02241       free (pwordexp->we_wordv);
02242       pwordexp->we_wordv = NULL;
02243     }
02244 }
02245 libc_hidden_def (wordfree)
02246 
02247 /*
02248  * wordexp()
02249  */
02250 
02251 int
02252 wordexp (const char *words, wordexp_t *pwordexp, int flags)
02253 {
02254   size_t words_offset;
02255   size_t word_length;
02256   size_t max_length;
02257   char *word = w_newword (&word_length, &max_length);
02258   int error;
02259   char *ifs;
02260   char ifs_white[4];
02261   wordexp_t old_word = *pwordexp;
02262 
02263   if (flags & WRDE_REUSE)
02264     {
02265       /* Minimal implementation of WRDE_REUSE for now */
02266       wordfree (pwordexp);
02267       old_word.we_wordv = NULL;
02268     }
02269 
02270   if ((flags & WRDE_APPEND) == 0)
02271     {
02272       pwordexp->we_wordc = 0;
02273 
02274       if (flags & WRDE_DOOFFS)
02275        {
02276          pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
02277          if (pwordexp->we_wordv == NULL)
02278            {
02279              error = WRDE_NOSPACE;
02280              goto do_error;
02281            }
02282        }
02283       else
02284        {
02285          pwordexp->we_wordv = calloc (1, sizeof (char *));
02286          if (pwordexp->we_wordv == NULL)
02287            {
02288              error = WRDE_NOSPACE;
02289              goto do_error;
02290            }
02291 
02292          pwordexp->we_offs = 0;
02293        }
02294     }
02295 
02296   /* Find out what the field separators are.
02297    * There are two types: whitespace and non-whitespace.
02298    */
02299   ifs = getenv ("IFS");
02300 
02301   if (ifs == NULL)
02302     /* IFS unset - use <space><tab><newline>. */
02303     ifs = strcpy (ifs_white, " \t\n");
02304   else
02305     {
02306       char *ifsch = ifs;
02307       char *whch = ifs_white;
02308 
02309       while (*ifsch != '\0')
02310        {
02311          if (*ifsch == ' ' || *ifsch == '\t' || *ifsch == '\n')
02312            {
02313              /* Whitespace IFS.  See first whether it is already in our
02314                collection.  */
02315              char *runp = ifs_white;
02316 
02317              while (runp < whch && *runp != *ifsch)
02318               ++runp;
02319 
02320              if (runp == whch)
02321               *whch++ = *ifsch;
02322            }
02323 
02324          ++ifsch;
02325        }
02326       *whch = '\0';
02327     }
02328 
02329   for (words_offset = 0 ; words[words_offset] ; ++words_offset)
02330     switch (words[words_offset])
02331       {
02332       case '\\':
02333        error = parse_backslash (&word, &word_length, &max_length, words,
02334                              &words_offset);
02335 
02336        if (error)
02337          goto do_error;
02338 
02339        break;
02340 
02341       case '$':
02342        error = parse_dollars (&word, &word_length, &max_length, words,
02343                             &words_offset, flags, pwordexp, ifs, ifs_white,
02344                             0);
02345 
02346        if (error)
02347          goto do_error;
02348 
02349        break;
02350 
02351       case '`':
02352        if (flags & WRDE_NOCMD)
02353          {
02354            error = WRDE_CMDSUB;
02355            goto do_error;
02356          }
02357 
02358        ++words_offset;
02359        error = parse_backtick (&word, &word_length, &max_length, words,
02360                             &words_offset, flags, pwordexp, ifs,
02361                             ifs_white);
02362 
02363        if (error)
02364          goto do_error;
02365 
02366        break;
02367 
02368       case '"':
02369        ++words_offset;
02370        error = parse_dquote (&word, &word_length, &max_length, words,
02371                            &words_offset, flags, pwordexp, ifs, ifs_white);
02372 
02373        if (error)
02374          goto do_error;
02375 
02376        if (!word_length)
02377          {
02378            error = w_addword (pwordexp, NULL);
02379 
02380            if (error)
02381              return error;
02382          }
02383 
02384        break;
02385 
02386       case '\'':
02387        ++words_offset;
02388        error = parse_squote (&word, &word_length, &max_length, words,
02389                            &words_offset);
02390 
02391        if (error)
02392          goto do_error;
02393 
02394        if (!word_length)
02395          {
02396            error = w_addword (pwordexp, NULL);
02397 
02398            if (error)
02399              return error;
02400          }
02401 
02402        break;
02403 
02404       case '~':
02405        error = parse_tilde (&word, &word_length, &max_length, words,
02406                           &words_offset, pwordexp->we_wordc);
02407 
02408        if (error)
02409          goto do_error;
02410 
02411        break;
02412 
02413       case '*':
02414       case '[':
02415       case '?':
02416        error = parse_glob (&word, &word_length, &max_length, words,
02417                          &words_offset, flags, pwordexp, ifs, ifs_white);
02418 
02419        if (error)
02420          goto do_error;
02421 
02422        break;
02423 
02424       default:
02425        /* Is it a word separator? */
02426        if (strchr (" \t", words[words_offset]) == NULL)
02427          {
02428            char ch = words[words_offset];
02429 
02430            /* Not a word separator -- but is it a valid word char? */
02431            if (strchr ("\n|&;<>(){}", ch))
02432              {
02433               /* Fail */
02434               error = WRDE_BADCHAR;
02435               goto do_error;
02436              }
02437 
02438            /* "Ordinary" character -- add it to word */
02439            word = w_addchar (word, &word_length, &max_length,
02440                            ch);
02441            if (word == NULL)
02442              {
02443               error = WRDE_NOSPACE;
02444               goto do_error;
02445              }
02446 
02447            break;
02448          }
02449 
02450        /* If a word has been delimited, add it to the list. */
02451        if (word != NULL)
02452          {
02453            error = w_addword (pwordexp, word);
02454            if (error)
02455              goto do_error;
02456          }
02457 
02458        word = w_newword (&word_length, &max_length);
02459       }
02460 
02461   /* End of string */
02462 
02463   /* There was a word separator at the end */
02464   if (word == NULL) /* i.e. w_newword */
02465     return 0;
02466 
02467   /* There was no field separator at the end */
02468   return w_addword (pwordexp, word);
02469 
02470 do_error:
02471   /* Error:
02472    *   free memory used (unless error is WRDE_NOSPACE), and
02473    *   set pwordexp members back to what they were.
02474    */
02475 
02476   free (word);
02477 
02478   if (error == WRDE_NOSPACE)
02479     return WRDE_NOSPACE;
02480 
02481   if ((flags & WRDE_APPEND) == 0)
02482     wordfree (pwordexp);
02483 
02484   *pwordexp = old_word;
02485   return error;
02486 }