| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| #include "debug.h" | ||
|
|
||
| #include <ctype.h> | ||
| #include <stdarg.h> | ||
| #include <stddef.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| #undef lua_State | ||
| #define lua_State void | ||
| #undef LUA_MAXCAPTURES | ||
| #define LUA_MAXCAPTURES 256 | ||
| #undef MAXCCALLS | ||
| #define MAXCCALLS 200 | ||
| #undef LUA_QL | ||
| #define LUA_QL(x) "'" x "'" | ||
| #undef uchar | ||
| #define uchar(c) ((unsigned char)(c)) | ||
|
|
||
| static int luaL_error (void *ms, const char *fmt, ...) | ||
| { | ||
| va_list va; | ||
| va_start(va, fmt); | ||
| vdebug(D_FATAL|D_NOTICE|D_DEBUG, fmt, va); | ||
| va_end(va); | ||
| abort(); | ||
| return 0; | ||
| } | ||
|
|
||
| #include "luapatt.c" | ||
|
|
||
| ptrdiff_t pattern_vmatch (const char *str, const char *patt, va_list va) | ||
| { | ||
| MatchState ms; | ||
| int anchor = (*patt == '^'); | ||
| if (anchor) { | ||
| patt++; /* skip anchor character */ | ||
| } | ||
| ms.matchdepth = MAXCCALLS; | ||
| ms.src_init = str; | ||
| ms.src_end = str + strlen(str); | ||
| ms.p_end = patt + strlen(patt); | ||
| do { | ||
| const char *rest; | ||
| ms.level = 0; | ||
| if ((rest = match(&ms, str, patt))) { | ||
| int i; | ||
| for (i = 0; i < ms.level; i++) { | ||
| ptrdiff_t l = ms.capture[i].len; | ||
| if (l == CAP_UNFINISHED) | ||
| luaL_error(ms.L, "unfinished capture"); | ||
| else if (l == CAP_POSITION) { | ||
| size_t *capture = va_arg(va, size_t *); | ||
| *capture = ms.capture[i].init - ms.src_init + 1; | ||
| } else { | ||
| char **capture = va_arg(va, char **); | ||
| *capture = malloc(l+1); | ||
| if (*capture == NULL) | ||
| luaL_error(ms.L, "out of memory"); | ||
| strncpy(*capture, ms.capture[i].init, l); | ||
| (*capture)[l] = '\0'; | ||
| } | ||
| } | ||
| return str-ms.src_init; | ||
| } | ||
| } while (str++ < ms.src_end && !anchor); | ||
| return -1; | ||
| } | ||
|
|
||
| ptrdiff_t pattern_match (const char *str, const char *patt, ...) | ||
| { | ||
| ptrdiff_t rc; | ||
| va_list va; | ||
| va_start(va, patt); | ||
| rc = pattern_vmatch(str, patt, va); | ||
| va_end(va); | ||
| return rc; | ||
| } | ||
|
|
||
| /* vim: set noexpandtab tabstop=4: */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /* Copyright (C) 2014- The University of Notre Dame | ||
| * This software is distributed under the GNU General Public License. | ||
| * See the file COPYING for details. | ||
| */ | ||
|
|
||
| #ifndef PATTERN_H | ||
| #define PATTERN_H | ||
|
|
||
| #include <stdarg.h> | ||
| #include <stddef.h> | ||
|
|
||
| /** @file pattern.h Pattern Matching Facilities. | ||
| * | ||
| * Lua 5.2 pattern matching. See Lua manual for patterns supported. | ||
| * | ||
| * Captures are passed through C varargs. String captures are heap | ||
| * allocated and must be freed. | ||
| * | ||
| * @return offset in str where match occurred or -1 if no match. | ||
| * @see http://www.lua.org/manual/5.2/manual.html#6.4.1 | ||
| */ | ||
|
|
||
| ptrdiff_t pattern_vmatch (const char *str, const char *patt, va_list va); | ||
| ptrdiff_t pattern_match (const char *str, const char *patt, ...); | ||
|
|
||
| #endif /* PATTERN_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| #!/bin/sh | ||
|
|
||
| . ../../dttools/src/test_runner.common.sh | ||
|
|
||
| exe="pattern.test" | ||
|
|
||
| prepare() | ||
| { | ||
| gcc -I../src/ -g -o "$exe" -x c - -x none ../src/libdttools.a -lm <<EOF | ||
| #include "pattern.h" | ||
| #include "debug.h" | ||
| #include <errno.h> | ||
| #include <limits.h> | ||
| #include <stdarg.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #define check(expected,rc) \\ | ||
| do {\\ | ||
| ptrdiff_t e = (expected);\\ | ||
| if (e != rc)\\ | ||
| fatal("[%s:%d]: unexpected failure: %d (got) -> %d (expected)\n\t%s", __FILE__, __LINE__, (int)e, rc, #expected);\\ | ||
| } while (0) | ||
| int main (int argc, char *argv[]) | ||
| { | ||
| char *cap1; | ||
| char *cap2; | ||
| size_t ncap; | ||
| check(pattern_match("foo", "foo"), 0); | ||
| check(pattern_match("foo", "o"), 1); | ||
| check(pattern_match("foo", "oo"), 1); | ||
| check(pattern_match("foo", "o$"), 2); | ||
| check(pattern_match("foo", "^foo"), 0); | ||
| check(pattern_match("foo", "^f"), 0); | ||
| check(pattern_match("foo", "^"), 0); | ||
| check(pattern_match("foo", "^o"), -1); | ||
| check(pattern_match("foo", "(foo)", &cap1), 0); | ||
| check(strcmp(cap1, "foo"), 0); | ||
| free(cap1); | ||
| check(pattern_match("foo", "bar"), -1); | ||
| check(pattern_match("foo", "(foo)()", &cap1, &ncap), 0); | ||
| check(strcmp(cap1, "foo"), 0); | ||
| check(ncap, 4); | ||
| free(cap1); | ||
| check(pattern_match("foobar", "(foo)()b(.*)", &cap1, &ncap, &cap2), 0); | ||
| check(strcmp(cap1, "foo"), 0); | ||
| check(ncap, 4); | ||
| check(strcmp(cap2, "ar"), 0); | ||
| free(cap1); | ||
| free(cap2); | ||
| return 0; | ||
| } | ||
| EOF | ||
| return $? | ||
| } | ||
|
|
||
| run() | ||
| { | ||
| ./"$exe" | ||
| return $? | ||
| } | ||
|
|
||
| clean() | ||
| { | ||
| rm -f "$exe" | ||
| return 0 | ||
| } | ||
|
|
||
| dispatch "$@" | ||
|
|
||
| # vim: set noexpandtab tabstop=4: |