2 * This file is part of ltrace.
3 * Copyright (C) 2007, 2008, 2012 Petr Machata, Red Hat Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 #include <sys/types.h>
28 match_character_class(const char *glob, size_t length, size_t from)
32 for (i = from + 2; i < length - 1 && glob[++i] != ':'; )
34 if (i >= length || glob[++i] != ']')
40 match_brack(const char *glob, size_t length, size_t from, int *exclmp)
47 /* Complement operator. */
49 if (glob[i] == '^' || glob[i] == '!') {
50 *exclmp = glob[i++] == '!';
55 /* On first character, both [ and ] are legal. But when [ is
56 * followed with :, it's character class. */
57 if (glob[i] == '[' && glob[i + 1] == ':') {
58 ssize_t j = match_character_class(glob, length, i);
64 ++i; /* skip any character, including [ or ] */
67 for (; i < length; ++i) {
73 } else if (c == '[' && glob[i + 1] == ':') {
74 ssize_t j = match_character_class(glob, length, i);
79 } else if (c == ']') {
87 append(char **bufp, const char *str, size_t str_size,
88 size_t *sizep, size_t *allocp)
91 str_size = strlen(str);
92 size_t nsize = *sizep + str_size;
93 if (nsize > *allocp) {
94 size_t nalloc = nsize * 2;
95 char *nbuf = realloc(*bufp, nalloc);
102 memcpy(*bufp + *sizep, str, str_size);
108 glob_to_regex(const char *glob, char **retp)
114 size_t length = strlen(glob);
117 for(i = 0; i < length; ++i) {
121 if (append(&buf, "\\\\", 0,
122 &size, &allocd) < 0) {
128 } else if (c == '*') {
129 if (append(&buf, "\\*", 0, &size, &allocd) < 0)
131 } else if (c == '?') {
132 if (append(&buf, "?", 0, &size, &allocd) < 0)
134 } else if (append(&buf, (char[]){ '\\', c }, 2,
143 ssize_t j = match_brack(glob, length, i, &exclm);
149 && append(&buf, "[^", 2,
152 if (append(&buf, glob + i + 2*exclm,
158 } else if (c == '*') {
159 if (append(&buf, ".*", 0, &size, &allocd) < 0)
161 } else if (c == '?') {
162 if (append(&buf, ".", 0, &size, &allocd) < 0)
164 } else if (c == '.') {
165 if (append(&buf, "\\.", 0, &size, &allocd) < 0)
167 } else if (append(&buf, &c, 1, &size, &allocd) < 0)
179 if (append(&buf, &c, 1, &size, &allocd) < 0)
187 globcomp(regex_t *preg, const char *glob, int cflags)
190 int status = glob_to_regex(glob, ®ex);
191 if (status != REG_NOERROR)
193 assert(regex != NULL);
194 status = regcomp(preg, regex, cflags);
203 translate(const char *glob, int exp_status, const char *expect)
205 char *pattern = NULL;
206 int status = glob_to_regex(glob, &pattern);
207 if (status != exp_status) {
208 fprintf(stderr, "translating %s, expected status %d, got %d\n",
209 glob, exp_status, status);
214 assert(pattern != NULL);
215 if (strcmp(pattern, expect) != 0)
216 fprintf(stderr, "translating %s, expected %s, got %s\n",
217 glob, expect, pattern);
220 assert(pattern == NULL);
225 try_match(const char *glob, const char *str, int expect)
228 int status = globcomp(&preg, glob, 0);
230 status = regexec(&preg, str, 0, NULL, 0);
231 assert(status == expect);
238 translate("*", 0, ".*");
239 translate("?", 0, ".");
240 translate(".*", 0, "\\..*");
241 translate("*.*", 0, ".*\\..*");
242 translate("*a*", 0, ".*a.*");
243 translate("[abc]", 0, "[abc]");
244 translate("[^abc]", 0, "[^abc]");
245 translate("[!abc]", 0, "[^abc]");
246 translate("[]]", 0, "[]]");
247 translate("[[]", 0, "[[]");
248 translate("[^]]", 0, "[^]]");
249 translate("[^a-z]", 0, "[^a-z]");
250 translate("[abc\\]]", 0, "[abc\\]]");
251 translate("[abc\\]def]", 0, "[abc\\]def]");
252 translate("[[:space:]]", 0, "[[:space:]]");
253 translate("[^[:space:]]", 0, "[^[:space:]]");
254 translate("[![:space:]]", 0, "[^[:space:]]");
255 translate("[^a-z]*", 0, "[^a-z].*");
256 translate("[^a-z]bar*", 0, "[^a-z]bar.*");
257 translate("*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.", 0,
258 ".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\."
259 ".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.");
261 translate("\\", REG_EESCAPE, NULL);
262 translate("[^[:naotuh\\", REG_EBRACK, NULL);
263 translate("[^[:", REG_EBRACK, NULL);
264 translate("[^[", REG_EBRACK, NULL);
265 translate("[^", REG_EBRACK, NULL);
266 translate("[\\", REG_EBRACK, NULL);
267 translate("[", REG_EBRACK, NULL);
268 translate("abc[", REG_EBRACK, NULL);
270 try_match("abc*def", "abc012def", 0);
271 try_match("abc*def", "ab012def", REG_NOMATCH);
272 try_match("[abc]*def", "a1def", 0);
273 try_match("[abc]*def", "b1def", 0);
274 try_match("[abc]*def", "d1def", REG_NOMATCH);