@@ -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: */
@@ -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 */
@@ -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: