diff options
Diffstat (limited to 'c-api/compat-5.3.c')
-rw-r--r-- | c-api/compat-5.3.c | 289 |
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 | |||
76 | static 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 | ||
18 | COMPAT53_API int lua_absindex (lua_State *L, int i) { | 107 | COMPAT53_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 | ||
338 | COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { | 427 | COMPAT53_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 | ||
448 | static 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 | |||
457 | typedef 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 | |||
466 | static 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 | |||
477 | COMPAT53_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 | |||
495 | typedef 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 | |||
502 | static 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 | |||
520 | static 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 | |||
530 | static 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 | */ | ||
551 | static 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 | |||
564 | COMPAT53_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 | |||
627 | COMPAT53_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) || \ |