diff options
author | Anas Nashif <anas.nashif@intel.com> | 2013-01-15 08:32:18 -0800 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2013-01-15 08:32:18 -0800 |
commit | 689b9dbb8d7f88ab91e7741932ed000b6e49be9a (patch) | |
tree | 463f5a1df8b2d35644c260e7bf6c8e0a26198af1 /glob.c | |
parent | 59749d048d9e452f049f9151735b5256756919c3 (diff) | |
download | ltrace-689b9dbb8d7f88ab91e7741932ed000b6e49be9a.tar.gz ltrace-689b9dbb8d7f88ab91e7741932ed000b6e49be9a.tar.bz2 ltrace-689b9dbb8d7f88ab91e7741932ed000b6e49be9a.zip |
Imported Upstream version 0.7.2upstream/0.7.2
Diffstat (limited to 'glob.c')
-rw-r--r-- | glob.c | 279 |
1 files changed, 279 insertions, 0 deletions
@@ -0,0 +1,279 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2007, 2008, 2012 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <sys/types.h> +#include <regex.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +static ssize_t +match_character_class(const char *glob, size_t length, size_t from) +{ + size_t i; + if (length > 0) + for (i = from + 2; i < length - 1 && glob[++i] != ':'; ) + ; + if (i >= length || glob[++i] != ']') + return -1; + return i; +} + +static ssize_t +match_brack(const char *glob, size_t length, size_t from, int *exclmp) +{ + size_t i = from + 1; + + if (i >= length) + return -1; + + /* Complement operator. */ + *exclmp = 0; + if (glob[i] == '^' || glob[i] == '!') { + *exclmp = glob[i++] == '!'; + if (i >= length) + return -1; + } + + /* On first character, both [ and ] are legal. But when [ is + * followed with :, it's character class. */ + if (glob[i] == '[' && glob[i + 1] == ':') { + ssize_t j = match_character_class(glob, length, i); + if (j < 0) + fail: + return -1; + i = j; + } + ++i; /* skip any character, including [ or ] */ + + int escape = 0; + for (; i < length; ++i) { + char c = glob[i]; + if (escape) { + ++i; + escape = 0; + + } else if (c == '[' && glob[i + 1] == ':') { + ssize_t j = match_character_class(glob, length, i); + if (j < 0) + goto fail; + i = j; + + } else if (c == ']') { + return i; + } + } + return -1; +} + +static int +append(char **bufp, const char *str, size_t str_size, + size_t *sizep, size_t *allocp) +{ + if (str_size == 0) + str_size = strlen(str); + size_t nsize = *sizep + str_size; + if (nsize > *allocp) { + size_t nalloc = nsize * 2; + char *nbuf = realloc(*bufp, nalloc); + if (nbuf == NULL) + return -1; + *allocp = nalloc; + *bufp = nbuf; + } + + memcpy(*bufp + *sizep, str, str_size); + *sizep = nsize; + return 0; +} + +static int +glob_to_regex(const char *glob, char **retp) +{ + size_t allocd = 0; + size_t size = 0; + char *buf = NULL; + + size_t length = strlen(glob); + int escape = 0; + size_t i; + for(i = 0; i < length; ++i) { + char c = glob[i]; + if (escape) { + if (c == '\\') { + if (append(&buf, "\\\\", 0, + &size, &allocd) < 0) { + fail: + free(buf); + return REG_ESPACE; + } + + } else if (c == '*') { + if (append(&buf, "\\*", 0, &size, &allocd) < 0) + goto fail; + } else if (c == '?') { + if (append(&buf, "?", 0, &size, &allocd) < 0) + goto fail; + } else if (append(&buf, (char[]){ '\\', c }, 2, + &size, &allocd) < 0) + goto fail; + escape = 0; + } else { + if (c == '\\') + escape = 1; + else if (c == '[') { + int exclm; + ssize_t j = match_brack(glob, length, i, &exclm); + if (j < 0) { + free(buf); + return REG_EBRACK; + } + if (exclm + && append(&buf, "[^", 2, + &size, &allocd) < 0) + goto fail; + if (append(&buf, glob + i + 2*exclm, + j - i + 1 - 2*exclm, + &size, &allocd) < 0) + goto fail; + i = j; + + } else if (c == '*') { + if (append(&buf, ".*", 0, &size, &allocd) < 0) + goto fail; + } else if (c == '?') { + if (append(&buf, ".", 0, &size, &allocd) < 0) + goto fail; + } else if (c == '.') { + if (append(&buf, "\\.", 0, &size, &allocd) < 0) + goto fail; + } else if (append(&buf, &c, 1, &size, &allocd) < 0) + goto fail; + } + } + + if (escape) { + free(buf); + return REG_EESCAPE; + } + + { + char c = 0; + if (append(&buf, &c, 1, &size, &allocd) < 0) + goto fail; + } + *retp = buf; + return REG_NOERROR; +} + +int +globcomp(regex_t *preg, const char *glob, int cflags) +{ + char *regex = NULL; + int status = glob_to_regex(glob, ®ex); + if (status != REG_NOERROR) + return status; + assert(regex != NULL); + status = regcomp(preg, regex, cflags); + free(regex); + return status; +} + +#ifdef TEST +#include <stdio.h> + +static void +translate(const char *glob, int exp_status, const char *expect) +{ + char *pattern = NULL; + int status = glob_to_regex(glob, &pattern); + if (status != exp_status) { + fprintf(stderr, "translating %s, expected status %d, got %d\n", + glob, exp_status, status); + return; + } + + if (status == 0) { + assert(pattern != NULL); + if (strcmp(pattern, expect) != 0) + fprintf(stderr, "translating %s, expected %s, got %s\n", + glob, expect, pattern); + free(pattern); + } else { + assert(pattern == NULL); + } +} + +static void +try_match(const char *glob, const char *str, int expect) +{ + regex_t preg; + int status = globcomp(&preg, glob, 0); + assert(status == 0); + status = regexec(&preg, str, 0, NULL, 0); + assert(status == expect); + regfree(&preg); +} + +int +main(void) +{ + translate("*", 0, ".*"); + translate("?", 0, "."); + translate(".*", 0, "\\..*"); + translate("*.*", 0, ".*\\..*"); + translate("*a*", 0, ".*a.*"); + translate("[abc]", 0, "[abc]"); + translate("[^abc]", 0, "[^abc]"); + translate("[!abc]", 0, "[^abc]"); + translate("[]]", 0, "[]]"); + translate("[[]", 0, "[[]"); + translate("[^]]", 0, "[^]]"); + translate("[^a-z]", 0, "[^a-z]"); + translate("[abc\\]]", 0, "[abc\\]]"); + translate("[abc\\]def]", 0, "[abc\\]def]"); + translate("[[:space:]]", 0, "[[:space:]]"); + translate("[^[:space:]]", 0, "[^[:space:]]"); + translate("[![:space:]]", 0, "[^[:space:]]"); + translate("[^a-z]*", 0, "[^a-z].*"); + translate("[^a-z]bar*", 0, "[^a-z]bar.*"); + translate("*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.", 0, + ".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\." + ".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\."); + + translate("\\", REG_EESCAPE, NULL); + translate("[^[:naotuh\\", REG_EBRACK, NULL); + translate("[^[:", REG_EBRACK, NULL); + translate("[^[", REG_EBRACK, NULL); + translate("[^", REG_EBRACK, NULL); + translate("[\\", REG_EBRACK, NULL); + translate("[", REG_EBRACK, NULL); + translate("abc[", REG_EBRACK, NULL); + + try_match("abc*def", "abc012def", 0); + try_match("abc*def", "ab012def", REG_NOMATCH); + try_match("[abc]*def", "a1def", 0); + try_match("[abc]*def", "b1def", 0); + try_match("[abc]*def", "d1def", REG_NOMATCH); + + return 0; +} + +#endif |