diff -Nru lua-compat53-0.3/c-api/compat-5.3.c lua-compat53-0.7/c-api/compat-5.3.c --- lua-compat53-0.3/c-api/compat-5.3.c 2015-09-13 17:10:36.000000000 +0000 +++ lua-compat53-0.7/c-api/compat-5.3.c 2018-07-13 02:03:47.000000000 +0000 @@ -3,6 +3,7 @@ #include #include #include +#include #include "compat-5.3.h" /* don't compile it again if it already is included via compat53.h */ @@ -14,6 +15,75 @@ /* definitions for Lua 5.1 only */ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 +#ifndef COMPAT53_FOPEN_NO_LOCK +# if defined(_MSC_VER) +# define COMPAT53_FOPEN_NO_LOCK 1 +# else /* otherwise */ +# define COMPAT53_FOPEN_NO_LOCK 0 +# endif /* VC++ only so far */ +#endif /* No-lock fopen_s usage if possible */ + +#if defined(_MSC_VER) && COMPAT53_FOPEN_NO_LOCK +# include +#endif /* VC++ _fsopen for share-allowed file read */ + +#ifndef COMPAT53_HAVE_STRERROR_R +# if defined(__GLIBC__) || defined(_POSIX_VERSION) || defined(__APPLE__) || \ + (!defined (__MINGW32__) && defined(__GNUC__) && (__GNUC__ < 6)) +# define COMPAT53_HAVE_STRERROR_R 1 +# else /* none of the defines matched: define to 0 */ +# define COMPAT53_HAVE_STRERROR_R 0 +# endif /* have strerror_r of some form */ +#endif /* strerror_r */ + +#ifndef COMPAT53_HAVE_STRERROR_S +# if defined(_MSC_VER) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && \ + defined(__STDC_LIB_EXT1__) && __STDC_LIB_EXT1__) +# define COMPAT53_HAVE_STRERROR_S 1 +# else /* not VC++ or C11 */ +# define COMPAT53_HAVE_STRERROR_S 0 +# endif /* strerror_s from VC++ or C11 */ +#endif /* strerror_s */ + +#ifndef COMPAT53_LUA_FILE_BUFFER_SIZE +# define COMPAT53_LUA_FILE_BUFFER_SIZE 4096 +#endif /* Lua File Buffer Size */ + + +static char* compat53_strerror (int en, char* buff, size_t sz) { +#if COMPAT53_HAVE_STRERROR_R + /* use strerror_r here, because it's available on these specific platforms */ + if (sz > 0) { + buff[0] = '\0'; + /* we don't care whether the GNU version or the XSI version is used: */ + if (strerror_r(en, buff, sz)) { + /* Yes, we really DO want to ignore the return value! + * GCC makes that extra hard, not even a (void) cast will do. */ + } + if (buff[0] == '\0') { + /* Buffer is unchanged, so we probably have called GNU strerror_r which + * returned a static constant string. Chances are that strerror will + * return the same static constant string and therefore be thread-safe. */ + return strerror(en); + } + } + return buff; /* sz is 0 *or* strerror_r wrote into the buffer */ +#elif COMPAT53_HAVE_STRERROR_S + /* for MSVC and other C11 implementations, use strerror_s since it's + * provided by default by the libraries */ + strerror_s(buff, sz, en); + return buff; +#else + /* fallback, but strerror is not guaranteed to be threadsafe due to modifying + * errno itself and some impls not locking a static buffer for it ... but most + * known systems have threadsafe errno: this might only change if the locale + * is changed out from under someone while this function is being called */ + (void)buff; + (void)sz; + return strerror(en); +#endif +} + COMPAT53_API int lua_absindex (lua_State *L, int i) { if (i < 0 && i > LUA_REGISTRYINDEX) @@ -100,15 +170,17 @@ COMPAT53_API void lua_len (lua_State *L, int i) { switch (lua_type(L, i)) { - case LUA_TSTRING: /* fall through */ + case LUA_TSTRING: + lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); + break; case LUA_TTABLE: if (!luaL_callmeta(L, i, "__len")) - lua_pushnumber(L, (int)lua_objlen(L, i)); + lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); break; case LUA_TUSERDATA: if (luaL_callmeta(L, i, "__len")) break; - /* maybe fall through */ + /* FALLTHROUGH */ default: luaL_error(L, "attempt to get length of a %s value", lua_typename(L, lua_type(L, i))); @@ -132,15 +204,6 @@ } -COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum) { - lua_Integer n = lua_tointeger(L, i); - if (isnum != NULL) { - *isnum = (n != 0 || lua_isnumber(L, i)); -} - return n; -} - - COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum) { lua_Number n = lua_tonumber(L, i); if (isnum != NULL) { @@ -183,14 +246,15 @@ } -COMPAT53_API int luaL_len (lua_State *L, int i) { - int res = 0, isnum = 0; +COMPAT53_API lua_Integer luaL_len (lua_State *L, int i) { + lua_Integer res = 0; + int isnum = 0; luaL_checkstack(L, 1, "not enough stack slots"); lua_len(L, i); - res = (int)lua_tointegerx(L, -1, &isnum); + res = lua_tointegerx(L, -1, &isnum); lua_pop(L, 1); if (!isnum) - luaL_error(L, "object length is not a number"); + luaL_error(L, "object length is not an integer"); return res; } @@ -233,34 +297,6 @@ } -COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { - if (!luaL_callmeta(L, idx, "__tostring")) { - int t = lua_type(L, idx); - switch (t) { - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - case LUA_TSTRING: - case LUA_TNUMBER: - lua_pushvalue(L, idx); - break; - case LUA_TBOOLEAN: - if (lua_toboolean(L, idx)) - lua_pushliteral(L, "true"); - else - lua_pushliteral(L, "false"); - break; - default: - lua_pushfstring(L, "%s: %p", lua_typename(L, t), - lua_topointer(L, idx)); - break; - } - } - return lua_tolstring(L, -1, len); -} - - -#if !defined(COMPAT53_IS_LUAJIT) static int compat53_countlevels (lua_State *L) { lua_Debug ar; int li = 1, le = 1; @@ -361,26 +397,221 @@ COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { + const char *serr = NULL; int en = errno; /* calls to Lua API may change this value */ + char buf[512] = { 0 }; if (stat) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); + serr = compat53_strerror(en, buf, sizeof(buf)); if (fname) - lua_pushfstring(L, "%s: %s", fname, strerror(en)); + lua_pushfstring(L, "%s: %s", fname, serr); else - lua_pushstring(L, strerror(en)); + lua_pushstring(L, serr); lua_pushnumber(L, (lua_Number)en); return 3; } } +static int compat53_checkmode (lua_State *L, const char *mode, const char *modename, int err) { + if (mode && strchr(mode, modename[0]) == NULL) { + lua_pushfstring(L, "attempt to load a %s chunk (mode is '%s')", modename, mode); + return err; + } + return LUA_OK; +} + + +typedef struct { + lua_Reader reader; + void *ud; + int has_peeked_data; + const char *peeked_data; + size_t peeked_data_size; +} compat53_reader_data; + + +static const char *compat53_reader (lua_State *L, void *ud, size_t *size) { + compat53_reader_data *data = (compat53_reader_data *)ud; + if (data->has_peeked_data) { + data->has_peeked_data = 0; + *size = data->peeked_data_size; + return data->peeked_data; + } else + return data->reader(L, data->ud, size); +} + + +COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *source, const char *mode) { + int status = LUA_OK; + compat53_reader_data compat53_data = { reader, data, 1, 0, 0 }; + compat53_data.peeked_data = reader(L, data, &(compat53_data.peeked_data_size)); + if (compat53_data.peeked_data && compat53_data.peeked_data_size && + compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */ + status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); + else + status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); + if (status != LUA_OK) + return status; + /* we need to call the original 5.1 version of lua_load! */ +#undef lua_load + return lua_load(L, compat53_reader, &compat53_data, source); +#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) +} + + +typedef struct { + int n; /* number of pre-read characters */ + FILE *f; /* file being read */ + char buff[COMPAT53_LUA_FILE_BUFFER_SIZE]; /* area for reading file */ +} compat53_LoadF; + + +static const char *compat53_getF (lua_State *L, void *ud, size_t *size) { + compat53_LoadF *lf = (compat53_LoadF *)ud; + (void)L; /* not used */ + if (lf->n > 0) { /* are there pre-read characters to be read? */ + *size = lf->n; /* return them (chars already in buffer) */ + lf->n = 0; /* no more pre-read characters */ + } + else { /* read a block from file */ + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'compat53_getF' called 'fread', it might still wait for user input. + The next check avoids this problem. */ + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ + } + return lf->buff; +} + + +static int compat53_errfile (lua_State *L, const char *what, int fnameindex) { + char buf[512] = {0}; + const char *serr = compat53_strerror(errno, buf, sizeof(buf)); + const char *filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + + +static int compat53_skipBOM (compat53_LoadF *lf) { + const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ + int c; + lf->n = 0; + do { + c = getc(lf->f); + if (c == EOF || c != *(const unsigned char *)p++) return c; + lf->buff[lf->n++] = (char)c; /* to be read by the parser */ + } while (*p != '\0'); + lf->n = 0; /* prefix matched; discard it */ + return getc(lf->f); /* return next character */ +} + + +/* +** reads the first character of file 'f' and skips an optional BOM mark +** in its beginning plus its first line if it starts with '#'. Returns +** true if it skipped the first line. In any case, '*cp' has the +** first "valid" character of the file (after the optional BOM and +** a first-line comment). +*/ +static int compat53_skipcomment (compat53_LoadF *lf, int *cp) { + int c = *cp = compat53_skipBOM(lf); + if (c == '#') { /* first line is a comment (Unix exec. file)? */ + do { /* skip first line */ + c = getc(lf->f); + } while (c != EOF && c != '\n'); + *cp = getc(lf->f); /* skip end-of-line, if present */ + return 1; /* there was a comment */ + } + else return 0; /* no comment */ +} + + +COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode) { + compat53_LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + if (filename == NULL) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); +#if defined(_MSC_VER) + /* This code is here to stop a deprecation error that stops builds + * if a certain macro is defined. While normally not caring would + * be best, some header-only libraries and builds can't afford to + * dictate this to the user. A quick check shows that fopen_s this + * goes back to VS 2005, and _fsopen goes back to VS 2003 .NET, + * possibly even before that so we don't need to do any version + * number checks, since this has been there since forever. */ + + /* TO USER: if you want the behavior of typical fopen_s/fopen, + * which does lock the file on VC++, define the macro used below to 0 */ +#if COMPAT53_FOPEN_NO_LOCK + lf.f = _fsopen(filename, "r", _SH_DENYNO); /* do not lock the file in any way */ + if (lf.f == NULL) + return compat53_errfile(L, "open", fnameindex); +#else /* use default locking version */ + if (fopen_s(&lf.f, filename, "r") != 0) + return compat53_errfile(L, "open", fnameindex); +#endif /* Locking vs. No-locking fopen variants */ +#else + lf.f = fopen(filename, "r"); /* default stdlib doesn't forcefully lock files here */ + if (lf.f == NULL) return compat53_errfile(L, "open", fnameindex); +#endif + } + if (compat53_skipcomment(&lf, &c)) /* read initial portion */ + lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ + if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ +#if defined(_MSC_VER) + if (freopen_s(&lf.f, filename, "rb", lf.f) != 0) + return compat53_errfile(L, "reopen", fnameindex); +#else + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) return compat53_errfile(L, "reopen", fnameindex); +#endif + compat53_skipcomment(&lf, &c); /* re-read initial portion */ + } + if (c != EOF) + lf.buff[lf.n++] = (char)c; /* 'c' is the first character of the stream */ + status = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1), mode); + readstatus = ferror(lf.f); + if (filename) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ + return compat53_errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; +} + + +COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode) { + int status = LUA_OK; + if (sz > 0 && buff[0] == LUA_SIGNATURE[0]) { + status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); + } + else { + status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); + } + if (status != LUA_OK) + return status; + return luaL_loadbuffer(L, buff, sz, name); +} + + #if !defined(l_inspectstat) && \ (defined(unix) || defined(__unix) || defined(__unix__) || \ - defined(__TOS_AIX__) || defined(_SYSTYPE_BSD)) + defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \ + (defined(__APPLE__) && defined(__MACH__))) /* some form of unix; check feature macros in unistd.h for details */ # include /* check posix version; the relevant include files and macros probably @@ -414,7 +645,6 @@ return 3; } } -#endif /* not COMPAT53_IS_LUAJIT */ COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B) { @@ -501,6 +731,22 @@ } +COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum) { + int ok = 0; + lua_Number n = lua_tonumberx(L, i, &ok); + if (ok) { + if (n == (lua_Integer)n) { + if (isnum) + *isnum = 1; + return (lua_Integer)n; + } + } + if (isnum) + *isnum = 0; + return 0; +} + + static void compat53_reverse (lua_State *L, int a, int b) { for (; a < b; ++a, --b) { lua_pushvalue(L, a); @@ -537,7 +783,7 @@ #if !defined(lua_str2number) -# define lua_str2number(s, p) strtod(s, p) +# define lua_str2number(s, p) strtod((s), (p)) #endif COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s) { @@ -555,6 +801,40 @@ } +COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { + if (!luaL_callmeta(L, idx, "__tostring")) { + int t = lua_type(L, idx), tt = 0; + char const* name = NULL; + switch (t) { + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + case LUA_TSTRING: + case LUA_TNUMBER: + lua_pushvalue(L, idx); + break; + case LUA_TBOOLEAN: + if (lua_toboolean(L, idx)) + lua_pushliteral(L, "true"); + else + lua_pushliteral(L, "false"); + break; + default: + tt = luaL_getmetafield(L, idx, "__name"); + name = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : lua_typename(L, t); + lua_pushfstring(L, "%s: %p", name, lua_topointer(L, idx)); + if (tt != LUA_TNIL) + lua_replace(L, -2); + break; + } + } else { + if (!lua_isstring(L, -1)) + luaL_error(L, "'__tostring' must return a string"); + } + return lua_tolstring(L, -1, len); +} + + COMPAT53_API void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb) { luaL_checkstack(L, 3, "not enough stack slots available"); diff -Nru lua-compat53-0.3/c-api/compat-5.3.h lua-compat53-0.7/c-api/compat-5.3.h --- lua-compat53-0.3/c-api/compat-5.3.h 2015-09-13 17:10:36.000000000 +0000 +++ lua-compat53-0.7/c-api/compat-5.3.h 2018-07-13 02:03:47.000000000 +0000 @@ -4,16 +4,18 @@ #include #include #include -#if defined( __cplusplus ) && !defined( COMPAT53_LUA_CPP ) +#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) extern "C" { #endif #include #include -#if defined( __cplusplus ) && !defined( COMPAT53_LUA_CPP ) +#include +#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) } #endif +#undef COMPAT53_INCLUDE_SOURCE #if defined(COMPAT53_PREFIX) /* - change the symbol names of functions to avoid linker conflicts * - compat-5.3.c needs to be compiled (and linked) separately @@ -21,13 +23,11 @@ # if !defined(COMPAT53_API) # define COMPAT53_API extern # endif -# undef COMPAT53_INCLUDE_SOURCE #else /* COMPAT53_PREFIX */ /* - make all functions static and include the source. - * - don't mess with the symbol names of functions * - compat-5.3.c doesn't need to be compiled (and linked) separately */ -# define COMPAT53_PREFIX lua +# define COMPAT53_PREFIX compat53 # undef COMPAT53_API # if defined(__GNUC__) || defined(__clang__) # define COMPAT53_API __attribute__((__unused__)) static @@ -51,29 +51,54 @@ * lua_upvaluejoin * lua_version * lua_yieldk - * luaL_loadbufferx - * luaL_loadfilex */ -/* PUC-Rio Lua uses lconfig_h as include guard for luaconf.h, - * LuaJIT uses luaconf_h. If you use PUC-Rio's include files - * but LuaJIT's library, you will need to define the macro - * COMPAT53_IS_LUAJIT yourself! */ -#if !defined(COMPAT53_IS_LUAJIT) && defined(luaconf_h) -# define COMPAT53_IS_LUAJIT -#endif - -#define LUA_OK 0 -#define LUA_OPADD 0 -#define LUA_OPSUB 1 -#define LUA_OPMUL 2 -#define LUA_OPDIV 3 -#define LUA_OPMOD 4 -#define LUA_OPPOW 5 -#define LUA_OPUNM 6 -#define LUA_OPEQ 0 -#define LUA_OPLT 1 -#define LUA_OPLE 2 +#ifndef LUA_OK +# define LUA_OK 0 +#endif +#ifndef LUA_OPADD +# define LUA_OPADD 0 +#endif +#ifndef LUA_OPSUB +# define LUA_OPSUB 1 +#endif +#ifndef LUA_OPMUL +# define LUA_OPMUL 2 +#endif +#ifndef LUA_OPDIV +# define LUA_OPDIV 3 +#endif +#ifndef LUA_OPMOD +# define LUA_OPMOD 4 +#endif +#ifndef LUA_OPPOW +# define LUA_OPPOW 5 +#endif +#ifndef LUA_OPUNM +# define LUA_OPUNM 6 +#endif +#ifndef LUA_OPEQ +# define LUA_OPEQ 0 +#endif +#ifndef LUA_OPLT +# define LUA_OPLT 1 +#endif +#ifndef LUA_OPLE +# define LUA_OPLE 2 +#endif + +/* LuaJIT/Lua 5.1 does not have the updated + * error codes for thread status/function returns (but some patched versions do) + * define it only if it's not found + */ +#if !defined(LUA_ERRGCMM) +/* Use + 2 because in some versions of Lua (Lua 5.1) + * LUA_ERRFILE is defined as (LUA_ERRERR+1) + * so we need to avoid it (LuaJIT might have something at this + * integer value too) + */ +# define LUA_ERRGCMM (LUA_ERRERR + 2) +#endif /* LUA_ERRGCMM define */ typedef size_t lua_Unsigned; @@ -86,6 +111,14 @@ } luaL_Buffer_53; #define luaL_Buffer luaL_Buffer_53 +/* In PUC-Rio 5.1, userdata is a simple FILE* + * In LuaJIT, it's a struct where the first member is a FILE* + * We can't support the `closef` member + */ +typedef struct luaL_Stream { + FILE *f; +} luaL_Stream; + #define lua_absindex COMPAT53_CONCAT(COMPAT53_PREFIX, _absindex) COMPAT53_API int lua_absindex (lua_State *L, int i); @@ -99,20 +132,30 @@ COMPAT53_API void lua_copy (lua_State *L, int from, int to); #define lua_getuservalue(L, i) \ - (lua_getfenv(L, i), lua_type(L, -1)) + (lua_getfenv((L), (i)), lua_type((L), -1)) #define lua_setuservalue(L, i) \ - (luaL_checktype(L, -1, LUA_TTABLE), lua_setfenv(L, i)) + (luaL_checktype((L), -1, LUA_TTABLE), lua_setfenv((L), (i))) #define lua_len COMPAT53_CONCAT(COMPAT53_PREFIX, _len) COMPAT53_API void lua_len (lua_State *L, int i); -#define luaL_newlibtable(L, l) \ - (lua_createtable(L, 0, sizeof(l)/sizeof(*(l))-1)) -#define luaL_newlib(L, l) \ - (luaL_newlibtable(L, l), luaL_register(L, NULL, l)) +#define lua_pushstring(L, s) \ + (lua_pushstring((L), (s)), lua_tostring((L), -1)) + +#define lua_pushlstring(L, s, len) \ + ((((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))), lua_tostring((L), -1)) + +#ifndef luaL_newlibtable +# define luaL_newlibtable(L, l) \ + (lua_createtable((L), 0, sizeof((l))/sizeof(*(l))-1)) +#endif +#ifndef luaL_newlib +# define luaL_newlib(L, l) \ + (luaL_newlibtable((L), (l)), luaL_register((L), NULL, (l))) +#endif #define lua_pushglobaltable(L) \ - lua_pushvalue(L, LUA_GLOBALSINDEX) + lua_pushvalue((L), LUA_GLOBALSINDEX) #define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp) COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p); @@ -120,10 +163,9 @@ #define lua_rawsetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawsetp) COMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p); -#define lua_rawlen(L, i) lua_objlen(L, i) +#define lua_rawlen(L, i) lua_objlen((L), (i)) -#define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx) -COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum); +#define lua_tointeger(L, i) lua_tointegerx((L), (i), NULL) #define lua_tonumberx COMPAT53_CONCAT(COMPAT53_PREFIX, _tonumberx) COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum); @@ -131,6 +173,15 @@ #define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) COMPAT53_API void luaL_checkversion (lua_State *L); +#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) +COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char* source, const char* mode); + +#define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex) +COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode); + +#define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx) +COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); + #define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg); @@ -138,7 +189,7 @@ COMPAT53_API int luaL_getsubtable (lua_State* L, int i, const char *name); #define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len) -COMPAT53_API int luaL_len (lua_State *L, int i); +COMPAT53_API lua_Integer luaL_len (lua_State *L, int i); #define luaL_setfuncs COMPAT53_CONCAT(COMPAT53_PREFIX, L_setfuncs) COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); @@ -149,10 +200,6 @@ #define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata) COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname); -#define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring) -COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); - -#if !defined(COMPAT53_IS_LUAJIT) #define luaL_traceback COMPAT53_CONCAT(COMPAT53_PREFIX, L_traceback) COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level); @@ -161,12 +208,14 @@ #define luaL_execresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_execresult) COMPAT53_API int luaL_execresult (lua_State *L, int stat); -#endif /* COMPAT53_IS_LUAJIT */ #define lua_callk(L, na, nr, ctx, cont) \ - ((void)(ctx), (void)(cont), lua_call(L, na, nr)) + ((void)(ctx), (void)(cont), lua_call((L), (na), (nr))) #define lua_pcallk(L, na, nr, err, ctx, cont) \ - ((void)(ctx), (void)(cont), lua_pcall(L, na, nr, err)) + ((void)(ctx), (void)(cont), lua_pcall((L), (na), (nr), (err))) + +#define lua_resume(L, from, nargs) \ + ((void)(from), lua_resume((L), (nargs))) #define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53) COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B); @@ -185,15 +234,15 @@ #undef luaL_buffinitsize #define luaL_buffinitsize(L, B, s) \ - (luaL_buffinit(L, B), luaL_prepbuffsize(B, s)) + (luaL_buffinit((L), (B)), luaL_prepbuffsize((B), (s))) #undef luaL_prepbuffer #define luaL_prepbuffer(B) \ - luaL_prepbuffsize(B, LUAL_BUFFERSIZE) + luaL_prepbuffsize((B), LUAL_BUFFERSIZE) #undef luaL_addchar #define luaL_addchar(B, c) \ - ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize(B, 1)), \ + ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize((B), 1)), \ ((B)->ptr[(B)->nelems++] = (c))) #undef luaL_addsize @@ -202,23 +251,23 @@ #undef luaL_addstring #define luaL_addstring(B, s) \ - luaL_addlstring(B, s, strlen(s)) + luaL_addlstring((B), (s), strlen((s))) #undef luaL_pushresultsize #define luaL_pushresultsize(B, s) \ - (luaL_addsize(B, s), luaL_pushresult(B)) + (luaL_addsize((B), (s)), luaL_pushresult((B))) #if defined(LUA_COMPAT_APIINTCASTS) #define lua_pushunsigned(L, n) \ - lua_pushinteger(L, (lua_Integer)(n)) + lua_pushinteger((L), (lua_Integer)(n)) #define lua_tounsignedx(L, i, is) \ - ((lua_Unsigned)lua_tointegerx(L, i, is)) + ((lua_Unsigned)lua_tointegerx((L), (i), (is))) #define lua_tounsigned(L, i) \ - lua_tounsignedx(L, i, NULL) + lua_tounsignedx((L), (i), NULL) #define luaL_checkunsigned(L, a) \ - ((lua_Unsigned)luaL_checkinteger(L, a)) + ((lua_Unsigned)luaL_checkinteger((L), (a))) #define luaL_optunsigned(L, a, d) \ - ((lua_Unsigned)luaL_optinteger(L, a, (lua_Integer)(d))) + ((lua_Unsigned)luaL_optinteger((L), (a), (lua_Integer)(d))) #endif #endif /* Lua 5.1 only */ @@ -233,13 +282,13 @@ typedef int (*lua_KFunction)(lua_State *L, int status, lua_KContext ctx); #define lua_dump(L, w, d, s) \ - ((void)(s), lua_dump(L, w, d)) + ((void)(s), lua_dump((L), (w), (d))) #define lua_getfield(L, i, k) \ - (lua_getfield(L, i, k), lua_type(L, -1)) + (lua_getfield((L), (i), (k)), lua_type((L), -1)) #define lua_gettable(L, i) \ - (lua_gettable(L, i), lua_type(L, -1)) + (lua_gettable((L), (i)), lua_type((L), -1)) #define lua_geti COMPAT53_CONCAT(COMPAT53_PREFIX, _geti) COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i); @@ -247,14 +296,17 @@ #define lua_isinteger COMPAT53_CONCAT(COMPAT53_PREFIX, _isinteger) COMPAT53_API int lua_isinteger (lua_State *L, int index); +#define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx_53) +COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum); + #define lua_numbertointeger(n, p) \ ((*(p) = (lua_Integer)(n)), 1) #define lua_rawget(L, i) \ - (lua_rawget(L, i), lua_type(L, -1)) + (lua_rawget((L), (i)), lua_type((L), -1)) #define lua_rawgeti(L, i, n) \ - (lua_rawgeti(L, i, n), lua_type(L, -1)) + (lua_rawgeti((L), (i), (n)), lua_type((L), -1)) #define lua_rotate COMPAT53_CONCAT(COMPAT53_PREFIX, _rotate) COMPAT53_API void lua_rotate (lua_State *L, int idx, int n); @@ -265,11 +317,14 @@ #define lua_stringtonumber COMPAT53_CONCAT(COMPAT53_PREFIX, _stringtonumber) COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s); +#define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring) +COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); + #define luaL_getmetafield(L, o, e) \ - (luaL_getmetafield(L, o, e) ? lua_type(L, -1) : LUA_TNIL) + (luaL_getmetafield((L), (o), (e)) ? lua_type((L), -1) : LUA_TNIL) #define luaL_newmetatable(L, tn) \ - (luaL_newmetatable(L, tn) ? (lua_pushstring(L, tn), lua_setfield(L, -2, "__name"), 1) : 0) + (luaL_newmetatable((L), (tn)) ? (lua_pushstring((L), (tn)), lua_setfield((L), -2, "__name"), 1) : 0) #define luaL_requiref COMPAT53_CONCAT(COMPAT53_PREFIX, L_requiref_53) COMPAT53_API void luaL_requiref (lua_State *L, const char *modname, @@ -290,13 +345,16 @@ */ #define lua_getglobal(L, n) \ - (lua_getglobal(L, n), lua_type(L, -1)) + (lua_getglobal((L), (n)), lua_type((L), -1)) #define lua_getuservalue(L, i) \ - (lua_getuservalue(L, i), lua_type(L, -1)) + (lua_getuservalue((L), (i)), lua_type((L), -1)) + +#define lua_pushlstring(L, s, len) \ + (((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))) #define lua_rawgetp(L, i, p) \ - (lua_rawgetp(L, i, p), lua_type(L, -1)) + (lua_rawgetp((L), (i), (p)), lua_type((L), -1)) #define LUA_KFUNCTION(_name) \ static int (_name)(lua_State *L, int status, lua_KContext ctx); \ @@ -308,30 +366,30 @@ static int (_name)(lua_State *L, int status, lua_KContext ctx) #define lua_pcallk(L, na, nr, err, ctx, cont) \ - lua_pcallk(L, na, nr, err, ctx, cont ## _52) + lua_pcallk((L), (na), (nr), (err), (ctx), cont ## _52) #define lua_callk(L, na, nr, ctx, cont) \ - lua_callk(L, na, nr, ctx, cont ## _52) + lua_callk((L), (na), (nr), (ctx), cont ## _52) #define lua_yieldk(L, nr, ctx, cont) \ - lua_yieldk(L, nr, ctx, cont ## _52) + lua_yieldk((L), (nr), (ctx), cont ## _52) #ifdef lua_call # undef lua_call # define lua_call(L, na, nr) \ - (lua_callk)(L, na, nr, 0, NULL) + (lua_callk)((L), (na), (nr), 0, NULL) #endif #ifdef lua_pcall # undef lua_pcall # define lua_pcall(L, na, nr, err) \ - (lua_pcallk)(L, na, nr, err, 0, NULL) + (lua_pcallk)((L), (na), (nr), (err), 0, NULL) #endif #ifdef lua_yield # undef lua_yield # define lua_yield(L, nr) \ - (lua_yieldk)(L, nr, 0, NULL) + (lua_yieldk)((L), (nr), 0, NULL) #endif #endif /* Lua 5.2 only */ diff -Nru lua-compat53-0.3/compat53/module.lua lua-compat53-0.7/compat53/module.lua --- lua-compat53-0.3/compat53/module.lua 2015-09-13 17:10:36.000000000 +0000 +++ lua-compat53-0.7/compat53/module.lua 2018-07-13 02:03:47.000000000 +0000 @@ -548,7 +548,7 @@ return chunk end - M.loadstring = load + M.loadstring = M.load function M.loadfile(file, mode, env) mode = mode or "bt" @@ -601,7 +601,10 @@ if code == 0 then return true, "exit", code else - return nil, "exit", code/256 -- only correct on Linux! + if package.config:sub(1, 1) == '/' then + code = code/256 -- only correct on Linux! + end + return nil, "exit", code end end end diff -Nru lua-compat53-0.3/debian/changelog lua-compat53-0.7/debian/changelog --- lua-compat53-0.3/debian/changelog 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/changelog 2019-10-29 03:42:31.000000000 +0000 @@ -1,3 +1,29 @@ +lua-compat53 (0.7-2) unstable; urgency=medium + + * Upload to unstable + + -- James McCoy Mon, 28 Oct 2019 23:42:31 -0400 + +lua-compat53 (0.7-1) experimental; urgency=medium + + [ Jason Pleau ] + * New upstream release + * debian/watch: fix typo in orig tarball filename + * Bump debhelper compat to 11 + * Update Vcs-* fields to use salsa.debian.org + * Add myself to Uploaders and debian/copyright + + [ James McCoy ] + * Install compat-5.3.{c,h} to /usr/include/lua5.x/ (Closes: #846602) + This only supports including compat-5.3.h without "#define + COMPAT53_PREFIX", i.e. a static build. + * Stop installing compat-5.3.{c,h} under + /usr/share/doc/lua-compat53/examples + * Add myself to Uploaders and debian/copyright + * control: Add Rules-Requires-Root: no + + -- James McCoy Tue, 22 Oct 2019 22:38:41 -0400 + lua-compat53 (0.3-3) unstable; urgency=medium * Clarify copyright on c-api/compat-5.3.c (parts come from Lua source code) diff -Nru lua-compat53-0.3/debian/compat lua-compat53-0.7/debian/compat --- lua-compat53-0.3/debian/compat 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/compat 2019-10-29 03:42:31.000000000 +0000 @@ -1 +1 @@ -9 +11 diff -Nru lua-compat53-0.3/debian/control lua-compat53-0.7/debian/control --- lua-compat53-0.3/debian/control 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/control 2019-10-29 03:42:31.000000000 +0000 @@ -2,21 +2,49 @@ Section: interpreters Priority: optional Maintainer: Ondřej Surý -Build-Depends: debhelper (>= 9), - dh-lua +Uploaders: + Jason Pleau , + James Mccoy , +Build-Depends: + debhelper (>= 11~), + dh-lua, Standards-Version: 3.9.8 Homepage: https://github.com/keplerproject/lua-compat-5.3 -Vcs-Git: git://anonscm.debian.org/pkg-lua/lua-compat53.git -Vcs-Browser: https://anonscm.debian.org/git/pkg-lua/lua-compat53.git +Rules-Requires-Root: no +Vcs-Git: https://salsa.debian.org/lua-team/lua-compat53/ +Vcs-Browser: https://salsa.debian.org/lua-team/lua-compat53/ Package: lua-compat53 Architecture: any Multi-Arch: same -Depends: ${shlibs:Depends}, ${misc:Depends} -Provides: ${lua:Provides} +Depends: + ${misc:Depends}, + ${shlibs:Depends}, +Provides: + ${lua:Provides}, XB-Lua-Versions: ${lua:Versions} Description: Lua-5.3-style APIs for Lua 5.2 and 5.1 This is a small module that aims to make it easier to write code in a Lua-5.3-style that is compatible with Lua 5.1, Lua 5.2, and Lua 5.3. This does not make Lua 5.2 (or even Lua 5.1) entirely compatible with Lua 5.3, but it brings the API closer to that of Lua 5.3. + +Package: lua-compat53-dev +Architecture: any +Multi-Arch: same +Pre-Depends: + ${misc:Pre-Depends}, +Section: libdevel +Depends: + lua-compat53 (= ${binary:Version}), + ${misc:Depends}, +Provides: + ${lua:Provides}, +XB-Lua-Versions: ${lua:Versions} +Description: Lua-5.3-style APIs for Lua 5.2 and 5.1 (development files) + This is a small module that aims to make it easier to write code in a + Lua-5.3-style that is compatible with Lua 5.1, Lua 5.2, and Lua + 5.3. This does not make Lua 5.2 (or even Lua 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + . + This package provides the static library and header files for lua-compat53 diff -Nru lua-compat53-0.3/debian/copyright lua-compat53-0.7/debian/copyright --- lua-compat53-0.3/debian/copyright 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/copyright 2019-10-29 03:42:31.000000000 +0000 @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: lua-compat53 Source: https://github.com/keplerproject/lua-compat-5.3 @@ -8,12 +8,14 @@ Files: c-api/compat-5.3.c Copyright: 2015 Kepler - 1994-2014 Lua.org, PUC-Rio. + 1994-2014 Lua.org, PUC-Rio. License: Expat Comment: This file contains parts of Lua 5.2's and Lua 5.3's source code Files: debian/* Copyright: 2016 Ondřej Surý + 2018 Jason Pleau + 2019 James McCoy License: Expat License: Expat diff -Nru lua-compat53-0.3/debian/lua5.1.string.dh-lua.conf lua-compat53-0.7/debian/lua5.1.string.dh-lua.conf --- lua-compat53-0.3/debian/lua5.1.string.dh-lua.conf 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/lua5.1.string.dh-lua.conf 2019-10-29 03:42:31.000000000 +0000 @@ -10,7 +10,7 @@ LUA_MODNAME_CPART=compat53.string ### things relative to the lua library part -LUA_HEADER=lprefix.h +LUA_HEADER= LUA_SOURCES= LUA_SOURCES_MANGLER= LUA_MODNAME=compat53 diff -Nru lua-compat53-0.3/debian/lua5.1.table.dh-lua.conf lua-compat53-0.7/debian/lua5.1.table.dh-lua.conf --- lua-compat53-0.3/debian/lua5.1.table.dh-lua.conf 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/lua5.1.table.dh-lua.conf 2019-10-29 03:42:31.000000000 +0000 @@ -10,7 +10,7 @@ LUA_MODNAME_CPART=compat53.table ### things relative to the lua library part -LUA_HEADER=lprefix.h +LUA_HEADER= LUA_SOURCES= LUA_SOURCES_MANGLER= LUA_MODNAME=compat53 diff -Nru lua-compat53-0.3/debian/lua5.1.utf8.dh-lua.conf lua-compat53-0.7/debian/lua5.1.utf8.dh-lua.conf --- lua-compat53-0.3/debian/lua5.1.utf8.dh-lua.conf 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/lua5.1.utf8.dh-lua.conf 2019-10-29 03:42:31.000000000 +0000 @@ -10,7 +10,7 @@ LUA_MODNAME_CPART=compat53.utf8 ### things relative to the lua library part -LUA_HEADER=lprefix.h +LUA_HEADER= LUA_SOURCES= LUA_SOURCES_MANGLER= LUA_MODNAME=compat53 diff -Nru lua-compat53-0.3/debian/lua5.2.string.dh-lua.conf lua-compat53-0.7/debian/lua5.2.string.dh-lua.conf --- lua-compat53-0.3/debian/lua5.2.string.dh-lua.conf 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/lua5.2.string.dh-lua.conf 2019-10-29 03:42:31.000000000 +0000 @@ -10,7 +10,7 @@ LUA_MODNAME_CPART=compat53.string ### things relative to the lua library part -LUA_HEADER=lprefix.h +LUA_HEADER= LUA_SOURCES= LUA_SOURCES_MANGLER= LUA_MODNAME=compat53 diff -Nru lua-compat53-0.3/debian/lua5.2.table.dh-lua.conf lua-compat53-0.7/debian/lua5.2.table.dh-lua.conf --- lua-compat53-0.3/debian/lua5.2.table.dh-lua.conf 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/lua5.2.table.dh-lua.conf 2019-10-29 03:42:31.000000000 +0000 @@ -10,7 +10,7 @@ LUA_MODNAME_CPART=compat53.table ### things relative to the lua library part -LUA_HEADER=lprefix.h +LUA_HEADER= LUA_SOURCES= LUA_SOURCES_MANGLER= LUA_MODNAME=compat53 diff -Nru lua-compat53-0.3/debian/lua5.2.utf8.dh-lua.conf lua-compat53-0.7/debian/lua5.2.utf8.dh-lua.conf --- lua-compat53-0.3/debian/lua5.2.utf8.dh-lua.conf 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/lua5.2.utf8.dh-lua.conf 2019-10-29 03:42:31.000000000 +0000 @@ -10,7 +10,7 @@ LUA_MODNAME_CPART=compat53.utf8 ### things relative to the lua library part -LUA_HEADER=lprefix.h +LUA_HEADER= LUA_SOURCES= LUA_SOURCES_MANGLER= LUA_MODNAME=compat53 diff -Nru lua-compat53-0.3/debian/lua-compat53-dev.install.in lua-compat53-0.7/debian/lua-compat53-dev.install.in --- lua-compat53-0.3/debian/lua-compat53-dev.install.in 1970-01-01 00:00:00.000000000 +0000 +++ lua-compat53-0.7/debian/lua-compat53-dev.install.in 2019-10-29 03:42:31.000000000 +0000 @@ -0,0 +1,2 @@ +include @@TEMPLATE@@/dev.install.in +c-api/* /usr/include/lua@@LUA_VERSION@@/ diff -Nru lua-compat53-0.3/debian/lua-compat53.examples lua-compat53-0.7/debian/lua-compat53.examples --- lua-compat53-0.3/debian/lua-compat53.examples 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/lua-compat53.examples 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -c-api/* diff -Nru lua-compat53-0.3/debian/rules lua-compat53-0.7/debian/rules --- lua-compat53-0.3/debian/rules 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/rules 2019-10-29 03:42:31.000000000 +0000 @@ -28,5 +28,5 @@ override_dh_install: # merge extra libraries into lua-compat53 - for module in string table utf8; do cat debian/lua-compat53-$${module}.install >> debian/lua-compat53.install; done + for module in string table utf8; do cat debian/lua-compat53-$${module}.install >> debian/lua-compat53.install; cat debian/lua-compat53-$${module}-dev.install >> debian/lua-compat53-dev.install; done dh_install diff -Nru lua-compat53-0.3/debian/watch lua-compat53-0.7/debian/watch --- lua-compat53-0.3/debian/watch 2016-07-14 07:19:51.000000000 +0000 +++ lua-compat53-0.7/debian/watch 2019-10-29 03:42:31.000000000 +0000 @@ -1,3 +1,3 @@ version=3 -opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/-$1\.tar\.gz/ \ +opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/lua-compat53-$1\.tar\.gz/ \ https://github.com/keplerproject/lua-compat-5.3/tags .*/v?(\d\S*)\.tar\.gz diff -Nru lua-compat53-0.3/lprefix.h lua-compat53-0.7/lprefix.h --- lua-compat53-0.3/lprefix.h 2015-09-13 17:10:36.000000000 +0000 +++ lua-compat53-0.7/lprefix.h 2018-07-13 02:03:47.000000000 +0000 @@ -48,18 +48,13 @@ #undef LUAMOD_API #define LUAMOD_API extern + #ifdef lutf8lib_c # define luaopen_utf8 luaopen_compat53_utf8 -# include /* we don't support the %U format string of lua_pushfstring! * code below adapted from the Lua 5.3 sources: */ -static const char *compat53_utf8_escape (lua_State* L, ...) { - long x = 0; - va_list argp; - va_start(argp, L); - x = (long)va_arg(argp, long); - va_end(argp); +static const char *compat53_utf8_escape (lua_State* L, long x) { if (x < 0x80) { /* ASCII */ char c = (char)x; lua_pushlstring(L, &c, 1); @@ -81,24 +76,18 @@ compat53_utf8_escape(L, l) #endif + #ifdef ltablib_c # define luaopen_table luaopen_compat53_table -/* lua_rawgeti in compat53.h is implemented as a macro, so the - * function signature doesn't match when you use a function pointer - */ -static int compat53_rawgeti (lua_State *L, int i, lua_Integer n) { - return lua_rawgeti(L, i, n); -} -# undef lua_rawgeti -# define lua_rawgeti compat53_rawgeti -static void compat53_rawseti (lua_State *L, int i, lua_Integer n) { - lua_rawseti(L, i, (int)n); -} -# undef lua_rawseti -# define lua_rawseti compat53_rawseti +# ifndef LUA_MAXINTEGER +/* conservative estimate: */ +# define LUA_MAXINTEGER INT_MAX +# endif #endif /* ltablib_c */ + #ifdef lstrlib_c +#include #include /* move the string library open function out of the way (we only take * the string packing functions)! @@ -109,11 +98,50 @@ # define LUA_INTEGER_FRMLEN "" # define LUA_NUMBER_FRMLEN "" # endif +# ifndef LUA_MININTEGER +# define LUA_MININTEGER 0 +# endif +# ifndef LUA_INTEGER_FMT +# define LUA_INTEGER_FMT "%d" +# endif +# ifndef LUAI_UACINT +# define LUAI_UACINT lua_Integer +# endif +/* different Lua 5.3 versions have conflicting variants of this macro + * in luaconf.h, there's a fallback implementation in lstrlib.c, and + * the macro isn't used for string (un)packing anyway! + * */ +# undef lua_number2strx # if LUA_VERSION_NUM < 503 /* lstrlib assumes that lua_Integer and lua_Unsigned have the same * size, so we use the unsigned equivalent of ptrdiff_t! */ -# define lua_Unsigned size_t +# define lua_Unsigned size_t +# endif +# ifndef l_mathlim +# ifdef LUA_NUMBER_DOUBLE +# define l_mathlim(n) (DBL_##n) +# else +# define l_mathlim(n) (FLT_##n) +# endif +# endif +# ifndef l_mathop +# ifdef LUA_NUMBER_DOUBLE +# define l_mathop(op) op +# else +# define l_mathop(op) op##f +# endif +# endif +# ifndef lua_getlocaledecpoint +# define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) # endif +# ifndef l_sprintf +# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +# define l_sprintf(s,sz,f,i) (snprintf(s, sz, f, i)) +# else +# define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s, f, i)) +# endif +# endif + static int str_pack (lua_State *L); static int str_packsize (lua_State *L); static int str_unpack (lua_State *L); @@ -127,12 +155,20 @@ luaL_newlib(L, funcs); return 1; } +/* fake CLANG feature detection on other compilers */ +# ifndef __has_attribute +# define __has_attribute(x) 0 +# endif /* make luaopen_string(_XXX) static, so it (and all other referenced * string functions) won't be included in the resulting dll * (hopefully). */ # undef LUAMOD_API -# define LUAMOD_API static +# if defined(__GNUC__) || __has_attribute(__unused__) +# define LUAMOD_API __attribute__((__unused__)) static +# else +# define LUAMOD_API static +# endif #endif /* lstrlib.c */ #endif diff -Nru lua-compat53-0.3/lstrlib.c lua-compat53-0.7/lstrlib.c --- lua-compat53-0.3/lstrlib.c 2015-09-13 17:10:36.000000000 +0000 +++ lua-compat53-0.7/lstrlib.c 2018-07-13 02:03:47.000000000 +0000 @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.221 2014/12/11 14:03:07 roberto Exp $ +** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -11,7 +11,9 @@ #include +#include #include +#include #include #include #include @@ -25,7 +27,8 @@ /* ** maximum number of captures that a pattern can do during -** pattern-matching. This limit is arbitrary. +** pattern-matching. This limit is arbitrary, but must fit in +** an unsigned char. */ #if !defined(LUA_MAXCAPTURES) #define LUA_MAXCAPTURES 32 @@ -40,8 +43,10 @@ ** 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) ? (~(size_t)0) : (size_t)(INT_MAX)) + (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) @@ -70,7 +75,7 @@ if (start < 1) start = 1; if (end > (lua_Integer)l) end = l; if (start <= end) - lua_pushlstring(L, s + start - 1, (size_t)(end - start + 1)); + lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); else lua_pushliteral(L, ""); return 1; } @@ -149,9 +154,9 @@ if (posi < 1) posi = 1; if (pose > (lua_Integer)l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ - n = (int)(pose - posi + 1); - if (posi + n <= pose) /* arithmetic overflow? */ + if (pose - posi >= 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; icapture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) - lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); + lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); else lua_pushlstring(ms->L, ms->capture[i].init, l); } @@ -583,6 +588,22 @@ } +static void prepstate (MatchState *ms, lua_State *L, + const char *s, size_t ls, const char *p, size_t lp) { + ms->L = L; + ms->matchdepth = MAXCCALLS; + ms->src_init = s; + ms->src_end = s + ls; + ms->p_end = p + lp; +} + + +static void reprepstate (MatchState *ms) { + ms->level = 0; + lua_assert(ms->matchdepth == MAXCCALLS); +} + + static int str_find_aux (lua_State *L, int find) { size_t ls, lp; const char *s = luaL_checklstring(L, 1, &ls); @@ -598,8 +619,8 @@ /* do a plain search */ const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); if (s2) { - lua_pushinteger(L, s2 - s + 1); - lua_pushinteger(L, s2 - s + lp); + lua_pushinteger(L, (s2 - s) + 1); + lua_pushinteger(L, (s2 - s) + lp); return 2; } } @@ -610,18 +631,13 @@ if (anchor) { p++; lp--; /* skip anchor character */ } - ms.L = L; - ms.matchdepth = MAXCCALLS; - ms.src_init = s; - ms.src_end = s + ls; - ms.p_end = p + lp; + prepstate(&ms, L, s, ls, p, lp); do { const char *res; - ms.level = 0; - lua_assert(ms.matchdepth == MAXCCALLS); + reprepstate(&ms); if ((res=match(&ms, s1, p)) != NULL) { if (find) { - lua_pushinteger(L, s1 - s + 1); /* start */ + lua_pushinteger(L, (s1 - s) + 1); /* start */ lua_pushinteger(L, res - s); /* end */ return push_captures(&ms, NULL, 0) + 2; } @@ -645,29 +661,25 @@ } +/* state for 'gmatch' */ +typedef struct GMatchState { + const char *src; /* current position */ + const char *p; /* pattern */ + const char *lastmatch; /* end of last match */ + MatchState ms; /* match state */ +} GMatchState; + + static int gmatch_aux (lua_State *L) { - MatchState ms; - size_t ls, lp; - const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); - const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); + GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); const char *src; - ms.L = L; - ms.matchdepth = MAXCCALLS; - ms.src_init = s; - ms.src_end = s+ls; - ms.p_end = p + lp; - for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); - src <= ms.src_end; - src++) { + gm->ms.L = L; + for (src = gm->src; src <= gm->ms.src_end; src++) { const char *e; - ms.level = 0; - lua_assert(ms.matchdepth == MAXCCALLS); - if ((e = match(&ms, src, p)) != NULL) { - lua_Integer newstart = e-s; - if (e == src) newstart++; /* empty match? go at least one position */ - lua_pushinteger(L, newstart); - lua_replace(L, lua_upvalueindex(3)); - return push_captures(&ms, src, e); + reprepstate(&gm->ms); + if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { + gm->src = gm->lastmatch = e; + return push_captures(&gm->ms, src, e); } } return 0; /* not found */ @@ -675,10 +687,14 @@ static int gmatch (lua_State *L) { - luaL_checkstring(L, 1); - luaL_checkstring(L, 2); - lua_settop(L, 2); - lua_pushinteger(L, 0); + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + GMatchState *gm; + lua_settop(L, 2); /* keep them on closure to avoid being collected */ + gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); + prepstate(&gm->ms, L, s, ls, p, lp); + gm->src = s; gm->p = p; gm->lastmatch = NULL; lua_pushcclosure(L, gmatch_aux, 3); return 1; } @@ -745,12 +761,13 @@ static int str_gsub (lua_State *L) { size_t srcl, lp; - const char *src = luaL_checklstring(L, 1, &srcl); - const char *p = luaL_checklstring(L, 2, &lp); - int tr = lua_type(L, 3); - lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); + const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ + const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ + const char *lastmatch = NULL; /* end of last match */ + int tr = lua_type(L, 3); /* replacement type */ + lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ int anchor = (*p == '^'); - lua_Integer n = 0; + lua_Integer n = 0; /* replacement count */ MatchState ms; luaL_Buffer b; luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || @@ -760,25 +777,18 @@ if (anchor) { p++; lp--; /* skip anchor character */ } - ms.L = L; - ms.matchdepth = MAXCCALLS; - ms.src_init = src; - ms.src_end = src+srcl; - ms.p_end = p + lp; + prepstate(&ms, L, src, srcl, p, lp); while (n < max_s) { const char *e; - ms.level = 0; - lua_assert(ms.matchdepth == MAXCCALLS); - e = match(&ms, src, p); - if (e) { + reprepstate(&ms); /* (re)prepare state for new match */ + if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ n++; - add_value(&ms, &b, src, e, tr); + add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ + src = lastmatch = e; } - if (e && e>src) /* non empty match? */ - src = e; /* skip it */ - else if (src < ms.src_end) + else if (src < ms.src_end) /* otherwise, skip one character */ luaL_addchar(&b, *src++); - else break; + else break; /* end of subject */ if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); @@ -797,34 +807,117 @@ ** ======================================================= */ -/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ -#define MAX_ITEM 512 +#if !defined(lua_number2strx) /* { */ + +/* +** Hexadecimal floating-point formatter +*/ + +#include + +#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) + + +/* +** Number of bits that goes into the first digit. It can be any value +** between 1 and 4; the following definition tries to align the number +** to nibble boundaries by making what is left after that first digit a +** multiple of 4. +*/ +#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) + + +/* +** Add integer part of 'x' to buffer and return new 'x' +*/ +static lua_Number adddigit (char *buff, int n, lua_Number x) { + lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ + int d = (int)dd; + buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ + return x - dd; /* return what is left */ +} + + +static int num2straux (char *buff, int sz, lua_Number x) { + /* if 'inf' or 'NaN', format it like '%g' */ + if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) + return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); + else if (x == 0) { /* can be -0... */ + /* create "0" or "-0" followed by exponent */ + return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); + } + else { + int e; + lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ + int n = 0; /* character count */ + if (m < 0) { /* is number negative? */ + buff[n++] = '-'; /* add signal */ + m = -m; /* make it positive */ + } + buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ + m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ + e -= L_NBFD; /* this digit goes before the radix point */ + if (m > 0) { /* more digits? */ + buff[n++] = lua_getlocaledecpoint(); /* add radix point */ + do { /* add as many digits as needed */ + m = adddigit(buff, n++, m * 16); + } while (m > 0); + } + n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ + lua_assert(n < sz); + return n; + } +} + + +static int lua_number2strx (lua_State *L, char *buff, int sz, + const char *fmt, lua_Number x) { + int n = num2straux(buff, sz, x); + if (fmt[SIZELENMOD] == 'A') { + int i; + for (i = 0; i < n; i++) + buff[i] = toupper(uchar(buff[i])); + } + else if (fmt[SIZELENMOD] != 'a') + luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); + return n; +} + +#endif /* } */ + + +/* +** Maximum size of each formatted item. This maximum size is produced +** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', +** and '\0') + number of decimal digits to represent maxfloat (which +** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra +** expenses", such as locale-dependent stuff) +*/ +#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) + /* valid flags in a format specification */ #define FLAGS "-+ #0" /* ** maximum size of each format specification (such as "%-099.99d") -** (+2 for length modifiers; +10 accounts for %99.99x plus margin of error) */ -#define MAX_FORMAT (sizeof(FLAGS) + 2 + 10) +#define MAX_FORMAT 32 -static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); +static void addquoted (luaL_Buffer *b, const char *s, size_t len) { luaL_addchar(b, '"'); - while (l--) { + while (len--) { if (*s == '"' || *s == '\\' || *s == '\n') { luaL_addchar(b, '\\'); luaL_addchar(b, *s); } - else if (*s == '\0' || iscntrl(uchar(*s))) { + else if (iscntrl(uchar(*s))) { char buff[10]; if (!isdigit(uchar(*(s+1)))) - sprintf(buff, "\\%d", (int)uchar(*s)); + l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); else - sprintf(buff, "\\%03d", (int)uchar(*s)); + l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); luaL_addstring(b, buff); } else @@ -834,6 +927,57 @@ luaL_addchar(b, '"'); } + +/* +** Ensures the 'buff' string uses a dot as the radix character. +*/ +static void checkdp (char *buff, int nb) { + if (memchr(buff, '.', nb) == NULL) { /* no dot? */ + char point = lua_getlocaledecpoint(); /* try locale point */ + char *ppoint = (char *)memchr(buff, point, nb); + if (ppoint) *ppoint = '.'; /* change it to a dot */ + } +} + + +static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { + switch (lua_type(L, arg)) { + case LUA_TSTRING: { + size_t len; + const char *s = lua_tolstring(L, arg, &len); + addquoted(b, s, len); + break; + } + case LUA_TNUMBER: { + char *buff = luaL_prepbuffsize(b, MAX_ITEM); + int nb; + if (!lua_isinteger(L, arg)) { /* float? */ + lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ + nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); + checkdp(buff, nb); /* ensure it uses a dot */ + } + else { /* integers */ + lua_Integer n = lua_tointeger(L, arg); + const char *format = (n == LUA_MININTEGER) /* corner case? */ + ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ + : LUA_INTEGER_FMT; /* else use default format */ + nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); + } + luaL_addsize(b, nb); + break; + } + case LUA_TNIL: case LUA_TBOOLEAN: { + luaL_tolstring(L, arg, NULL); + luaL_addvalue(b); + break; + } + default: { + luaL_argerror(L, arg, "value has no literal form"); + } + } +} + + static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ @@ -849,8 +993,8 @@ if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; - memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char)); - form += p - strfrmt + 1; + memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); + form += (p - strfrmt) + 1; *form = '\0'; return p; } @@ -891,49 +1035,56 @@ strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { - nb = sprintf(buff, form, (int)luaL_checkinteger(L, arg)); + nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); break; } case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { lua_Integer n = luaL_checkinteger(L, arg); addlenmod(form, LUA_INTEGER_FRMLEN); - nb = sprintf(buff, form, n); + nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); break; } -#if defined(LUA_USE_AFORMAT) case 'a': case 'A': -#endif + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = lua_number2strx(L, buff, MAX_ITEM, form, + luaL_checknumber(L, arg)); + break; case 'e': case 'E': case 'f': case 'g': case 'G': { + lua_Number n = luaL_checknumber(L, arg); addlenmod(form, LUA_NUMBER_FRMLEN); - nb = sprintf(buff, form, luaL_checknumber(L, arg)); + nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); break; } case 'q': { - addquoted(L, &b, arg); + addliteral(L, &b, arg); break; } case 's': { size_t l; const char *s = luaL_tolstring(L, arg, &l); - if (!strchr(form, '.') && l >= 100) { - /* no precision and string is too long to be formatted; - keep original string */ - luaL_addvalue(&b); - break; - } + if (form[2] == '\0') /* no modifiers? */ + luaL_addvalue(&b); /* keep entire string */ else { - nb = sprintf(buff, form, s); - lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ - break; + luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); + if (!strchr(form, '.') && l >= 100) { + /* no precision and string is too long to be formatted */ + luaL_addvalue(&b); /* keep entire string */ + } + else { /* format the string into 'buff' */ + nb = l_sprintf(buff, MAX_ITEM, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + } } + break; } default: { /* also treat cases 'pnLlh' */ return luaL_error(L, "invalid option '%%%c' to 'format'", *(strfrmt - 1)); } } + lua_assert(nb < MAX_ITEM); luaL_addsize(&b, nb); } } @@ -952,8 +1103,8 @@ /* value used for padding */ -#if !defined(LUA_PACKPADBYTE) -#define LUA_PACKPADBYTE 0x00 +#if !defined(LUAL_PACKPADBYTE) +#define LUAL_PACKPADBYTE 0x00 #endif /* maximum size for the binary representation of an integer */ @@ -1110,7 +1261,7 @@ ** 'psize' is filled with option's size, 'notoalign' with its ** alignment requirements. ** Local variable 'size' gets the size to be aligned. (Kpadal option -** always gets its full alignment, other options are limited by +** always gets its full alignment, other options are limited by ** the maximum alignment ('maxalign'). Kchar option needs no alignment ** despite its size. */ @@ -1190,7 +1341,7 @@ KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); totalsize += ntoalign + size; while (ntoalign-- > 0) - luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */ + luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ arg++; switch (opt) { case Kint: { /* signed integers */ @@ -1225,8 +1376,11 @@ case Kchar: { /* fixed-size string */ size_t len; const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, len == (size_t)size, arg, "wrong length"); - luaL_addlstring(&b, s, size); + luaL_argcheck(L, len <= (size_t)size, arg, + "string longer than given size"); + luaL_addlstring(&b, s, len); /* add string */ + while (len++ < (size_t)size) /* pad extra space */ + luaL_addchar(&b, LUAL_PACKPADBYTE); break; } case Kstring: { /* strings with length count */ @@ -1249,7 +1403,7 @@ totalsize += len + 1; break; } - case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* go through */ + case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ case Kpaddalign: case Knop: arg--; /* undo increment */ break; @@ -1276,7 +1430,7 @@ case Kstring: /* strings with length count */ case Kzstr: /* zero-terminated string */ luaL_argerror(L, 1, "variable-length format"); - break; + /* call never return, but to avoid warnings: *//* FALLTHROUGH */ default: break; } } diff -Nru lua-compat53-0.3/ltablib.c lua-compat53-0.7/ltablib.c --- lua-compat53-0.3/ltablib.c 2015-09-13 17:10:36.000000000 +0000 +++ lua-compat53-0.7/ltablib.c 2018-07-13 02:03:47.000000000 +0000 @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.79 2014/11/02 19:19:04 roberto Exp $ +** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #include #include +#include #include "lua.h" @@ -19,40 +20,42 @@ #include "lualib.h" - /* -** Structure with table-access functions +** Operations that an object must define to mimic a table +** (some functions only need some of them) */ -typedef struct { - int (*geti) (lua_State *L, int idx, lua_Integer n); - void (*seti) (lua_State *L, int idx, lua_Integer n); -} TabA; +#define TAB_R 1 /* read */ +#define TAB_W 2 /* write */ +#define TAB_L 4 /* length */ +#define TAB_RW (TAB_R | TAB_W) /* read/write */ -/* -** Check that 'arg' has a table and set access functions in 'ta' to raw -** or non-raw according to the presence of corresponding metamethods. -*/ -static void checktab (lua_State *L, int arg, TabA *ta) { - ta->geti = NULL; ta->seti = NULL; - if (lua_getmetatable(L, arg)) { - lua_pushliteral(L, "__index"); /* 'index' metamethod */ - if (lua_rawget(L, -2) != LUA_TNIL) - ta->geti = lua_geti; - lua_pushliteral(L, "__newindex"); /* 'newindex' metamethod */ - if (lua_rawget(L, -3) != LUA_TNIL) - ta->seti = lua_seti; - lua_pop(L, 3); /* pop metatable plus both metamethods */ - } - if (ta->geti == NULL || ta->seti == NULL) { - luaL_checktype(L, arg, LUA_TTABLE); /* must be table for raw methods */ - if (ta->geti == NULL) ta->geti = lua_rawgeti; - if (ta->seti == NULL) ta->seti = lua_rawseti; - } +#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) + + +static int checkfield (lua_State *L, const char *key, int n) { + lua_pushstring(L, key); + return (lua_rawget(L, -n) != LUA_TNIL); } -#define aux_getn(L,n,ta) (checktab(L, n, ta), luaL_len(L, n)) +/* +** Check that 'arg' either is a table or can behave like one (that is, +** has a metatable with the required metamethods) +*/ +static void checktab (lua_State *L, int arg, int what) { + if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ + int n = 1; /* number of elements to pop */ + if (lua_getmetatable(L, arg) && /* must have metatable */ + (!(what & TAB_R) || checkfield(L, "__index", ++n)) && + (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && + (!(what & TAB_L) || checkfield(L, "__len", ++n))) { + lua_pop(L, n); /* pop metatable and tested metamethods */ + } + else + luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ + } +} #if defined(LUA_COMPAT_MAXN) @@ -74,8 +77,7 @@ static int tinsert (lua_State *L) { - TabA ta; - lua_Integer e = aux_getn(L, 1, &ta) + 1; /* first empty element */ + lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ lua_Integer pos; /* where to insert new element */ switch (lua_gettop(L)) { case 2: { /* called with only 2 arguments */ @@ -87,8 +89,8 @@ pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); for (i = e; i > pos; i--) { /* move up elements */ - (*ta.geti)(L, 1, i - 1); - (*ta.seti)(L, 1, i); /* t[i] = t[i - 1] */ + lua_geti(L, 1, i - 1); + lua_seti(L, 1, i); /* t[i] = t[i - 1] */ } break; } @@ -96,65 +98,67 @@ return luaL_error(L, "wrong number of arguments to 'insert'"); } } - (*ta.seti)(L, 1, pos); /* t[pos] = v */ + lua_seti(L, 1, pos); /* t[pos] = v */ return 0; } static int tremove (lua_State *L) { - TabA ta; - lua_Integer size = aux_getn(L, 1, &ta); + lua_Integer size = aux_getn(L, 1, TAB_RW); lua_Integer pos = luaL_optinteger(L, 2, size); if (pos != size) /* validate 'pos' if given */ luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); - (*ta.geti)(L, 1, pos); /* result = t[pos] */ + lua_geti(L, 1, pos); /* result = t[pos] */ for ( ; pos < size; pos++) { - (*ta.geti)(L, 1, pos + 1); - (*ta.seti)(L, 1, pos); /* t[pos] = t[pos + 1] */ + lua_geti(L, 1, pos + 1); + lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ } lua_pushnil(L); - (*ta.seti)(L, 1, pos); /* t[pos] = nil */ + lua_seti(L, 1, pos); /* t[pos] = nil */ return 1; } +/* +** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever +** possible, copy in increasing order, which is better for rehashing. +** "possible" means destination after original range, or smaller +** than origin, or copying to another table. +*/ static int tmove (lua_State *L) { - TabA ta; lua_Integer f = luaL_checkinteger(L, 2); lua_Integer e = luaL_checkinteger(L, 3); lua_Integer t = luaL_checkinteger(L, 4); int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ - /* the following restriction avoids several problems with overflows */ - luaL_argcheck(L, f > 0, 2, "initial position must be positive"); + checktab(L, 1, TAB_R); + checktab(L, tt, TAB_W); if (e >= f) { /* otherwise, nothing to move */ lua_Integer n, i; - ta.geti = (luaL_getmetafield(L, 1, "__index") == LUA_TNIL) - ? (luaL_checktype(L, 1, LUA_TTABLE), lua_rawgeti) - : lua_geti; - ta.seti = (luaL_getmetafield(L, tt, "__newindex") == LUA_TNIL) - ? (luaL_checktype(L, tt, LUA_TTABLE), lua_rawseti) - : lua_seti; + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, + "too many elements to move"); n = e - f + 1; /* number of elements to move */ - if (t > f) { - for (i = n - 1; i >= 0; i--) { - (*ta.geti)(L, 1, f + i); - (*ta.seti)(L, tt, t + i); + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, + "destination wrap around"); + if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { + for (i = 0; i < n; i++) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); } } else { - for (i = 0; i < n; i++) { - (*ta.geti)(L, 1, f + i); - (*ta.seti)(L, tt, t + i); + for (i = n - 1; i >= 0; i--) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); } } } - lua_pushvalue(L, tt); /* return "to table" */ + lua_pushvalue(L, tt); /* return destination table */ return 1; } -static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) { - (*ta->geti)(L, 1, i); +static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { + lua_geti(L, 1, i); if (!lua_isstring(L, -1)) luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", luaL_typename(L, -1), i); @@ -163,21 +167,19 @@ static int tconcat (lua_State *L) { - TabA ta; luaL_Buffer b; + lua_Integer last = aux_getn(L, 1, TAB_R); size_t lsep; - lua_Integer i, last; const char *sep = luaL_optlstring(L, 2, "", &lsep); - checktab(L, 1, &ta); - i = luaL_optinteger(L, 3, 1); - last = luaL_opt(L, luaL_checkinteger, 4, luaL_len(L, 1)); + lua_Integer i = luaL_optinteger(L, 3, 1); + last = luaL_optinteger(L, 4, last); luaL_buffinit(L, &b); for (; i < last; i++) { - addfield(L, &b, &ta, i); + addfield(L, &b, i); luaL_addlstring(&b, sep, lsep); } if (i == last) /* add last value (if interval was not empty) */ - addfield(L, &b, &ta, i); + addfield(L, &b, i); luaL_pushresult(&b); return 1; } @@ -195,7 +197,7 @@ lua_createtable(L, n, 1); /* create result table */ lua_insert(L, 1); /* put it at index 1 */ for (i = n; i >= 1; i--) /* assign elements */ - lua_rawseti(L, 1, i); + lua_seti(L, 1, i); lua_pushinteger(L, n); lua_setfield(L, 1, "n"); /* t.n = number of elements */ return 1; /* return table */ @@ -203,20 +205,17 @@ static int unpack (lua_State *L) { - TabA ta; - lua_Integer i, e; lua_Unsigned n; - checktab(L, 1, &ta); - i = luaL_optinteger(L, 2, 1); - e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); + lua_Integer i = luaL_optinteger(L, 2, 1); + lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); if (i > e) return 0; /* empty range */ n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) return luaL_error(L, "too many results to unpack"); - do { /* must have at least one element */ - (*ta.geti)(L, 1, i); /* push arg[i..e] */ - } while (i++ < e); - + for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ + lua_geti(L, 1, i); + } + lua_geti(L, 1, e); /* push last element */ return (int)n; } @@ -233,97 +232,191 @@ */ -static void set2 (lua_State *L, TabA *ta, int i, int j) { - (*ta->seti)(L, 1, i); - (*ta->seti)(L, 1, j); +/* type for array indices */ +typedef unsigned int IdxT; + + +/* +** Produce a "random" 'unsigned int' to randomize pivot choice. This +** macro is used only when 'sort' detects a big imbalance in the result +** of a partition. (If you don't want/need this "randomness", ~0 is a +** good choice.) +*/ +#if !defined(l_randomizePivot) /* { */ + +#include + +/* size of 'e' measured in number of 'unsigned int's */ +#define sof(e) (sizeof(e) / sizeof(unsigned int)) + +/* +** Use 'time' and 'clock' as sources of "randomness". Because we don't +** know the types 'clock_t' and 'time_t', we cannot cast them to +** anything without risking overflows. A safe way to use their values +** is to copy them to an array of a known type and use the array values. +*/ +static unsigned int l_randomizePivot (void) { + clock_t c = clock(); + time_t t = time(NULL); + unsigned int buff[sof(c) + sof(t)]; + unsigned int i, rnd = 0; + memcpy(buff, &c, sof(c) * sizeof(unsigned int)); + memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); + for (i = 0; i < sof(buff); i++) + rnd += buff[i]; + return rnd; } +#endif /* } */ + + +/* arrays larger than 'RANLIMIT' may use randomized pivots */ +#define RANLIMIT 100u + + +static void set2 (lua_State *L, IdxT i, IdxT j) { + lua_seti(L, 1, i); + lua_seti(L, 1, j); +} + + +/* +** Return true iff value at stack index 'a' is less than the value at +** index 'b' (according to the order of the sort). +*/ static int sort_comp (lua_State *L, int a, int b) { - if (!lua_isnil(L, 2)) { /* function? */ + if (lua_isnil(L, 2)) /* no function? */ + return lua_compare(L, a, b, LUA_OPLT); /* a < b */ + else { /* function */ int res; - lua_pushvalue(L, 2); + lua_pushvalue(L, 2); /* push function */ lua_pushvalue(L, a-1); /* -1 to compensate function */ lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ - lua_call(L, 2, 1); - res = lua_toboolean(L, -1); - lua_pop(L, 1); + lua_call(L, 2, 1); /* call function */ + res = lua_toboolean(L, -1); /* get result */ + lua_pop(L, 1); /* pop result */ return res; } - else /* a < b? */ - return lua_compare(L, a, b, LUA_OPLT); } -static void auxsort (lua_State *L, TabA *ta, int l, int u) { - while (l < u) { /* for tail recursion */ - int i, j; - /* sort elements a[l], a[(l+u)/2] and a[u] */ - (*ta->geti)(L, 1, l); - (*ta->geti)(L, 1, u); - if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ - set2(L, ta, l, u); /* swap a[l] - a[u] */ + +/* +** Does the partition: Pivot P is at the top of the stack. +** precondition: a[lo] <= P == a[up-1] <= a[up], +** so it only needs to do the partition from lo + 1 to up - 2. +** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] +** returns 'i'. +*/ +static IdxT partition (lua_State *L, IdxT lo, IdxT up) { + IdxT i = lo; /* will be incremented before first use */ + IdxT j = up - 1; /* will be decremented before first use */ + /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ + for (;;) { + /* next loop: repeat ++i while a[i] < P */ + while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ + /* next loop: repeat --j while P < a[j] */ + while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j < i) /* j < i but a[j] > P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ + if (j < i) { /* no elements out of place? */ + /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ + lua_pop(L, 1); /* pop a[j] */ + /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ + set2(L, up - 1, i); + return i; + } + /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ + set2(L, i, j); + } +} + + +/* +** Choose an element in the middle (2nd-3th quarters) of [lo,up] +** "randomized" by 'rnd' +*/ +static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { + IdxT r4 = (up - lo) / 4; /* range/4 */ + IdxT p = rnd % (r4 * 2) + (lo + r4); + lua_assert(lo + r4 <= p && p <= up - r4); + return p; +} + + +/* +** QuickSort algorithm (recursive function) +*/ +static void auxsort (lua_State *L, IdxT lo, IdxT up, + unsigned int rnd) { + while (lo < up) { /* loop for tail recursion */ + IdxT p; /* Pivot index */ + IdxT n; /* to be used later */ + /* sort elements 'lo', 'p', and 'up' */ + lua_geti(L, 1, lo); + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ + set2(L, lo, up); /* swap a[lo] - a[up] */ else - lua_pop(L, 2); - if (u-l == 1) break; /* only 2 elements */ - i = (l+u)/2; - (*ta->geti)(L, 1, i); - (*ta->geti)(L, 1, l); - if (sort_comp(L, -2, -1)) /* a[i]geti)(L, 1, u); - if (sort_comp(L, -1, -2)) /* a[u]geti)(L, 1, i); /* Pivot */ - lua_pushvalue(L, -1); - (*ta->geti)(L, 1, u-1); - set2(L, ta, i, u-1); - /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */ - i = l; j = u-1; - for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */ - /* repeat ++i until a[i] >= P */ - while ((*ta->geti)(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i>=u) luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[i] */ - } - /* repeat --j until a[j] <= P */ - while ((*ta->geti)(L, 1, --j), sort_comp(L, -3, -1)) { - if (j<=l) luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[j] */ - } - if (jgeti)(L, 1, u-1); - (*ta->geti)(L, 1, i); - set2(L, ta, u-1, i); /* swap pivot (a[u-1]) with a[i] */ - /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ - /* adjust so that smaller half is in [j..i] and larger one in [l..u] */ - if (i-l < u-i) { - j=l; i=i-1; l=i+2; + if (up - lo == 2) /* only 3 elements? */ + return; /* already sorted */ + lua_geti(L, 1, p); /* get middle element (Pivot) */ + lua_pushvalue(L, -1); /* push Pivot */ + lua_geti(L, 1, up - 1); /* push a[up - 1] */ + set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ + p = partition(L, lo, up); + /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ + if (p - lo < up - p) { /* lower interval is smaller? */ + auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ + n = p - lo; /* size of smaller interval */ + lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ } else { - j=i+1; i=u; u=j-2; + auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ + n = up - p; /* size of smaller interval */ + up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ } - auxsort(L, ta, j, i); /* call recursively the smaller one */ - } /* repeat the routine for the larger one */ + if ((up - lo) / 128 > n) /* partition too imbalanced? */ + rnd = l_randomizePivot(); /* try a new randomization */ + } /* tail call auxsort(L, lo, up, rnd) */ } + static int sort (lua_State *L) { - TabA ta; - int n = (int)aux_getn(L, 1, &ta); - luaL_checkstack(L, 50, ""); /* assume array is smaller than 2^50 */ - if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ - luaL_checktype(L, 2, LUA_TFUNCTION); - lua_settop(L, 2); /* make sure there are two arguments */ - auxsort(L, &ta, 1, n); + lua_Integer n = aux_getn(L, 1, TAB_RW); + if (n > 1) { /* non-trivial interval? */ + luaL_argcheck(L, n < INT_MAX, 1, "array too big"); + if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ + lua_settop(L, 2); /* make sure there are two arguments */ + auxsort(L, 1, (IdxT)n, 0); + } return 0; } diff -Nru lua-compat53-0.3/lutf8lib.c lua-compat53-0.7/lutf8lib.c --- lua-compat53-0.3/lutf8lib.c 2015-09-13 17:10:36.000000000 +0000 +++ lua-compat53-0.7/lutf8lib.c 2018-07-13 02:03:47.000000000 +0000 @@ -1,5 +1,5 @@ /* -** $Id: lutf8lib.c,v 1.13 2014/11/02 19:19:04 roberto Exp $ +** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp $ ** Standard library for UTF-8 manipulation ** See Copyright Notice in lua.h */ @@ -11,6 +11,7 @@ #include +#include #include #include @@ -37,7 +38,7 @@ ** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. */ static const char *utf8_decode (const char *o, int *val) { - static unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; + static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; const unsigned char *s = (const unsigned char *)o; unsigned int c = s[0]; unsigned int res = 0; /* final result */ @@ -106,9 +107,9 @@ luaL_argcheck(L, posi >= 1, 2, "out of range"); luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); if (posi > pose) return 0; /* empty interval; return no values */ - n = (int)(pose - posi + 1); - if (posi + n <= pose) /* (lua_Integer -> int) overflow? */ + if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; luaL_checkstack(L, n, "string slice too long"); n = 0; se = s + pose; @@ -193,7 +194,7 @@ lua_pushinteger(L, posi + 1); else /* no such character */ lua_pushnil(L); - return 1; + return 1; } @@ -234,7 +235,7 @@ #define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" -static struct luaL_Reg funcs[] = { +static const luaL_Reg funcs[] = { {"offset", byteoffset}, {"codepoint", codepoint}, {"char", utfchar}, @@ -248,7 +249,7 @@ LUAMOD_API int luaopen_utf8 (lua_State *L) { luaL_newlib(L, funcs); - lua_pushliteral(L, UTF8PATT); + lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); lua_setfield(L, -2, "charpattern"); return 1; } diff -Nru lua-compat53-0.3/README.md lua-compat53-0.7/README.md --- lua-compat53-0.3/README.md 2015-09-13 17:10:36.000000000 +0000 +++ lua-compat53-0.7/README.md 2018-07-13 02:03:47.000000000 +0000 @@ -1,3 +1,5 @@ +[![Build Status](https://travis-ci.org/keplerproject/lua-compat-5.3.svg?branch=master)](https://travis-ci.org/keplerproject/lua-compat-5.3) + # lua-compat-5.3 Lua-5.3-style APIs for Lua 5.2 and 5.1. @@ -72,7 +74,11 @@ compatibility functions in your code. You have to compile and link `compat-5.3.c` to your project yourself. You can change the way the functions are exported using the `COMPAT53_API` macro (e.g. if you need - some `__declspec` magic). + some `__declspec` magic). While it is technically possible to use + the "lua" prefix (and it looks better in the debugger), this is + discouraged because LuaJIT has started to implement its own Lua 5.2+ + C API functions, and with the "lua" prefix you'd violate the + one-definition rule with recent LuaJIT versions. ## What's implemented @@ -129,6 +135,7 @@ * `lua_isinteger` * `lua_numbertointeger` * `lua_callk` and `lua_pcallk` (limited compatibility, see [here][14]) +* `lua_resume` * `lua_rawget` and `lua_rawgeti` (return values) * `lua_rawgetp` and `lua_rawsetp` * `luaL_requiref` (now checks `package.loaded` first) @@ -137,12 +144,17 @@ For Lua 5.1 additionally: * `LUA_OK` +* `LUA_ERRGCMM` * `LUA_OP*` macros for `lua_arith` and `lua_compare` +* `LUA_FILEHANDLE` * `lua_Unsigned` +* `luaL_Stream` (limited compatibility, see [here][19]) * `lua_absindex` -* `lua_arith` (see [here][19]) +* `lua_arith` (see [here][20]) * `lua_compare` * `lua_len`, `lua_rawlen`, and `luaL_len` +* `lua_load` (mode argument) +* `lua_pushstring`, `lua_pushlstring` (return value) * `lua_copy` * `lua_pushglobaltable` * `luaL_testudata` @@ -152,11 +164,13 @@ * `luaL_traceback` * `luaL_execresult` * `luaL_fileresult` +* `luaL_loadbufferx` +* `luaL_loadfilex` * `luaL_checkversion` (with empty body, only to avoid compile errors, - see [here][20]) + see [here][21]) * `luaL_tolstring` * `luaL_buffinitsize`, `luaL_prepbuffsize`, and `luaL_pushresultsize` - (see [here][21]) + (see [here][22]) * `lua_pushunsigned`, `lua_tounsignedx`, `lua_tounsigned`, `luaL_checkunsigned`, `luaL_optunsigned`, if `LUA_COMPAT_APIINTCASTS` is defined. @@ -179,8 +193,6 @@ * `lua_upvaluejoin` (5.1) * `lua_version` (5.1) * `lua_yieldk` (5.1) - * `luaL_loadbufferx` (5.1) - * `luaL_loadfilex` (5.1) ## See also @@ -197,6 +209,8 @@ * Tomás Guisasola Gorham ([@tomasguisasola](http://github.com/tomasguisasola)) * Hisham Muhammad ([@hishamhm](http://github.com/hishamhm)) * Renato Maia ([@renatomaia](http://github.com/renatomaia)) +* [@ThePhD](http://github.com/ThePhD) +* [@Daurnimator](http://github.com/Daurnimator) [1]: http://www.inf.puc-rio.br/~roberto/struct/ @@ -217,8 +231,9 @@ [16]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_getuservalue [17]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_setuservalue [18]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_stringtonumber - [19]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_arith - [20]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_checkversion - [21]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_Buffer - [22]: https://github.com/keplerproject/lua-compat-5.3/wiki/coroutine.running + [19]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_Stream + [20]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_arith + [21]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_checkversion + [22]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_Buffer + [23]: https://github.com/keplerproject/lua-compat-5.3/wiki/coroutine.running diff -Nru lua-compat53-0.3/rockspecs/compat53-0.3-1.rockspec lua-compat53-0.7/rockspecs/compat53-0.3-1.rockspec --- lua-compat53-0.3/rockspecs/compat53-0.3-1.rockspec 1970-01-01 00:00:00.000000000 +0000 +++ lua-compat53-0.7/rockspecs/compat53-0.3-1.rockspec 2018-07-13 02:03:47.000000000 +0000 @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.3-1" +source = { + url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.3.zip", + dir = "lua-compat-5.3-0.3", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/keplerproject/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.4", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + } +} + diff -Nru lua-compat53-0.3/rockspecs/compat53-0.4-1.rockspec lua-compat53-0.7/rockspecs/compat53-0.4-1.rockspec --- lua-compat53-0.3/rockspecs/compat53-0.4-1.rockspec 1970-01-01 00:00:00.000000000 +0000 +++ lua-compat53-0.7/rockspecs/compat53-0.4-1.rockspec 2018-07-13 02:03:47.000000000 +0000 @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.4-1" +source = { + url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.4.zip", + dir = "lua-compat-5.3-0.4", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/keplerproject/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.4", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + } +} + diff -Nru lua-compat53-0.3/rockspecs/compat53-0.5-1.rockspec lua-compat53-0.7/rockspecs/compat53-0.5-1.rockspec --- lua-compat53-0.3/rockspecs/compat53-0.5-1.rockspec 1970-01-01 00:00:00.000000000 +0000 +++ lua-compat53-0.7/rockspecs/compat53-0.5-1.rockspec 2018-07-13 02:03:47.000000000 +0000 @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.5-1" +source = { + url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.5.zip", + dir = "lua-compat-5.3-0.5", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/keplerproject/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.4", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + } +} + diff -Nru lua-compat53-0.3/tests/test.lua lua-compat53-0.7/tests/test.lua --- lua-compat53-0.3/tests/test.lua 2015-09-13 17:10:36.000000000 +0000 +++ lua-compat53-0.7/tests/test.lua 2018-07-13 02:03:47.000000000 +0000 @@ -40,9 +40,9 @@ if arg[1] == "module" then mode = "module" end +local self = arg[0] - -package.path = "../?.lua;../?/init.lua;"..package.path +package.path = "../?.lua;../?/init.lua" package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll" if mode == "module" then print("testing Lua API using `compat53.module` ...") @@ -248,6 +248,49 @@ ___'' +if utf8.len then + local unpack = table.unpack or unpack + local function utf8rt(s) + local t = { utf8.codepoint(s, 1, #s) } + local ps, cs = {}, {} + for p,c in utf8.codes(s) do + ps[#ps+1], cs[#cs+1] = p, c + end + print("utf8.codes", unpack(ps)) + print("utf8.codes", unpack(cs)) + print("utf8.codepoint", unpack(t)) + print("utf8.len", utf8.len(s), #t, #s) + print("utf8.char", utf8.char(unpack(t))) + end + utf8rt("äöüßÄÖÜ") + utf8rt("abcdefg") + ___'' + local s = "äöüßÄÖÜ" + print("utf8.offset", utf8.offset(s, 1, 1)) + print("utf8.offset", utf8.offset(s, 2, 1)) + print("utf8.offset", utf8.offset(s, 3, 1)) + print("utf8.offset", pcall(utf8.offset, s, 3, 2)) + print("utf8.offset", utf8.offset(s, 3, 3)) + print("utf8.offset", utf8.offset(s, -1, 7)) + print("utf8.offset", utf8.offset(s, -2, 7)) + print("utf8.offset", utf8.offset(s, -3, 7)) + print("utf8.offset", utf8.offset(s, -1)) + ___'' +else + print("XXX: utf8 module not available") +end + + +if string.pack then + local format = "bBhHlLjJdc3z" + local s = string.pack(format, -128, 255, -32768, 65535, -2147483648, 4294967295, -32768, 65536, 1.25, "abc", "defgh") + print("string.unpack", string.unpack(format, s)) + ___'' +else + print("XXX: string packing not available") +end + + print("testing Lua API for Lua 5.1 ...") ___'' @@ -560,11 +603,11 @@ ___'' do writefile("data.txt", "123 18.8 hello world\ni'm here\n") - for a,b in io.lines("test.lua", 2, "*l") do + for a,b in io.lines(self, 2, "*l") do print("io.lines()", a, b) break end - for l in io.lines("test.lua") do + for l in io.lines(self) do print("io.lines()", l) break end @@ -581,7 +624,7 @@ for l in io.lines("no_such_file.txt") do print(l) end end)) if mode ~= "module" then - local f = assert(io.open("test.lua", "r")) + local f = assert(io.open(self, "r")) for a,b in f:lines(2, "*l") do print("file:lines()", a, b) break @@ -614,127 +657,163 @@ print("testing C API ...") local mod = require("testmod") ___'' -print(mod.isinteger(1)) -print(mod.isinteger(0)) -print(mod.isinteger(1234567)) -print(mod.isinteger(12.3)) -print(mod.isinteger(math.huge)) -print(mod.isinteger(math.sqrt(-1))) +print("isinteger", mod.isinteger(1)) +print("isinteger", mod.isinteger(0)) +print("isinteger", mod.isinteger(1234567)) +print("isinteger", mod.isinteger(12.3)) +print("isinteger", mod.isinteger(math.huge)) +print("isinteger", mod.isinteger(math.sqrt(-1))) ___'' -print(mod.rotate(1, 1, 2, 3, 4, 5, 6)) -print(mod.rotate(-1, 1, 2, 3, 4, 5, 6)) -print(mod.rotate(4, 1, 2, 3, 4, 5, 6)) -print(mod.rotate(-4, 1, 2, 3, 4, 5, 6)) +print("rotate", mod.rotate(1, 1, 2, 3, 4, 5, 6)) +print("rotate", mod.rotate(-1, 1, 2, 3, 4, 5, 6)) +print("rotate", mod.rotate(4, 1, 2, 3, 4, 5, 6)) +print("rotate", mod.rotate(-4, 1, 2, 3, 4, 5, 6)) ___'' -print(mod.strtonum("+123")) -print(mod.strtonum(" 123 ")) -print(mod.strtonum("-1.23")) -print(mod.strtonum(" 123 abc")) -print(mod.strtonum("jkl")) +print("strtonum", mod.strtonum("+123")) +print("strtonum", mod.strtonum(" 123 ")) +print("strtonum", mod.strtonum("-1.23")) +print("strtonum", mod.strtonum(" 123 abc")) +print("strtonum", mod.strtonum("jkl")) ___'' local a, b, c = mod.requiref() -print( type(a), type(b), type(c), - a.boolean, b.boolean, c.boolean, - type(requiref1), type(requiref2), type(requiref3)) +print("requiref", type(a), type(b), type(c), + a.boolean, b.boolean, c.boolean, + type(requiref1), type(requiref2), type(requiref3)) ___'' local proxy, backend = {}, {} setmetatable(proxy, { __index = backend, __newindex = backend }) -print(rawget(proxy, 1), rawget(backend, 1)) -print(mod.getseti(proxy, 1)) -print(rawget(proxy, 1), rawget(backend, 1)) -print(mod.getseti(proxy, 1)) -print(rawget(proxy, 1), rawget(backend, 1)) +print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) +print("geti/seti", mod.getseti(proxy, 1)) +print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) +print("geti/seti", mod.getseti(proxy, 1)) +print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) -- tests for Lua 5.1 ___'' -print(mod.tonumber(12)) -print(mod.tonumber("12")) -print(mod.tonumber("0")) -print(mod.tonumber(false)) -print(mod.tonumber("error")) - -___'' -print(mod.tointeger(12)) -print(mod.tointeger("12")) -print(mod.tointeger("0")) -print( "aaa" ) -print(mod.tointeger(math.pi)) -print( "bbb" ) -print(mod.tointeger(false)) -print(mod.tointeger("error")) - -___'' -print(mod.len("123")) -print(mod.len({ 1, 2, 3})) -print(pcall(mod.len, true)) +print("tonumber", mod.tonumber(12)) +print("tonumber", mod.tonumber("12")) +print("tonumber", mod.tonumber("0")) +print("tonumber", mod.tonumber(false)) +print("tonumber", mod.tonumber("error")) + +___'' +print("tointeger", mod.tointeger(12)) +print("tointeger", mod.tointeger(-12)) +print("tointeger", mod.tointeger(12.1)) +print("tointeger", mod.tointeger(12.9)) +print("tointeger", mod.tointeger(-12.1)) +print("tointeger", mod.tointeger(-12.9)) +print("tointeger", mod.tointeger("12")) +print("tointeger", mod.tointeger("0")) +print("tointeger", mod.tointeger(math.pi)) +print("tointeger", mod.tointeger(false)) +print("tointeger", mod.tointeger("error")) + +___'' +print("len", mod.len("123")) +print("len", mod.len({ 1, 2, 3})) +print("len", pcall(mod.len, true)) local ud, meta = mod.newproxy() meta.__len = function() return 5 end -print(mod.len(ud)) +print("len", mod.len(ud)) meta.__len = function() return true end -print(pcall(mod.len, ud)) +print("len", pcall(mod.len, ud)) ___'' -print(mod.copy(true, "string", {}, 1)) +print("copy", mod.copy(true, "string", {}, 1)) ___'' -print(mod.rawxetp()) -print(mod.rawxetp("I'm back")) +print("rawgetp/rawsetp", mod.rawxetp()) +print("rawgetp/rawsetp", mod.rawxetp("I'm back")) ___'' -print(F(mod.globals()), mod.globals() == _G) +print("globals", F(mod.globals()), mod.globals() == _G) ___'' local t = {} -print(F(mod.subtable(t))) +print("getsubtable", F(mod.subtable(t))) local x, msg = mod.subtable(t) -print(F(x, msg, x == t.xxx)) +print("getsubtable", F(x, msg, x == t.xxx)) ___'' -print(F(mod.udata())) -print(mod.udata("nosuchtype")) +print("udata", F(mod.udata())) +print("udata", mod.udata("nosuchtype")) ___'' -print(F(mod.uservalue())) +print("uservalue", F(mod.uservalue())) ___'' -print(mod.getupvalues()) +print("upvalues", mod.getupvalues()) ___'' -print(mod.absindex("hi", true)) +print("absindex", mod.absindex("hi", true)) ___'' -print(mod.arith(2, 1)) -print(mod.arith(3, 5)) +print("arith", mod.arith(2, 1)) +print("arith", mod.arith(3, 5)) ___'' -print(mod.compare(1, 1)) -print(mod.compare(2, 1)) -print(mod.compare(1, 2)) +print("compare", mod.compare(1, 1)) +print("compare", mod.compare(2, 1)) +print("compare", mod.compare(1, 2)) ___'' -print(mod.tolstring("string")) +print("tolstring", mod.tolstring("string")) local t = setmetatable({}, { __tostring = function(v) return "mytable" end }) -print(mod.tolstring(t)) +print("tolstring", mod.tolstring(t)) local t = setmetatable({}, { __tostring = function(v) return nil end }) -print(pcall(mod.tolstring, t)) +print("tolstring", pcall(mod.tolstring, t)) +local ud, meta = mod.newproxy() +meta.__name = "XXX" +print("tolstring", mod.tolstring(ud):gsub(":.*$", ": yyy")) + +___'' +print("pushstring", mod.pushstring()) + +___'' +print("Buffer", mod.buffer()) ___'' -print(mod.buffer()) +print("execresult", mod.exec("exit 0")) +print("execresult", mod.exec("exit 1")) +print("execresult", mod.exec("exit 25")) ___'' -print(mod.exec("exit 0")) -print(mod.exec("exit 1")) -print(mod.exec("exit 25")) +do + local bin = string.dump(function() end) + local modes = { "t", "b", "bt" } + local codes = { + "", "return true", bin, "invalidsource", "\27invalidbinary" + } + for _,m in ipairs(modes) do + for i,c in ipairs(codes) do + print("loadbufferx", m, i, F(mod.loadstring(c, m))) + end + end + + ___'' + local bom = "\239\187\191" + local shebang = "#!/usr/bin/env lua\n" + codes[#codes+1] = bom .. shebang .. "return true" + codes[#codes+1] = bom .. shebang .. bin + codes[#codes+1] = bom .. shebang .. "invalidsource" + codes[#codes+1] = bom .. shebang .. "\027invalidbinary" + for _,m in ipairs(modes) do + for i,c in ipairs(codes) do + print("loadfilex", m, i, F(mod.loadfile(c, m))) + end + end +end ___'' diff -Nru lua-compat53-0.3/tests/testmod.c lua-compat53-0.7/tests/testmod.c --- lua-compat53-0.3/tests/testmod.c 2015-09-13 17:10:36.000000000 +0000 +++ lua-compat53-0.7/tests/testmod.c 2018-07-13 02:03:47.000000000 +0000 @@ -1,7 +1,5 @@ #include #include -#include -#include #include "compat-5.3.h" @@ -12,7 +10,7 @@ static int test_rotate (lua_State *L) { - int r = luaL_checkint(L, 1); + int r = (int)luaL_checkinteger(L, 1); int n = lua_gettop(L)-1; luaL_argcheck(L, (r < 0 ? -r : r) <= n, 1, "not enough arguments"); lua_rotate(L, 2, r); @@ -154,7 +152,8 @@ lua_pushnil(L); else lua_pushinteger(L, n); - return 1; + lua_pushinteger(L, lua_tointeger(L, 1)); + return 2; } static int test_len (lua_State *L) { @@ -227,9 +226,9 @@ int ui = lua_gettop(L); lua_newtable(L); lua_setuservalue(L, ui); - lua_getuservalue(L, ui); + lua_pushinteger(L, lua_getuservalue(L, ui)); (void)udata; - return 1; + return 2; } static int test_upvalues (lua_State *L) { @@ -246,6 +245,15 @@ return 2; } +static int test_pushstring (lua_State *L) { + lua_pushstring(L, lua_pushliteral(L, "abc")); + lua_pushstring(L, lua_pushlstring(L, "abc", 2)); + lua_pushstring(L, lua_pushlstring(L, NULL, 0)); + lua_pushstring(L, lua_pushstring(L, "abc")); + lua_pushboolean(L, NULL == lua_pushstring(L, NULL)); + return 10; +} + static int test_buffer (lua_State *L) { luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE+1); @@ -265,6 +273,33 @@ return luaL_execresult(L, system(cmd)); } +static int test_loadstring (lua_State *L) { + size_t len = 0; + char const* s = luaL_checklstring(L, 1, &len); + char const* mode = luaL_optstring(L, 2, "bt"); + lua_pushinteger(L, luaL_loadbufferx(L, s, len, s, mode)); + return 2; +} + +static int test_loadfile (lua_State *L) { + char filename[L_tmpnam+1] = { 0 }; + size_t len = 0; + char const* s = luaL_checklstring(L, 1, &len); + char const* mode = luaL_optstring(L, 2, "bt"); + if (tmpnam(filename)) { + FILE* f = fopen(filename, "wb"); + if (f) { + fwrite(s, 1, len, f); + fclose(f); + lua_pushinteger(L, luaL_loadfilex(L, filename, mode)); + remove(filename); + return 2; + } else + remove(filename); + } + return 0; +} + static const luaL_Reg funcs[] = { { "isinteger", test_isinteger }, @@ -285,8 +320,11 @@ { "uservalue", test_uservalue }, { "globals", test_globals }, { "tolstring", test_tolstring }, + { "pushstring", test_pushstring }, { "buffer", test_buffer }, { "exec", test_exec }, + { "loadstring", test_loadstring }, + { "loadfile", test_loadfile }, { NULL, NULL } }; @@ -297,6 +335,9 @@ }; +#ifdef __cplusplus +extern "C" { +#endif int luaopen_testmod (lua_State *L) { int i = 1; luaL_newlib(L, funcs); @@ -305,4 +346,7 @@ luaL_setfuncs(L, more_funcs, NUP); return 1; } +#ifdef __cplusplus +} +#endif diff -Nru lua-compat53-0.3/.travis.yml lua-compat53-0.7/.travis.yml --- lua-compat53-0.3/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ lua-compat53-0.7/.travis.yml 2018-07-13 02:03:47.000000000 +0000 @@ -0,0 +1,47 @@ +language: c +compiler: gcc + +sudo: false + +env: + - LUA="lua=5.1" + - LUA="lua=5.1" EXTERNAL=true + - LUA="lua=5.1" COMPILER="g++" + - LUA="lua=5.1" EXTERNAL=true COMPILER="g++" + - LUA="luajit=@v2.1 --compat=none" + - LUA="luajit=@v2.1 --compat=none" EXTERNAL=true + - LUA="luajit=@v2.1 --compat=all" + - LUA="luajit=@v2.1 --compat=all" EXTERNAL=true + - LUA="lua=5.2" + - LUA="lua=5.2" EXTERNAL=true + - LUA="lua=5.2" COMPILER="g++" + - LUA="lua=5.2" EXTERNAL=true COMPILER="g++" + +branches: + only: + - master + +git: + depth: 3 + +notifications: + email: false + +before_install: + - pip install --user hererocks + - hererocks old --$LUA + - test -e old/bin/lua || (cd old/bin && ln -s luajit* lua) + - hererocks new --lua=5.3 + +install: + - export CC="${COMPILER:-gcc}" DEF="" SRC="" CFLAGS="-Wall -Wextra -Ic-api -O2 -fPIC" + - if [ "x${EXTERNAL:-}" = xtrue ]; then DEF="-DCOMPAT53_PREFIX=compat53" SRC="c-api/compat-5.3.c"; fi + - ${CC} ${CFLAGS} -Iold/include ${DEF} -shared -o old/testmod.so tests/testmod.c ${SRC} + - ${CC} ${CFLAGS} -Inew/include ${DEF} -shared -o new/testmod.so tests/testmod.c ${SRC} + - gcc ${CFLAGS} -Iold/include ${DEF} -shared -o old/compat53.so ltablib.c lutf8lib.c lstrlib.c ${SRC} + +script: + - (cd old && bin/lua ../tests/test.lua) > old.txt + - (cd new && bin/lua ../tests/test.lua) > new.txt + - diff old.txt new.txt || true +