Date: Thu, 14 Jan 2021 05:58:22 GMT From: Kyle Evans <kevans@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 0495ed398c4f - main - contrib/lua: update to 5.4.2 Message-ID: <202101140558.10E5wMNW079125@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=0495ed398c4f64013bab2327eb13a303e1f90c13 commit 0495ed398c4f64013bab2327eb13a303e1f90c13 Merge: 7ae27c2d6c4f 0ea45b9cd43c Author: Kyle Evans <kevans@FreeBSD.org> AuthorDate: 2021-01-14 05:56:18 +0000 Commit: Kyle Evans <kevans@FreeBSD.org> CommitDate: 2021-01-14 05:56:18 +0000 contrib/lua: update to 5.4.2 Merge commit '0ea45b9cd43ce1247eb3eee9bfd5cee3d19068e7' into main contrib/lua/Makefile | 30 +- contrib/lua/README | 2 +- contrib/lua/doc/contents.html | 81 +- contrib/lua/doc/lua.1 | 93 +- contrib/lua/doc/manual.html | 3260 ++++++++++++++++++++++++++-------------- contrib/lua/doc/readme.html | 115 +- contrib/lua/src/Makefile | 83 +- contrib/lua/src/lapi.c | 706 +++++---- contrib/lua/src/lapi.h | 27 +- contrib/lua/src/lauxlib.c | 385 ++--- contrib/lua/src/lauxlib.h | 54 +- contrib/lua/src/lbaselib.c | 139 +- contrib/lua/src/lbitlib.c | 233 --- contrib/lua/src/lcode.c | 1141 ++++++++++---- contrib/lua/src/lcode.h | 34 +- contrib/lua/src/lcorolib.c | 89 +- contrib/lua/src/lctype.c | 43 +- contrib/lua/src/lctype.h | 18 +- contrib/lua/src/ldblib.c | 94 +- contrib/lua/src/ldebug.c | 462 ++++-- contrib/lua/src/ldebug.h | 21 +- contrib/lua/src/ldo.c | 559 +++---- contrib/lua/src/ldo.h | 38 +- contrib/lua/src/ldump.c | 197 +-- contrib/lua/src/lfunc.c | 223 ++- contrib/lua/src/lfunc.h | 50 +- contrib/lua/src/lgc.c | 1387 +++++++++++------ contrib/lua/src/lgc.h | 128 +- contrib/lua/src/linit.c | 7 +- contrib/lua/src/liolib.c | 121 +- contrib/lua/src/ljumptab.h | 112 ++ contrib/lua/src/llex.c | 74 +- contrib/lua/src/llex.h | 12 +- contrib/lua/src/llimits.h | 134 +- contrib/lua/src/lmathlib.c | 433 +++++- contrib/lua/src/lmem.c | 178 ++- contrib/lua/src/lmem.h | 72 +- contrib/lua/src/loadlib.c | 261 ++-- contrib/lua/src/lobject.c | 340 +++-- contrib/lua/src/lobject.h | 737 ++++++--- contrib/lua/src/lopcodes.c | 190 ++- contrib/lua/src/lopcodes.h | 401 +++-- contrib/lua/src/lopnames.h | 103 ++ contrib/lua/src/loslib.c | 85 +- contrib/lua/src/lparser.c | 967 ++++++++---- contrib/lua/src/lparser.h | 80 +- contrib/lua/src/lprefix.h | 4 +- contrib/lua/src/lstate.c | 221 ++- contrib/lua/src/lstate.h | 202 ++- contrib/lua/src/lstring.c | 135 +- contrib/lua/src/lstring.h | 22 +- contrib/lua/src/lstrlib.c | 504 +++++-- contrib/lua/src/ltable.c | 692 ++++++--- contrib/lua/src/ltable.h | 22 +- contrib/lua/src/ltablib.c | 52 +- contrib/lua/src/ltm.c | 173 ++- contrib/lua/src/ltm.h | 37 +- contrib/lua/src/lua.c | 439 +++--- contrib/lua/src/lua.h | 60 +- contrib/lua/src/luac.c | 470 ++++-- contrib/lua/src/luaconf.h.dist | 253 ++-- contrib/lua/src/lualib.h | 5 +- contrib/lua/src/lundump.c | 266 ++-- contrib/lua/src/lundump.h | 8 +- contrib/lua/src/lutf8lib.c | 117 +- contrib/lua/src/lvm.c | 1762 ++++++++++++++-------- contrib/lua/src/lvm.h | 91 +- contrib/lua/src/lzio.c | 2 +- contrib/lua/src/lzio.h | 2 +- lib/liblua/Makefile | 2 +- lib/liblua/luaconf.h | 248 ++- stand/liblua/luaconf.h | 244 ++- 72 files changed, 12945 insertions(+), 7087 deletions(-) diff --cc contrib/lua/Makefile index a2820e04fe24,000000000000..36447a0f61c7 mode 100644,000000..100644 --- a/contrib/lua/Makefile +++ b/contrib/lua/Makefile @@@ -1,114 -1,0 +1,106 @@@ +# Makefile for installing Lua +# See doc/readme.html for installation and customization instructions. + +# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= + +# Your platform. See PLATS for possible values. - PLAT= none ++PLAT= guess + +# Where to install. The installation starts in the src and doc directories, +# so take care if INSTALL_TOP is not an absolute path. See the local target. +# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with +# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h. +INSTALL_TOP= /usr/local +INSTALL_BIN= $(INSTALL_TOP)/bin +INSTALL_INC= $(INSTALL_TOP)/include +INSTALL_LIB= $(INSTALL_TOP)/lib +INSTALL_MAN= $(INSTALL_TOP)/man/man1 +INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V +INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V + +# How to install. If your install program does not support "-p", then +# you may have to run ranlib on the installed liblua.a. +INSTALL= install -p +INSTALL_EXEC= $(INSTALL) -m 0755 +INSTALL_DATA= $(INSTALL) -m 0644 +# +# If you don't have "install" you can use "cp" instead. +# INSTALL= cp -p +# INSTALL_EXEC= $(INSTALL) +# INSTALL_DATA= $(INSTALL) + +# Other utilities. +MKDIR= mkdir -p +RM= rm -f + +# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= + +# Convenience platforms targets. - PLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris ++PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris + +# What to install. +TO_BIN= lua luac +TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp +TO_LIB= liblua.a +TO_MAN= lua.1 luac.1 + +# Lua version and release. - V= 5.3 - R= $V.6 ++V= 5.4 ++R= $V.2 + +# Targets start here. +all: $(PLAT) + - $(PLATS) clean: - cd src && $(MAKE) $@ - - test: dummy - src/lua -v ++$(PLATS) help test clean: ++ @cd src && $(MAKE) $@ + +install: dummy + cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD) + cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN) + cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC) + cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) + cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) + +uninstall: + cd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN) + cd src && cd $(INSTALL_INC) && $(RM) $(TO_INC) + cd src && cd $(INSTALL_LIB) && $(RM) $(TO_LIB) + cd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN) + +local: + $(MAKE) install INSTALL_TOP=../install + - none: - @echo "Please do 'make PLATFORM' where PLATFORM is one of these:" - @echo " $(PLATS)" - @echo "See doc/readme.html for complete instructions." - - # make may get confused with test/ and install/ ++# make may get confused with install/ if it does not support .PHONY. +dummy: + - # echo config parameters ++# Echo config parameters. +echo: + @cd src && $(MAKE) -s echo + @echo "PLAT= $(PLAT)" + @echo "V= $V" + @echo "R= $R" + @echo "TO_BIN= $(TO_BIN)" + @echo "TO_INC= $(TO_INC)" + @echo "TO_LIB= $(TO_LIB)" + @echo "TO_MAN= $(TO_MAN)" + @echo "INSTALL_TOP= $(INSTALL_TOP)" + @echo "INSTALL_BIN= $(INSTALL_BIN)" + @echo "INSTALL_INC= $(INSTALL_INC)" + @echo "INSTALL_LIB= $(INSTALL_LIB)" + @echo "INSTALL_MAN= $(INSTALL_MAN)" + @echo "INSTALL_LMOD= $(INSTALL_LMOD)" + @echo "INSTALL_CMOD= $(INSTALL_CMOD)" + @echo "INSTALL_EXEC= $(INSTALL_EXEC)" + @echo "INSTALL_DATA= $(INSTALL_DATA)" + - # echo pkg-config data ++# Echo pkg-config data. +pc: + @echo "version=$R" + @echo "prefix=$(INSTALL_TOP)" + @echo "libdir=$(INSTALL_LIB)" + @echo "includedir=$(INSTALL_INC)" + - # list targets that do not create files (but not all makes understand .PHONY) - .PHONY: all $(PLATS) clean test install local none dummy echo pecho lecho ++# Targets that do not create files (not all makes understand .PHONY). ++.PHONY: all $(PLATS) help test clean install uninstall local dummy echo pc + +# (end of Makefile) diff --cc contrib/lua/README index f8bdb6f41d00,000000000000..bc8a9d737d26 mode 100644,000000..100644 --- a/contrib/lua/README +++ b/contrib/lua/README @@@ -1,6 -1,0 +1,6 @@@ + - This is Lua 5.3.6, released on 14 Sep 2020. ++This is Lua 5.4.2, released on 13 Nov 2020. + +For installation instructions, license details, and +further information about Lua, see doc/readme.html. + diff --cc contrib/lua/src/ljumptab.h index 000000000000,8306f250ccb6..8306f250ccb6 mode 000000,100644..100644 --- a/contrib/lua/src/ljumptab.h +++ b/contrib/lua/src/ljumptab.h diff --cc contrib/lua/src/lopnames.h index 000000000000,965cec9bf2fa..965cec9bf2fa mode 000000,100644..100644 --- a/contrib/lua/src/lopnames.h +++ b/contrib/lua/src/lopnames.h diff --cc contrib/lua/src/lstrlib.c index 28064960818f,000000000000..ed88abdb4db2 mode 100644,000000..100644 --- a/contrib/lua/src/lstrlib.c +++ b/contrib/lua/src/lstrlib.c @@@ -1,1605 -1,0 +1,1825 @@@ +/* - ** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $ ++** $Id: lstrlib.c $ +** Standard library for string operations and pattern-matching +** See Copyright Notice in lua.h +*/ + +#define lstrlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include <ctype.h> +#include <float.h> +#include <limits.h> +#include <locale.h> ++#include <math.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** maximum number of captures that a pattern can do during +** pattern-matching. This limit is arbitrary, but must fit in +** an unsigned char. +*/ +#if !defined(LUA_MAXCAPTURES) +#define LUA_MAXCAPTURES 32 +#endif + + +/* macro to 'unsign' a character */ +#define uchar(c) ((unsigned char)(c)) + + +/* +** Some sizes are better limited to fit in 'int', but must also fit in +** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) +*/ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +#define MAXSIZE \ + (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) + + + + +static int str_len (lua_State *L) { + size_t l; + luaL_checklstring(L, 1, &l); + lua_pushinteger(L, (lua_Integer)l); + return 1; +} + + - /* translate a relative string position: negative means back from end */ - static lua_Integer posrelat (lua_Integer pos, size_t len) { - if (pos >= 0) return pos; - else if (0u - (size_t)pos > len) return 0; - else return (lua_Integer)len + pos + 1; ++/* ++** translate a relative initial string position ++** (negative means back from end): clip result to [1, inf). ++** The length of any string in Lua must fit in a lua_Integer, ++** so there are no overflows in the casts. ++** The inverted comparison avoids a possible overflow ++** computing '-pos'. ++*/ ++static size_t posrelatI (lua_Integer pos, size_t len) { ++ if (pos > 0) ++ return (size_t)pos; ++ else if (pos == 0) ++ return 1; ++ else if (pos < -(lua_Integer)len) /* inverted comparison */ ++ return 1; /* clip to 1 */ ++ else return len + (size_t)pos + 1; ++} ++ ++ ++/* ++** Gets an optional ending string position from argument 'arg', ++** with default value 'def'. ++** Negative means back from end: clip result to [0, len] ++*/ ++static size_t getendpos (lua_State *L, int arg, lua_Integer def, ++ size_t len) { ++ lua_Integer pos = luaL_optinteger(L, arg, def); ++ if (pos > (lua_Integer)len) ++ return len; ++ else if (pos >= 0) ++ return (size_t)pos; ++ else if (pos < -(lua_Integer)len) ++ return 0; ++ else return len + (size_t)pos + 1; +} + + +static int str_sub (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); - lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); - lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); - if (start < 1) start = 1; - if (end > (lua_Integer)l) end = l; ++ size_t start = posrelatI(luaL_checkinteger(L, 2), l); ++ size_t end = getendpos(L, 3, -1, l); + if (start <= end) - lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); ++ lua_pushlstring(L, s + start - 1, (end - start) + 1); + else lua_pushliteral(L, ""); + return 1; +} + + +static int str_reverse (lua_State *L) { + size_t l, i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); + return 1; +} + + +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i=0; i<l; i++) + p[i] = tolower(uchar(s[i])); + luaL_pushresultsize(&b, l); + return 1; +} + + +static int str_upper (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i=0; i<l; i++) + p[i] = toupper(uchar(s[i])); + luaL_pushresultsize(&b, l); + return 1; +} + + +static int str_rep (lua_State *L) { + size_t l, lsep; + const char *s = luaL_checklstring(L, 1, &l); + lua_Integer n = luaL_checkinteger(L, 2); + const char *sep = luaL_optlstring(L, 3, "", &lsep); + if (n <= 0) lua_pushliteral(L, ""); + else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */ + return luaL_error(L, "resulting string too large"); + else { + size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, totallen); + while (n-- > 1) { /* first n-1 copies (followed by separator) */ + memcpy(p, s, l * sizeof(char)); p += l; + if (lsep > 0) { /* empty 'memcpy' is not that cheap */ + memcpy(p, sep, lsep * sizeof(char)); + p += lsep; + } + } + memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ + luaL_pushresultsize(&b, totallen); + } + return 1; +} + + +static int str_byte (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); - lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); - lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); ++ lua_Integer pi = luaL_optinteger(L, 2, 1); ++ size_t posi = posrelatI(pi, l); ++ size_t pose = getendpos(L, 3, pi, l); + int n, i; - if (posi < 1) posi = 1; - if (pose > (lua_Integer)l) pose = l; + if (posi > pose) return 0; /* empty interval; return no values */ - if (pose - posi >= INT_MAX) /* arithmetic overflow? */ ++ if (pose - posi >= (size_t)INT_MAX) /* arithmetic overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i<n; i++) + lua_pushinteger(L, uchar(s[posi+i-1])); + return n; +} + + +static int str_char (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, n); + for (i=1; i<=n; i++) { - lua_Integer c = luaL_checkinteger(L, i); - luaL_argcheck(L, uchar(c) == c, i, "value out of range"); ++ lua_Unsigned c = (lua_Unsigned)luaL_checkinteger(L, i); ++ luaL_argcheck(L, c <= (lua_Unsigned)UCHAR_MAX, i, "value out of range"); + p[i - 1] = uchar(c); + } + luaL_pushresultsize(&b, n); + return 1; +} + + - static int writer (lua_State *L, const void *b, size_t size, void *B) { - (void)L; - luaL_addlstring((luaL_Buffer *) B, (const char *)b, size); ++/* ++** Buffer to store the result of 'string.dump'. It must be initialized ++** after the call to 'lua_dump', to ensure that the function is on the ++** top of the stack when 'lua_dump' is called. ('luaL_buffinit' might ++** push stuff.) ++*/ ++struct str_Writer { ++ int init; /* true iff buffer has been initialized */ ++ luaL_Buffer B; ++}; ++ ++ ++static int writer (lua_State *L, const void *b, size_t size, void *ud) { ++ struct str_Writer *state = (struct str_Writer *)ud; ++ if (!state->init) { ++ state->init = 1; ++ luaL_buffinit(L, &state->B); ++ } ++ luaL_addlstring(&state->B, (const char *)b, size); + return 0; +} + + +static int str_dump (lua_State *L) { - luaL_Buffer b; ++ struct str_Writer state; + int strip = lua_toboolean(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, 1); - luaL_buffinit(L,&b); - if (lua_dump(L, writer, &b, strip) != 0) ++ lua_settop(L, 1); /* ensure function is on the top of the stack */ ++ state.init = 0; ++ if (lua_dump(L, writer, &state, strip) != 0) + return luaL_error(L, "unable to dump given function"); - luaL_pushresult(&b); ++ luaL_pushresult(&state.B); + return 1; +} + + + ++/* ++** {====================================================== ++** METAMETHODS ++** ======================================================= ++*/ ++ ++#if defined(LUA_NOCVTS2N) /* { */ ++ ++/* no coercion from strings to numbers */ ++ ++static const luaL_Reg stringmetamethods[] = { ++ {"__index", NULL}, /* placeholder */ ++ {NULL, NULL} ++}; ++ ++#else /* }{ */ ++ ++static int tonum (lua_State *L, int arg) { ++ if (lua_type(L, arg) == LUA_TNUMBER) { /* already a number? */ ++ lua_pushvalue(L, arg); ++ return 1; ++ } ++ else { /* check whether it is a numerical string */ ++ size_t len; ++ const char *s = lua_tolstring(L, arg, &len); ++ return (s != NULL && lua_stringtonumber(L, s) == len + 1); ++ } ++} ++ ++ ++static void trymt (lua_State *L, const char *mtname) { ++ lua_settop(L, 2); /* back to the original arguments */ ++ if (lua_type(L, 2) == LUA_TSTRING || !luaL_getmetafield(L, 2, mtname)) ++ luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2, ++ luaL_typename(L, -2), luaL_typename(L, -1)); ++ lua_insert(L, -3); /* put metamethod before arguments */ ++ lua_call(L, 2, 1); /* call metamethod */ ++} ++ ++ ++static int arith (lua_State *L, int op, const char *mtname) { ++ if (tonum(L, 1) && tonum(L, 2)) ++ lua_arith(L, op); /* result will be on the top */ ++ else ++ trymt(L, mtname); ++ return 1; ++} ++ ++ ++static int arith_add (lua_State *L) { ++ return arith(L, LUA_OPADD, "__add"); ++} ++ ++static int arith_sub (lua_State *L) { ++ return arith(L, LUA_OPSUB, "__sub"); ++} ++ ++static int arith_mul (lua_State *L) { ++ return arith(L, LUA_OPMUL, "__mul"); ++} ++ ++static int arith_mod (lua_State *L) { ++ return arith(L, LUA_OPMOD, "__mod"); ++} ++ ++static int arith_pow (lua_State *L) { ++ return arith(L, LUA_OPPOW, "__pow"); ++} ++ ++static int arith_div (lua_State *L) { ++ return arith(L, LUA_OPDIV, "__div"); ++} ++ ++static int arith_idiv (lua_State *L) { ++ return arith(L, LUA_OPIDIV, "__idiv"); ++} ++ ++static int arith_unm (lua_State *L) { ++ return arith(L, LUA_OPUNM, "__unm"); ++} ++ ++ ++static const luaL_Reg stringmetamethods[] = { ++ {"__add", arith_add}, ++ {"__sub", arith_sub}, ++ {"__mul", arith_mul}, ++ {"__mod", arith_mod}, ++ {"__pow", arith_pow}, ++ {"__div", arith_div}, ++ {"__idiv", arith_idiv}, ++ {"__unm", arith_unm}, ++ {"__index", NULL}, /* placeholder */ ++ {NULL, NULL} ++}; ++ ++#endif /* } */ ++ ++/* }====================================================== */ ++ +/* +** {====================================================== +** PATTERN MATCHING +** ======================================================= +*/ + + +#define CAP_UNFINISHED (-1) +#define CAP_POSITION (-2) + + +typedef struct MatchState { + const char *src_init; /* init of source string */ + const char *src_end; /* end ('\0') of source string */ + const char *p_end; /* end ('\0') of pattern */ + lua_State *L; + int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ + unsigned char level; /* total number of captures (finished or unfinished) */ + struct { + const char *init; + ptrdiff_t len; + } capture[LUA_MAXCAPTURES]; +} MatchState; + + +/* recursive function */ +static const char *match (MatchState *ms, const char *s, const char *p); + + +/* maximum recursion depth for 'match' */ +#if !defined(MAXCCALLS) +#define MAXCCALLS 200 +#endif + + +#define L_ESC '%' +#define SPECIALS "^$*+?.([%-" + + +static int check_capture (MatchState *ms, int l) { + l -= '1'; + if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); + return l; +} + + +static int capture_to_close (MatchState *ms) { + int level = ms->level; + for (level--; level>=0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); +} + + +static const char *classend (MatchState *ms, const char *p) { + switch (*p++) { + case L_ESC: { + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (ends with '%%')"); + return p+1; + } + case '[': { + if (*p == '^') p++; + do { /* look for a ']' */ + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (missing ']')"); + if (*(p++) == L_ESC && p < ms->p_end) + p++; /* skip escapes (e.g. '%]') */ + } while (*p != ']'); + return p+1; + } + default: { + return p; + } + } +} + + +static int match_class (int c, int cl) { + int res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'g' : res = isgraph(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; + case 'z' : res = (c == 0); break; /* deprecated option */ + default: return (cl == c); + } + return (islower(cl) ? res : !res); +} + + +static int matchbracketclass (int c, const char *p, const char *ec) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the '^' */ + } + while (++p < ec) { + if (*p == L_ESC) { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < ec)) { + p+=2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; +} + + +static int singlematch (MatchState *ms, const char *s, const char *p, + const char *ep) { + if (s >= ms->src_end) + return 0; + else { + int c = uchar(*s); + switch (*p) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } + } +} + + +static const char *matchbalance (MatchState *ms, const char *s, + const char *p) { + if (p >= ms->p_end - 1) + luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); + if (*s != *p) return NULL; + else { + int b = *p; + int e = *(p+1); + int cont = 1; + while (++s < ms->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} + + +static const char *max_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + ptrdiff_t i = 0; /* counts maximum expand for item */ + while (singlematch(ms, s + i, p, ep)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + const char *res = match(ms, (s+i), ep+1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; +} + + +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + for (;;) { + const char *res = match(ms, s, ep+1); + if (res != NULL) + return res; + else if (singlematch(ms, s, p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { + const char *res; + int level = ms->level; + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level+1; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; +} + + +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); + const char *res; + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; +} + + +static const char *match_capture (MatchState *ms, const char *s, int l) { + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end-s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} + + +static const char *match (MatchState *ms, const char *s, const char *p) { + if (ms->matchdepth-- == 0) + luaL_error(ms->L, "pattern too complex"); + init: /* using goto's to optimize tail recursion */ + if (p != ms->p_end) { /* end of pattern? */ + switch (*p) { + case '(': { /* start capture */ + if (*(p + 1) == ')') /* position capture? */ + s = start_capture(ms, s, p + 2, CAP_POSITION); + else + s = start_capture(ms, s, p + 1, CAP_UNFINISHED); + break; + } + case ')': { /* end capture */ + s = end_capture(ms, s, p + 1); + break; + } + case '$': { + if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ + goto dflt; /* no; go to default */ + s = (s == ms->src_end) ? s : NULL; /* check end of string */ + break; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ + switch (*(p + 1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p + 2); + if (s != NULL) { + p += 4; goto init; /* return match(ms, s, p + 4); */ + } /* else fail (s == NULL) */ + break; + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (*p != '[') + luaL_error(ms->L, "missing '[' after '%%f' in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s - 1); + if (!matchbracketclass(uchar(previous), p, ep - 1) && + matchbracketclass(uchar(*s), p, ep - 1)) { + p = ep; goto init; /* return match(ms, s, ep); */ + } + s = NULL; /* match failed */ + break; + } + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p + 1))); + if (s != NULL) { + p += 2; goto init; /* return match(ms, s, p + 2) */ + } + break; + } + default: goto dflt; + } + break; + } + default: dflt: { /* pattern class plus optional suffix */ + const char *ep = classend(ms, p); /* points to optional suffix */ + /* does not match at least once? */ + if (!singlematch(ms, s, p, ep)) { + if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ + p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ + } + else /* '+' or no suffix */ + s = NULL; /* fail */ + } + else { /* matched once */ + switch (*ep) { /* handle optional suffix */ + case '?': { /* optional */ + const char *res; + if ((res = match(ms, s + 1, ep + 1)) != NULL) + s = res; + else { + p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ + } + break; + } + case '+': /* 1 or more repetitions */ + s++; /* 1 match already done */ + /* FALLTHROUGH */ + case '*': /* 0 or more repetitions */ + s = max_expand(ms, s, p, ep); + break; + case '-': /* 0 or more repetitions (minimum) */ + s = min_expand(ms, s, p, ep); + break; + default: /* no suffix */ + s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ + } + } + break; + } + } + } + ms->matchdepth++; + return s; +} + + + +static const char *lmemfind (const char *s1, size_t l1, + const char *s2, size_t l2) { + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ + else { + const char *init; /* to search for a '*s2' inside 's1' */ + l2--; /* 1st char will be checked by 'memchr' */ + l1 = l1-l2; /* 's2' cannot be found after that */ + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { + init++; /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct 'l1' and 's1' to try again */ + l1 -= init-s1; + s1 = init; + } + } + return NULL; /* not found */ + } +} + + - static void push_onecapture (MatchState *ms, int i, const char *s, - const char *e) { ++/* ++** get information about the i-th capture. If there are no captures ++** and 'i==0', return information about the whole match, which ++** is the range 's'..'e'. If the capture is a string, return ++** its length and put its address in '*cap'. If it is an integer ++** (a position), push it on the stack and return CAP_POSITION. ++*/ ++static size_t get_onecapture (MatchState *ms, int i, const char *s, ++ const char *e, const char **cap) { + if (i >= ms->level) { - if (i == 0) /* ms->level == 0, too */ - lua_pushlstring(ms->L, s, e - s); /* add whole match */ - else ++ if (i != 0) + luaL_error(ms->L, "invalid capture index %%%d", i + 1); ++ *cap = s; ++ return e - s; + } + else { *** 6490 LINES SKIPPED ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101140558.10E5wMNW079125>