diff options
Diffstat (limited to 'posix/wordexp.c')
-rw-r--r-- | posix/wordexp.c | 240 |
1 files changed, 123 insertions, 117 deletions
diff --git a/posix/wordexp.c b/posix/wordexp.c index 2a58b6061a..64d5b3c5a5 100644 --- a/posix/wordexp.c +++ b/posix/wordexp.c @@ -75,6 +75,13 @@ static int eval_expr (char *expr, long int *result) internal_function; #define W_CHUNK (100) 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) */ { @@ -337,6 +344,64 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length, return *word ? 0 : WRDE_NOSPACE; } + +static int +internal_function +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 internal_function parse_glob (char **word, size_t *word_length, size_t *max_length, @@ -344,13 +409,15 @@ parse_glob (char **word, size_t *word_length, size_t *max_length, wordexp_t *pwordexp, const char *ifs, const char *ifs_white) { /* We are poised just after a '*', a '[' or a '?'. */ - int error; - glob_t globbuf; - int match; - char *matching_word; + 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 */ - for (; words[*offset]; (*offset)++) + 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]))) @@ -384,103 +451,48 @@ parse_glob (char **word, size_t *word_length, size_t *max_length, /* Sort out other special characters */ if (quoted != 1 && words[*offset] == '$') { - error = parse_dollars (word, word_length, max_length, words, offset, - flags, pwordexp, ifs, ifs_white, quoted == 2); + error = parse_dollars (word, word_length, max_length, words, + offset, flags, &glob_list, ifs, ifs_white, + quoted == 2); if (error) - return error; + goto tidy_up; continue; } else if (words[*offset] == '\\') { if (quoted) - error = parse_qtd_backslash (word, word_length, max_length, words, - offset); + error = parse_qtd_backslash (word, word_length, max_length, + words, offset); else - error = parse_backslash (word, word_length, max_length, words, - offset); + error = parse_backslash (word, word_length, max_length, + words, offset); if (error) - return error; + goto tidy_up; continue; } *word = w_addchar (*word, word_length, max_length, words[*offset]); if (*word == NULL) - return WRDE_NOSPACE; + goto tidy_up; } - error = glob (*word, GLOB_NOCHECK, NULL, &globbuf); + /* Don't forget to re-parse the character we stopped at. */ + --*offset; - if (error != 0) - { - /* We can only run into memory problems. */ - assert (error == GLOB_NOSPACE); - - return WRDE_NOSPACE; - } + /* 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); - if (ifs && !*ifs) - { - /* No field splitting allowed */ - size_t length = strlen (globbuf.gl_pathv[0]); - char *old_word = *word; - *word = realloc (*word, length + 1); - if (*word == NULL) - { - free (old_word); - goto no_space; - } - - memcpy (*word, globbuf.gl_pathv[0], length + 1); - *word_length = length; - - 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]); - } - - /* Re-parse white space on return */ - globfree (&globbuf); - --(*offset); - return *word ? 0 : WRDE_NOSPACE; - } - - /* here ifs != "" */ - free (*word); - *word = NULL; - *word_length = 0; - - matching_word = __strdup (globbuf.gl_pathv[0]); - if (matching_word == NULL) - goto no_space; - - if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE) - goto no_space; - - for (match = 1; match < globbuf.gl_pathc; ++match) - { - matching_word = __strdup (globbuf.gl_pathv[match]); - if (matching_word == NULL) - goto no_space; - - if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE) - goto no_space; - } - - globfree (&globbuf); - - /* Re-parse white space on return */ - --(*offset); - return 0; - -no_space: - globfree (&globbuf); - return WRDE_NOSPACE; + /* Now tidy up */ +tidy_up: + wordfree (&glob_list); + return error; } static int @@ -638,10 +650,11 @@ parse_arith (char **word, size_t *word_length, size_t *max_length, /* We are poised just after "$((" or "$[" */ int error; int paren_depth = 1; - size_t expr_length = 0; - size_t expr_maxlen = 0; - char *expr = NULL; + size_t expr_length; + size_t expr_maxlen; + char *expr; + expr = w_newword (&expr_length, &expr_maxlen); for (; words[*offset]; ++(*offset)) { switch (words[*offset]) @@ -934,9 +947,7 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length, return WRDE_NOSPACE; } - *word = NULL; - *word_length = 0; - *max_length = 0; + *word = w_newword (word_length, max_length); /* fall back round the loop.. */ } else @@ -974,10 +985,10 @@ parse_comm (char **word, size_t *word_length, size_t *max_length, /* We are poised just after "$(" */ int paren_depth = 1; int error = 0; - size_t comm_length = 0; - size_t comm_maxlen = 0; - char *comm = NULL; 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)) { @@ -1052,13 +1063,13 @@ parse_param (char **word, size_t *word_length, size_t *max_length, ACT_NONNULL_SUBST = '+', ACT_NULL_ASSIGN = '=' }; - size_t env_length = 0; - size_t env_maxlen = 0; - size_t pat_length = 0; - size_t pat_maxlen = 0; + size_t env_length; + size_t env_maxlen; + size_t pat_length; + size_t pat_maxlen; size_t start = *offset; - char *env = NULL; - char *pattern = NULL; + char *env; + char *pattern; char *value = NULL; enum action action = ACT_NONE; int depth = 0; @@ -1071,6 +1082,9 @@ parse_param (char **word, size_t *word_length, size_t *max_length, char buffer[21]; int brace = words[*offset] == '{'; + env = w_newword (&env_length, &env_maxlen); + pattern = w_newword (&pat_length, &pat_maxlen); + if (brace) ++*offset; @@ -1247,7 +1261,7 @@ envsubst: return *word ? 0 : WRDE_NOSPACE; } } - /* Is it a numberic parameter? */ + /* Is it a numeric parameter? */ else if (isdigit (env[0])) { int n = atoi (env); @@ -1345,8 +1359,7 @@ envsubst: } /* Start a new word with the last parameter. */ - *word = NULL; - *max_length = *word_length = 0; + *word = w_newword (word_length, max_length); value = __strdup (__libc_argv[p]); if (value == NULL) goto no_space; @@ -1690,8 +1703,7 @@ envsubst: return WRDE_NOSPACE; } - *word = NULL; - *word_length = *max_length = 0; + *word = w_newword (word_length, max_length); } /* Skip IFS whitespace before the field */ @@ -1825,10 +1837,10 @@ parse_backtick (char **word, size_t *word_length, size_t *max_length, { /* We are poised just after "`" */ int error; - size_t comm_length = 0; - size_t comm_maxlen = 0; - char *comm = NULL; int squoting = 0; + size_t comm_length; + size_t comm_maxlen; + char *comm = w_newword (&comm_length, &comm_maxlen); for (; words[*offset]; ++(*offset)) { @@ -1974,9 +1986,9 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags) { size_t wordv_offset; size_t words_offset; - size_t word_length = 0; - size_t max_length = 0; - char *word = NULL; + size_t word_length; + size_t max_length; + char *word = w_newword (&word_length, &max_length); int error; char *ifs; char ifs_white[4]; @@ -2169,17 +2181,13 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags) goto do_error; } - word = NULL; - word_length = 0; - max_length = 0; + word = w_newword (&word_length, &max_length); break; } /* It's a non-whitespace IFS char */ - /* Multiple non-whitespace IFS chars are treated as one; - * IS THIS CORRECT? - */ + /* Multiple non-whitespace IFS chars are treated as one. */ if (word != NULL) { if (w_addword (pwordexp, word) == WRDE_NOSPACE) @@ -2189,9 +2197,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags) } } - word = NULL; - word_length = 0; - max_length = 0; + word = w_newword (&word_length, &max_length); } /* End of string */ |