From 8ee5245c2782df1d66fafdf4a574a739fda55704 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Wed, 13 Sep 2017 00:30:47 -0400 Subject: implement luaL_loadbufferx and luaL_loadfilex --- c-api/compat-5.3.c | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++- c-api/compat-5.3.h | 8 +- 2 files changed, 264 insertions(+), 4 deletions(-) (limited to 'c-api') diff --git a/c-api/compat-5.3.c b/c-api/compat-5.3.c index fab89c0..9723d25 100644 --- a/c-api/compat-5.3.c +++ b/c-api/compat-5.3.c @@ -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,88 @@ /* 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 +# if ((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || (defined(_XOPEN_SOURCE) || _XOPEN_SOURCE >= 600)) && (!defined(_GNU_SOURCE) || !_GNU_SOURCE) +# ifndef COMPAT53_HAVE_STRERROR_R_XSI +# define COMPAT53_HAVE_STRERROR_R_XSI 1 +# endif /* XSI-Compliant strerror_r */ +# ifndef COMPAT53_HAVE_STRERROR_R_GNU +# define COMPAT53_HAVE_STRERROR_R_GNU 0 +# endif /* GNU strerror_r */ +# else /* XSI/Posix vs. GNU strerror_r */ +# ifndef COMPAT53_HAVE_STRERROR_R_GNU +# define COMPAT53_HAVE_STRERROR_R_GNU 1 +# endif /* GNU variant strerror_r */ +# ifndef COMPAT53_HAVE_STRERROR_R_XSI +# define COMPAT53_HAVE_STRERROR_R_XSI 0 +# endif /* XSI strerror_r */ +# endif /* XSI/Posix vs. GNU strerror_r */ +# else /* none of the defines matched: define to 0 */ +# define COMPAT53_HAVE_STRERROR_R 0 +# ifndef COMPAT53_HAVE_STRERROR_R_XSI +# define COMPAT53_HAVE_STRERROR_R_XSI 0 +# endif /* XSI strerror_r */ +# ifndef COMPAT53_HAVE_STRERROR_R_GNU +# define COMPAT53_HAVE_STRERROR_R_GNU 0 +# endif /* GNU strerror_r */ +# 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 COMPAT53_HAVE_STRERROR_R_XSI + /* XSI Compliant */ + strerror_r(en, buff, sz); + return buff; +#else + /* GNU-specific which returns const char* */ + return strerror_r(en, buff, sz); +#endif +#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) @@ -336,23 +419,196 @@ COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, 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 when 'mode' is '%s'", modename, mode); + return err; + } + return LUA_OK; +} + + +typedef struct compat53_LoadF { + 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++] = 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) { + static const char lua_signature[] = "\x1bLua"; + 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]) { /* binary file? */ + status = compat53_checkmode(L, mode, "binary", LUA_ERRFILE); + if (status != LUA_OK) { + fclose(lf.f); + return compat53_errfile(L, "improper mode", fnameindex); + } +#if defined(_MSC_VER) + if (freopen_s(&lf.f, filename, "r", lf.f) != 0) return compat53_errfile(L, "open", 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 */ + } + else { /* text file */ + status = compat53_checkmode(L, mode, "text", LUA_ERRFILE); + if (status != LUA_OK) { + fclose(lf.f); + return compat53_errfile(L, "improper mode", fnameindex); + } + } + if (c != EOF) + lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ + status = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1)); + 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] == '\x1b') { + 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) || \ diff --git a/c-api/compat-5.3.h b/c-api/compat-5.3.h index 3d20d21..af08b6a 100644 --- a/c-api/compat-5.3.h +++ b/c-api/compat-5.3.h @@ -50,8 +50,6 @@ extern "C" { * lua_upvaluejoin * lua_version * lua_yieldk - * luaL_loadbufferx - * luaL_loadfilex */ #ifndef LUA_OK @@ -154,6 +152,12 @@ COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum); #define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) COMPAT53_API void luaL_checkversion (lua_State *L); +#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); -- cgit v1.2.3-55-g6feb From 73a7b6b352cce72edd74f62abb3d1280e62bfc1f Mon Sep 17 00:00:00 2001 From: The Phantom Derpstorm Date: Wed, 13 Sep 2017 01:23:06 -0400 Subject: fix usage of tabs --- c-api/compat-5.3.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'c-api') diff --git a/c-api/compat-5.3.c b/c-api/compat-5.3.c index 9723d25..9d63b5d 100644 --- a/c-api/compat-5.3.c +++ b/c-api/compat-5.3.c @@ -530,11 +530,11 @@ COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char 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*/ + /* 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, -- cgit v1.2.3-55-g6feb From 3b52d81dcf1b5d6d49e1837612e207b2cab6b74d Mon Sep 17 00:00:00 2001 From: Philipp Janda Date: Sat, 16 Sep 2017 15:11:29 +0200 Subject: Add Lua 5.3 version of `lua_load`. Change `luaL_loadfilex` to use the modified `lua_load` function. Add more credits to the README.md. --- README.md | 3 ++ c-api/compat-5.3.c | 104 ++++++++++++++++++++++++++++++++++------------------- c-api/compat-5.3.h | 3 ++ 3 files changed, 73 insertions(+), 37 deletions(-) (limited to 'c-api') diff --git a/README.md b/README.md index dedd228..caaca22 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,7 @@ For Lua 5.1 additionally: * `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` @@ -206,6 +207,8 @@ This package contains code written by: * 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/ diff --git a/c-api/compat-5.3.c b/c-api/compat-5.3.c index bd9e277..4bd984a 100644 --- a/c-api/compat-5.3.c +++ b/c-api/compat-5.3.c @@ -28,9 +28,12 @@ #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)) +# if defined(__GLIBC__) || defined(_POSIX_VERSION) || defined(__APPLE__) || \ + (!defined (__MINGW32__) && defined(__GNUC__) && (__GNUC__ < 6)) # define COMPAT53_HAVE_STRERROR_R 1 -# if ((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || (defined(_XOPEN_SOURCE) || _XOPEN_SOURCE >= 600)) && (!defined(_GNU_SOURCE) || !_GNU_SOURCE) +# if ((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ + (defined(_XOPEN_SOURCE) || _XOPEN_SOURCE >= 600)) && \ + (!defined(_GNU_SOURCE) || !_GNU_SOURCE) # ifndef COMPAT53_HAVE_STRERROR_R_XSI # define COMPAT53_HAVE_STRERROR_R_XSI 1 # endif /* XSI-Compliant strerror_r */ @@ -57,7 +60,8 @@ #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__) +# 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 @@ -68,7 +72,8 @@ #define COMPAT53_LUA_FILE_BUFFER_SIZE 4096 #endif /* Lua File Buffer Size */ -static char* compat53_strerror(int en, char* buff, size_t sz) { + +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 COMPAT53_HAVE_STRERROR_R_XSI @@ -98,6 +103,7 @@ static char* compat53_strerror(int en, char* buff, size_t sz) { #endif } + COMPAT53_API int lua_absindex (lua_State *L, int i) { if (i < 0 && i > LUA_REGISTRYINDEX) i += lua_gettop(L) + 1; @@ -448,7 +454,46 @@ static int compat53_checkmode (lua_State *L, const char *mode, const char *moden } -typedef struct compat53_LoadF { +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) { + 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) { + int status = LUA_OK; + if (compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */ + status = compat53_checkmode(L, mode, "binary", LUA_ERRFILE); + else + status = compat53_checkmode(L, mode, "text", LUA_ERRFILE); + 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 */ @@ -518,7 +563,6 @@ static int compat53_skipcomment (compat53_LoadF *lf, int *cp) { COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode) { - static const char lua_signature[] = "\x1bLua"; compat53_LoadF lf; int status, readstatus; int c; @@ -530,29 +574,25 @@ COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char 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 + /* 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, + /* 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) { + if (lf.f == NULL) return compat53_errfile(L, "open", fnameindex); - } #else /* use default locking version */ - if (fopen_s(&lf.f, filename, "r") != 0) { + 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 */ @@ -561,30 +601,19 @@ COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char } if (compat53_skipcomment(&lf, &c)) /* read initial portion */ lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ - if (c == lua_signature[0]) { /* binary file? */ - status = compat53_checkmode(L, mode, "binary", LUA_ERRFILE); - if (status != LUA_OK) { - fclose(lf.f); - return compat53_errfile(L, "improper mode", fnameindex); - } + if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ #if defined(_MSC_VER) - if (freopen_s(&lf.f, filename, "r", lf.f) != 0) return compat53_errfile(L, "open", fnameindex); + 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 */ } - else { /* text file */ - status = compat53_checkmode(L, mode, "text", LUA_ERRFILE); - if (status != LUA_OK) { - fclose(lf.f); - return compat53_errfile(L, "improper mode", fnameindex); - } - } if (c != EOF) lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ - status = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1)); + 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) { @@ -598,7 +627,7 @@ COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char 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] == '\x1b') { + if (sz > 0 && buff[0] == LUA_SIGNATURE[0]) { status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); } else { @@ -609,6 +638,7 @@ COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, co return luaL_loadbuffer(L, buff, sz, name); } + #if !defined(l_inspectstat) && \ (defined(unix) || defined(__unix) || defined(__unix__) || \ defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \ diff --git a/c-api/compat-5.3.h b/c-api/compat-5.3.h index c62d6bf..755c23e 100644 --- a/c-api/compat-5.3.h +++ b/c-api/compat-5.3.h @@ -174,6 +174,9 @@ COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum); #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); -- cgit v1.2.3-55-g6feb From 09b201c87c904066e1de5d44cf1e02538970c168 Mon Sep 17 00:00:00 2001 From: Philipp Janda Date: Sat, 16 Sep 2017 17:19:35 +0200 Subject: Add tests for `luaL_load{buffer,file}x`. Fix bug regarding empty input in `lua_load`. Adapt error message and error code. --- c-api/compat-5.3.c | 19 +++---- tests/test.lua | 157 +++++++++++++++++++++++++++++++---------------------- tests/testmod.c | 29 ++++++++++ 3 files changed, 129 insertions(+), 76 deletions(-) (limited to 'c-api') diff --git a/c-api/compat-5.3.c b/c-api/compat-5.3.c index 4bd984a..e87808c 100644 --- a/c-api/compat-5.3.c +++ b/c-api/compat-5.3.c @@ -447,7 +447,7 @@ COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { 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 when 'mode' is '%s'", modename, mode); + lua_pushfstring(L, "attempt to load a %s chunk (mode is '%s')", modename, mode); return err; } return LUA_OK; @@ -475,17 +475,16 @@ static const char *compat53_reader (lua_State *L, void *ud, size_t *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) { - int status = LUA_OK; - if (compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */ - status = compat53_checkmode(L, mode, "binary", LUA_ERRFILE); - else - status = compat53_checkmode(L, mode, "text", LUA_ERRFILE); - if (status != LUA_OK) - return status; - } + 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); diff --git a/tests/test.lua b/tests/test.lua index 582f55e..8fafdf3 100755 --- a/tests/test.lua +++ b/tests/test.lua @@ -657,133 +657,158 @@ ___'' 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("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(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("tointeger", mod.tointeger(12)) +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(mod.len("123")) -print(mod.len({ 1, 2, 3})) -print(pcall(mod.len, true)) +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(mod.tolstring(ud):gsub(":.*$", ": yyy")) +print("tolstring", mod.tolstring(ud):gsub(":.*$", ": yyy")) ___'' -print(mod.pushstring()) +print("pushstring", mod.pushstring()) ___'' -print(mod.buffer()) +print("Buffer", mod.buffer()) ___'' -print(mod.exec("exit 0")) -print(mod.exec("exit 1")) -print(mod.exec("exit 25")) +print("execresult", mod.exec("exit 0")) +print("execresult", mod.exec("exit 1")) +print("execresult", 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 --git a/tests/testmod.c b/tests/testmod.c index 868136b..1034d20 100644 --- a/tests/testmod.c +++ b/tests/testmod.c @@ -274,6 +274,33 @@ static int test_exec (lua_State *L) { 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 }, @@ -297,6 +324,8 @@ static const luaL_Reg funcs[] = { { "pushstring", test_pushstring }, { "buffer", test_buffer }, { "exec", test_exec }, + { "loadstring", test_loadstring }, + { "loadfile", test_loadfile }, { NULL, NULL } }; -- cgit v1.2.3-55-g6feb