diff options
| author | Philipp Janda <siffiejoe@gmx.net> | 2017-09-16 13:14:29 +0200 |
|---|---|---|
| committer | Philipp Janda <siffiejoe@gmx.net> | 2017-09-16 13:14:29 +0200 |
| commit | 8425f997b48b2e2bdef2b2a614472769d92da73f (patch) | |
| tree | 1d705ebe5109f8b7efb31dc106bdf30be08f4afe /c-api | |
| parent | 9435c6c2e1f1373a5a9ffdb85a1a63ee0b7e6057 (diff) | |
| parent | 73a7b6b352cce72edd74f62abb3d1280e62bfc1f (diff) | |
| download | lua-compat-5.3-8425f997b48b2e2bdef2b2a614472769d92da73f.tar.gz lua-compat-5.3-8425f997b48b2e2bdef2b2a614472769d92da73f.tar.bz2 lua-compat-5.3-8425f997b48b2e2bdef2b2a614472769d92da73f.zip | |
Merge branch 'feature/luaL_loadfilebufferx' of https://github.com/ThePhD/lua-compat-5.3 into ThePhD-feature/luaL_loadfilebufferx
Diffstat (limited to 'c-api')
| -rw-r--r-- | c-api/compat-5.3.c | 260 | ||||
| -rw-r--r-- | c-api/compat-5.3.h | 8 |
2 files changed, 264 insertions, 4 deletions
diff --git a/c-api/compat-5.3.c b/c-api/compat-5.3.c index 811f248..bd9e277 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 | |||
| 71 | static 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 | ||
| 18 | COMPAT53_API int lua_absindex (lua_State *L, int i) { | 101 | COMPAT53_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 | ||
| 338 | COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { | 421 | COMPAT53_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 | ||
| 442 | static 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 | |||
| 451 | typedef 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 | |||
| 458 | static 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 | |||
| 476 | static 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 | |||
| 486 | static 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 | */ | ||
| 507 | static 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 | |||
| 520 | COMPAT53_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 | |||
| 599 | COMPAT53_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 d8e6827..c62d6bf 100644 --- a/c-api/compat-5.3.h +++ b/c-api/compat-5.3.h | |||
| @@ -51,8 +51,6 @@ extern "C" { | |||
| 51 | * lua_upvaluejoin | 51 | * lua_upvaluejoin |
| 52 | * lua_version | 52 | * lua_version |
| 53 | * lua_yieldk | 53 | * lua_yieldk |
| 54 | * luaL_loadbufferx | ||
| 55 | * luaL_loadfilex | ||
| 56 | */ | 54 | */ |
| 57 | 55 | ||
| 58 | #ifndef LUA_OK | 56 | #ifndef LUA_OK |
| @@ -176,6 +174,12 @@ COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum); | |||
| 176 | #define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) | 174 | #define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) |
| 177 | COMPAT53_API void luaL_checkversion (lua_State *L); | 175 | COMPAT53_API void luaL_checkversion (lua_State *L); |
| 178 | 176 | ||
| 177 | #define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex) | ||
| 178 | COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode); | ||
| 179 | |||
| 180 | #define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx) | ||
| 181 | COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); | ||
| 182 | |||
| 179 | #define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) | 183 | #define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) |
| 180 | COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg); | 184 | COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg); |
| 181 | 185 | ||
