diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/wslua/lrexlib | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/wslua/lrexlib')
-rw-r--r-- | epan/wslua/lrexlib/CMakeLists.txt | 30 | ||||
-rw-r--r-- | epan/wslua/lrexlib/README.rst | 56 | ||||
-rw-r--r-- | epan/wslua/lrexlib/algo.h | 779 | ||||
-rw-r--r-- | epan/wslua/lrexlib/common.c | 331 | ||||
-rw-r--r-- | epan/wslua/lrexlib/common.h | 128 | ||||
-rw-r--r-- | epan/wslua/lrexlib/pcre2/lpcre2.c | 544 | ||||
-rw-r--r-- | epan/wslua/lrexlib/pcre2/lpcre2_f.c | 240 |
7 files changed, 2108 insertions, 0 deletions
diff --git a/epan/wslua/lrexlib/CMakeLists.txt b/epan/wslua/lrexlib/CMakeLists.txt new file mode 100644 index 00000000..2f7231ef --- /dev/null +++ b/epan/wslua/lrexlib/CMakeLists.txt @@ -0,0 +1,30 @@ + +set(REX_SRC + common.c + pcre2/lpcre2.c + pcre2/lpcre2_f.c +) + +add_library(lrexlib STATIC ${REX_SRC}) + +target_link_libraries(lrexlib PRIVATE + ${LUA_LIBRARIES} + $<IF:$<CONFIG:Debug>,${PCRE2_DEBUG_LIBRARIES},${PCRE2_LIBRARIES}> +) + +target_include_directories(lrexlib SYSTEM PRIVATE + ${CMAKE_SOURCE_DIR}/epan + ${LUA_INCLUDE_DIRS} + ${PCRE2_INCLUDE_DIRS} +) + +add_dependencies(lrexlib register_wslua) + +if(FETCH_lua) + add_dependencies(lrexlib lua52) +endif() + +add_compile_definitions( + VERSION=\"2.9.1\" + PCRE2_CODE_UNIT_WIDTH=8 +) diff --git a/epan/wslua/lrexlib/README.rst b/epan/wslua/lrexlib/README.rst new file mode 100644 index 00000000..b9679d35 --- /dev/null +++ b/epan/wslua/lrexlib/README.rst @@ -0,0 +1,56 @@ +Lrexlib +======= + +| by Reuben Thomas (rrt@sc3d.org) +| and Shmuel Zeigerman (shmuz@013net.net) + +**Lrexlib** provides bindings of five regular expression library APIs +(POSIX_, PCRE_, PCRE2_, GNU_, TRE_ and Oniguruma_) to Lua_ >= 5.1. +The bindings for TRE and Oniguruma are not currently complete. + +**Lrexlib** is copyright Reuben Thomas 2000-2020 and copyright Shmuel +Zeigerman 2004-2020, and is released under the same license as Lua, +the MIT_ license (otherwise known as the revised BSD license). There +is no warranty. + +.. _POSIX: http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html +.. _PCRE: http://www.pcre.org/pcre.txt +.. _PCRE2: http://www.pcre.org/pcre2.txt +.. _GNU: ftp://ftp.gnu.org/old-gnu/regex/ +.. _Oniguruma: https://github.com/kkos/oniguruma +.. _TRE: http://laurikari.net/tre/documentation/ +.. _Lua: http://www.lua.org +.. _MIT: http://www.opensource.org/licenses/mit-license.php + +Please report bugs and make suggestions to the maintainer, or use the +LuaForge trackers and mailing lists. + +Thanks to Thatcher Ulrich for bug and warning fixes, and to Nick +Gammon for adding support for PCRE named subpatterns. + +----------------------------------------------------------- + +Installation +------------ + +Lrexlib is installed with LuaRocks_, using the command:: + + luarocks install lrexlib-FLAVOUR + +where **FLAVOUR** is one of PCRE, PCRE2, POSIX, oniguruma, TRE, GNU + +.. _LuaRocks: http://www.luarocks.org + + +Links +----- + +- License_ +- `Reference Manual`_ +- `LuaForge Project Page`_ +- Download_ + +.. _License: http://rrthomas.github.com/lrexlib/license.html +.. _Reference Manual: http://rrthomas.github.com/lrexlib/manual.html +.. _LuaForge Project Page: http://luaforge.net/projects/lrexlib/ +.. _Download: https://github.com/rrthomas/lrexlib/downloads diff --git a/epan/wslua/lrexlib/algo.h b/epan/wslua/lrexlib/algo.h new file mode 100644 index 00000000..2e7a38ab --- /dev/null +++ b/epan/wslua/lrexlib/algo.h @@ -0,0 +1,779 @@ +/* algo.h */ +/* + * Copyright (C) Reuben Thomas 2000-2020 + * Copyright (C) Shmuel Zeigerman 2004-2020 + + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the + * Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "common.h" + +#define REX_VERSION "Lrexlib " VERSION + +/* Forward declarations */ +static void gmatch_pushsubject (lua_State *L, TArgExec *argE); +static int findmatch_exec (TUserdata *ud, TArgExec *argE); +static int split_exec (TUserdata *ud, TArgExec *argE, int offset); +static int gsub_exec (TUserdata *ud, TArgExec *argE, int offset); +static int gmatch_exec (TUserdata *ud, TArgExec *argE); +static int compile_regex (lua_State *L, const TArgComp *argC, TUserdata **pud); +static int generate_error (lua_State *L, const TUserdata *ud, int errcode); + +#if LUA_VERSION_NUM == 501 +# define ALG_ENVIRONINDEX LUA_ENVIRONINDEX +#else +# define ALG_ENVIRONINDEX lua_upvalueindex(1) +#endif + +#ifndef ALG_CHARSIZE +# define ALG_CHARSIZE 1 +#endif + +#ifndef BUFFERZ_PUTREPSTRING +# define BUFFERZ_PUTREPSTRING bufferZ_putrepstring +#endif + +#ifndef ALG_GETCARGS +# define ALG_GETCARGS(a,b,c) +#endif + +#ifndef DO_NAMED_SUBPATTERNS +#define DO_NAMED_SUBPATTERNS(a,b,c) +#endif + +#define METHOD_FIND 0 +#define METHOD_MATCH 1 +#define METHOD_EXEC 2 +#define METHOD_TFIND 3 + + +static int OptLimit (lua_State *L, int pos) { + if (lua_isnoneornil (L, pos)) + return GSUB_UNLIMITED; + if (lua_isfunction (L, pos)) + return GSUB_CONDITIONAL; + if (lua_isnumber (L, pos)) { + int a = lua_tointeger (L, pos); + return a < 0 ? 0 : a; + } + return luaL_typerror (L, pos, "number or function"); +} + + +static int get_startoffset(lua_State *L, int stackpos, size_t len) { + int startoffset = (int)luaL_optinteger(L, stackpos, 1); + if(startoffset > 0) + startoffset--; + else if(startoffset < 0) { + startoffset += len/ALG_CHARSIZE; + if(startoffset < 0) + startoffset = 0; + } + return startoffset*ALG_CHARSIZE; +} + + +static TUserdata* test_ud (lua_State *L, int pos) +{ + TUserdata *ud; + if (lua_getmetatable(L, pos) && + lua_rawequal(L, -1, ALG_ENVIRONINDEX) && + (ud = (TUserdata *)lua_touserdata(L, pos)) != NULL) { + lua_pop(L, 1); + return ud; + } + return NULL; +} + + +static TUserdata* check_ud (lua_State *L) +{ + TUserdata *ud = test_ud(L, 1); + if (ud == NULL) luaL_typerror(L, 1, REX_TYPENAME); + return ud; +} + + +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 = (const char*) lua_touserdata (L, -1); + lua_pop (L, 1); +#if LUA_VERSION_NUM == 501 + if (luaL_callmeta (L, pos, "__len")) { + if (lua_type (L, -1) != LUA_TNUMBER) + luaL_argerror (L, pos, "subject's length is not a number"); + argE->textlen = lua_tointeger (L, -1); + lua_pop (L, 1); + } + else + argE->textlen = lua_objlen (L, pos); +#else + argE->textlen = luaL_len (L, pos); +#endif + } +} + +static void check_pattern (lua_State *L, int pos, TArgComp *argC) +{ + if (lua_isstring (L, pos)) { + argC->pattern = lua_tolstring (L, pos, &argC->patlen); + argC->ud = NULL; + } + else if ((argC->ud = test_ud (L, pos)) == NULL) + luaL_typerror(L, pos, "string or " REX_TYPENAME); +} + +static void checkarg_new (lua_State *L, TArgComp *argC) { + argC->pattern = luaL_checklstring (L, 1, &argC->patlen); + argC->cflags = ALG_GETCFLAGS (L, 2); + ALG_GETCARGS (L, 3, argC); +} + + +/* function gsub (s, patt, f, [n], [cf], [ef], [larg...]) */ +static void checkarg_gsub (lua_State *L, TArgComp *argC, TArgExec *argE) { + 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); + if (argE->reptype != LUA_TSTRING && argE->reptype != LUA_TTABLE && + argE->reptype != LUA_TFUNCTION) { + luaL_typerror (L, 3, "string, table or function"); + } + argE->funcpos = 3; + argE->funcpos2 = 4; + argE->maxmatch = OptLimit (L, 4); + argC->cflags = ALG_GETCFLAGS (L, 5); + argE->eflags = (int)luaL_optinteger (L, 6, ALG_EFLAGS_DFLT); + ALG_GETCARGS (L, 7, argC); +} + + +/* function count (s, patt, [cf], [ef], [larg...]) */ +static void checkarg_count (lua_State *L, TArgComp *argC, TArgExec *argE) { + check_subject (L, 1, argE); + check_pattern (L, 2, argC); + argC->cflags = ALG_GETCFLAGS (L, 3); + argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT); + ALG_GETCARGS (L, 5, argC); +} + + +/* 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) { + check_subject (L, 1, argE); + check_pattern (L, 2, argC); + argE->startoffset = get_startoffset (L, 3, argE->textlen); + argC->cflags = ALG_GETCFLAGS (L, 4); + argE->eflags = (int)luaL_optinteger (L, 5, ALG_EFLAGS_DFLT); + ALG_GETCARGS (L, 6, argC); +} + + +/* 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) { + check_subject (L, 1, argE); + check_pattern (L, 2, argC); + argC->cflags = ALG_GETCFLAGS (L, 3); + argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT); + ALG_GETCARGS (L, 5, argC); +} + + +/* method r:tfind (s, [st], [ef]) */ +/* method r:exec (s, [st], [ef]) */ +/* method r:find (s, [st], [ef]) */ +/* method r:match (s, [st], [ef]) */ +static void checkarg_find_method (lua_State *L, TArgExec *argE, TUserdata **ud) { + *ud = check_ud (L); + check_subject (L, 2, argE); + argE->startoffset = get_startoffset (L, 3, argE->textlen); + argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT); +} + + +static int algf_new (lua_State *L) { + TArgComp argC; + checkarg_new (L, &argC); + return compile_regex (L, &argC, NULL); +} + +static void push_substrings (lua_State *L, TUserdata *ud, const char *text, + TFreeList *freelist) { + int i; + if (lua_checkstack (L, ALG_NSUB(ud)) == 0) { + if (freelist) + freelist_free (freelist); + luaL_error (L, "cannot add %d stack slots", ALG_NSUB(ud)); + } + for (i = 1; i <= ALG_NSUB(ud); i++) { + ALG_PUSHSUB_OR_FALSE (L, ud, text, i); + } +} + +static int algf_gsub (lua_State *L) { + TUserdata *ud; + TArgComp argC; + TArgExec argE; + int n_match = 0, n_subst = 0, st = 0, last_to = -1; + TBuffer BufOut, BufRep, BufTemp, *pBuf = &BufOut; + TFreeList freelist; + /*------------------------------------------------------------------*/ + checkarg_gsub (L, &argC, &argE); + if (argC.ud) { + ud = (TUserdata*) argC.ud; + lua_pushvalue (L, 2); + } + else compile_regex (L, &argC, &ud); + freelist_init (&freelist); + /*------------------------------------------------------------------*/ + if (argE.reptype == LUA_TSTRING) { + buffer_init (&BufRep, 256, L, &freelist); + BUFFERZ_PUTREPSTRING (&BufRep, argE.funcpos, ALG_NSUB(ud)); + } + /*------------------------------------------------------------------*/ + if (argE.maxmatch == GSUB_CONDITIONAL) { + buffer_init (&BufTemp, 1024, L, &freelist); + pBuf = &BufTemp; + } + /*------------------------------------------------------------------*/ + buffer_init (&BufOut, 1024, L, &freelist); + while ((argE.maxmatch < 0 || n_match < argE.maxmatch) && st <= (int)argE.textlen) { + int from, to, res; + int curr_subst = 0; + res = gsub_exec (ud, &argE, st); + if (ALG_NOMATCH (res)) { + break; + } + else if (!ALG_ISMATCH (res)) { + freelist_free (&freelist); + return generate_error (L, ud, res); + } + from = ALG_BASE(st) + ALG_SUBBEG(ud,0); + to = ALG_BASE(st) + ALG_SUBEND(ud,0); + if (to == last_to) { /* discard an empty match adjacent to the previous match */ + if (st < (int)argE.textlen) { /* advance by 1 char (not replaced) */ + buffer_addlstring (&BufOut, argE.text + st, ALG_CHARSIZE); + st += ALG_CHARSIZE; + continue; + } + break; + } + last_to = to; + ++n_match; + if (st < from) { + buffer_addlstring (&BufOut, argE.text + st, from - st); +#ifdef ALG_PULL + st = from; +#endif + } + /*----------------------------------------------------------------*/ + if (argE.reptype == LUA_TSTRING) { + size_t iter = 0, num; + const char *str; + while (bufferZ_next (&BufRep, &iter, &num, &str)) { + if (str) + buffer_addlstring (pBuf, str, num); + else if (num == 0 || ALG_SUBVALID (ud,num)) + buffer_addlstring (pBuf, argE.text + ALG_BASE(st) + ALG_SUBBEG(ud,num), ALG_SUBLEN(ud,num)); + } + curr_subst = 1; + } + /*----------------------------------------------------------------*/ + else if (argE.reptype == LUA_TTABLE) { + if (ALG_NSUB(ud) > 0) + ALG_PUSHSUB_OR_FALSE (L, ud, argE.text + ALG_BASE(st), 1); + else + lua_pushlstring (L, argE.text + from, to - from); + lua_gettable (L, argE.funcpos); + } + /*----------------------------------------------------------------*/ + else if (argE.reptype == LUA_TFUNCTION) { + int narg; + lua_pushvalue (L, argE.funcpos); + if (ALG_NSUB(ud) > 0) { + push_substrings (L, ud, argE.text + ALG_BASE(st), &freelist); + narg = ALG_NSUB(ud); + } + else { + lua_pushlstring (L, argE.text + from, to - from); + narg = 1; + } + if (0 != lua_pcall (L, narg, 1, 0)) { + freelist_free (&freelist); + return lua_error (L); /* re-raise the error */ + } + } + /*----------------------------------------------------------------*/ + if (argE.reptype == LUA_TTABLE || argE.reptype == LUA_TFUNCTION) { + if (lua_tostring (L, -1)) { + buffer_addvalue (pBuf, -1); + curr_subst = 1; + } + else if (!lua_toboolean (L, -1)) + buffer_addlstring (pBuf, argE.text + from, to - from); + else { + freelist_free (&freelist); + luaL_error (L, "invalid replacement value (a %s)", luaL_typename (L, -1)); + } + if (argE.maxmatch != GSUB_CONDITIONAL) + lua_pop (L, 1); + } + /*----------------------------------------------------------------*/ + if (argE.maxmatch == GSUB_CONDITIONAL) { + /* Call the function */ + lua_pushvalue (L, argE.funcpos2); + lua_pushinteger (L, from/ALG_CHARSIZE + 1); + lua_pushinteger (L, to/ALG_CHARSIZE); + if (argE.reptype == LUA_TSTRING) + buffer_pushresult (&BufTemp); + else { + lua_pushvalue (L, -4); + lua_remove (L, -5); + } + if (0 != lua_pcall (L, 3, 2, 0)) { + freelist_free (&freelist); + lua_error (L); /* re-raise the error */ + } + /* Handle the 1-st return value */ + if (lua_isstring (L, -2)) { /* coercion is allowed here */ + buffer_addvalue (&BufOut, -2); /* rep2 */ + curr_subst = 1; + } + else if (lua_toboolean (L, -2)) + buffer_addbuffer (&BufOut, &BufTemp); /* rep1 */ + else { + buffer_addlstring (&BufOut, argE.text + from, to - from); /* "no" */ + curr_subst = 0; + } + /* Handle the 2-nd return value */ + if (lua_type (L, -1) == LUA_TNUMBER) { /* no coercion is allowed here */ + int n = lua_tointeger (L, -1); + if (n < 0) /* n */ + n = 0; + argE.maxmatch = n_match + n; + } + else if (lua_toboolean (L, -1)) /* "yes to all" */ + argE.maxmatch = GSUB_UNLIMITED; + else + buffer_clear (&BufTemp); + + lua_pop (L, 2); + if (argE.maxmatch != GSUB_CONDITIONAL) + pBuf = &BufOut; + } + /*----------------------------------------------------------------*/ + n_subst += curr_subst; + if (st < to) { + st = to; + } + else if (st < (int)argE.textlen) { + /* advance by 1 char (not replaced) */ + buffer_addlstring (&BufOut, argE.text + st, ALG_CHARSIZE); + st += ALG_CHARSIZE; + } + else break; + } + /*------------------------------------------------------------------*/ + buffer_addlstring (&BufOut, argE.text + st, argE.textlen - st); + buffer_pushresult (&BufOut); + lua_pushinteger (L, n_match); + lua_pushinteger (L, n_subst); + freelist_free (&freelist); + return 3; +} + + +static int algf_count (lua_State *L) { + TUserdata *ud; + TArgComp argC; + TArgExec argE; + int n_match = 0, st = 0, last_to = -1; + /*------------------------------------------------------------------*/ + checkarg_count (L, &argC, &argE); + if (argC.ud) { + ud = (TUserdata*) argC.ud; + lua_pushvalue (L, 2); + } + else compile_regex (L, &argC, &ud); + /*------------------------------------------------------------------*/ + while (st <= (int)argE.textlen) { + int to, res; + res = gsub_exec (ud, &argE, st); + if (ALG_NOMATCH (res)) { + break; + } + else if (!ALG_ISMATCH (res)) { + return generate_error (L, ud, res); + } + to = ALG_BASE(st) + ALG_SUBEND(ud,0); + if (to == last_to) { /* discard an empty match adjacent to the previous match */ + if (st < (int)argE.textlen) { /* advance by 1 char */ + st += ALG_CHARSIZE; + continue; + } + break; + } + last_to = to; + ++n_match; +#ifdef ALG_PULL + { + int from = ALG_BASE(st) + ALG_SUBBEG(ud,0); + if (st < from) + st = from; + } +#endif + /*----------------------------------------------------------------*/ + if (st < to) { + st = to; + } + else if (st < (int)argE.textlen) { + /* advance by 1 char (not replaced) */ + st += ALG_CHARSIZE; + } + else break; + } + /*------------------------------------------------------------------*/ + lua_pushinteger (L, n_match); + return 1; +} + + +static int finish_generic_find (lua_State *L, TUserdata *ud, TArgExec *argE, + int method, int res) +{ + if (ALG_ISMATCH (res)) { + if (method == METHOD_FIND) + ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE->startoffset), 0); + if (ALG_NSUB(ud)) /* push captures */ + push_substrings (L, ud, argE->text, NULL); + else if (method != METHOD_FIND) { + ALG_PUSHSUB (L, ud, argE->text, 0); + return 1; + } + return (method == METHOD_FIND) ? ALG_NSUB(ud) + 2 : ALG_NSUB(ud); + } + else if (ALG_NOMATCH (res)) + return lua_pushnil (L), 1; + else + return generate_error (L, ud, res); +} + + +static int generic_find_func (lua_State *L, int method) { + TUserdata *ud; + TArgComp argC; + TArgExec argE; + int res; + + checkarg_find_func (L, &argC, &argE); + if (argE.startoffset > (int)argE.textlen) + return lua_pushnil (L), 1; + + if (argC.ud) { + ud = (TUserdata*) argC.ud; + lua_pushvalue (L, 2); + } + else compile_regex (L, &argC, &ud); + res = findmatch_exec (ud, &argE); + return finish_generic_find (L, ud, &argE, method, res); +} + + +static int algf_find (lua_State *L) { + return generic_find_func (L, METHOD_FIND); +} + + +static int algf_match (lua_State *L) { + return generic_find_func (L, METHOD_MATCH); +} + + +static int gmatch_iter (lua_State *L) { + int last_end, res; + TArgExec argE; + TUserdata *ud = (TUserdata*) lua_touserdata (L, lua_upvalueindex (1)); + argE.text = lua_tolstring (L, lua_upvalueindex (2), &argE.textlen); + argE.eflags = lua_tointeger (L, lua_upvalueindex (3)); + argE.startoffset = lua_tointeger (L, lua_upvalueindex (4)); + last_end = lua_tointeger (L, lua_upvalueindex (5)); + + while (1) { + if (argE.startoffset > (int)argE.textlen) + return 0; + res = gmatch_exec (ud, &argE); + if (ALG_ISMATCH (res)) { + int incr = 0; + if (!ALG_SUBLEN(ud,0)) { /* no progress: prevent endless loop */ + if (last_end == ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0)) { + argE.startoffset += ALG_CHARSIZE; + continue; + } + incr = ALG_CHARSIZE; + } + last_end = ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0); + lua_pushinteger(L, last_end + incr); /* update start offset */ + lua_replace (L, lua_upvalueindex (4)); + lua_pushinteger(L, last_end); /* update last end of match */ + lua_replace (L, lua_upvalueindex (5)); + /* push either captures or entire match */ + if (ALG_NSUB(ud)) { + push_substrings (L, ud, argE.text, NULL); + return ALG_NSUB(ud); + } + else { + ALG_PUSHSUB (L, ud, argE.text, 0); + return 1; + } + } + else if (ALG_NOMATCH (res)) + return 0; + else + return generate_error (L, ud, res); + } +} + + +static int split_iter (lua_State *L) { + int incr, last_end, newoffset, res; + TArgExec argE; + TUserdata *ud = (TUserdata*) lua_touserdata (L, lua_upvalueindex (1)); + argE.text = lua_tolstring (L, lua_upvalueindex (2), &argE.textlen); + argE.eflags = lua_tointeger (L, lua_upvalueindex (3)); + argE.startoffset = lua_tointeger (L, lua_upvalueindex (4)); + incr = lua_tointeger (L, lua_upvalueindex (5)); + last_end = lua_tointeger (L, lua_upvalueindex (6)); + + if (incr < 0) + return 0; + + while (1) { + if ((newoffset = argE.startoffset + incr) > (int)argE.textlen) + break; + res = split_exec (ud, &argE, newoffset); + if (ALG_ISMATCH (res)) { + if (!ALG_SUBLEN(ud,0)) { /* no progress: prevent endless loop */ + if (last_end == ALG_BASE(argE.startoffset) + ALG_SUBEND(ud,0)) { + incr += ALG_CHARSIZE; + continue; + } + } + lua_pushinteger(L, ALG_BASE(newoffset) + ALG_SUBEND(ud,0)); /* update start offset and last_end */ + lua_pushvalue (L, -1); + lua_replace (L, lua_upvalueindex (4)); + lua_replace (L, lua_upvalueindex (6)); + lua_pushinteger (L, ALG_SUBLEN(ud,0) ? 0 : ALG_CHARSIZE); /* update incr */ + lua_replace (L, lua_upvalueindex (5)); + /* push text preceding the match */ + lua_pushlstring (L, argE.text + argE.startoffset, + ALG_SUBBEG(ud,0) + ALG_BASE(newoffset) - argE.startoffset); + /* push either captures or entire match */ + if (ALG_NSUB(ud)) { + push_substrings (L, ud, argE.text + ALG_BASE(newoffset), NULL); + return 1 + ALG_NSUB(ud); + } + else { + ALG_PUSHSUB (L, ud, argE.text + ALG_BASE(newoffset), 0); + return 2; + } + } + else if (ALG_NOMATCH (res)) + break; + else + return generate_error (L, ud, res); + } + lua_pushinteger (L, -1); /* mark as last iteration */ + lua_replace (L, lua_upvalueindex (5)); /* incr = -1 */ + lua_pushlstring (L, argE.text+argE.startoffset, argE.textlen-argE.startoffset); + return 1; +} + + +static int algf_gmatch (lua_State *L) +{ + TArgComp argC; + TArgExec argE; + checkarg_gmatch_split (L, &argC, &argE); + if (argC.ud) + lua_pushvalue (L, 2); + else + compile_regex (L, &argC, NULL); /* 1-st upvalue: ud */ + gmatch_pushsubject (L, &argE); /* 2-nd upvalue: s */ + lua_pushinteger (L, argE.eflags); /* 3-rd upvalue: ef */ + lua_pushinteger (L, 0); /* 4-th upvalue: startoffset */ + lua_pushinteger (L, -1); /* 5-th upvalue: last end of match */ + lua_pushcclosure (L, gmatch_iter, 5); + return 1; +} + +static int algf_split (lua_State *L) +{ + TArgComp argC; + TArgExec argE; + checkarg_gmatch_split (L, &argC, &argE); + if (argC.ud) + lua_pushvalue (L, 2); + else + compile_regex (L, &argC, NULL); /* 1-st upvalue: ud */ + gmatch_pushsubject (L, &argE); /* 2-nd upvalue: s */ + lua_pushinteger (L, argE.eflags); /* 3-rd upvalue: ef */ + lua_pushinteger (L, 0); /* 4-th upvalue: startoffset */ + lua_pushinteger (L, 0); /* 5-th upvalue: incr */ + lua_pushinteger (L, -1); /* 6-th upvalue: last_end */ + lua_pushcclosure (L, split_iter, 6); + return 1; +} + + +static void push_substring_table (lua_State *L, TUserdata *ud, const char *text) { + int i; + lua_newtable (L); + for (i = 1; i <= ALG_NSUB(ud); i++) { + ALG_PUSHSUB_OR_FALSE (L, ud, text, i); + lua_rawseti (L, -2, i); + } +} + + +static void push_offset_table (lua_State *L, TUserdata *ud, int startoffset) { + int i, j; + lua_newtable (L); + for (i=1, j=1; i <= ALG_NSUB(ud); i++) { + if (ALG_SUBVALID (ud,i)) { + ALG_PUSHSTART (L, ud, startoffset, i); + lua_rawseti (L, -2, j++); + ALG_PUSHEND (L, ud, startoffset, i); + lua_rawseti (L, -2, j++); + } + else { + lua_pushboolean (L, 0); + lua_rawseti (L, -2, j++); + lua_pushboolean (L, 0); + lua_rawseti (L, -2, j++); + } + } +} + + +static int generic_find_method (lua_State *L, int method) { + TUserdata *ud; + TArgExec argE; + int res; + + checkarg_find_method (L, &argE, &ud); + if (argE.startoffset > (int)argE.textlen) + return lua_pushnil(L), 1; + + res = findmatch_exec (ud, &argE); + if (ALG_ISMATCH (res)) { + switch (method) { + case METHOD_EXEC: + ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE.startoffset), 0); + push_offset_table (L, ud, ALG_BASE(argE.startoffset)); + DO_NAMED_SUBPATTERNS (L, ud, argE.text); + return 3; + case METHOD_TFIND: + ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE.startoffset), 0); + push_substring_table (L, ud, argE.text); + DO_NAMED_SUBPATTERNS (L, ud, argE.text); + return 3; + case METHOD_MATCH: + case METHOD_FIND: + return finish_generic_find (L, ud, &argE, method, res); + } + return 0; + } + else if (ALG_NOMATCH (res)) + return lua_pushnil (L), 1; + else + return generate_error(L, ud, res); +} + + +static int algm_find (lua_State *L) { + return generic_find_method (L, METHOD_FIND); +} +static int algm_match (lua_State *L) { + return generic_find_method (L, METHOD_MATCH); +} +static int algm_tfind (lua_State *L) { + return generic_find_method (L, METHOD_TFIND); +} +static int algm_exec (lua_State *L) { + return generic_find_method (L, METHOD_EXEC); +} + +static void alg_register (lua_State *L, const luaL_Reg *r_methods, + const luaL_Reg *r_functions, const char *name) { + /* Create a new function environment to serve as a metatable for methods. */ +#if LUA_VERSION_NUM == 501 + lua_newtable (L); + lua_pushvalue (L, -1); + lua_replace (L, LUA_ENVIRONINDEX); + luaL_register (L, NULL, r_methods); +#else + luaL_newmetatable(L, REX_TYPENAME); + lua_pushvalue(L, -1); + luaL_setfuncs (L, r_methods, 1); +#endif + lua_pushvalue(L, -1); /* mt.__index = mt */ + lua_setfield(L, -2, "__index"); + + /* Register functions. */ + lua_createtable(L, 0, 8); +#if LUA_VERSION_NUM == 501 + luaL_register (L, NULL, r_functions); +#else + lua_pushvalue(L, -2); + luaL_setfuncs (L, r_functions, 1); +#endif +#ifdef REX_CREATEGLOBALVAR + lua_pushvalue(L, -1); + lua_setglobal(L, REX_LIBNAME); +#endif + lua_pushfstring (L, REX_VERSION" (for %s)", name); + lua_setfield (L, -2, "_VERSION"); +#ifndef REX_NOEMBEDDEDTEST + lua_pushcfunction (L, newmembuffer); + lua_setfield (L, -2, "_newmembuffer"); +#endif +} diff --git a/epan/wslua/lrexlib/common.c b/epan/wslua/lrexlib/common.c new file mode 100644 index 00000000..4d42de9c --- /dev/null +++ b/epan/wslua/lrexlib/common.c @@ -0,0 +1,331 @@ +/* common.c */ +/* + * Copyright (C) Reuben Thomas 2000-2020 + * Copyright (C) Shmuel Zeigerman 2004-2020 + + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the + * Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <wireshark.h> +DIAG_OFF_CLANG(shorten-64-to-32) +#ifdef _MSC_VER +/* disable: " warning C4244: '=': conversion from 'lua _Integer' to 'int', + * possible loss of data" */ +#pragma warning(disable:4244) +/* warning C4267: '+=': conversion from 'size_t' to 'int', + * possible loss of data */ +#pragma warning(disable:4267) +#endif + +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include "lua.h" +#include "lauxlib.h" +#include "common.h" + +#define N_ALIGN sizeof(int) + +/* the table must be on Lua stack top */ +int get_int_field (lua_State *L, const char* field) +{ + int val; + lua_getfield (L, -1, field); + val = lua_tointeger (L, -1); + lua_pop (L, 1); + return val; +} + +/* the table must be on Lua stack top */ +void set_int_field (lua_State *L, const char* field, int val) +{ + lua_pushinteger (L, val); + lua_setfield (L, -2, field); +} + +void *Lmalloc(lua_State *L, size_t size) { + void *ud; + lua_Alloc lalloc = lua_getallocf(L, &ud); + return lalloc(ud, NULL, 0, size); +} + +void *Lrealloc(lua_State *L, void *p, size_t osize, size_t nsize) { + void *ud; + lua_Alloc lalloc = lua_getallocf(L, &ud); + return lalloc(ud, p, osize, nsize); +} + +void Lfree(lua_State *L, void *p, size_t osize) { + void *ud; + lua_Alloc lalloc = lua_getallocf(L, &ud); + lalloc(ud, p, osize, 0); +} + +/* This function fills a table with string-number pairs. + The table can be passed as the 1-st lua-function parameter, + otherwise it is created. The return value is the filled table. +*/ +int get_flags (lua_State *L, const flag_pair **arrs) { + const flag_pair *p; + const flag_pair **pp; + int nparams = lua_gettop(L); + + if(nparams == 0) + lua_newtable(L); + else { + if(!lua_istable(L, 1)) + luaL_argerror(L, 1, "not a table"); + if(nparams > 1) + lua_pushvalue(L, 1); + } + + for(pp=arrs; *pp; ++pp) { + for(p=*pp; p->key; ++p) { + lua_pushstring(L, p->key); + lua_pushinteger(L, p->val); + lua_rawset(L, -3); + } + } + return 1; +} + +const char *get_flag_key (const flag_pair *fp, int val) { + for (; fp->key; ++fp) { + if (fp->val == val) + return fp->key; + } + return NULL; +} + +/* Classes */ + +/* + * class TFreeList + * *************** + * Simple array of pointers to TBuffer's. + * The array has fixed capacity (not expanded automatically). + */ + +void freelist_init (TFreeList *fl) { + fl->top = 0; +} + +void freelist_add (TFreeList *fl, TBuffer *buf) { + fl->list[fl->top++] = buf; +} + +void freelist_free (TFreeList *fl) { + while (fl->top > 0) + buffer_free (fl->list[--fl->top]); +} + +/* + * class TBuffer + * ************* + * Auto-extensible array of characters for building long strings incrementally. + * * Differs from luaL_Buffer in that: + * * its operations do not change Lua stack top position + * * buffer_addvalue does not extract the value from Lua stack + * * buffer_pushresult does not have to be the last operation + * * Uses TFreeList class: + * * for inserting itself into a TFreeList instance for future clean-up + * * calls freelist_free prior to calling luaL_error. + * * Has specialized "Z-operations" for maintaining mixed string/integer + * array: bufferZ_addlstring, bufferZ_addnum and bufferZ_next. + * * if the array is intended to be "mixed", then the methods + * buffer_addlstring and buffer_addvalue must not be used + * (the application will crash on bufferZ_next). + * * conversely, if the array is not intended to be "mixed", + * then the method bufferZ_next must not be used. + */ + +enum { ID_NUMBER, ID_STRING }; + +void buffer_init (TBuffer *buf, size_t sz, lua_State *L, TFreeList *fl) { + buf->arr = (char*) Lmalloc(L, sz); + if (!buf->arr) { + freelist_free (fl); + luaL_error (L, "malloc failed"); + } + buf->size = sz; + buf->top = 0; + buf->L = L; + buf->freelist = fl; + freelist_add (fl, buf); +} + +void buffer_free (TBuffer *buf) { + Lfree(buf->L, buf->arr, buf->size); +} + +void buffer_clear (TBuffer *buf) { + buf->top = 0; +} + +void buffer_pushresult (TBuffer *buf) { + lua_pushlstring (buf->L, buf->arr, buf->top); +} + +void buffer_addbuffer (TBuffer *trg, TBuffer *src) { + buffer_addlstring (trg, src->arr, src->top); +} + +void buffer_addlstring (TBuffer *buf, const void *src, size_t sz) { + size_t newtop = buf->top + sz; + if (newtop > buf->size) { + char *p = (char*) Lrealloc (buf->L, buf->arr, buf->size, 2 * newtop); /* 2x expansion */ + if (!p) { + freelist_free (buf->freelist); + luaL_error (buf->L, "realloc failed"); + } + buf->arr = p; + buf->size = 2 * newtop; + } + if (src) + memcpy (buf->arr + buf->top, src, sz); + buf->top = newtop; +} + +void buffer_addvalue (TBuffer *buf, int stackpos) { + size_t len; + const char *p = lua_tolstring (buf->L, stackpos, &len); + buffer_addlstring (buf, p, len); +} + +void bufferZ_addlstring (TBuffer *buf, const void *src, size_t len) { + int n; + size_t header[2] = { ID_STRING }; + header[1] = len; + buffer_addlstring (buf, header, sizeof (header)); + buffer_addlstring (buf, src, len); + n = len % N_ALIGN; + if (n) buffer_addlstring (buf, NULL, N_ALIGN - n); +} + +void bufferZ_addnum (TBuffer *buf, size_t num) { + size_t header[2] = { ID_NUMBER }; + header[1] = num; + buffer_addlstring (buf, header, sizeof (header)); +} + +/* 1. When called repeatedly on the same TBuffer, its existing data + is discarded and overwritten by the new data. + 2. The TBuffer's array is never shrunk by this function. +*/ +void bufferZ_putrepstring (TBuffer *BufRep, int reppos, int nsub) { + char dbuf[] = { 0, 0 }; + size_t replen; + const char *p = lua_tolstring (BufRep->L, reppos, &replen); + const char *end = p + replen; + BufRep->top = 0; + while (p < end) { + const char *q; + for (q = p; q < end && *q != '%'; ++q) + {} + if (q != p) + bufferZ_addlstring (BufRep, p, q - p); + if (q < end) { + if (++q < end) { /* skip % */ + if (g_ascii_isdigit (*q)) { + int num; + *dbuf = *q; + num = strtol (dbuf, NULL, 10); + if (num == 1 && nsub == 0) + num = 0; + else if (num > nsub) { + freelist_free (BufRep->freelist); + luaL_error (BufRep->L, "invalid capture index"); + } + bufferZ_addnum (BufRep, num); + } + else bufferZ_addlstring (BufRep, q, 1); + } + p = q + 1; + } + else break; + } +} + +/****************************************************************************** + The intended use of this function is as follows: + size_t iter = 0; + while (bufferZ_next (buf, &iter, &num, &str)) { + if (str) do_something_with_string (str, num); + else do_something_with_number (num); + } +******************************************************************************* +*/ +int bufferZ_next (TBuffer *buf, size_t *iter, size_t *num, const char **str) { + if (*iter < buf->top) { + size_t *ptr_header = (size_t*)(buf->arr + *iter); + *num = ptr_header[1]; + *iter += 2 * sizeof (size_t); + *str = NULL; + if (*ptr_header == ID_STRING) { + int n; + *str = buf->arr + *iter; + *iter += *num; + n = *iter % N_ALIGN; + if (n) *iter += (N_ALIGN - n); + } + return 1; + } + return 0; +} + +#if LUA_VERSION_NUM > 501 +int luaL_typerror (lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", + tname, luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); +} +#endif + +#ifndef REX_NOEMBEDDEDTEST +static int ud_topointer (lua_State *L) { + lua_pushlightuserdata (L, lua_touserdata (L, 1)); + return 1; +} + +static int ud_len (lua_State *L) { + lua_pushinteger (L, lua_objlen (L, 1)); + return 1; +} + +/* for testing purposes only */ +int newmembuffer (lua_State *L) { + size_t len; + const char* s = luaL_checklstring (L, 1, &len); + void *ud = lua_newuserdata (L, len); + memcpy (ud, s, len); + lua_newtable (L); /* metatable */ + lua_pushvalue (L, -1); + lua_setfield (L, -2, "__index"); /* metatable.__index = metatable */ + lua_pushcfunction (L, ud_topointer); + lua_setfield (L, -2, "topointer"); + lua_pushcfunction (L, ud_len); + lua_setfield (L, -2, "__len"); + lua_setmetatable (L, -2); + return 1; +} +#endif /* #ifndef REX_NOEMBEDDEDTEST */ diff --git a/epan/wslua/lrexlib/common.h b/epan/wslua/lrexlib/common.h new file mode 100644 index 00000000..121e54c7 --- /dev/null +++ b/epan/wslua/lrexlib/common.h @@ -0,0 +1,128 @@ +/* common.h */ +/* + * Copyright (C) Reuben Thomas 2000-2020 + * Copyright (C) Shmuel Zeigerman 2004-2020 + + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the + * Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef COMMON_H +#define COMMON_H + +#include "lua.h" + +#if LUA_VERSION_NUM > 501 +# define lua_objlen lua_rawlen + int luaL_typerror (lua_State *L, int narg, const char *tname); +#endif + +/* REX_API can be overridden from the command line or Makefile */ +#ifndef REX_API +# define REX_API LUALIB_API +#endif + +/* Special values for maxmatch in gsub. They all must be negative. */ +#define GSUB_UNLIMITED -1 +#define GSUB_CONDITIONAL -2 + +/* Common structs and functions */ + +typedef struct { + const char* key; + int val; +} flag_pair; + +typedef struct { /* compile arguments */ + const char * pattern; + size_t patlen; + void * ud; + int cflags; + const char * locale; /* PCRE, Oniguruma */ + const unsigned char * tables; /* PCRE */ + int tablespos; /* PCRE */ + void * syntax; /* Oniguruma */ + const unsigned char * translate; /* GNU */ + int gnusyn; /* GNU */ +} TArgComp; + +typedef struct { /* exec arguments */ + const char * text; + size_t textlen; + int startoffset; + int eflags; + int funcpos; + int maxmatch; + int funcpos2; /* used with gsub */ + int reptype; /* used with gsub */ + size_t ovecsize; /* PCRE: dfa_exec */ + size_t wscount; /* PCRE: dfa_exec */ +} TArgExec; + +struct tagFreeList; /* forward declaration */ + +struct tagBuffer { + size_t size; + size_t top; + char * arr; + lua_State * L; + struct tagFreeList * freelist; +}; + +struct tagFreeList { + struct tagBuffer * list[16]; + int top; +}; + +typedef struct tagBuffer TBuffer; +typedef struct tagFreeList TFreeList; + +void freelist_init (TFreeList *fl); +void freelist_add (TFreeList *fl, TBuffer *buf); +void freelist_free (TFreeList *fl); + +void buffer_init (TBuffer *buf, size_t sz, lua_State *L, TFreeList *fl); +void buffer_free (TBuffer *buf); +void buffer_clear (TBuffer *buf); +void buffer_addbuffer (TBuffer *trg, TBuffer *src); +void buffer_addlstring (TBuffer *buf, const void *src, size_t sz); +void buffer_addvalue (TBuffer *buf, int stackpos); +void buffer_pushresult (TBuffer *buf); + +void bufferZ_putrepstring (TBuffer *buf, int reppos, int nsub); +int bufferZ_next (TBuffer *buf, size_t *iter, size_t *len, const char **str); +void bufferZ_addlstring (TBuffer *buf, const void *src, size_t len); +void bufferZ_addnum (TBuffer *buf, size_t num); + +int get_int_field (lua_State *L, const char* field); +void set_int_field (lua_State *L, const char* field, int val); +int get_flags (lua_State *L, const flag_pair **arr); +const char *get_flag_key (const flag_pair *fp, int val); +void *Lmalloc (lua_State *L, size_t size); +void *Lrealloc (lua_State *L, void *p, size_t osize, size_t nsize); +void Lfree (lua_State *L, void *p, size_t size); + +#ifndef REX_NOEMBEDDEDTEST +int newmembuffer (lua_State *L); +#endif + +#endif diff --git a/epan/wslua/lrexlib/pcre2/lpcre2.c b/epan/wslua/lrexlib/pcre2/lpcre2.c new file mode 100644 index 00000000..f24cbec8 --- /dev/null +++ b/epan/wslua/lrexlib/pcre2/lpcre2.c @@ -0,0 +1,544 @@ +/* lpcre2.c - Lua binding of PCRE2 library */ +/* + * Copyright (C) Reuben Thomas 2000-2020 + * Copyright (C) Shmuel Zeigerman 2004-2020 + + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the + * Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <wireshark.h> +DIAG_OFF_CLANG(shorten-64-to-32) +DIAG_OFF_CLANG(comma) +#ifdef _MSC_VER +/* disable: " warning C4244: '=': conversion from 'lua _Integer' to 'int', + * possible loss of data" */ +#pragma warning(disable:4244) +/* warning C4267: '+=': conversion from 'size_t' to 'int', + * possible loss of data */ +#pragma warning(disable:4267) +#endif + +#define malloc_free free +#define rex_atoi atoi + +#include <stdlib.h> +#include <string.h> +#include <locale.h> +#include <ctype.h> +#include <stdint.h> +#include <pcre2.h> + +#include "lua.h" +#include "lauxlib.h" +#include "../common.h" + +#include <wslua/wslua.h> + +extern int Lpcre2_get_flags (lua_State *L); +extern int Lpcre2_config (lua_State *L); +extern flag_pair pcre2_error_flags[]; + +/* These 2 settings may be redefined from the command-line or the makefile. + * They should be kept in sync between themselves and with the target name. + */ +#ifndef REX_LIBNAME +# define REX_LIBNAME "rex_pcre2" +#endif +#ifndef REX_OPENLIB +# define REX_OPENLIB luaopen_rex_pcre2 +#endif + +#define REX_TYPENAME REX_LIBNAME"_regex" + +#define ALG_CFLAGS_DFLT 0 +#define ALG_EFLAGS_DFLT 0 + +static int getcflags (lua_State *L, int pos); +#define ALG_GETCFLAGS(L,pos) getcflags(L, pos) + +static void checkarg_compile (lua_State *L, int pos, TArgComp *argC); +#define ALG_GETCARGS(a,b,c) checkarg_compile(a,b,c) + +#define ALG_NOMATCH(res) ((res) == PCRE2_ERROR_NOMATCH) +#define ALG_ISMATCH(res) ((res) >= 0) +#define ALG_SUBBEG(ud,n) ((int)(ud)->ovector[(n)+(n)]) +#define ALG_SUBEND(ud,n) ((int)(ud)->ovector[(n)+(n)+1]) +#define ALG_SUBLEN(ud,n) (ALG_SUBEND((ud),(n)) - ALG_SUBBEG((ud),(n))) +#define ALG_SUBVALID(ud,n) (0 == pcre2_substring_length_bynumber((ud)->match_data, (n), NULL)) +#define ALG_NSUB(ud) ((int)(ud)->ncapt) + +#define ALG_PUSHSUB(L,ud,text,n) \ + lua_pushlstring (L, (text) + ALG_SUBBEG((ud),(n)), ALG_SUBLEN((ud),(n))) + +#define ALG_PUSHSUB_OR_FALSE(L,ud,text,n) \ + (ALG_SUBVALID(ud,n) ? (void) ALG_PUSHSUB (L,ud,text,n) : lua_pushboolean (L,0)) + +#define ALG_PUSHSTART(L,ud,offs,n) lua_pushinteger(L, (offs) + ALG_SUBBEG(ud,n) + 1) +#define ALG_PUSHEND(L,ud,offs,n) lua_pushinteger(L, (offs) + ALG_SUBEND(ud,n)) +#define ALG_PUSHOFFSETS(L,ud,offs,n) \ + (ALG_PUSHSTART(L,ud,offs,n), ALG_PUSHEND(L,ud,offs,n)) + +#define ALG_BASE(st) 0 +#define ALG_PULL + +typedef struct { + pcre2_code *pr; + pcre2_compile_context *ccontext; + pcre2_match_data *match_data; + PCRE2_SIZE *ovector; + int ncapt; + const unsigned char *tables; + int freed; +} TPcre2; + +#define TUserdata TPcre2 + +static void do_named_subpatterns (lua_State *L, TPcre2 *ud, const char *text); +# define DO_NAMED_SUBPATTERNS do_named_subpatterns + +#include "../algo.h" + +/* Locations of the 2 permanent tables in the function environment */ +#define INDEX_CHARTABLES_META 1 /* chartables type's metatable */ +#define INDEX_CHARTABLES_LINK 2 /* link chartables to compiled regex */ + +const char chartables_typename[] = "chartables"; + +/* Functions + ****************************************************************************** + */ + +static int push_error_message (lua_State *L, int errorcode) //### is this function needed? +{ + PCRE2_UCHAR buf[256]; + if (pcre2_get_error_message(errorcode, buf, 256) > 0) + { + lua_pushstring(L, (const char*)buf); + return 1; + } + return 0; +} + +static int getcflags (lua_State *L, int pos) { + switch (lua_type (L, pos)) { + case LUA_TNONE: + case LUA_TNIL: + return ALG_CFLAGS_DFLT; + case LUA_TNUMBER: + return lua_tointeger (L, pos); + case LUA_TSTRING: { + const char *s = lua_tostring (L, pos); + int res = 0, ch; + while ((ch = *s++) != '\0') { + if (ch == 'i') res |= PCRE2_CASELESS; + else if (ch == 'm') res |= PCRE2_MULTILINE; + else if (ch == 's') res |= PCRE2_DOTALL; + else if (ch == 'x') res |= PCRE2_EXTENDED; + else if (ch == 'U') res |= PCRE2_UNGREEDY; + //else if (ch == 'X') res |= PCRE2_EXTRA; //### does not exist in PCRE2 -> reflect in manual + } + return res; + } + default: + return luaL_typerror (L, pos, "number or string"); + } +} + +static int generate_error (lua_State *L, const TPcre2 *ud, int errcode) { + const char *key = get_flag_key (pcre2_error_flags, errcode); + (void) ud; + if (key) + return luaL_error (L, "error PCRE2_%s", key); + else + return luaL_error (L, "PCRE2 error code %d", errcode); +} + +/* method r:dfa_exec (s, [st], [ef], [ovecsize], [wscount]) */ +static void checkarg_dfa_exec (lua_State *L, TArgExec *argE, TPcre2 **ud) { + *ud = check_ud (L); + argE->text = luaL_checklstring (L, 2, &argE->textlen); + argE->startoffset = get_startoffset (L, 3, argE->textlen); + argE->eflags = (int)luaL_optinteger (L, 4, ALG_EFLAGS_DFLT); + argE->ovecsize = (size_t)luaL_optinteger (L, 5, 100); + argE->wscount = (size_t)luaL_optinteger (L, 6, 50); +} + +static void push_chartables_meta (lua_State *L) { + lua_pushinteger (L, INDEX_CHARTABLES_META); + lua_rawget (L, ALG_ENVIRONINDEX); +} + +static int Lpcre2_maketables (lua_State *L) { + *(const void**)lua_newuserdata (L, sizeof(void*)) = pcre2_maketables(NULL); //### argument NULL + push_chartables_meta (L); + lua_setmetatable (L, -2); + return 1; +} + +static void **check_chartables (lua_State *L, int pos) { + void **q; + /* Compare the metatable against the C function environment. */ + if (lua_getmetatable(L, pos)) { + push_chartables_meta (L); + if (lua_rawequal(L, -1, -2) && + (q = (void **)lua_touserdata(L, pos)) != NULL) { + lua_pop(L, 2); + return q; + } + } + luaL_argerror(L, pos, lua_pushfstring (L, "not a %s", chartables_typename)); + return NULL; +} + +static int chartables_gc (lua_State *L) { + void **ud = check_chartables (L, 1); + if (*ud) { + malloc_free (*ud); //### free() should be called only if pcre2_maketables was called with NULL argument + *ud = NULL; + } + return 0; +} + +static int chartables_tostring (lua_State *L) { + void **ud = check_chartables (L, 1); + lua_pushfstring (L, "%s (%p)", chartables_typename, ud); + return 1; +} + +static void checkarg_compile (lua_State *L, int pos, TArgComp *argC) { + argC->locale = NULL; + argC->tables = NULL; + if (!lua_isnoneornil (L, pos)) { + if (lua_isstring (L, pos)) + argC->locale = lua_tostring (L, pos); + else { + argC->tablespos = pos; + argC->tables = (const unsigned char*) *check_chartables (L, pos); + } + } +} + +static int compile_regex (lua_State *L, const TArgComp *argC, TPcre2 **pud) { + int errcode; + PCRE2_SIZE erroffset; + TPcre2 *ud; + + ud = (TPcre2*)lua_newuserdata (L, sizeof (TPcre2)); + memset (ud, 0, sizeof (TPcre2)); /* initialize all members to 0 */ + lua_pushvalue (L, ALG_ENVIRONINDEX); + lua_setmetatable (L, -2); + + ud->ccontext = pcre2_compile_context_create(NULL); + if (ud->ccontext == NULL) + return luaL_error (L, "malloc failed"); + + if (argC->locale) { + char old_locale[256]; + g_strlcpy (old_locale, setlocale (LC_CTYPE, NULL), sizeof(old_locale)); /* store the locale */ + if (NULL == setlocale (LC_CTYPE, argC->locale)) /* set new locale */ + return luaL_error (L, "cannot set locale"); + ud->tables = pcre2_maketables (NULL); /* make tables with new locale */ //### argument NULL + pcre2_set_character_tables(ud->ccontext, ud->tables); + setlocale (LC_CTYPE, old_locale); /* restore the old locale */ + } + else if (argC->tables) { + pcre2_set_character_tables(ud->ccontext, argC->tables); + lua_pushinteger (L, INDEX_CHARTABLES_LINK); + lua_rawget (L, ALG_ENVIRONINDEX); + lua_pushvalue (L, -2); + lua_pushvalue (L, argC->tablespos); + lua_rawset (L, -3); + lua_pop (L, 1); + } + + ud->pr = pcre2_compile ((PCRE2_SPTR)argC->pattern, argC->patlen, argC->cflags, &errcode, + &erroffset, ud->ccontext); //### DOUBLE-CHECK ALL ARGUMENTS + if (!ud->pr) { + if (push_error_message(L, errcode)) + return luaL_error (L, "%s (pattern offset: %d)", lua_tostring(L,-1), erroffset + 1); + else + return luaL_error (L, "%s (pattern offset: %d)", "pattern compile error", erroffset + 1); + } + + if (0 != pcre2_pattern_info (ud->pr, PCRE2_INFO_CAPTURECOUNT, &ud->ncapt)) //### + return luaL_error (L, "could not get pattern info"); + + /* need (2 ints per capture, plus one for substring match) * 3/2 */ + ud->match_data = pcre2_match_data_create(ud->ncapt+1, NULL); //### CHECK ALL + if (!ud->match_data) + return luaL_error (L, "malloc failed"); + + ud->ovector = pcre2_get_ovector_pointer(ud->match_data); + + if (pud) *pud = ud; + return 1; +} + +/* the target table must be on lua stack top */ +static void do_named_subpatterns (lua_State *L, TPcre2 *ud, const char *text) { + int i, namecount, name_entry_size; + unsigned char *name_table; + PCRE2_SPTR tabptr; + + /* do named subpatterns - NJG */ + pcre2_pattern_info (ud->pr, PCRE2_INFO_NAMECOUNT, &namecount); + if (namecount <= 0) + return; + pcre2_pattern_info (ud->pr, PCRE2_INFO_NAMETABLE, &name_table); + pcre2_pattern_info (ud->pr, PCRE2_INFO_NAMEENTRYSIZE, &name_entry_size); + tabptr = name_table; + for (i = 0; i < namecount; i++) { + int n = (tabptr[0] << 8) | tabptr[1]; /* number of the capturing parenthesis */ + if (n > 0 && n <= ALG_NSUB(ud)) { /* check range */ + lua_pushstring (L, (char *)tabptr + 2); /* name of the capture, zero terminated */ + ALG_PUSHSUB_OR_FALSE (L, ud, text, n); + lua_rawset (L, -3); + } + tabptr += name_entry_size; + } +} + +static int Lpcre2_dfa_exec (lua_State *L) +{ + TArgExec argE; + TPcre2 *ud; + int res; + int *wspace; + size_t wsize; + + checkarg_dfa_exec (L, &argE, &ud); + wsize = argE.wscount * sizeof(int); + wspace = (int*) Lmalloc (L, wsize); + if (!wspace) + luaL_error (L, "malloc failed"); + + ud->match_data = pcre2_match_data_create(argE.ovecsize/2, NULL); //### CHECK ALL + if (!ud->match_data) + return luaL_error (L, "malloc failed"); + + res = pcre2_dfa_match (ud->pr, (PCRE2_SPTR)argE.text, argE.textlen, argE.startoffset, + argE.eflags, ud->match_data, NULL, wspace, argE.wscount); //### CHECK ALL + + if (ALG_ISMATCH (res) || res == PCRE2_ERROR_PARTIAL) { + int i; + int max = (res>0) ? res : (res==0) ? (int)argE.ovecsize/2 : 1; + PCRE2_SIZE* ovector = pcre2_get_ovector_pointer(ud->match_data); + + lua_pushinteger (L, ovector[0] + 1); /* 1-st return value */ + lua_newtable (L); /* 2-nd return value */ + for (i=0; i<max; i++) { + lua_pushinteger (L, ovector[i+i+1]); + lua_rawseti (L, -2, i+1); + } + lua_pushinteger (L, res); /* 3-rd return value */ + Lfree (L, wspace, wsize); + return 3; + } + else { + Lfree (L, wspace, wsize); + if (ALG_NOMATCH (res)) + return lua_pushnil (L), 1; + else + return generate_error (L, ud, res); + } +} + +static int gmatch_exec (TUserdata *ud, TArgExec *argE) { + return pcre2_match (ud->pr, (PCRE2_SPTR)argE->text, argE->textlen, + argE->startoffset, argE->eflags, ud->match_data, NULL); //### +} + +static void gmatch_pushsubject (lua_State *L, TArgExec *argE) { + lua_pushlstring (L, argE->text, argE->textlen); +} + +static int findmatch_exec (TPcre2 *ud, TArgExec *argE) { + return pcre2_match (ud->pr, (PCRE2_SPTR)argE->text, argE->textlen, + argE->startoffset, argE->eflags, ud->match_data, NULL); //### +} + +static int gsub_exec (TPcre2 *ud, TArgExec *argE, int st) { + return pcre2_match (ud->pr, (PCRE2_SPTR)argE->text, argE->textlen, + st, argE->eflags, ud->match_data, NULL); //### +} + +static int split_exec (TPcre2 *ud, TArgExec *argE, int offset) { + return pcre2_match (ud->pr, (PCRE2_SPTR)argE->text, argE->textlen, + offset, argE->eflags, ud->match_data, NULL); //### +} + +static int Lpcre2_gc (lua_State *L) { + TPcre2 *ud = check_ud (L); + if (ud->freed == 0) { /* precaution against "manual" __gc calling */ + ud->freed = 1; + if (ud->pr) pcre2_code_free (ud->pr); + //if (ud->tables) pcre_free ((void *)ud->tables); //### + if (ud->ccontext) pcre2_compile_context_free (ud->ccontext); + if (ud->match_data) pcre2_match_data_free (ud->match_data); + } + return 0; +} + +static int Lpcre2_tostring (lua_State *L) { + TPcre2 *ud = check_ud (L); + if (ud->freed == 0) + lua_pushfstring (L, "%s (%p)", REX_TYPENAME, (void*)ud); + else + lua_pushfstring (L, "%s (deleted)", REX_TYPENAME); + return 1; +} + +static int Lpcre2_version (lua_State *L) { + char buf[64]; + pcre2_config(PCRE2_CONFIG_VERSION, buf); + lua_pushstring (L, buf); + return 1; +} + +//### TODO: document this method. +//### TODO: write tests for this method. +static int Lpcre2_jit_compile (lua_State *L) { + TPcre2 *ud = check_ud (L); + uint32_t options = (uint32_t) luaL_optinteger (L, 2, PCRE2_JIT_COMPLETE); + int errcode = pcre2_jit_compile (ud->pr, options); + if (errcode == 0) { + lua_pushboolean(L, 1); + return 1; + } + lua_pushboolean(L, 0); + return 1 + push_error_message(L, errcode); +} + +#define SET_INFO_FIELD(L,ud,what,name,valtype) { \ + valtype val; \ + if (0 == pcre2_pattern_info (ud->pr, what, &val)) { \ + lua_pushnumber (L, val); \ + lua_setfield (L, -2, name); \ + } \ +} + +static int Lpcre2_pattern_info (lua_State *L) { + TPcre2 *ud = check_ud (L); + lua_newtable(L); + + SET_INFO_FIELD (L, ud, PCRE2_INFO_ALLOPTIONS, "ALLOPTIONS", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_ARGOPTIONS, "ARGOPTIONS", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_BACKREFMAX, "BACKREFMAX", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_BSR, "BSR", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_CAPTURECOUNT, "CAPTURECOUNT", uint32_t) + //### SET_INFO_FIELD (L, ud, PCRE2_INFO_FIRSTBITMAP, "FIRSTBITMAP", ???) + SET_INFO_FIELD (L, ud, PCRE2_INFO_FIRSTCODETYPE, "FIRSTCODETYPE", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_FIRSTCODEUNIT, "FIRSTCODEUNIT", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_HASBACKSLASHC, "HASBACKSLASHC", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_HASCRORLF, "HASCRORLF", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_JCHANGED, "JCHANGED", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_JITSIZE, "JITSIZE", size_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_LASTCODETYPE, "LASTCODETYPE", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_LASTCODEUNIT, "LASTCODEUNIT", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_MATCHEMPTY, "MATCHEMPTY", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_MATCHLIMIT, "MATCHLIMIT", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_MAXLOOKBEHIND, "MAXLOOKBEHIND", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_MINLENGTH, "MINLENGTH", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_NAMECOUNT, "NAMECOUNT", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_NAMEENTRYSIZE, "NAMEENTRYSIZE", uint32_t) + //### SET_INFO_FIELD (L, ud, PCRE2_INFO_NAMETABLE, "NAMETABLE", ???) + SET_INFO_FIELD (L, ud, PCRE2_INFO_NEWLINE, "NEWLINE", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_RECURSIONLIMIT, "RECURSIONLIMIT", uint32_t) + SET_INFO_FIELD (L, ud, PCRE2_INFO_SIZE, "SIZE", size_t) + + return 1; +} + +static const luaL_Reg chartables_meta[] = { + { "__gc", chartables_gc }, + { "__tostring", chartables_tostring }, + { NULL, NULL } +}; + +static const luaL_Reg r_methods[] = { + { "exec", algm_exec }, + { "tfind", algm_tfind }, /* old name: match */ + { "find", algm_find }, + { "match", algm_match }, + { "dfa_exec", Lpcre2_dfa_exec }, + { "patterninfo", Lpcre2_pattern_info }, //### document name change: fullinfo -> patterninfo + { "fullinfo", Lpcre2_pattern_info }, //### compatibility name + { "jit_compile", Lpcre2_jit_compile }, + { "__gc", Lpcre2_gc }, + { "__tostring", Lpcre2_tostring }, + { NULL, NULL } +}; + +static const luaL_Reg r_functions[] = { + { "match", algf_match }, + { "find", algf_find }, + { "gmatch", algf_gmatch }, + { "gsub", algf_gsub }, + { "count", algf_count }, + { "split", algf_split }, + { "new", algf_new }, + { "flags", Lpcre2_get_flags }, + { "version", Lpcre2_version }, + { "maketables", Lpcre2_maketables }, + { "config", Lpcre2_config }, + { NULL, NULL } +}; + +/* Open the library */ +REX_API int REX_OPENLIB (lua_State *L) { + char buf_ver[64]; + pcre2_config(PCRE2_CONFIG_VERSION, buf_ver); + if (PCRE2_MAJOR > rex_atoi (buf_ver)) { + return luaL_error (L, "%s requires at least version %d of PCRE2 library", + REX_LIBNAME, (int)PCRE2_MAJOR); + } + + alg_register(L, r_methods, r_functions, "PCRE2"); + + /* create a table and register it as a metatable for "chartables" userdata */ + lua_newtable (L); + lua_pushliteral (L, "access denied"); + lua_setfield (L, -2, "__metatable"); +#if LUA_VERSION_NUM == 501 + luaL_register (L, NULL, chartables_meta); + lua_rawseti (L, LUA_ENVIRONINDEX, INDEX_CHARTABLES_META); +#else + lua_pushvalue(L, -3); + luaL_setfuncs (L, chartables_meta, 1); + lua_rawseti (L, -3, INDEX_CHARTABLES_META); +#endif + + /* create a table for connecting "chartables" userdata to "regex" userdata */ + lua_newtable (L); + lua_pushliteral (L, "k"); /* weak keys */ + lua_setfield (L, -2, "__mode"); + lua_pushvalue (L, -1); /* setmetatable (tb, tb) */ + lua_setmetatable (L, -2); +#if LUA_VERSION_NUM == 501 + lua_rawseti (L, LUA_ENVIRONINDEX, INDEX_CHARTABLES_LINK); +#else + lua_rawseti (L, -3, INDEX_CHARTABLES_LINK); +#endif + + return 1; +} diff --git a/epan/wslua/lrexlib/pcre2/lpcre2_f.c b/epan/wslua/lrexlib/pcre2/lpcre2_f.c new file mode 100644 index 00000000..659c8ac7 --- /dev/null +++ b/epan/wslua/lrexlib/pcre2/lpcre2_f.c @@ -0,0 +1,240 @@ +/* lpcre2_f.c - Lua binding of PCRE2 library */ +/* + * Copyright (C) Reuben Thomas 2000-2020 + * Copyright (C) Shmuel Zeigerman 2004-2020 + + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the + * Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <pcre2.h> +#include "lua.h" +#include "lauxlib.h" +#include "../common.h" + +#define VERSION_PCRE2 (PCRE2_MAJOR*100 + PCRE2_MINOR) + +extern int Lpcre2_get_flags (lua_State *L); +extern int Lpcre2_config (lua_State *L); + +static flag_pair pcre2_flags[] = { + { "MAJOR", PCRE2_MAJOR }, + { "MINOR", PCRE2_MINOR }, +/*---------------------------------------------------------------------------*/ + { "ANCHORED", PCRE2_ANCHORED }, + { "NO_UTF_CHECK", PCRE2_NO_UTF_CHECK }, + { "ALLOW_EMPTY_CLASS", PCRE2_ALLOW_EMPTY_CLASS }, + { "ALT_BSUX", PCRE2_ALT_BSUX }, + { "AUTO_CALLOUT", PCRE2_AUTO_CALLOUT }, + { "CASELESS", PCRE2_CASELESS }, + { "DOLLAR_ENDONLY", PCRE2_DOLLAR_ENDONLY }, + { "DOTALL", PCRE2_DOTALL }, + { "DUPNAMES", PCRE2_DUPNAMES }, + { "EXTENDED", PCRE2_EXTENDED }, + { "FIRSTLINE", PCRE2_FIRSTLINE }, + { "MATCH_UNSET_BACKREF", PCRE2_MATCH_UNSET_BACKREF }, + { "MULTILINE", PCRE2_MULTILINE }, + { "NEVER_UCP", PCRE2_NEVER_UCP }, + { "NEVER_UTF", PCRE2_NEVER_UTF }, + { "NO_AUTO_CAPTURE", PCRE2_NO_AUTO_CAPTURE }, + { "NO_AUTO_POSSESS", PCRE2_NO_AUTO_POSSESS }, + { "NO_DOTSTAR_ANCHOR", PCRE2_NO_DOTSTAR_ANCHOR }, + { "NO_START_OPTIMIZE", PCRE2_NO_START_OPTIMIZE }, + { "UCP", PCRE2_UCP }, + { "UNGREEDY", PCRE2_UNGREEDY }, + { "UTF", PCRE2_UTF }, + { "NEVER_BACKSLASH_C", PCRE2_NEVER_BACKSLASH_C }, + { "ALT_CIRCUMFLEX", PCRE2_ALT_CIRCUMFLEX }, + { "ALT_VERBNAMES", PCRE2_ALT_VERBNAMES }, + { "USE_OFFSET_LIMIT", PCRE2_USE_OFFSET_LIMIT }, + { "JIT_COMPLETE", PCRE2_JIT_COMPLETE }, + { "JIT_PARTIAL_SOFT", PCRE2_JIT_PARTIAL_SOFT }, + { "JIT_PARTIAL_HARD", PCRE2_JIT_PARTIAL_HARD }, + { "NOTBOL", PCRE2_NOTBOL }, + { "NOTEOL", PCRE2_NOTEOL }, + { "NOTEMPTY", PCRE2_NOTEMPTY }, + { "NOTEMPTY_ATSTART", PCRE2_NOTEMPTY_ATSTART }, + { "PARTIAL_SOFT", PCRE2_PARTIAL_SOFT }, + { "PARTIAL_HARD", PCRE2_PARTIAL_HARD }, + { "DFA_RESTART", PCRE2_DFA_RESTART }, + { "DFA_SHORTEST", PCRE2_DFA_SHORTEST }, + { "SUBSTITUTE_GLOBAL", PCRE2_SUBSTITUTE_GLOBAL }, + { "SUBSTITUTE_EXTENDED", PCRE2_SUBSTITUTE_EXTENDED }, + { "SUBSTITUTE_UNSET_EMPTY", PCRE2_SUBSTITUTE_UNSET_EMPTY }, + { "SUBSTITUTE_UNKNOWN_UNSET", PCRE2_SUBSTITUTE_UNKNOWN_UNSET }, + { "SUBSTITUTE_OVERFLOW_LENGTH", PCRE2_SUBSTITUTE_OVERFLOW_LENGTH }, +#ifdef PCRE2_NO_JIT + { "NO_JIT", PCRE2_NO_JIT }, +#endif + { "NEWLINE_CR", PCRE2_NEWLINE_CR }, + { "NEWLINE_LF", PCRE2_NEWLINE_LF }, + { "NEWLINE_CRLF", PCRE2_NEWLINE_CRLF }, + { "NEWLINE_ANY", PCRE2_NEWLINE_ANY }, + { "NEWLINE_ANYCRLF", PCRE2_NEWLINE_ANYCRLF }, + { "BSR_UNICODE", PCRE2_BSR_UNICODE }, + { "BSR_ANYCRLF", PCRE2_BSR_ANYCRLF }, +/*---------------------------------------------------------------------------*/ + { "INFO_ALLOPTIONS", PCRE2_INFO_ALLOPTIONS }, + { "INFO_ARGOPTIONS", PCRE2_INFO_ARGOPTIONS }, + { "INFO_BACKREFMAX", PCRE2_INFO_BACKREFMAX }, + { "INFO_BSR", PCRE2_INFO_BSR }, + { "INFO_CAPTURECOUNT", PCRE2_INFO_CAPTURECOUNT }, + { "INFO_FIRSTCODEUNIT", PCRE2_INFO_FIRSTCODEUNIT }, + { "INFO_FIRSTCODETYPE", PCRE2_INFO_FIRSTCODETYPE }, + { "INFO_FIRSTBITMAP", PCRE2_INFO_FIRSTBITMAP }, + { "INFO_HASCRORLF", PCRE2_INFO_HASCRORLF }, + { "INFO_JCHANGED", PCRE2_INFO_JCHANGED }, + { "INFO_JITSIZE", PCRE2_INFO_JITSIZE }, + { "INFO_LASTCODEUNIT", PCRE2_INFO_LASTCODEUNIT }, + { "INFO_LASTCODETYPE", PCRE2_INFO_LASTCODETYPE }, + { "INFO_MATCHEMPTY", PCRE2_INFO_MATCHEMPTY }, + { "INFO_MATCHLIMIT", PCRE2_INFO_MATCHLIMIT }, + { "INFO_MAXLOOKBEHIND", PCRE2_INFO_MAXLOOKBEHIND }, + { "INFO_MINLENGTH", PCRE2_INFO_MINLENGTH }, + { "INFO_NAMECOUNT", PCRE2_INFO_NAMECOUNT }, + { "INFO_NAMEENTRYSIZE", PCRE2_INFO_NAMEENTRYSIZE }, + { "INFO_NAMETABLE", PCRE2_INFO_NAMETABLE }, + { "INFO_NEWLINE", PCRE2_INFO_NEWLINE }, + { "INFO_RECURSIONLIMIT", PCRE2_INFO_RECURSIONLIMIT }, + { "INFO_SIZE", PCRE2_INFO_SIZE }, + { "INFO_HASBACKSLASHC", PCRE2_INFO_HASBACKSLASHC }, +/*---------------------------------------------------------------------------*/ + { NULL, 0 } +}; + +flag_pair pcre2_error_flags[] = { + { "ERROR_NOMATCH", PCRE2_ERROR_NOMATCH }, + { "ERROR_PARTIAL", PCRE2_ERROR_PARTIAL }, + { "ERROR_UTF8_ERR1", PCRE2_ERROR_UTF8_ERR1 }, + { "ERROR_UTF8_ERR2", PCRE2_ERROR_UTF8_ERR2 }, + { "ERROR_UTF8_ERR3", PCRE2_ERROR_UTF8_ERR3 }, + { "ERROR_UTF8_ERR4", PCRE2_ERROR_UTF8_ERR4 }, + { "ERROR_UTF8_ERR5", PCRE2_ERROR_UTF8_ERR5 }, + { "ERROR_UTF8_ERR6", PCRE2_ERROR_UTF8_ERR6 }, + { "ERROR_UTF8_ERR7", PCRE2_ERROR_UTF8_ERR7 }, + { "ERROR_UTF8_ERR8", PCRE2_ERROR_UTF8_ERR8 }, + { "ERROR_UTF8_ERR9", PCRE2_ERROR_UTF8_ERR9 }, + { "ERROR_UTF8_ERR10", PCRE2_ERROR_UTF8_ERR10 }, + { "ERROR_UTF8_ERR11", PCRE2_ERROR_UTF8_ERR11 }, + { "ERROR_UTF8_ERR12", PCRE2_ERROR_UTF8_ERR12 }, + { "ERROR_UTF8_ERR13", PCRE2_ERROR_UTF8_ERR13 }, + { "ERROR_UTF8_ERR14", PCRE2_ERROR_UTF8_ERR14 }, + { "ERROR_UTF8_ERR15", PCRE2_ERROR_UTF8_ERR15 }, + { "ERROR_UTF8_ERR16", PCRE2_ERROR_UTF8_ERR16 }, + { "ERROR_UTF8_ERR17", PCRE2_ERROR_UTF8_ERR17 }, + { "ERROR_UTF8_ERR18", PCRE2_ERROR_UTF8_ERR18 }, + { "ERROR_UTF8_ERR19", PCRE2_ERROR_UTF8_ERR19 }, + { "ERROR_UTF8_ERR20", PCRE2_ERROR_UTF8_ERR20 }, + { "ERROR_UTF8_ERR21", PCRE2_ERROR_UTF8_ERR21 }, + { "ERROR_UTF16_ERR1", PCRE2_ERROR_UTF16_ERR1 }, + { "ERROR_UTF16_ERR2", PCRE2_ERROR_UTF16_ERR2 }, + { "ERROR_UTF16_ERR3", PCRE2_ERROR_UTF16_ERR3 }, + { "ERROR_UTF32_ERR1", PCRE2_ERROR_UTF32_ERR1 }, + { "ERROR_UTF32_ERR2", PCRE2_ERROR_UTF32_ERR2 }, + { "ERROR_BADDATA", PCRE2_ERROR_BADDATA }, + { "ERROR_MIXEDTABLES", PCRE2_ERROR_MIXEDTABLES }, + { "ERROR_BADMAGIC", PCRE2_ERROR_BADMAGIC }, + { "ERROR_BADMODE", PCRE2_ERROR_BADMODE }, + { "ERROR_BADOFFSET", PCRE2_ERROR_BADOFFSET }, + { "ERROR_BADOPTION", PCRE2_ERROR_BADOPTION }, + { "ERROR_BADREPLACEMENT", PCRE2_ERROR_BADREPLACEMENT }, + { "ERROR_BADUTFOFFSET", PCRE2_ERROR_BADUTFOFFSET }, + { "ERROR_CALLOUT", PCRE2_ERROR_CALLOUT }, + { "ERROR_DFA_BADRESTART", PCRE2_ERROR_DFA_BADRESTART }, + { "ERROR_DFA_RECURSE", PCRE2_ERROR_DFA_RECURSE }, + { "ERROR_DFA_UCOND", PCRE2_ERROR_DFA_UCOND }, + { "ERROR_DFA_UFUNC", PCRE2_ERROR_DFA_UFUNC }, + { "ERROR_DFA_UITEM", PCRE2_ERROR_DFA_UITEM }, + { "ERROR_DFA_WSSIZE", PCRE2_ERROR_DFA_WSSIZE }, + { "ERROR_INTERNAL", PCRE2_ERROR_INTERNAL }, + { "ERROR_JIT_BADOPTION", PCRE2_ERROR_JIT_BADOPTION }, + { "ERROR_JIT_STACKLIMIT", PCRE2_ERROR_JIT_STACKLIMIT }, + { "ERROR_MATCHLIMIT", PCRE2_ERROR_MATCHLIMIT }, + { "ERROR_NOMEMORY", PCRE2_ERROR_NOMEMORY }, + { "ERROR_NOSUBSTRING", PCRE2_ERROR_NOSUBSTRING }, + { "ERROR_NOUNIQUESUBSTRING", PCRE2_ERROR_NOUNIQUESUBSTRING }, + { "ERROR_NULL", PCRE2_ERROR_NULL }, + { "ERROR_RECURSELOOP", PCRE2_ERROR_RECURSELOOP }, + { "ERROR_RECURSIONLIMIT", PCRE2_ERROR_RECURSIONLIMIT }, + { "ERROR_UNAVAILABLE", PCRE2_ERROR_UNAVAILABLE }, + { "ERROR_UNSET", PCRE2_ERROR_UNSET }, + { "ERROR_BADOFFSETLIMIT", PCRE2_ERROR_BADOFFSETLIMIT }, + { "ERROR_BADREPESCAPE", PCRE2_ERROR_BADREPESCAPE }, + { "ERROR_REPMISSINGBRACE", PCRE2_ERROR_REPMISSINGBRACE }, + { "ERROR_BADSUBSTITUTION", PCRE2_ERROR_BADSUBSTITUTION }, + { "ERROR_BADSUBSPATTERN", PCRE2_ERROR_BADSUBSPATTERN }, + { "ERROR_TOOMANYREPLACE", PCRE2_ERROR_TOOMANYREPLACE }, +#ifdef PCRE2_ERROR_BADSERIALIZEDDATA + { "ERROR_BADSERIALIZEDDATA", PCRE2_ERROR_BADSERIALIZEDDATA }, +#endif +/*---------------------------------------------------------------------------*/ + { NULL, 0 } +}; + +static flag_pair pcre2_config_flags[] = { + { "PCRE2_CONFIG_BSR", PCRE2_CONFIG_BSR }, + { "PCRE2_CONFIG_JIT", PCRE2_CONFIG_JIT }, + { "PCRE2_CONFIG_JITTARGET", PCRE2_CONFIG_JITTARGET }, + { "PCRE2_CONFIG_LINKSIZE", PCRE2_CONFIG_LINKSIZE }, + { "PCRE2_CONFIG_MATCHLIMIT", PCRE2_CONFIG_MATCHLIMIT }, + { "PCRE2_CONFIG_NEWLINE", PCRE2_CONFIG_NEWLINE }, + { "PCRE2_CONFIG_PARENSLIMIT", PCRE2_CONFIG_PARENSLIMIT }, + { "PCRE2_CONFIG_RECURSIONLIMIT", PCRE2_CONFIG_RECURSIONLIMIT }, + { "PCRE2_CONFIG_STACKRECURSE", PCRE2_CONFIG_STACKRECURSE }, + { "PCRE2_CONFIG_UNICODE", PCRE2_CONFIG_UNICODE }, + { "PCRE2_CONFIG_UNICODE_VERSION", PCRE2_CONFIG_UNICODE_VERSION }, + { "PCRE2_CONFIG_VERSION", PCRE2_CONFIG_VERSION }, +/*---------------------------------------------------------------------------*/ + { NULL, 0 } +}; + +extern int Lpcre2_config (lua_State *L) { + flag_pair *fp; + if (lua_istable (L, 1)) + lua_settop (L, 1); + else + lua_newtable (L); + for (fp = pcre2_config_flags; fp->key; ++fp) { + if (fp->val == PCRE2_CONFIG_JITTARGET) { +#if PCRE2_CODE_UNIT_WIDTH == 8 + char buf[64]; + if (PCRE2_ERROR_BADOPTION != pcre2_config (fp->val, buf)) { + lua_pushstring (L, buf); + lua_setfield (L, -2, fp->key); + } +#endif + } + else { + int val; + if (0 == pcre2_config (fp->val, &val)) { + lua_pushinteger (L, val); + lua_setfield (L, -2, fp->key); + } + } + } + return 1; +} + +extern int Lpcre2_get_flags (lua_State *L) { + const flag_pair* fps[] = { pcre2_flags, pcre2_error_flags, NULL }; + return get_flags (L, fps); +} |