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