summaryrefslogtreecommitdiff
path: root/apps/plugins/lua/lbaselib.c
diff options
context:
space:
mode:
authorRichard Quirk <richard.quirk@gmail.com>2014-03-19 19:31:31 +0100
committerMarcin Bukat <marcin.bukat@gmail.com>2014-04-02 20:31:54 +0200
commit36378988ad4059982742f05f5eb50580b456840a (patch)
treeee70be810d894566c5e351f21a1ebb79be742a85 /apps/plugins/lua/lbaselib.c
parent020f16a1c7d5bc9a302671cef03f56ac735e20c5 (diff)
downloadrockbox-36378988ad4059982742f05f5eb50580b456840a.tar.gz
rockbox-36378988ad4059982742f05f5eb50580b456840a.zip
Update lua plugin to 5.2.3
Prior to this patch the Lua plugin used version 5.1.4. This change reduces the number of modifications in the Lua source using some new defines and because the upstream source is now more flexible. Unless otherwise stated, l*.[ch] files are taken unmodified from the upstream lua-5.2.3. fscanf.c: file descriptors in rockbox are just ints, they are hidden behind a void* now so liolib requires less modifications. fscanf is updated to use void* too. getc.c: this is a new file required for getc implementation in lauxlib.c lauxlib.c: LoadF replaced FILE* with int, the rockbox file descriptor int are cast to FILE* (actually void* due to typedef). getc uses the PREFIX version. stdin is not used, as per 5.1.4. lbaselib.c: now uses strspn in the number parsing. print uses DEBUGF now rather than being commented out. lbitlib.c: use the built-in version from 5.2.3 rather than Reuben Thomas's external library. Backwards compatible and adds some new bit operations. ldo.c: the LUAI_THROW/TRY defines are now in the core lua code, so have been removed from rockconf.h liolib.c: here the implementation has changed to use the LStream from the original source, and cast the FILE* pointers to int. This has reduced the number of modifications from the upstream version. llex.c: the only change from upstream is to remove the locale include. lmathlib.c: updated from the 5.2.3 version and re-applied the changes that were made vs 5.1.4 for random numbers and to remove unsupported float functions. loadlib.c: upstream version, with the 5.1.4 changes for missing functions. lobject.c: upstream version, with ctype.h added and sprintf changed to snprintf. loslib.c: upstream version with locale.h removed and 5.1.4 changes for unsupportable functions. lstrlib.c: sprintf changed to snprintf. ltable.c: upstream with the hashnum function from 5.1.4 to avoid frexp in luai_hashnum. luaconf.h: updated to 5.2.3 version, restored relevant parts from the original 5.1.4 configuration. The COMPAT defines that are no longer available are not included. lundump.c: VERSION macro conflicts with the core Rockbox equivalent. rocklib.c: luaL_reg is no longer available, replaced by luaL_Reg equivalent. Moved checkboolean/optboolean functions to this file and out of core lua files. luaL_getn is no longer available, replaced by luaL_rawlen. luaL_register is deprecated, use the newlib/setfuncs replacements. rli_init has to be called before setting up the newlib to avoid overwriting the rb table. rocklib_aux.pl: use rli_checkboolean from rocklib.c. rocklua.c: new default bits library used, update the library loading code with idiomatic 5.2 code. strcspn.c: no longer needed, but strspn.c is required for strspn in lbaselib.c Change-Id: I0c7945c755f79083afe98ec117e1e8cf13de2651 Reviewed-on: http://gerrit.rockbox.org/774 Tested: Richard Quirk <richard.quirk@gmail.com> Reviewed-by: Marcin Bukat <marcin.bukat@gmail.com>
Diffstat (limited to 'apps/plugins/lua/lbaselib.c')
-rw-r--r--apps/plugins/lua/lbaselib.c571
1 files changed, 186 insertions, 385 deletions
diff --git a/apps/plugins/lua/lbaselib.c b/apps/plugins/lua/lbaselib.c
index 008e3629fe..5255b3cd9b 100644
--- a/apps/plugins/lua/lbaselib.c
+++ b/apps/plugins/lua/lbaselib.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $ 2** $Id: lbaselib.c,v 1.276.1.1 2013/04/12 18:48:47 roberto Exp $
3** Basic library 3** Basic library
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -20,62 +20,68 @@
20#include "lualib.h" 20#include "lualib.h"
21 21
22 22
23
24
25/*
26** If your system does not support `stdout', you can just remove this function.
27** If you need, you can define your own `print' function, following this
28** model but changing `fputs' to put the strings at a proper place
29** (a console window or a log file, for instance).
30*/
31#if 0
32static int luaB_print (lua_State *L) { 23static int luaB_print (lua_State *L) {
33 int n = lua_gettop(L); /* number of arguments */ 24 int n = lua_gettop(L); /* number of arguments */
34 int i; 25 int i;
35 lua_getglobal(L, "tostring"); 26 lua_getglobal(L, "tostring");
36 for (i=1; i<=n; i++) { 27 for (i=1; i<=n; i++) {
37 const char *s; 28 const char *s;
29 size_t l;
38 lua_pushvalue(L, -1); /* function to be called */ 30 lua_pushvalue(L, -1); /* function to be called */
39 lua_pushvalue(L, i); /* value to print */ 31 lua_pushvalue(L, i); /* value to print */
40 lua_call(L, 1, 1); 32 lua_call(L, 1, 1);
41 s = lua_tostring(L, -1); /* get result */ 33 s = lua_tolstring(L, -1, &l); /* get result */
42 if (s == NULL) 34 if (s == NULL)
43 return luaL_error(L, LUA_QL("tostring") " must return a string to " 35 return luaL_error(L,
44 LUA_QL("print")); 36 LUA_QL("tostring") " must return a string to " LUA_QL("print"));
45 if (i>1) fputs("\t", stdout); 37 if (i>1) luai_writestring("\t", 1);
46 fputs(s, stdout); 38 luai_writestring(s, l);
47 lua_pop(L, 1); /* pop result */ 39 lua_pop(L, 1); /* pop result */
48 } 40 }
49 fputs("\n", stdout); 41 luai_writeline();
50 return 0; 42 return 0;
51} 43}
52#endif
53 44
54 45
46#define SPACECHARS " \f\n\r\t\v"
47
55static int luaB_tonumber (lua_State *L) { 48static int luaB_tonumber (lua_State *L) {
56 int base = luaL_optint(L, 2, 10); 49 if (lua_isnoneornil(L, 2)) { /* standard conversion */
57 if (base == 10) { /* standard conversion */ 50 int isnum;
58 luaL_checkany(L, 1); 51 lua_Number n = lua_tonumberx(L, 1, &isnum);
59 if (lua_isnumber(L, 1)) { 52 if (isnum) {
60 lua_pushnumber(L, lua_tonumber(L, 1)); 53 lua_pushnumber(L, n);
61 return 1; 54 return 1;
62 } 55 } /* else not a number; must be something */
56 luaL_checkany(L, 1);
63 } 57 }
64 else { 58 else {
65 const char *s1 = luaL_checkstring(L, 1); 59 size_t l;
66 char *s2; 60 const char *s = luaL_checklstring(L, 1, &l);
67 unsigned long n; 61 const char *e = s + l; /* end point for 's' */
62 int base = luaL_checkint(L, 2);
63 int neg = 0;
68 luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); 64 luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
69 n = strtoul(s1, &s2, base); 65 s += strspn(s, SPACECHARS); /* skip initial spaces */
70 if (s1 != s2) { /* at least one valid digit? */ 66 if (*s == '-') { s++; neg = 1; } /* handle signal */
71 while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ 67 else if (*s == '+') s++;
72 if (*s2 == '\0') { /* no invalid trailing characters? */ 68 if (isalnum((unsigned char)*s)) {
73 lua_pushnumber(L, (lua_Number)n); 69 lua_Number n = 0;
70 do {
71 int digit = (isdigit((unsigned char)*s)) ? *s - '0'
72 : toupper((unsigned char)*s) - 'A' + 10;
73 if (digit >= base) break; /* invalid numeral; force a fail */
74 n = n * (lua_Number)base + (lua_Number)digit;
75 s++;
76 } while (isalnum((unsigned char)*s));
77 s += strspn(s, SPACECHARS); /* skip trailing spaces */
78 if (s == e) { /* no invalid trailing characters? */
79 lua_pushnumber(L, (neg) ? -n : n);
74 return 1; 80 return 1;
75 } 81 } /* else not a number */
76 } 82 } /* else not a number */
77 } 83 }
78 lua_pushnil(L); /* else not a number */ 84 lua_pushnil(L); /* not a number */
79 return 1; 85 return 1;
80} 86}
81 87
@@ -109,57 +115,13 @@ static int luaB_setmetatable (lua_State *L) {
109 luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, 115 luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
110 "nil or table expected"); 116 "nil or table expected");
111 if (luaL_getmetafield(L, 1, "__metatable")) 117 if (luaL_getmetafield(L, 1, "__metatable"))
112 luaL_error(L, "cannot change a protected metatable"); 118 return luaL_error(L, "cannot change a protected metatable");
113 lua_settop(L, 2); 119 lua_settop(L, 2);
114 lua_setmetatable(L, 1); 120 lua_setmetatable(L, 1);
115 return 1; 121 return 1;
116} 122}
117 123
118 124
119static void getfunc (lua_State *L, int opt) {
120 if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
121 else {
122 lua_Debug ar;
123 int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1);
124 luaL_argcheck(L, level >= 0, 1, "level must be non-negative");
125 if (lua_getstack(L, level, &ar) == 0)
126 luaL_argerror(L, 1, "invalid level");
127 lua_getinfo(L, "f", &ar);
128 if (lua_isnil(L, -1))
129 luaL_error(L, "no function environment for tail call at level %d",
130 level);
131 }
132}
133
134
135static int luaB_getfenv (lua_State *L) {
136 getfunc(L, 1);
137 if (lua_iscfunction(L, -1)) /* is a C function? */
138 lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */
139 else
140 lua_getfenv(L, -1);
141 return 1;
142}
143
144
145static int luaB_setfenv (lua_State *L) {
146 luaL_checktype(L, 2, LUA_TTABLE);
147 getfunc(L, 0);
148 lua_pushvalue(L, 2);
149 if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) {
150 /* change environment of current thread */
151 lua_pushthread(L);
152 lua_insert(L, -2);
153 lua_setfenv(L, -2);
154 return 0;
155 }
156 else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0)
157 luaL_error(L,
158 LUA_QL("setfenv") " cannot change environment of given object");
159 return 1;
160}
161
162
163static int luaB_rawequal (lua_State *L) { 125static int luaB_rawequal (lua_State *L) {
164 luaL_checkany(L, 1); 126 luaL_checkany(L, 1);
165 luaL_checkany(L, 2); 127 luaL_checkany(L, 2);
@@ -168,6 +130,15 @@ static int luaB_rawequal (lua_State *L) {
168} 130}
169 131
170 132
133static int luaB_rawlen (lua_State *L) {
134 int t = lua_type(L, 1);
135 luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
136 "table or string expected");
137 lua_pushinteger(L, lua_rawlen(L, 1));
138 return 1;
139}
140
141
171static int luaB_rawget (lua_State *L) { 142static int luaB_rawget (lua_State *L) {
172 luaL_checktype(L, 1, LUA_TTABLE); 143 luaL_checktype(L, 1, LUA_TTABLE);
173 luaL_checkany(L, 2); 144 luaL_checkany(L, 2);
@@ -186,32 +157,29 @@ static int luaB_rawset (lua_State *L) {
186} 157}
187 158
188 159
189static int luaB_gcinfo (lua_State *L) {
190 lua_pushinteger(L, lua_getgccount(L));
191 return 1;
192}
193
194
195static int luaB_collectgarbage (lua_State *L) { 160static int luaB_collectgarbage (lua_State *L) {
196 static const char *const opts[] = {"stop", "restart", "collect", 161 static const char *const opts[] = {"stop", "restart", "collect",
197 "count", "step", "setpause", "setstepmul", NULL}; 162 "count", "step", "setpause", "setstepmul",
163 "setmajorinc", "isrunning", "generational", "incremental", NULL};
198 static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, 164 static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
199 LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; 165 LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
200 int o = luaL_checkoption(L, 1, "collect", opts); 166 LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
167 int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
201 int ex = luaL_optint(L, 2, 0); 168 int ex = luaL_optint(L, 2, 0);
202 int res = lua_gc(L, optsnum[o], ex); 169 int res = lua_gc(L, o, ex);
203 switch (optsnum[o]) { 170 switch (o) {
204 case LUA_GCCOUNT: { 171 case LUA_GCCOUNT: {
205 int b = lua_gc(L, LUA_GCCOUNTB, 0); 172 int b = lua_gc(L, LUA_GCCOUNTB, 0);
206 lua_pushnumber(L, res + ((lua_Number)b/1024)); 173 lua_pushnumber(L, res + ((lua_Number)b/1024));
207 return 1; 174 lua_pushinteger(L, b);
175 return 2;
208 } 176 }
209 case LUA_GCSTEP: { 177 case LUA_GCSTEP: case LUA_GCISRUNNING: {
210 lua_pushboolean(L, res); 178 lua_pushboolean(L, res);
211 return 1; 179 return 1;
212 } 180 }
213 default: { 181 default: {
214 lua_pushnumber(L, res); 182 lua_pushinteger(L, res);
215 return 1; 183 return 1;
216 } 184 }
217 } 185 }
@@ -225,6 +193,23 @@ static int luaB_type (lua_State *L) {
225} 193}
226 194
227 195
196static int pairsmeta (lua_State *L, const char *method, int iszero,
197 lua_CFunction iter) {
198 if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */
199 luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
200 lua_pushcfunction(L, iter); /* will return generator, */
201 lua_pushvalue(L, 1); /* state, */
202 if (iszero) lua_pushinteger(L, 0); /* and initial value */
203 else lua_pushnil(L);
204 }
205 else {
206 lua_pushvalue(L, 1); /* argument 'self' to metamethod */
207 lua_call(L, 1, 3); /* get 3 values from metamethod */
208 }
209 return 3;
210}
211
212
228static int luaB_next (lua_State *L) { 213static int luaB_next (lua_State *L) {
229 luaL_checktype(L, 1, LUA_TTABLE); 214 luaL_checktype(L, 1, LUA_TTABLE);
230 lua_settop(L, 2); /* create a 2nd argument if there isn't one */ 215 lua_settop(L, 2); /* create a 2nd argument if there isn't one */
@@ -238,11 +223,7 @@ static int luaB_next (lua_State *L) {
238 223
239 224
240static int luaB_pairs (lua_State *L) { 225static int luaB_pairs (lua_State *L) {
241 luaL_checktype(L, 1, LUA_TTABLE); 226 return pairsmeta(L, "__pairs", 0, luaB_next);
242 lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
243 lua_pushvalue(L, 1); /* state, */
244 lua_pushnil(L); /* and initial value */
245 return 3;
246} 227}
247 228
248 229
@@ -252,23 +233,25 @@ static int ipairsaux (lua_State *L) {
252 i++; /* next value */ 233 i++; /* next value */
253 lua_pushinteger(L, i); 234 lua_pushinteger(L, i);
254 lua_rawgeti(L, 1, i); 235 lua_rawgeti(L, 1, i);
255 return (lua_isnil(L, -1)) ? 0 : 2; 236 return (lua_isnil(L, -1)) ? 1 : 2;
256} 237}
257 238
258 239
259static int luaB_ipairs (lua_State *L) { 240static int luaB_ipairs (lua_State *L) {
260 luaL_checktype(L, 1, LUA_TTABLE); 241 return pairsmeta(L, "__ipairs", 1, ipairsaux);
261 lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
262 lua_pushvalue(L, 1); /* state, */
263 lua_pushinteger(L, 0); /* and initial value */
264 return 3;
265} 242}
266 243
267 244
268static int load_aux (lua_State *L, int status) { 245static int load_aux (lua_State *L, int status, int envidx) {
269 if (status == 0) /* OK? */ 246 if (status == LUA_OK) {
247 if (envidx != 0) { /* 'env' parameter? */
248 lua_pushvalue(L, envidx); /* environment for loaded function */
249 if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
250 lua_pop(L, 1); /* remove 'env' if not used by previous call */
251 }
270 return 1; 252 return 1;
271 else { 253 }
254 else { /* error (message is on top of the stack) */
272 lua_pushnil(L); 255 lua_pushnil(L);
273 lua_insert(L, -2); /* put before error message */ 256 lua_insert(L, -2); /* put before error message */
274 return 2; /* return nil plus error message */ 257 return 2; /* return nil plus error message */
@@ -276,87 +259,97 @@ static int load_aux (lua_State *L, int status) {
276} 259}
277 260
278 261
279static int luaB_loadstring (lua_State *L) {
280 size_t l;
281 const char *s = luaL_checklstring(L, 1, &l);
282 const char *chunkname = luaL_optstring(L, 2, s);
283 return load_aux(L, luaL_loadbuffer(L, s, l, chunkname));
284}
285
286
287static int luaB_loadfile (lua_State *L) { 262static int luaB_loadfile (lua_State *L) {
288 const char *fname = luaL_optstring(L, 1, NULL); 263 const char *fname = luaL_optstring(L, 1, NULL);
289 return load_aux(L, luaL_loadfile(L, fname)); 264 const char *mode = luaL_optstring(L, 2, NULL);
265 int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
266 int status = luaL_loadfilex(L, fname, mode);
267 return load_aux(L, status, env);
290} 268}
291 269
292 270
293/* 271/*
272** {======================================================
273** Generic Read function
274** =======================================================
275*/
276
277
278/*
279** reserved slot, above all arguments, to hold a copy of the returned
280** string to avoid it being collected while parsed. 'load' has four
281** optional arguments (chunk, source name, mode, and environment).
282*/
283#define RESERVEDSLOT 5
284
285
286/*
294** Reader for generic `load' function: `lua_load' uses the 287** Reader for generic `load' function: `lua_load' uses the
295** stack for internal stuff, so the reader cannot change the 288** stack for internal stuff, so the reader cannot change the
296** stack top. Instead, it keeps its resulting string in a 289** stack top. Instead, it keeps its resulting string in a
297** reserved slot inside the stack. 290** reserved slot inside the stack.
298*/ 291*/
299static const char *generic_reader (lua_State *L, void *ud, size_t *size) { 292static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
300 (void)ud; /* to avoid warnings */ 293 (void)(ud); /* not used */
301 luaL_checkstack(L, 2, "too many nested functions"); 294 luaL_checkstack(L, 2, "too many nested functions");
302 lua_pushvalue(L, 1); /* get function */ 295 lua_pushvalue(L, 1); /* get function */
303 lua_call(L, 0, 1); /* call it */ 296 lua_call(L, 0, 1); /* call it */
304 if (lua_isnil(L, -1)) { 297 if (lua_isnil(L, -1)) {
298 lua_pop(L, 1); /* pop result */
305 *size = 0; 299 *size = 0;
306 return NULL; 300 return NULL;
307 } 301 }
308 else if (lua_isstring(L, -1)) { 302 else if (!lua_isstring(L, -1))
309 lua_replace(L, 3); /* save string in a reserved stack slot */ 303 luaL_error(L, "reader function must return a string");
310 return lua_tolstring(L, 3, size); 304 lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
311 } 305 return lua_tolstring(L, RESERVEDSLOT, size);
312 else luaL_error(L, "reader function must return a string");
313 return NULL; /* to avoid warnings */
314} 306}
315 307
316 308
317static int luaB_load (lua_State *L) { 309static int luaB_load (lua_State *L) {
318 int status; 310 int status;
319 const char *cname = luaL_optstring(L, 2, "=(load)"); 311 size_t l;
320 luaL_checktype(L, 1, LUA_TFUNCTION); 312 const char *s = lua_tolstring(L, 1, &l);
321 lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ 313 const char *mode = luaL_optstring(L, 3, "bt");
322 status = lua_load(L, generic_reader, NULL, cname); 314 int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
323 return load_aux(L, status); 315 if (s != NULL) { /* loading a string? */
316 const char *chunkname = luaL_optstring(L, 2, s);
317 status = luaL_loadbufferx(L, s, l, chunkname, mode);
318 }
319 else { /* loading from a reader function */
320 const char *chunkname = luaL_optstring(L, 2, "=(load)");
321 luaL_checktype(L, 1, LUA_TFUNCTION);
322 lua_settop(L, RESERVEDSLOT); /* create reserved slot */
323 status = lua_load(L, generic_reader, NULL, chunkname, mode);
324 }
325 return load_aux(L, status, env);
326}
327
328/* }====================================================== */
329
330
331static int dofilecont (lua_State *L) {
332 return lua_gettop(L) - 1;
324} 333}
325 334
326 335
327static int luaB_dofile (lua_State *L) { 336static int luaB_dofile (lua_State *L) {
328 const char *fname = luaL_optstring(L, 1, NULL); 337 const char *fname = luaL_optstring(L, 1, NULL);
329 int n = lua_gettop(L); 338 lua_settop(L, 1);
330 if (luaL_loadfile(L, fname) != 0) lua_error(L); 339 if (luaL_loadfile(L, fname) != LUA_OK)
331 lua_call(L, 0, LUA_MULTRET); 340 return lua_error(L);
332 return lua_gettop(L) - n; 341 lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
342 return dofilecont(L);
333} 343}
334 344
335 345
336static int luaB_assert (lua_State *L) { 346static int luaB_assert (lua_State *L) {
337 luaL_checkany(L, 1);
338 if (!lua_toboolean(L, 1)) 347 if (!lua_toboolean(L, 1))
339 return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); 348 return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
340 return lua_gettop(L); 349 return lua_gettop(L);
341} 350}
342 351
343 352
344static int luaB_unpack (lua_State *L) {
345 int i, e, n;
346 luaL_checktype(L, 1, LUA_TTABLE);
347 i = luaL_optint(L, 2, 1);
348 e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1));
349 if (i > e) return 0; /* empty range */
350 n = e - i + 1; /* number of elements */
351 if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */
352 return luaL_error(L, "too many results to unpack");
353 lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */
354 while (i++ < e) /* push arg[i + 1...e] */
355 lua_rawgeti(L, 1, i);
356 return n;
357}
358
359
360static int luaB_select (lua_State *L) { 353static int luaB_select (lua_State *L) {
361 int n = lua_gettop(L); 354 int n = lua_gettop(L);
362 if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { 355 if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
@@ -373,75 +366,50 @@ static int luaB_select (lua_State *L) {
373} 366}
374 367
375 368
369static int finishpcall (lua_State *L, int status) {
370 if (!lua_checkstack(L, 1)) { /* no space for extra boolean? */
371 lua_settop(L, 0); /* create space for return values */
372 lua_pushboolean(L, 0);
373 lua_pushstring(L, "stack overflow");
374 return 2; /* return false, msg */
375 }
376 lua_pushboolean(L, status); /* first result (status) */
377 lua_replace(L, 1); /* put first result in first slot */
378 return lua_gettop(L);
379}
380
381
382static int pcallcont (lua_State *L) {
383 int status = lua_getctx(L, NULL);
384 return finishpcall(L, (status == LUA_YIELD));
385}
386
387
376static int luaB_pcall (lua_State *L) { 388static int luaB_pcall (lua_State *L) {
377 int status; 389 int status;
378 luaL_checkany(L, 1); 390 luaL_checkany(L, 1);
379 status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); 391 lua_pushnil(L);
380 lua_pushboolean(L, (status == 0)); 392 lua_insert(L, 1); /* create space for status result */
381 lua_insert(L, 1); 393 status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont);
382 return lua_gettop(L); /* return status + all results */ 394 return finishpcall(L, (status == LUA_OK));
383} 395}
384 396
385 397
386static int luaB_xpcall (lua_State *L) { 398static int luaB_xpcall (lua_State *L) {
387 int status; 399 int status;
388 luaL_checkany(L, 2); 400 int n = lua_gettop(L);
389 lua_settop(L, 2); 401 luaL_argcheck(L, n >= 2, 2, "value expected");
390 lua_insert(L, 1); /* put error function under function to be called */ 402 lua_pushvalue(L, 1); /* exchange function... */
391 status = lua_pcall(L, 0, LUA_MULTRET, 1); 403 lua_copy(L, 2, 1); /* ...and error handler */
392 lua_pushboolean(L, (status == 0)); 404 lua_replace(L, 2);
393 lua_replace(L, 1); 405 status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont);
394 return lua_gettop(L); /* return status + all results */ 406 return finishpcall(L, (status == LUA_OK));
395} 407}
396 408
397 409
398static int luaB_tostring (lua_State *L) { 410static int luaB_tostring (lua_State *L) {
399 luaL_checkany(L, 1); 411 luaL_checkany(L, 1);
400 if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ 412 luaL_tolstring(L, 1, NULL);
401 return 1; /* use its value */
402 switch (lua_type(L, 1)) {
403 case LUA_TNUMBER:
404 lua_pushstring(L, lua_tostring(L, 1));
405 break;
406 case LUA_TSTRING:
407 lua_pushvalue(L, 1);
408 break;
409 case LUA_TBOOLEAN:
410 lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false"));
411 break;
412 case LUA_TNIL:
413 lua_pushliteral(L, "nil");
414 break;
415 default:
416 lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1));
417 break;
418 }
419 return 1;
420}
421
422
423static int luaB_newproxy (lua_State *L) {
424 lua_settop(L, 1);
425 lua_newuserdata(L, 0); /* create proxy */
426 if (lua_toboolean(L, 1) == 0)
427 return 1; /* no metatable */
428 else if (lua_isboolean(L, 1)) {
429 lua_newtable(L); /* create a new metatable `m' ... */
430 lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */
431 lua_pushboolean(L, 1);
432 lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */
433 }
434 else {
435 int validproxy = 0; /* to check if weaktable[metatable(u)] == true */
436 if (lua_getmetatable(L, 1)) {
437 lua_rawget(L, lua_upvalueindex(1));
438 validproxy = lua_toboolean(L, -1);
439 lua_pop(L, 1); /* remove value */
440 }
441 luaL_argcheck(L, validproxy, 1, "boolean or proxy expected");
442 lua_getmetatable(L, 1); /* metatable is valid; get it */
443 }
444 lua_setmetatable(L, 2);
445 return 1; 413 return 1;
446} 414}
447 415
@@ -451,207 +419,40 @@ static const luaL_Reg base_funcs[] = {
451 {"collectgarbage", luaB_collectgarbage}, 419 {"collectgarbage", luaB_collectgarbage},
452 {"dofile", luaB_dofile}, 420 {"dofile", luaB_dofile},
453 {"error", luaB_error}, 421 {"error", luaB_error},
454 {"gcinfo", luaB_gcinfo},
455 {"getfenv", luaB_getfenv},
456 {"getmetatable", luaB_getmetatable}, 422 {"getmetatable", luaB_getmetatable},
423 {"ipairs", luaB_ipairs},
457 {"loadfile", luaB_loadfile}, 424 {"loadfile", luaB_loadfile},
458 {"load", luaB_load}, 425 {"load", luaB_load},
459 {"loadstring", luaB_loadstring}, 426#if defined(LUA_COMPAT_LOADSTRING)
427 {"loadstring", luaB_load},
428#endif
460 {"next", luaB_next}, 429 {"next", luaB_next},
430 {"pairs", luaB_pairs},
461 {"pcall", luaB_pcall}, 431 {"pcall", luaB_pcall},
462#if 0
463 {"print", luaB_print}, 432 {"print", luaB_print},
464#endif
465 {"rawequal", luaB_rawequal}, 433 {"rawequal", luaB_rawequal},
434 {"rawlen", luaB_rawlen},
466 {"rawget", luaB_rawget}, 435 {"rawget", luaB_rawget},
467 {"rawset", luaB_rawset}, 436 {"rawset", luaB_rawset},
468 {"select", luaB_select}, 437 {"select", luaB_select},
469 {"setfenv", luaB_setfenv},
470 {"setmetatable", luaB_setmetatable}, 438 {"setmetatable", luaB_setmetatable},
471 {"tonumber", luaB_tonumber}, 439 {"tonumber", luaB_tonumber},
472 {"tostring", luaB_tostring}, 440 {"tostring", luaB_tostring},
473 {"type", luaB_type}, 441 {"type", luaB_type},
474 {"unpack", luaB_unpack},
475 {"xpcall", luaB_xpcall}, 442 {"xpcall", luaB_xpcall},
476 {NULL, NULL} 443 {NULL, NULL}
477}; 444};
478 445
479 446
480/* 447LUAMOD_API int luaopen_base (lua_State *L) {
481** {======================================================
482** Coroutine library
483** =======================================================
484*/
485
486#define CO_RUN 0 /* running */
487#define CO_SUS 1 /* suspended */
488#define CO_NOR 2 /* 'normal' (it resumed another coroutine) */
489#define CO_DEAD 3
490
491static const char *const statnames[] =
492 {"running", "suspended", "normal", "dead"};
493
494static int costatus (lua_State *L, lua_State *co) {
495 if (L == co) return CO_RUN;
496 switch (lua_status(co)) {
497 case LUA_YIELD:
498 return CO_SUS;
499 case 0: {
500 lua_Debug ar;
501 if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
502 return CO_NOR; /* it is running */
503 else if (lua_gettop(co) == 0)
504 return CO_DEAD;
505 else
506 return CO_SUS; /* initial state */
507 }
508 default: /* some error occured */
509 return CO_DEAD;
510 }
511}
512
513
514static int luaB_costatus (lua_State *L) {
515 lua_State *co = lua_tothread(L, 1);
516 luaL_argcheck(L, co, 1, "coroutine expected");
517 lua_pushstring(L, statnames[costatus(L, co)]);
518 return 1;
519}
520
521
522static int auxresume (lua_State *L, lua_State *co, int narg) {
523 int status = costatus(L, co);
524 if (!lua_checkstack(co, narg))
525 luaL_error(L, "too many arguments to resume");
526 if (status != CO_SUS) {
527 lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]);
528 return -1; /* error flag */
529 }
530 lua_xmove(L, co, narg);
531 lua_setlevel(L, co);
532 status = lua_resume(co, narg);
533 if (status == 0 || status == LUA_YIELD) {
534 int nres = lua_gettop(co);
535 if (!lua_checkstack(L, nres + 1))
536 luaL_error(L, "too many results to resume");
537 lua_xmove(co, L, nres); /* move yielded values */
538 return nres;
539 }
540 else {
541 lua_xmove(co, L, 1); /* move error message */
542 return -1; /* error flag */
543 }
544}
545
546
547static int luaB_coresume (lua_State *L) {
548 lua_State *co = lua_tothread(L, 1);
549 int r;
550 luaL_argcheck(L, co, 1, "coroutine expected");
551 r = auxresume(L, co, lua_gettop(L) - 1);
552 if (r < 0) {
553 lua_pushboolean(L, 0);
554 lua_insert(L, -2);
555 return 2; /* return false + error message */
556 }
557 else {
558 lua_pushboolean(L, 1);
559 lua_insert(L, -(r + 1));
560 return r + 1; /* return true + `resume' returns */
561 }
562}
563
564
565static int luaB_auxwrap (lua_State *L) {
566 lua_State *co = lua_tothread(L, lua_upvalueindex(1));
567 int r = auxresume(L, co, lua_gettop(L));
568 if (r < 0) {
569 if (lua_isstring(L, -1)) { /* error object is a string? */
570 luaL_where(L, 1); /* add extra info */
571 lua_insert(L, -2);
572 lua_concat(L, 2);
573 }
574 lua_error(L); /* propagate error */
575 }
576 return r;
577}
578
579
580static int luaB_cocreate (lua_State *L) {
581 lua_State *NL = lua_newthread(L);
582 luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
583 "Lua function expected");
584 lua_pushvalue(L, 1); /* move function to top */
585 lua_xmove(L, NL, 1); /* move function from L to NL */
586 return 1;
587}
588
589
590static int luaB_cowrap (lua_State *L) {
591 luaB_cocreate(L);
592 lua_pushcclosure(L, luaB_auxwrap, 1);
593 return 1;
594}
595
596
597static int luaB_yield (lua_State *L) {
598 return lua_yield(L, lua_gettop(L));
599}
600
601
602static int luaB_corunning (lua_State *L) {
603 if (lua_pushthread(L))
604 lua_pushnil(L); /* main thread is not a coroutine */
605 return 1;
606}
607
608
609static const luaL_Reg co_funcs[] = {
610 {"create", luaB_cocreate},
611 {"resume", luaB_coresume},
612 {"running", luaB_corunning},
613 {"status", luaB_costatus},
614 {"wrap", luaB_cowrap},
615 {"yield", luaB_yield},
616 {NULL, NULL}
617};
618
619/* }====================================================== */
620
621
622static void auxopen (lua_State *L, const char *name,
623 lua_CFunction f, lua_CFunction u) {
624 lua_pushcfunction(L, u);
625 lua_pushcclosure(L, f, 1);
626 lua_setfield(L, -2, name);
627}
628
629
630static void base_open (lua_State *L) {
631 /* set global _G */ 448 /* set global _G */
632 lua_pushvalue(L, LUA_GLOBALSINDEX); 449 lua_pushglobaltable(L);
633 lua_setglobal(L, "_G"); 450 lua_pushglobaltable(L);
451 lua_setfield(L, -2, "_G");
634 /* open lib into global table */ 452 /* open lib into global table */
635 luaL_register(L, "_G", base_funcs); 453 luaL_setfuncs(L, base_funcs, 0);
636 lua_pushliteral(L, LUA_VERSION); 454 lua_pushliteral(L, LUA_VERSION);
637 lua_setglobal(L, "_VERSION"); /* set global _VERSION */ 455 lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */
638 /* `ipairs' and `pairs' need auxliliary functions as upvalues */ 456 return 1;
639 auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
640 auxopen(L, "pairs", luaB_pairs, luaB_next);
641 /* `newproxy' needs a weaktable as upvalue */
642 lua_createtable(L, 0, 1); /* new table `w' */
643 lua_pushvalue(L, -1); /* `w' will be its own metatable */
644 lua_setmetatable(L, -2);
645 lua_pushliteral(L, "kv");
646 lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */
647 lua_pushcclosure(L, luaB_newproxy, 1);
648 lua_setglobal(L, "newproxy"); /* set global `newproxy' */
649}
650
651
652LUALIB_API int luaopen_base (lua_State *L) {
653 base_open(L);
654 luaL_register(L, LUA_COLIBNAME, co_funcs);
655 return 2;
656} 457}
657 458