diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-03-13 06:37:21 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-03-13 06:37:21 +0000 |
commit | b740cfc90a273243618ffce714bc0fbe2f61a082 (patch) | |
tree | 0444cf026af420960c6dcde4544d7c6a80f0eef6 /libc/misc | |
parent | 485ed9315e18b58ba686c3eb9e8c285c549dc98a (diff) |
Delete wordexp. There isn't much point in having this since
so few apps use it, and it is just a stub anyways. Better
to just skip it.
Diffstat (limited to 'libc/misc')
-rw-r--r-- | libc/misc/Makefile | 2 | ||||
-rw-r--r-- | libc/misc/wordexp/Makefile | 45 | ||||
-rw-r--r-- | libc/misc/wordexp/wordexp.c | 2411 | ||||
-rw-r--r-- | libc/misc/wordexp/wordexp_stub.c | 252 |
4 files changed, 1 insertions, 2709 deletions
diff --git a/libc/misc/Makefile b/libc/misc/Makefile index 86a574104..fcaf6b473 100644 --- a/libc/misc/Makefile +++ b/libc/misc/Makefile @@ -26,7 +26,7 @@ LIBC=$(TOPDIR)libc.a DIRS = assert crypt ctype fnmatch glob internals lsearch mntent syslog shm \ - time utmp tsearch wordexp + time utmp tsearch # regex bombs out with an internal compiler error using m68k-pic-coff-gcc. ifneq ($(TARGET_ARCH),m68k) diff --git a/libc/misc/wordexp/Makefile b/libc/misc/wordexp/Makefile deleted file mode 100644 index 731dc919b..000000000 --- a/libc/misc/wordexp/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# Makefile for uClibc -# -# Copyright (C) 2000 by Lineo, inc. -# -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU Library General Public License as published by the Free -# Software Foundation; either version 2 of the License, or (at your option) any -# later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more -# details. -# -# You should have received a copy of the GNU Library General Public License -# along with this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Derived in part from the Linux-8086 C library, the GNU C Library, and several -# other sundry sources. Files within this library are copyright by their -# respective copyright holders. - -TOPDIR=../../ -include $(TOPDIR)Rules.mak -LIBC=$(TOPDIR)libc.a - -#CSRC=wordexp.c -CSRC=wordexp_stub.c -COBJS=$(patsubst %.c,%.o, $(CSRC)) -OBJS=$(COBJS) - -all: $(OBJS) $(LIBC) - -$(LIBC): ar-target - -ar-target: $(OBJS) - $(AR) $(ARFLAGS) $(LIBC) $(OBJS) - -$(COBJS): %.o : %.c - $(CC) $(CFLAGS) -c $< -o $@ - $(STRIPTOOL) -x -R .note -R .comment $*.o - -clean: - rm -f *.[oa] *~ core - diff --git a/libc/misc/wordexp/wordexp.c b/libc/misc/wordexp/wordexp.c deleted file mode 100644 index 9e468d6a5..000000000 --- a/libc/misc/wordexp/wordexp.c +++ /dev/null @@ -1,2411 +0,0 @@ -/* POSIX.2 wordexp implementation. - Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Tim Waugh <tim@cyberelk.demon.co.uk>. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#include <wordexp.h> -#include <signal.h> -#include <stdlib.h> -#include <pwd.h> -#include <sys/types.h> -#include <string.h> -#include <glob.h> -#include <ctype.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <paths.h> -#include <errno.h> -#include <sys/param.h> -#include <stdio.h> -#include <fnmatch.h> - -/* Undefine the following line for the production version. */ -/* #define NDEBUG 1 */ -#include <assert.h> - -/* - * This is a recursive-descent-style word expansion routine. - */ - -/* These variables are defined and initialized in the startup code. */ -extern int __libc_argc; -extern char **__libc_argv; - -/* Some forward declarations */ -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); -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); -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); -static int eval_expr (char *expr, long int *result); - -/* The w_*() functions manipulate word lists. */ - -#define W_CHUNK (100) - -/* Result of w_newword will be ignored if it's the last word. */ -static inline char * -w_newword (size_t *actlen, size_t *maxlen) -{ - *actlen = *maxlen = 0; - return NULL; -} - -static inline char * -w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch) - /* (lengths exclude trailing zero) */ -{ - /* Add a character to the buffer, allocating room for it if needed. - */ - - if (*actlen == *maxlen) - { - char *old_buffer = buffer; - assert (buffer == NULL || *maxlen != 0); - *maxlen += W_CHUNK; - buffer = realloc (buffer, 1 + *maxlen); - - if (buffer == NULL) - free (old_buffer); - } - - if (buffer != NULL) - { - buffer[*actlen] = ch; - buffer[++(*actlen)] = '\0'; - } - - return buffer; -} - -static char * -w_addmem (char *buffer, size_t *actlen, size_t *maxlen, const char *str, - size_t len) -{ - /* Add a string to the buffer, allocating room for it if needed. - */ - if (*actlen + len > *maxlen) - { - char *old_buffer = buffer; - assert (buffer == NULL || *maxlen != 0); - *maxlen += MAX (2 * len, W_CHUNK); - buffer = realloc (old_buffer, 1 + *maxlen); - - if (buffer == NULL) - free (old_buffer); - } - - if (buffer != NULL) - { - *((char *) mempcpy (&buffer[*actlen], str, len)) = '\0'; - *actlen += len; - } - - return buffer; -} - -static char * -w_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str) - /* (lengths exclude trailing zero) */ -{ - /* Add a string to the buffer, allocating room for it if needed. - */ - size_t len; - - assert (str != NULL); /* w_addstr only called from this file */ - len = strlen (str); - - return w_addmem (buffer, actlen, maxlen, str, len); -} - -static int -w_addword (wordexp_t *pwordexp, char *word) -{ - /* Add a word to the wordlist */ - size_t num_p; - char **new_wordv; - - /* Internally, NULL acts like "". Convert NULLs to "" before - * the caller sees them. - */ - if (word == NULL) - { - word = strdup (""); - if (word == NULL) - goto no_space; - } - - num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs; - new_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p); - if (new_wordv != NULL) - { - pwordexp->we_wordv = new_wordv; - pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc++] = word; - pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc] = NULL; - return 0; - } - -no_space: - return WRDE_NOSPACE; -} - -/* The parse_*() functions should leave *offset being the offset in 'words' - * to the last character processed. - */ - -static int -parse_backslash (char **word, size_t *word_length, size_t *max_length, - const char *words, size_t *offset) -{ - /* We are poised _at_ a backslash, not in quotes */ - - switch (words[1 + *offset]) - { - case 0: - /* Backslash is last character of input words */ - return WRDE_SYNTAX; - - case '\n': - ++(*offset); - break; - - default: - *word = w_addchar (*word, word_length, max_length, words[1 + *offset]); - if (*word == NULL) - return WRDE_NOSPACE; - - ++(*offset); - break; - } - - return 0; -} - -static int -parse_qtd_backslash (char **word, size_t *word_length, size_t *max_length, - const char *words, size_t *offset) -{ - /* We are poised _at_ a backslash, inside quotes */ - - switch (words[1 + *offset]) - { - case 0: - /* Backslash is last character of input words */ - return WRDE_SYNTAX; - - case '\n': - ++(*offset); - break; - - case '$': - case '`': - case '"': - case '\\': - *word = w_addchar (*word, word_length, max_length, words[1 + *offset]); - if (*word == NULL) - return WRDE_NOSPACE; - - ++(*offset); - break; - - default: - *word = w_addchar (*word, word_length, max_length, words[*offset]); - if (*word != NULL) - *word = w_addchar (*word, word_length, max_length, words[1 + *offset]); - - if (*word == NULL) - return WRDE_NOSPACE; - - ++(*offset); - break; - } - - return 0; -} - -static int -parse_tilde (char **word, size_t *word_length, size_t *max_length, - const char *words, size_t *offset, size_t wordc) -{ - /* We are poised _at_ a tilde */ - size_t i; - - if (*word_length != 0) - { - if (!((*word)[*word_length - 1] == '=' && wordc == 0)) - { - if (!((*word)[*word_length - 1] == ':' - && strchr (*word, '=') && wordc == 0)) - { - *word = w_addchar (*word, word_length, max_length, '~'); - return *word ? 0 : WRDE_NOSPACE; - } - } - } - - for (i = 1 + *offset; words[i]; i++) - { - if (words[i] == ':' || words[i] == '/' || words[i] == ' ' || - words[i] == '\t' || words[i] == 0 ) - break; - - if (words[i] == '\\') - { - *word = w_addchar (*word, word_length, max_length, '~'); - return *word ? 0 : WRDE_NOSPACE; - } - } - - if (i == 1 + *offset) - { - /* Tilde appears on its own */ - uid_t uid; - struct passwd pwd, *tpwd; - int buflen = 1000; - char* home; - char* buffer; - int result; - - /* POSIX.2 says ~ expands to $HOME and if HOME is unset the - results are unspecified. We do a lookup on the uid if - HOME is unset. */ - - home = getenv ("HOME"); - if (home != NULL) - { - *word = w_addstr (*word, word_length, max_length, home); - if (*word == NULL) - return WRDE_NOSPACE; - } - else - { - uid = getuid (); - buffer = alloca (buflen); - - while ((result = getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0 - && errno == ERANGE) - { - buflen += 1000; - buffer = alloca (buflen); - } - - if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL) - { - *word = w_addstr (*word, word_length, max_length, pwd.pw_dir); - if (*word == NULL) - return WRDE_NOSPACE; - } - else - { - *word = w_addchar (*word, word_length, max_length, '~'); - if (*word == NULL) - return WRDE_NOSPACE; - } - } - } - else - { - /* Look up user name in database to get home directory */ - char *user = strndup (&words[1 + *offset], i - (1 + *offset)); - struct passwd pwd, *tpwd; - int buflen = 1000; - char* buffer = alloca (buflen); - int result; - - while ((result = getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0 - && errno == ERANGE) - { - buflen += 1000; - buffer = alloca (buflen); - } - - if (result == 0 && tpwd != NULL && pwd.pw_dir) - *word = w_addstr (*word, word_length, max_length, pwd.pw_dir); - else - { - /* (invalid login name) */ - *word = w_addchar (*word, word_length, max_length, '~'); - if (*word != NULL) - *word = w_addstr (*word, word_length, max_length, user); - } - - *offset = i - 1; - } - return *word ? 0 : WRDE_NOSPACE; -} - - -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) -{ - int error; - int match; - glob_t globbuf; - - error = glob (glob_word, GLOB_NOCHECK, NULL, &globbuf); - - if (error != 0) - { - /* We can only run into memory problems. */ - assert (error == GLOB_NOSPACE); - return WRDE_NOSPACE; - } - - if (ifs && !*ifs) - { - /* No field splitting allowed. */ - assert (globbuf.gl_pathv[0] != NULL); - *word = w_addstr (*word, word_length, max_length, globbuf.gl_pathv[0]); - for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match) - { - *word = w_addchar (*word, word_length, max_length, ' '); - if (*word != NULL) - *word = w_addstr (*word, word_length, max_length, - globbuf.gl_pathv[match]); - } - - globfree (&globbuf); - return *word ? 0 : WRDE_NOSPACE; - } - - assert (ifs == NULL || *ifs != '\0'); - if (*word != NULL) - { - free (*word); - *word = w_newword (word_length, max_length); - } - - for (match = 0; match < globbuf.gl_pathc; ++match) - { - char *matching_word = strdup (globbuf.gl_pathv[match]); - if (matching_word == NULL || w_addword (pwordexp, matching_word)) - { - globfree (&globbuf); - return WRDE_NOSPACE; - } - } - - globfree (&globbuf); - return 0; -} - -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) -{ - /* We are poised just after a '*', a '[' or a '?'. */ - int error = WRDE_NOSPACE; - int quoted = 0; /* 1 if singly-quoted, 2 if doubly */ - int i; - wordexp_t glob_list; /* List of words to glob */ - - glob_list.we_wordc = 0; - glob_list.we_wordv = NULL; - glob_list.we_offs = 0; - for (; words[*offset] != '\0'; ++*offset) - { - if ((ifs && strchr (ifs, words[*offset])) || - (!ifs && strchr (" \t\n", words[*offset]))) - /* Reached IFS */ - break; - - /* Sort out quoting */ - if (words[*offset] == '\'') - { - if (quoted == 0) - { - quoted = 1; - continue; - } - else if (quoted == 1) - { - quoted = 0; - continue; - } - } - else if (words[*offset] == '"') - { - if (quoted == 0) - { - quoted = 2; - continue; - } - else if (quoted == 2) - { - quoted = 0; - continue; - } - } - - /* Sort out other special characters */ - if (quoted != 1 && words[*offset] == '$') - { - error = parse_dollars (word, word_length, max_length, words, - offset, flags, &glob_list, ifs, ifs_white, - quoted == 2); - if (error) - goto tidy_up; - - continue; - } - else if (words[*offset] == '\\') - { - if (quoted) - error = parse_qtd_backslash (word, word_length, max_length, - words, offset); - else - error = parse_backslash (word, word_length, max_length, - words, offset); - - if (error) - goto tidy_up; - - continue; - } - - *word = w_addchar (*word, word_length, max_length, words[*offset]); - if (*word == NULL) - goto tidy_up; - } - - /* Don't forget to re-parse the character we stopped at. */ - --*offset; - - /* Glob the words */ - error = w_addword (&glob_list, *word); - *word = w_newword (word_length, max_length); - for (i = 0; error == 0 && i < glob_list.we_wordc; i++) - error = do_parse_glob (glob_list.we_wordv[i], word, word_length, - max_length, pwordexp, ifs, ifs_white); - - /* Now tidy up */ -tidy_up: - wordfree (&glob_list); - return error; -} - -static int -parse_squote (char **word, size_t *word_length, size_t *max_length, - const char *words, size_t *offset) -{ - /* We are poised just after a single quote */ - for (; words[*offset]; ++(*offset)) - { - if (words[*offset] != '\'') - { - *word = w_addchar (*word, word_length, max_length, words[*offset]); - if (*word == NULL) - return WRDE_NOSPACE; - } - else return 0; - } - - /* Unterminated string */ - return WRDE_SYNTAX; -} - -/* Functions to evaluate an arithmetic expression */ -static int -eval_expr_val (char **expr, long int *result) -{ - int sgn = +1; - char *digit; - - /* Skip white space */ - for (digit = *expr; digit && *digit && isspace (*digit); ++digit); - - switch (*digit) - { - case '(': - - /* Scan for closing paren */ - for (++digit; **expr && **expr != ')'; ++(*expr)); - - /* Is there one? */ - if (!**expr) - return WRDE_SYNTAX; - - *(*expr)++ = 0; - - if (eval_expr (digit, result)) - return WRDE_SYNTAX; - - return 0; - - case '+': /* Positive value */ - ++digit; - break; - - case '-': /* Negative value */ - ++digit; - sgn = -1; - break; - - default: - if (!isdigit (*digit)) - return WRDE_SYNTAX; - } - - *result = 0; - for (; *digit && isdigit (*digit); ++digit) - *result = (*result * 10) + (*digit - '0'); - - *expr = digit; - *result *= sgn; - return 0; -} - -static int -eval_expr_multdiv (char **expr, long int *result) -{ - long int arg; - - /* Read a Value */ - if (eval_expr_val (expr, result) != 0) - return WRDE_SYNTAX; - - while (**expr) - { - /* Skip white space */ - for (; *expr && **expr && isspace (**expr); ++(*expr)); - - if (**expr == '*') - { - ++(*expr); - if (eval_expr_val (expr, &arg) != 0) - return WRDE_SYNTAX; - - *result *= arg; - } - else if (**expr == '/') - { - ++(*expr); - if (eval_expr_val (expr, &arg) != 0) - return WRDE_SYNTAX; - - *result /= arg; - } - else break; - } - - return 0; -} - -static int -eval_expr (char *expr, long int *result) -{ - long int arg; - - /* Read a Multdiv */ - if (eval_expr_multdiv (&expr, result) != 0) - return WRDE_SYNTAX; - - while (*expr) - { - /* Skip white space */ - for (; expr && *expr && isspace (*expr); ++expr); - - if (*expr == '+') - { - ++expr; - if (eval_expr_multdiv (&expr, &arg) != 0) - return WRDE_SYNTAX; - - *result += arg; - } - else if (*expr == '-') - { - ++expr; - if (eval_expr_multdiv (&expr, &arg) != 0) - return WRDE_SYNTAX; - - *result -= arg; - } - else break; - } - - return 0; -} - -static int -parse_arith (char **word, size_t *word_length, size_t *max_length, - const char *words, size_t *offset, int flags, int bracket) -{ - /* We are poised just after "$((" or "$[" */ - int error; - int paren_depth = 1; - size_t expr_length; - size_t expr_maxlen; - char *expr; - - expr = w_newword (&expr_length, &expr_maxlen); - for (; words[*offset]; ++(*offset)) - { - switch (words[*offset]) - { - case '$': - error = parse_dollars (&expr, &expr_length, &expr_maxlen, - words, offset, flags, NULL, NULL, NULL, 1); - /* The ``1'' here is to tell parse_dollars not to - * split the fields. - */ - if (error) - { - free (expr); - return error; - } - break; - - case '`': - (*offset)++; - error = parse_backtick (&expr, &expr_length, &expr_maxlen, - words, offset, flags, NULL, NULL, NULL); - /* The first NULL here is to tell parse_backtick not to - * split the fields. - */ - if (error) - { - free (expr); - return error; - } - break; - - case '\\': - error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen, - words, offset); - if (error) - { - free (expr); - return error; - } - /* I think that a backslash within an - * arithmetic expansion is bound to - * cause an error sooner or later anyway though. - */ - break; - - case ')': - if (--paren_depth == 0) - { - char result[21]; /* 21 = ceil(log10(2^64)) + 1 */ - long int numresult = 0; - long long int convertme; - - if (bracket || words[1 + *offset] != ')') - { - free (expr); - return WRDE_SYNTAX; - } - - ++(*offset); - - /* Go - evaluate. */ - if (*expr && eval_expr (expr, &numresult) != 0) - { - free (expr); - return WRDE_SYNTAX; - } - - if (numresult < 0) - { - convertme = -numresult; - *word = w_addchar (*word, word_length, max_length, '-'); - if (!*word) - { - free (expr); - return WRDE_NOSPACE; - } - } - else - convertme = numresult; - - result[20] = '\0'; - *word = w_addstr (*word, word_length, max_length, - itoa (convertme, &result[20], 10, 0)); - free (expr); - return *word ? 0 : WRDE_NOSPACE; - } - expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]); - if (expr == NULL) - return WRDE_NOSPACE; - - break; - - case ']': - if (bracket && paren_depth == 1) - { - char result[21]; /* 21 = ceil(log10(2^64)) + 1 */ - long int numresult = 0; - - /* Go - evaluate. */ - if (*expr && eval_expr (expr, &numresult) != 0) - { - free (expr); - return WRDE_SYNTAX; - } - - result[20] = '\0'; - *word = w_addstr (*word, word_length, max_length, - itoa_word (numresult, &result[20], 10, 0)); - free (expr); - return *word ? 0 : WRDE_NOSPACE; - } - - free (expr); - return WRDE_SYNTAX; - - case '\n': - case ';': - case '{': - case '}': - free (expr); - return WRDE_BADCHAR; - - case '(': - ++paren_depth; - default: - expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]); - if (expr == NULL) - return WRDE_NOSPACE; - } - } - - /* Premature end */ - free (expr); - return WRDE_SYNTAX; -} - -/* Function called by child process in exec_comm() */ -static void -exec_comm_child (char *comm, int *fildes, int showerr, int noexec) -{ - const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL }; - - /* Execute the command, or just check syntax? */ - if (noexec) - args[1] = "-nc"; - - /* Redirect output. */ - dup2 (fildes[1], 1); - close (fildes[1]); - - /* Redirect stderr to /dev/null if we have to. */ - if (showerr == 0) - { - int fd; - close (2); - fd = open (_PATH_DEVNULL, O_WRONLY); - if (fd >= 0 && fd != 2) - { - dup2 (fd, 2); - close (fd); - } - } - - /* Make sure the subshell doesn't field-split on our behalf. */ - unsetenv ("IFS"); - - close (fildes[0]); - execve (_PATH_BSHELL, (char *const *) args, __environ); - - /* Bad. What now? */ - abort (); -} - -/* Function to execute a command and retrieve the results */ -/* pwordexp contains NULL if field-splitting is forbidden */ -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) -{ - int fildes[2]; - int bufsize = 128; - int buflen; - int i; - int status = 0; - size_t maxnewlines = 0; - char *buffer; - pid_t pid; - - /* Don't fork() unless necessary */ - if (!comm || !*comm) - return 0; - - if (pipe (fildes)) - /* Bad */ - return WRDE_NOSPACE; - - if ((pid = fork ()) < 0) - { - /* Bad */ - close (fildes[0]); - close (fildes[1]); - return WRDE_NOSPACE; - } - - if (pid == 0) - exec_comm_child(comm, fildes, (flags & WRDE_SHOWERR), 0); - - /* Parent */ - - close (fildes[1]); - buffer = alloca (bufsize); - - if (!pwordexp) - /* Quoted - no field splitting */ - { - while (1) - { - if ((buflen = __read (fildes[0], buffer, bufsize)) < 1) - { - if (waitpid (pid, &status, WNOHANG) == 0) - continue; - if ((buflen = __read (fildes[0], buffer, bufsize)) < 1) - break; - } - - maxnewlines += buflen; - - *word = w_addmem (*word, word_length, max_length, buffer, buflen); - if (*word == NULL) - goto no_space; - } - } - else - /* Not quoted - split fields */ - { - int copying = 0; - /* 'copying' is: - * 0 when searching for first character in a field not IFS white space - * 1 when copying the text of a field - * 2 when searching for possible non-whitespace IFS - * 3 when searching for non-newline after copying field - */ - - while (1) - { - if ((buflen = __read (fildes[0], buffer, bufsize)) < 1) - { - if (waitpid (pid, &status, WNOHANG) == 0) - continue; - if ((buflen = __read (fildes[0], buffer, bufsize)) < 1) - break; - } - - for (i = 0; i < buflen; ++i) - { - if (strchr (ifs, buffer[i]) != NULL) - { - /* Current character is IFS */ - if (strchr (ifs_white, buffer[i]) == NULL) - { - /* Current character is IFS but not whitespace */ - if (copying == 2) - { - /* current character - * | - * V - * eg: text<space><comma><space>moretext - * - * So, strip whitespace IFS (like at the start) - */ - copying = 0; - continue; - } - - copying = 0; - /* fall through and delimit field.. */ - } - else - { - if (buffer[i] == '\n') - { - /* Current character is (IFS) newline */ - - /* If copying a field, this is the end of it, - but maybe all that's left is trailing newlines. - So start searching for a non-newline. */ - if (copying == 1) - copying = 3; - - continue; - } - else - { - /* Current character is IFS white space, but - not a newline */ - - /* If not either copying a field or searching - for non-newline after a field, ignore it */ - if (copying != 1 && copying != 3) - continue; - - /* End of field (search for non-ws IFS afterwards) */ - copying = 2; - } - } - - /* First IFS white space (non-newline), or IFS non-whitespace. - * Delimit the field. Nulls are converted by w_addword. */ - if (w_addword (pwordexp, *word) == WRDE_NOSPACE) - goto no_space; - - *word = w_newword (word_length, max_length); - - maxnewlines = 0; - /* fall back round the loop.. */ - } - else - { - /* Not IFS character */ - - if (copying == 3) - { - /* Nothing but (IFS) newlines since the last field, - so delimit it here before starting new word */ - if (w_addword (pwordexp, *word) == WRDE_NOSPACE) - goto no_space; - - *word = w_newword (word_length, max_length); - } - - copying = 1; - - if (buffer[i] == '\n') /* happens if newline not in IFS */ - maxnewlines++; - else - maxnewlines = 0; - - *word = w_addchar (*word, word_length, max_length, - buffer[i]); - if (*word == NULL) - goto no_space; - } - } - } - } - - /* Chop off trailing newlines (required by POSIX.2) */ - /* Ensure we don't go back further than the beginning of the - substitution (i.e. remove maxnewlines bytes at most) */ - while (maxnewlines-- != 0 && - *word_length > 0 && (*word)[*word_length - 1] == '\n') - { - (*word)[--*word_length] = '\0'; - - /* If the last word was entirely newlines, turn it into a new word - * which can be ignored if there's nothing following it. */ - if (*word_length == 0) - { - free (*word); - *word = w_newword (word_length, max_length); - break; - } - } - - close (fildes[0]); - - /* Check for syntax error (re-execute but with "-n" flag) */ - if (buflen < 1 && status != 0) - { - if ((pid = fork ()) < 0) - { - /* Bad */ - return WRDE_NOSPACE; - } - - if (pid == 0) - { - fildes[0] = fildes[1] = -1; - exec_comm_child(comm, fildes, 0, 1); - } - - if (waitpid (pid, &status, 0) == pid && status != 0) - return WRDE_SYNTAX; - } - - return 0; - -no_space: - kill (pid, SIGKILL); - waitpid (pid, NULL, 0); - close (fildes[0]); - return WRDE_NOSPACE; -} - -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) -{ - /* We are poised just after "$(" */ - int paren_depth = 1; - int error = 0; - int quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */ - size_t comm_length; - size_t comm_maxlen; - char *comm = w_newword (&comm_length, &comm_maxlen); - - for (; words[*offset]; ++(*offset)) - { - switch (words[*offset]) - { - case '\'': - if (quoted == 0) - quoted = 1; - else if (quoted == 1) - quoted = 0; - - break; - - case '"': - if (quoted == 0) - quoted = 2; - else if (quoted == 2) - quoted = 0; - - break; - - case ')': - if (!quoted && --paren_depth == 0) - { - /* Go -- give script to the shell */ - if (comm) - { - error = exec_comm (comm, word, word_length, max_length, - flags, pwordexp, ifs, ifs_white); - free (comm); - } - - return error; - } - - /* This is just part of the script */ - break; - - case '(': - if (!quoted) - ++paren_depth; - } - - comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]); - if (comm == NULL) - return WRDE_NOSPACE; - } - - /* Premature end */ - if (comm) - free (comm); - - return WRDE_SYNTAX; -} - -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) -{ - /* We are poised just after "$" */ - enum action - { - ACT_NONE, - ACT_RP_SHORT_LEFT = '#', - ACT_RP_LONG_LEFT = 'L', - ACT_RP_SHORT_RIGHT = '%', - ACT_RP_LONG_RIGHT = 'R', - ACT_NULL_ERROR = '?', - ACT_NULL_SUBST = '-', - ACT_NONNULL_SUBST = '+', - ACT_NULL_ASSIGN = '=' - }; - size_t env_length; - size_t env_maxlen; - size_t pat_length; - size_t pat_maxlen; - size_t start = *offset; - char *env; - char *pattern; - char *value = NULL; - enum action action = ACT_NONE; |