aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Janda <siffiejoe@gmx.net>2017-09-16 17:27:20 +0200
committerPhilipp Janda <siffiejoe@gmx.net>2017-09-16 17:27:20 +0200
commitc381aa35a9ca135aba4f512728c11e7fe14b12d0 (patch)
treee56be07e08699f920482212f07342acf8f9526ae
parent9435c6c2e1f1373a5a9ffdb85a1a63ee0b7e6057 (diff)
parent09b201c87c904066e1de5d44cf1e02538970c168 (diff)
downloadlua-compat-5.3-c381aa35a9ca135aba4f512728c11e7fe14b12d0.tar.gz
lua-compat-5.3-c381aa35a9ca135aba4f512728c11e7fe14b12d0.tar.bz2
lua-compat-5.3-c381aa35a9ca135aba4f512728c11e7fe14b12d0.zip
Merge branch 'ThePhD-feature/luaL_loadfilebufferx'
-rw-r--r--README.md7
-rw-r--r--c-api/compat-5.3.c289
-rw-r--r--c-api/compat-5.3.h11
-rwxr-xr-xtests/test.lua157
-rw-r--r--tests/testmod.c29
5 files changed, 421 insertions, 72 deletions
diff --git a/README.md b/README.md
index c1782a7..caaca22 100644
--- a/README.md
+++ b/README.md
@@ -151,6 +151,7 @@ For Lua 5.1 additionally:
151* `lua_arith` (see [here][20]) 151* `lua_arith` (see [here][20])
152* `lua_compare` 152* `lua_compare`
153* `lua_len`, `lua_rawlen`, and `luaL_len` 153* `lua_len`, `lua_rawlen`, and `luaL_len`
154* `lua_load` (mode argument)
154* `lua_pushstring`, `lua_pushlstring` (return value) 155* `lua_pushstring`, `lua_pushlstring` (return value)
155* `lua_copy` 156* `lua_copy`
156* `lua_pushglobaltable` 157* `lua_pushglobaltable`
@@ -161,6 +162,8 @@ For Lua 5.1 additionally:
161* `luaL_traceback` 162* `luaL_traceback`
162* `luaL_execresult` 163* `luaL_execresult`
163* `luaL_fileresult` 164* `luaL_fileresult`
165* `luaL_loadbufferx`
166* `luaL_loadfilex`
164* `luaL_checkversion` (with empty body, only to avoid compile errors, 167* `luaL_checkversion` (with empty body, only to avoid compile errors,
165 see [here][21]) 168 see [here][21])
166* `luaL_tolstring` 169* `luaL_tolstring`
@@ -188,8 +191,6 @@ For Lua 5.1 additionally:
188 * `lua_upvaluejoin` (5.1) 191 * `lua_upvaluejoin` (5.1)
189 * `lua_version` (5.1) 192 * `lua_version` (5.1)
190 * `lua_yieldk` (5.1) 193 * `lua_yieldk` (5.1)
191 * `luaL_loadbufferx` (5.1)
192 * `luaL_loadfilex` (5.1)
193 194
194## See also 195## See also
195 196
@@ -206,6 +207,8 @@ This package contains code written by:
206* Tomás Guisasola Gorham ([@tomasguisasola](http://github.com/tomasguisasola)) 207* Tomás Guisasola Gorham ([@tomasguisasola](http://github.com/tomasguisasola))
207* Hisham Muhammad ([@hishamhm](http://github.com/hishamhm)) 208* Hisham Muhammad ([@hishamhm](http://github.com/hishamhm))
208* Renato Maia ([@renatomaia](http://github.com/renatomaia)) 209* Renato Maia ([@renatomaia](http://github.com/renatomaia))
210* [@ThePhD](http://github.com/ThePhD)
211* [@Daurnimator](http://github.com/Daurnimator)
209 212
210 213
211 [1]: http://www.inf.puc-rio.br/~roberto/struct/ 214 [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 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) || \
diff --git a/c-api/compat-5.3.h b/c-api/compat-5.3.h
index d8e6827..755c23e 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,15 @@ 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)
177COMPAT53_API void luaL_checkversion (lua_State *L); 175COMPAT53_API void luaL_checkversion (lua_State *L);
178 176
177#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53)
178COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char* source, const char* mode);
179
180#define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex)
181COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode);
182
183#define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx)
184COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode);
185
179#define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) 186#define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53)
180COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg); 187COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg);
181 188
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 @@ ___''
657print("testing C API ...") 657print("testing C API ...")
658local mod = require("testmod") 658local mod = require("testmod")
659___'' 659___''
660print(mod.isinteger(1)) 660print("isinteger", mod.isinteger(1))
661print(mod.isinteger(0)) 661print("isinteger", mod.isinteger(0))
662print(mod.isinteger(1234567)) 662print("isinteger", mod.isinteger(1234567))
663print(mod.isinteger(12.3)) 663print("isinteger", mod.isinteger(12.3))
664print(mod.isinteger(math.huge)) 664print("isinteger", mod.isinteger(math.huge))
665print(mod.isinteger(math.sqrt(-1))) 665print("isinteger", mod.isinteger(math.sqrt(-1)))
666 666
667 667
668___'' 668___''
669print(mod.rotate(1, 1, 2, 3, 4, 5, 6)) 669print("rotate", mod.rotate(1, 1, 2, 3, 4, 5, 6))
670print(mod.rotate(-1, 1, 2, 3, 4, 5, 6)) 670print("rotate", mod.rotate(-1, 1, 2, 3, 4, 5, 6))
671print(mod.rotate(4, 1, 2, 3, 4, 5, 6)) 671print("rotate", mod.rotate(4, 1, 2, 3, 4, 5, 6))
672print(mod.rotate(-4, 1, 2, 3, 4, 5, 6)) 672print("rotate", mod.rotate(-4, 1, 2, 3, 4, 5, 6))
673 673
674 674
675___'' 675___''
676print(mod.strtonum("+123")) 676print("strtonum", mod.strtonum("+123"))
677print(mod.strtonum(" 123 ")) 677print("strtonum", mod.strtonum(" 123 "))
678print(mod.strtonum("-1.23")) 678print("strtonum", mod.strtonum("-1.23"))
679print(mod.strtonum(" 123 abc")) 679print("strtonum", mod.strtonum(" 123 abc"))
680print(mod.strtonum("jkl")) 680print("strtonum", mod.strtonum("jkl"))
681 681
682 682
683___'' 683___''
684local a, b, c = mod.requiref() 684local a, b, c = mod.requiref()
685print( type(a), type(b), type(c), 685print("requiref", type(a), type(b), type(c),
686 a.boolean, b.boolean, c.boolean, 686 a.boolean, b.boolean, c.boolean,
687 type(requiref1), type(requiref2), type(requiref3)) 687 type(requiref1), type(requiref2), type(requiref3))
688 688
689___'' 689___''
690local proxy, backend = {}, {} 690local proxy, backend = {}, {}
691setmetatable(proxy, { __index = backend, __newindex = backend }) 691setmetatable(proxy, { __index = backend, __newindex = backend })
692print(rawget(proxy, 1), rawget(backend, 1)) 692print("geti/seti", rawget(proxy, 1), rawget(backend, 1))
693print(mod.getseti(proxy, 1)) 693print("geti/seti", mod.getseti(proxy, 1))
694print(rawget(proxy, 1), rawget(backend, 1)) 694print("geti/seti", rawget(proxy, 1), rawget(backend, 1))
695print(mod.getseti(proxy, 1)) 695print("geti/seti", mod.getseti(proxy, 1))
696print(rawget(proxy, 1), rawget(backend, 1)) 696print("geti/seti", rawget(proxy, 1), rawget(backend, 1))
697 697
698-- tests for Lua 5.1 698-- tests for Lua 5.1
699___'' 699___''
700print(mod.tonumber(12)) 700print("tonumber", mod.tonumber(12))
701print(mod.tonumber("12")) 701print("tonumber", mod.tonumber("12"))
702print(mod.tonumber("0")) 702print("tonumber", mod.tonumber("0"))
703print(mod.tonumber(false)) 703print("tonumber", mod.tonumber(false))
704print(mod.tonumber("error")) 704print("tonumber", mod.tonumber("error"))
705 705
706___'' 706___''
707print(mod.tointeger(12)) 707print("tointeger", mod.tointeger(12))
708print(mod.tointeger("12")) 708print("tointeger", mod.tointeger("12"))
709print(mod.tointeger("0")) 709print("tointeger", mod.tointeger("0"))
710print( "aaa" ) 710print("tointeger", mod.tointeger(math.pi))
711print(mod.tointeger(math.pi)) 711print("tointeger", mod.tointeger(false))
712print( "bbb" ) 712print("tointeger", mod.tointeger("error"))
713print(mod.tointeger(false))
714print(mod.tointeger("error"))
715 713
716___'' 714___''
717print(mod.len("123")) 715print("len", mod.len("123"))
718print(mod.len({ 1, 2, 3})) 716print("len", mod.len({ 1, 2, 3}))
719print(pcall(mod.len, true)) 717print("len", pcall(mod.len, true))
720local ud, meta = mod.newproxy() 718local ud, meta = mod.newproxy()
721meta.__len = function() return 5 end 719meta.__len = function() return 5 end
722print(mod.len(ud)) 720print("len", mod.len(ud))
723meta.__len = function() return true end 721meta.__len = function() return true end
724print(pcall(mod.len, ud)) 722print("len", pcall(mod.len, ud))
725 723
726___'' 724___''
727print(mod.copy(true, "string", {}, 1)) 725print("copy", mod.copy(true, "string", {}, 1))
728 726
729___'' 727___''
730print(mod.rawxetp()) 728print("rawgetp/rawsetp", mod.rawxetp())
731print(mod.rawxetp("I'm back")) 729print("rawgetp/rawsetp", mod.rawxetp("I'm back"))
732 730
733___'' 731___''
734print(F(mod.globals()), mod.globals() == _G) 732print("globals", F(mod.globals()), mod.globals() == _G)
735 733
736___'' 734___''
737local t = {} 735local t = {}
738print(F(mod.subtable(t))) 736print("getsubtable", F(mod.subtable(t)))
739local x, msg = mod.subtable(t) 737local x, msg = mod.subtable(t)
740print(F(x, msg, x == t.xxx)) 738print("getsubtable", F(x, msg, x == t.xxx))
741 739
742___'' 740___''
743print(F(mod.udata())) 741print("udata", F(mod.udata()))
744print(mod.udata("nosuchtype")) 742print("udata", mod.udata("nosuchtype"))
745 743
746___'' 744___''
747print(F(mod.uservalue())) 745print("uservalue", F(mod.uservalue()))
748 746
749___'' 747___''
750print(mod.getupvalues()) 748print("upvalues", mod.getupvalues())
751 749
752___'' 750___''
753print(mod.absindex("hi", true)) 751print("absindex", mod.absindex("hi", true))
754 752
755___'' 753___''
756print(mod.arith(2, 1)) 754print("arith", mod.arith(2, 1))
757print(mod.arith(3, 5)) 755print("arith", mod.arith(3, 5))
758 756
759___'' 757___''
760print(mod.compare(1, 1)) 758print("compare", mod.compare(1, 1))
761print(mod.compare(2, 1)) 759print("compare", mod.compare(2, 1))
762print(mod.compare(1, 2)) 760print("compare", mod.compare(1, 2))
763 761
764___'' 762___''
765print(mod.tolstring("string")) 763print("tolstring", mod.tolstring("string"))
766local t = setmetatable({}, { 764local t = setmetatable({}, {
767 __tostring = function(v) return "mytable" end 765 __tostring = function(v) return "mytable" end
768}) 766})
769print(mod.tolstring(t)) 767print("tolstring", mod.tolstring(t))
770local t = setmetatable({}, { 768local t = setmetatable({}, {
771 __tostring = function(v) return nil end 769 __tostring = function(v) return nil end
772}) 770})
773print(pcall(mod.tolstring, t)) 771print("tolstring", pcall(mod.tolstring, t))
774local ud, meta = mod.newproxy() 772local ud, meta = mod.newproxy()
775meta.__name = "XXX" 773meta.__name = "XXX"
776print(mod.tolstring(ud):gsub(":.*$", ": yyy")) 774print("tolstring", mod.tolstring(ud):gsub(":.*$", ": yyy"))
777 775
778___'' 776___''
779print(mod.pushstring()) 777print("pushstring", mod.pushstring())
780 778
781___'' 779___''
782print(mod.buffer()) 780print("Buffer", mod.buffer())
783 781
784___'' 782___''
785print(mod.exec("exit 0")) 783print("execresult", mod.exec("exit 0"))
786print(mod.exec("exit 1")) 784print("execresult", mod.exec("exit 1"))
787print(mod.exec("exit 25")) 785print("execresult", mod.exec("exit 25"))
786
787___''
788do
789 local bin = string.dump(function() end)
790 local modes = { "t", "b", "bt" }
791 local codes = {
792 "", "return true", bin, "invalidsource", "\27invalidbinary"
793 }
794 for _,m in ipairs(modes) do
795 for i,c in ipairs(codes) do
796 print("loadbufferx", m, i, F(mod.loadstring(c, m)))
797 end
798 end
799
800 ___''
801 local bom = "\239\187\191"
802 local shebang = "#!/usr/bin/env lua\n"
803 codes[#codes+1] = bom .. shebang .. "return true"
804 codes[#codes+1] = bom .. shebang .. bin
805 codes[#codes+1] = bom .. shebang .. "invalidsource"
806 codes[#codes+1] = bom .. shebang .. "\027invalidbinary"
807 for _,m in ipairs(modes) do
808 for i,c in ipairs(codes) do
809 print("loadfilex", m, i, F(mod.loadfile(c, m)))
810 end
811 end
812end
788___'' 813___''
789 814
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) {
274 return luaL_execresult(L, system(cmd)); 274 return luaL_execresult(L, system(cmd));
275} 275}
276 276
277static int test_loadstring (lua_State *L) {
278 size_t len = 0;
279 char const* s = luaL_checklstring(L, 1, &len);
280 char const* mode = luaL_optstring(L, 2, "bt");
281 lua_pushinteger(L, luaL_loadbufferx(L, s, len, s, mode));
282 return 2;
283}
284
285static int test_loadfile (lua_State *L) {
286 char filename[L_tmpnam+1] = { 0 };
287 size_t len = 0;
288 char const* s = luaL_checklstring(L, 1, &len);
289 char const* mode = luaL_optstring(L, 2, "bt");
290 if (tmpnam(filename)) {
291 FILE* f = fopen(filename, "wb");
292 if (f) {
293 fwrite(s, 1, len, f);
294 fclose(f);
295 lua_pushinteger(L, luaL_loadfilex(L, filename, mode));
296 remove(filename);
297 return 2;
298 } else
299 remove(filename);
300 }
301 return 0;
302}
303
277 304
278static const luaL_Reg funcs[] = { 305static const luaL_Reg funcs[] = {
279 { "isinteger", test_isinteger }, 306 { "isinteger", test_isinteger },
@@ -297,6 +324,8 @@ static const luaL_Reg funcs[] = {
297 { "pushstring", test_pushstring }, 324 { "pushstring", test_pushstring },
298 { "buffer", test_buffer }, 325 { "buffer", test_buffer },
299 { "exec", test_exec }, 326 { "exec", test_exec },
327 { "loadstring", test_loadstring },
328 { "loadfile", test_loadfile },
300 { NULL, NULL } 329 { NULL, NULL }
301}; 330};
302 331