aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThePhD <phdofthehouse@gmail.com>2017-09-13 00:30:47 -0400
committerThePhD <phdofthehouse@gmail.com>2017-09-13 00:30:47 -0400
commit8ee5245c2782df1d66fafdf4a574a739fda55704 (patch)
tree1ec7596320fa1fc98d1b4e3a00c0e7dccdf71f84
parent08212947bb97a5fffa2e56ddd6313710758896d0 (diff)
downloadlua-compat-5.3-8ee5245c2782df1d66fafdf4a574a739fda55704.tar.gz
lua-compat-5.3-8ee5245c2782df1d66fafdf4a574a739fda55704.tar.bz2
lua-compat-5.3-8ee5245c2782df1d66fafdf4a574a739fda55704.zip
implement luaL_loadbufferx and luaL_loadfilex
-rw-r--r--c-api/compat-5.3.c260
-rw-r--r--c-api/compat-5.3.h8
2 files changed, 264 insertions, 4 deletions
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 @@
3#include <string.h> 3#include <string.h>
4#include <ctype.h> 4#include <ctype.h>
5#include <errno.h> 5#include <errno.h>
6#include <stdio.h>
6#include "compat-5.3.h" 7#include "compat-5.3.h"
7 8
8/* don't compile it again if it already is included via compat53.h */ 9/* don't compile it again if it already is included via compat53.h */
@@ -14,6 +15,88 @@
14/* definitions for Lua 5.1 only */ 15/* definitions for Lua 5.1 only */
15#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 16#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
16 17
18#ifndef COMPAT53_FOPEN_NO_LOCK
19# if defined(_MSC_VER)
20# define COMPAT53_FOPEN_NO_LOCK 1
21# else /* otherwise */
22# define COMPAT53_FOPEN_NO_LOCK 0
23# endif /* VC++ only so far */
24#endif /* No-lock fopen_s usage if possible */
25
26#if defined(_MSC_VER) && COMPAT53_FOPEN_NO_LOCK
27#include <share.h>
28#endif /* VC++ _fsopen for share-allowed file read */
29
30#ifndef COMPAT53_HAVE_STRERROR_R
31# if defined(__GLIBC__) || defined(_POSIX_VERSION) || defined(__APPLE__) || (!defined (__MINGW32__) && defined(__GNUC__) && (__GNUC__ < 6))
32# define COMPAT53_HAVE_STRERROR_R 1
33# if ((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || (defined(_XOPEN_SOURCE) || _XOPEN_SOURCE >= 600)) && (!defined(_GNU_SOURCE) || !_GNU_SOURCE)
34# ifndef COMPAT53_HAVE_STRERROR_R_XSI
35# define COMPAT53_HAVE_STRERROR_R_XSI 1
36# endif /* XSI-Compliant strerror_r */
37# ifndef COMPAT53_HAVE_STRERROR_R_GNU
38# define COMPAT53_HAVE_STRERROR_R_GNU 0
39# endif /* GNU strerror_r */
40# else /* XSI/Posix vs. GNU strerror_r */
41# ifndef COMPAT53_HAVE_STRERROR_R_GNU
42# define COMPAT53_HAVE_STRERROR_R_GNU 1
43# endif /* GNU variant strerror_r */
44# ifndef COMPAT53_HAVE_STRERROR_R_XSI
45# define COMPAT53_HAVE_STRERROR_R_XSI 0
46# endif /* XSI strerror_r */
47# endif /* XSI/Posix vs. GNU strerror_r */
48# else /* none of the defines matched: define to 0 */
49# define COMPAT53_HAVE_STRERROR_R 0
50# ifndef COMPAT53_HAVE_STRERROR_R_XSI
51# define COMPAT53_HAVE_STRERROR_R_XSI 0
52# endif /* XSI strerror_r */
53# ifndef COMPAT53_HAVE_STRERROR_R_GNU
54# define COMPAT53_HAVE_STRERROR_R_GNU 0
55# endif /* GNU strerror_r */
56# endif /* have strerror_r of some form */
57#endif /* strerror_r */
58
59#ifndef COMPAT53_HAVE_STRERROR_S
60# if defined(_MSC_VER) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || (defined(__STDC_LIB_EXT1__) && __STDC_LIB_EXT1__)
61# define COMPAT53_HAVE_STRERROR_S 1
62# else /* not VC++ or C11 */
63# define COMPAT53_HAVE_STRERROR_S 0
64# endif /* strerror_s from VC++ or C11 */
65#endif /* strerror_s */
66
67#ifndef COMPAT53_LUA_FILE_BUFFER_SIZE
68#define COMPAT53_LUA_FILE_BUFFER_SIZE 4096
69#endif /* Lua File Buffer Size */
70
71static char* compat53_strerror(int en, char* buff, size_t sz) {
72#if COMPAT53_HAVE_STRERROR_R
73 /* use strerror_r here, because it's available on these specific platforms */
74#if COMPAT53_HAVE_STRERROR_R_XSI
75 /* XSI Compliant */
76 strerror_r(en, buff, sz);
77 return buff;
78#else
79 /* GNU-specific which returns const char* */
80 return strerror_r(en, buff, sz);
81#endif
82#elif COMPAT53_HAVE_STRERROR_S
83 /* for MSVC and other C11 implementations, use strerror_s
84 * since it's provided by default by the libraries
85 */
86 strerror_s(buff, sz, en);
87 return buff;
88#else
89 /* fallback, but
90 * strerror is not guaranteed to be threadsafe due to modifying
91 * errno itself and some impls not locking a static buffer for it
92 * ... but most known systems have threadsafe errno: this might only change
93 * if the locale is changed out from under someone while this function is being called
94 */
95 (void)buff;
96 (void)sz;
97 return strerror(en);
98#endif
99}
17 100
18COMPAT53_API int lua_absindex (lua_State *L, int i) { 101COMPAT53_API int lua_absindex (lua_State *L, int i) {
19 if (i < 0 && i > LUA_REGISTRYINDEX) 102 if (i < 0 && i > LUA_REGISTRYINDEX)
@@ -336,23 +419,196 @@ COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1,
336 419
337 420
338COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { 421COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
422 const char *serr = NULL;
339 int en = errno; /* calls to Lua API may change this value */ 423 int en = errno; /* calls to Lua API may change this value */
424 char buf[512] = { 0 };
340 if (stat) { 425 if (stat) {
341 lua_pushboolean(L, 1); 426 lua_pushboolean(L, 1);
342 return 1; 427 return 1;
343 } 428 }
344 else { 429 else {
345 lua_pushnil(L); 430 lua_pushnil(L);
431 serr = compat53_strerror(en, buf, sizeof(buf));
346 if (fname) 432 if (fname)
347 lua_pushfstring(L, "%s: %s", fname, strerror(en)); 433 lua_pushfstring(L, "%s: %s", fname, serr);
348 else 434 else
349 lua_pushstring(L, strerror(en)); 435 lua_pushstring(L, serr);
350 lua_pushnumber(L, (lua_Number)en); 436 lua_pushnumber(L, (lua_Number)en);
351 return 3; 437 return 3;
352 } 438 }
353} 439}
354 440
355 441
442static int compat53_checkmode (lua_State *L, const char *mode, const char *modename, int err) {
443 if (mode && strchr(mode, modename[0]) == NULL) {
444 lua_pushfstring(L, "attempt to load a %s chunk when 'mode' is '%s'", modename, mode);
445 return err;
446 }
447 return LUA_OK;
448}
449
450
451typedef struct compat53_LoadF {
452 int n; /* number of pre-read characters */
453 FILE *f; /* file being read */
454 char buff[COMPAT53_LUA_FILE_BUFFER_SIZE]; /* area for reading file */
455} compat53_LoadF;
456
457
458static const char *compat53_getF (lua_State *L, void *ud, size_t *size) {
459 compat53_LoadF *lf = (compat53_LoadF *)ud;
460 (void)L; /* not used */
461 if (lf->n > 0) { /* are there pre-read characters to be read? */
462 *size = lf->n; /* return them (chars already in buffer) */
463 lf->n = 0; /* no more pre-read characters */
464 }
465 else { /* read a block from file */
466 /* 'fread' can return > 0 *and* set the EOF flag. If next call to
467 'compat53_getF' called 'fread', it might still wait for user input.
468 The next check avoids this problem. */
469 if (feof(lf->f)) return NULL;
470 *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */
471 }
472 return lf->buff;
473}
474
475
476static int compat53_errfile (lua_State *L, const char *what, int fnameindex) {
477 char buf[512] = {0};
478 const char *serr = compat53_strerror(errno, buf, sizeof(buf));
479 const char *filename = lua_tostring(L, fnameindex) + 1;
480 lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
481 lua_remove(L, fnameindex);
482 return LUA_ERRFILE;
483}
484
485
486static int compat53_skipBOM (compat53_LoadF *lf) {
487 const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
488 int c;
489 lf->n = 0;
490 do {
491 c = getc(lf->f);
492 if (c == EOF || c != *(const unsigned char *)p++) return c;
493 lf->buff[lf->n++] = c; /* to be read by the parser */
494 } while (*p != '\0');
495 lf->n = 0; /* prefix matched; discard it */
496 return getc(lf->f); /* return next character */
497}
498
499
500/*
501** reads the first character of file 'f' and skips an optional BOM mark
502** in its beginning plus its first line if it starts with '#'. Returns
503** true if it skipped the first line. In any case, '*cp' has the
504** first "valid" character of the file (after the optional BOM and
505** a first-line comment).
506*/
507static int compat53_skipcomment (compat53_LoadF *lf, int *cp) {
508 int c = *cp = compat53_skipBOM(lf);
509 if (c == '#') { /* first line is a comment (Unix exec. file)? */
510 do { /* skip first line */
511 c = getc(lf->f);
512 } while (c != EOF && c != '\n');
513 *cp = getc(lf->f); /* skip end-of-line, if present */
514 return 1; /* there was a comment */
515 }
516 else return 0; /* no comment */
517}
518
519
520COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode) {
521 static const char lua_signature[] = "\x1bLua";
522 compat53_LoadF lf;
523 int status, readstatus;
524 int c;
525 int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
526 if (filename == NULL) {
527 lua_pushliteral(L, "=stdin");
528 lf.f = stdin;
529 }
530 else {
531 lua_pushfstring(L, "@%s", filename);
532#if defined(_MSC_VER)
533 /* this code is here to stop a deprecation error that
534 * stops builds if a certain macro is defined
535 * while normally not caring would be best, some
536 * header-only libraries and builds can't afford
537 * to dictate this to the user*/
538 /* a quick check shows that fopen_s this goes back to VS 2005,
539 * and _fsopen goes back to VS 2003 .NET, possibly even before that
540 * so we don't need to do any version number checks,
541 * since this has been there since forever
542 */
543
544 /* TO USER: if you want the behavior of typical fopen_s/fopen,
545 * which does lock the file on VC++, define the macro used below to 0
546 */
547#if COMPAT53_FOPEN_NO_LOCK
548 lf.f = _fsopen(filename, "r", _SH_DENYNO); /* do not lock the file in any way */
549 if (lf.f == NULL) {
550 return compat53_errfile(L, "open", fnameindex);
551 }
552#else /* use default locking version */
553 if (fopen_s(&lf.f, filename, "r") != 0) {
554 return compat53_errfile(L, "open", fnameindex);
555 }
556#endif /* Locking vs. No-locking fopen variants */
557#else
558 lf.f = fopen(filename, "r"); /* default stdlib doesn't forcefully lock files here */
559 if (lf.f == NULL) return compat53_errfile(L, "open", fnameindex);
560#endif
561 }
562 if (compat53_skipcomment(&lf, &c)) /* read initial portion */
563 lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
564 if (c == lua_signature[0]) { /* binary file? */
565 status = compat53_checkmode(L, mode, "binary", LUA_ERRFILE);
566 if (status != LUA_OK) {
567 fclose(lf.f);
568 return compat53_errfile(L, "improper mode", fnameindex);
569 }
570#if defined(_MSC_VER)
571 if (freopen_s(&lf.f, filename, "r", lf.f) != 0) return compat53_errfile(L, "open", fnameindex);
572#else
573 lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
574 if (lf.f == NULL) return compat53_errfile(L, "reopen", fnameindex);
575#endif
576 compat53_skipcomment(&lf, &c); /* re-read initial portion */
577 }
578 else { /* text file */
579 status = compat53_checkmode(L, mode, "text", LUA_ERRFILE);
580 if (status != LUA_OK) {
581 fclose(lf.f);
582 return compat53_errfile(L, "improper mode", fnameindex);
583 }
584 }
585 if (c != EOF)
586 lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
587 status = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1));
588 readstatus = ferror(lf.f);
589 if (filename) fclose(lf.f); /* close file (even in case of errors) */
590 if (readstatus) {
591 lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
592 return compat53_errfile(L, "read", fnameindex);
593 }
594 lua_remove(L, fnameindex);
595 return status;
596}
597
598
599COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode) {
600 int status = LUA_OK;
601 if (sz > 0 && buff[0] == '\x1b') {
602 status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX);
603 }
604 else {
605 status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX);
606 }
607 if (status != LUA_OK)
608 return status;
609 return luaL_loadbuffer(L, buff, sz, name);
610}
611
356#if !defined(l_inspectstat) && \ 612#if !defined(l_inspectstat) && \
357 (defined(unix) || defined(__unix) || defined(__unix__) || \ 613 (defined(unix) || defined(__unix) || defined(__unix__) || \
358 defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \ 614 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" {
50 * lua_upvaluejoin 50 * lua_upvaluejoin
51 * lua_version 51 * lua_version
52 * lua_yieldk 52 * lua_yieldk
53 * luaL_loadbufferx
54 * luaL_loadfilex
55 */ 53 */
56 54
57#ifndef LUA_OK 55#ifndef LUA_OK
@@ -154,6 +152,12 @@ COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum);
154#define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) 152#define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion)
155COMPAT53_API void luaL_checkversion (lua_State *L); 153COMPAT53_API void luaL_checkversion (lua_State *L);
156 154
155#define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex)
156COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode);
157
158#define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx)
159COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode);
160
157#define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) 161#define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53)
158COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg); 162COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg);
159 163