diff options
author | Reuben Thomas <rrt@sc3d.org> | 2012-09-29 17:43:50 +0100 |
---|---|---|
committer | Reuben Thomas <rrt@sc3d.org> | 2012-09-29 17:43:50 +0100 |
commit | 2cdbe1c4460249a5d2d865d4406fc06a64dcd560 (patch) | |
tree | 03c7eb891b8c1f89c5aaf7f0d4ae8f6dec6d5cb9 | |
parent | b551acf755e894c9db15d17d24754793a5773612 (diff) | |
download | lrexlib-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.txt | 16 | ||||
-rw-r--r-- | src/algo.h | 38 | ||||
-rw-r--r-- | test/luatest.lua | 17 | ||||
-rw-r--r-- | test/onig_sets.lua | 8 | ||||
-rw-r--r-- | test/pcre_sets.lua | 8 | ||||
-rw-r--r-- | test/runtest.lua | 15 |
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. ------------------------------------------------------------ @@ -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 |