summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReuben Thomas <rrt@sc3d.org>2012-09-29 17:43:50 +0100
committerReuben Thomas <rrt@sc3d.org>2012-09-29 17:43:50 +0100
commit2cdbe1c4460249a5d2d865d4406fc06a64dcd560 (patch)
tree03c7eb891b8c1f89c5aaf7f0d4ae8f6dec6d5cb9
parentb551acf755e894c9db15d17d24754793a5773612 (diff)
downloadlrexlib-2cdbe1c4460249a5d2d865d4406fc06a64dcd560.tar.gz
Add the ability to use raw memory blocks as subjects.
The implementation is in algo.h, in the new check_subject function. Usage is documented in manual.txt. Optional tests have been added, using alien buffers.
-rw-r--r--doc/manual.txt16
-rw-r--r--src/algo.h38
-rw-r--r--test/luatest.lua17
-rw-r--r--test/onig_sets.lua8
-rw-r--r--test/pcre_sets.lua8
-rw-r--r--test/runtest.lua15
6 files changed, 87 insertions, 15 deletions
diff --git a/doc/manual.txt b/doc/manual.txt
index 6af4d5f..72790ba 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -38,9 +38,19 @@ Notes
too. In this case, the cf_ and larg_ arguments are ignored (should
be either supplied as nils or omitted).
+6. All functions that take a string-type subject accept a table (in Lua >= 5.2)
+ or userdata that has a ``topointer`` method and ``__len`` metamethod, and
+ take the subject to be a block of memory starting at the address returned by
+ ``subject:topointer()`` and of length ``#subject``. This works with buffers
+ objects from the alien library (https://github.com/mascarenhas/alien). Note
+ that special attention is needed with POSIX regex libraries that do not
+ support ``REG_STARTEND``, and hence need NUL-terminated subjects: the NUL is
+ not included in the string length, so alien buffers must be wrapped to
+ report a length that excludes the NUL.
+
.. _cf:
-6. The default value for *compilation flags* (*cf*) that Lrexlib uses when
+7. The default value for *compilation flags* (*cf*) that Lrexlib uses when
the parameter is not supplied or ``nil`` is:
* REG_EXTENDED for POSIX and TRE
@@ -65,7 +75,7 @@ Notes
.. _ef:
-7. The default value for *execution flags* (*ef*) that Lrexlib uses when
+8. The default value for *execution flags* (*ef*) that Lrexlib uses when
the parameter is not supplied or ``nil``, is:
* 0 for standard POSIX regex library
@@ -75,7 +85,7 @@ Notes
.. _larg:
-8. The notation *larg...* is used to indicate optional library-specific
+9. The notation *larg...* is used to indicate optional library-specific
arguments, which are documented in the ``new`` method of each library.
------------------------------------------------------------
diff --git a/src/algo.h b/src/algo.h
index a1ea61c..e268a02 100644
--- a/src/algo.h
+++ b/src/algo.h
@@ -115,6 +115,36 @@ static TUserdata* check_ud (lua_State *L)
}
+static void check_subject (lua_State *L, int pos, TArgExec *argE)
+{
+ int stype;
+ argE->text = lua_tolstring (L, pos, &argE->textlen);
+ stype = lua_type (L, pos);
+ if (stype != LUA_TSTRING && stype != LUA_TTABLE && stype != LUA_TUSERDATA) {
+ luaL_typerror (L, pos, "string, table or userdata");
+ } else if (argE->text == NULL) {
+ int type;
+ lua_getfield (L, pos, "topointer");
+ if (lua_type (L, -1) != LUA_TFUNCTION)
+ luaL_error (L, "subject has no topointer method");
+ lua_pushvalue (L, pos);
+ lua_call (L, 1, 1);
+ type = lua_type (L, -1);
+ if (type != LUA_TLIGHTUSERDATA)
+ luaL_error (L, "subject's topointer method returned %s (expected lightuserdata)",
+ lua_typename (L, type));
+ argE->text = lua_touserdata (L, -1);
+ lua_pop (L, 1);
+ lua_len (L, pos);
+ type = lua_type (L, -1);
+ if (type != LUA_TNUMBER)
+ luaL_error (L, "subject's length is %s (expected number)",
+ lua_typename (L, type));
+ argE->textlen = lua_tointeger (L, -1);
+ lua_pop (L, 1);
+ }
+}
+
static void check_pattern (lua_State *L, int pos, TArgComp *argC)
{
if (lua_isstring (L, pos)) {
@@ -134,7 +164,7 @@ static void checkarg_new (lua_State *L, TArgComp *argC) {
/* function gsub (s, patt, f, [n], [cf], [ef], [larg...]) */
static void checkarg_gsub (lua_State *L, TArgComp *argC, TArgExec *argE) {
- argE->text = luaL_checklstring (L, 1, &argE->textlen);
+ check_subject (L, 1, argE);
check_pattern (L, 2, argC);
lua_tostring (L, 3); /* converts number (if any) to string */
argE->reptype = lua_type (L, 3);
@@ -154,7 +184,7 @@ static void checkarg_gsub (lua_State *L, TArgComp *argC, TArgExec *argE) {
/* function find (s, patt, [st], [cf], [ef], [larg...]) */
/* function match (s, patt, [st], [cf], [ef], [larg...]) */
static void checkarg_find_func (lua_State *L, TArgComp *argC, TArgExec *argE) {
- argE->text = luaL_checklstring (L, 1, &argE->textlen);
+ check_subject (L, 1, argE);
check_pattern (L, 2, argC);
argE->startoffset = get_startoffset (L, 3, argE->textlen);
argC->cflags = ALG_GETCFLAGS (L, 4);
@@ -166,7 +196,7 @@ static void checkarg_find_func (lua_State *L, TArgComp *argC, TArgExec *argE) {
/* function gmatch (s, patt, [cf], [ef], [larg...]) */
/* function split (s, patt, [cf], [ef], [larg...]) */
static void checkarg_gmatch_split (lua_State *L, TArgComp *argC, TArgExec *argE) {
- argE->text = luaL_checklstring (L, 1, &argE->textlen);
+ check_subject (L, 1, argE);
check_pattern (L, 2, argC);
argC->cflags = ALG_GETCFLAGS (L, 3);
argE->eflags = luaL_optint (L, 4, ALG_EFLAGS_DFLT);
@@ -180,7 +210,7 @@ static void checkarg_gmatch_split (lua_State *L, TArgComp *argC, TArgExec *argE)
/* method r:match (s, [st], [ef]) */
static void checkarg_find_method (lua_State *L, TArgExec *argE, TUserdata **ud) {
*ud = check_ud (L);
- argE->text = luaL_checklstring (L, 2, &argE->textlen);
+ check_subject (L, 2, argE);
argE->startoffset = get_startoffset (L, 3, argE->textlen);
argE->eflags = luaL_optint (L, 4, ALG_EFLAGS_DFLT);
}
diff --git a/test/luatest.lua b/test/luatest.lua
index 5ea7ba8..3949d90 100644
--- a/test/luatest.lua
+++ b/test/luatest.lua
@@ -73,6 +73,22 @@ local function test_function (test, func)
if t[1] then
table.remove (t, 1)
res = t
+ if alien then
+ local subject = test[1][1]
+ local buf = alien.buffer (#subject)
+ if #subject > 0 then
+ alien.memmove (buf:topointer (), subject, #subject)
+ end
+ test[1][1] = buf
+ local t = packNT (pcall (func, unpackNT (test[1])))
+ if t[1] then
+ table.remove (t, 1)
+ res = t
+ else
+ print "alien test failed"
+ res = t[2] --> error_message
+ end
+ end
else
res = t[2] --> error_message
end
@@ -87,6 +103,7 @@ end
-- 3) test results table or error_message
local function test_method (test, constructor, name)
local res1, res2
+ local subject = test[2][1]
local ok, r = pcall (constructor, unpackNT (test[1]))
if ok then
local t = packNT (pcall (r[name], r, unpackNT (test[2])))
diff --git a/test/onig_sets.lua b/test/onig_sets.lua
index 83555a6..dd226ec 100644
--- a/test/onig_sets.lua
+++ b/test/onig_sets.lua
@@ -14,14 +14,14 @@ end
local function set_named_subpatterns (lib, flg)
return {
Name = "Named Subpatterns",
- Func = function (methodname, subj, patt, name1, name2)
+ Func = function (subj, methodname, patt, name1, name2)
local r = lib.new (patt)
local _,_,caps = r[methodname] (r, subj)
return norm(caps[name1]), norm(caps[name2])
end,
- --{}
- { {"tfind", "abcd", "(?<dog>.)b.(?<cat>d)", "dog", "cat"}, {"a","d"} },
- { {"exec", "abcd", "(?<dog>.)b.(?<cat>d)", "dog", "cat"}, {"a","d"} },
+ --{} N.B. subject is always first element
+ { {"abcd", "tfind", "(?<dog>.)b.(?<cat>d)", "dog", "cat"}, {"a","d"} },
+ { {"abcd", "exec", "(?<dog>.)b.(?<cat>d)", "dog", "cat"}, {"a","d"} },
}
end
diff --git a/test/pcre_sets.lua b/test/pcre_sets.lua
index 9c19bbe..e2db7a9 100644
--- a/test/pcre_sets.lua
+++ b/test/pcre_sets.lua
@@ -14,14 +14,14 @@ end
local function set_named_subpatterns (lib, flg)
return {
Name = "Named Subpatterns",
- Func = function (methodname, subj, patt, name1, name2)
+ Func = function (subj, methodname, patt, name1, name2)
local r = lib.new (patt)
local _,_,caps = r[methodname] (r, subj)
return norm(caps[name1]), norm(caps[name2])
end,
- --{}
- { {"tfind", "abcd", "(?P<dog>.)b.(?P<cat>d)", "dog", "cat"}, {"a","d"} },
- { {"exec", "abcd", "(?P<dog>.)b.(?P<cat>d)", "dog", "cat"}, {"a","d"} },
+ --{} N.B. subject is always first element
+ { {"abcd", "tfind", "(?P<dog>.)b.(?P<cat>d)", "dog", "cat"}, {"a","d"} },
+ { {"abcd", "exec", "(?P<dog>.)b.(?P<cat>d)", "dog", "cat"}, {"a","d"} },
}
end
diff --git a/test/runtest.lua b/test/runtest.lua
index 3c79970..d0d1435 100644
--- a/test/runtest.lua
+++ b/test/runtest.lua
@@ -1,5 +1,12 @@
-- See Copyright Notice in the file LICENSE
+-- See if we have alien, so we can do tests with buffer subjects
+local ok
+ok, alien = pcall (require, "alien")
+if not ok then
+ io.stderr:write ("Warning: alien not found, so cannot run tests with buffer subjects\n")
+end
+
do
local path = "./?.lua;"
if package.path:sub(1, #path) ~= path then
@@ -16,6 +23,13 @@ local function test_library (libname, setfile, verbose)
local lib = require (libname)
local f = require (setfile)
local sets = f (libname)
+
+ local realalien = alien
+ if libname == "rex_posix" and not lib.flags ().STARTEND and alien then
+ alien = nil
+ io.stderr:write ("Cannot run posix tests with alien without REG_STARTEND\n")
+ end
+
local n = 0 -- number of failures
for _, set in ipairs (sets) do
if verbose then
@@ -33,6 +47,7 @@ local function test_library (libname, setfile, verbose)
if verbose then
print ""
end
+ alien = realalien
return n
end