summaryrefslogtreecommitdiff
path: root/apps/plugins/lua/lbaselib.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/lua/lbaselib.c')
-rw-r--r--apps/plugins/lua/lbaselib.c571
1 files changed, 385 insertions, 186 deletions
diff --git a/apps/plugins/lua/lbaselib.c b/apps/plugins/lua/lbaselib.c
index 5255b3cd9b..008e3629fe 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.276.1.1 2013/04/12 18:48:47 roberto Exp $ 2** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 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,68 +20,62 @@
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
23static int luaB_print (lua_State *L) { 32static int luaB_print (lua_State *L) {
24 int n = lua_gettop(L); /* number of arguments */ 33 int n = lua_gettop(L); /* number of arguments */
25 int i; 34 int i;
26 lua_getglobal(L, "tostring"); 35 lua_getglobal(L, "tostring");
27 for (i=1; i<=n; i++) { 36 for (i=1; i<=n; i++) {
28 const char *s; 37 const char *s;
29 size_t l;
30 lua_pushvalue(L, -1); /* function to be called */ 38 lua_pushvalue(L, -1); /* function to be called */
31 lua_pushvalue(L, i); /* value to print */ 39 lua_pushvalue(L, i); /* value to print */
32 lua_call(L, 1, 1); 40 lua_call(L, 1, 1);
33 s = lua_tolstring(L, -1, &l); /* get result */ 41 s = lua_tostring(L, -1); /* get result */
34 if (s == NULL) 42 if (s == NULL)
35 return luaL_error(L, 43 return luaL_error(L, LUA_QL("tostring") " must return a string to "
36 LUA_QL("tostring") " must return a string to " LUA_QL("print")); 44 LUA_QL("print"));
37 if (i>1) luai_writestring("\t", 1); 45 if (i>1) fputs("\t", stdout);
38 luai_writestring(s, l); 46 fputs(s, stdout);
39 lua_pop(L, 1); /* pop result */ 47 lua_pop(L, 1); /* pop result */
40 } 48 }
41 luai_writeline(); 49 fputs("\n", stdout);
42 return 0; 50 return 0;
43} 51}
52#endif
44 53
45 54
46#define SPACECHARS " \f\n\r\t\v"
47
48static int luaB_tonumber (lua_State *L) { 55static int luaB_tonumber (lua_State *L) {
49 if (lua_isnoneornil(L, 2)) { /* standard conversion */ 56 int base = luaL_optint(L, 2, 10);
50 int isnum; 57 if (base == 10) { /* standard conversion */
51 lua_Number n = lua_tonumberx(L, 1, &isnum);
52 if (isnum) {
53 lua_pushnumber(L, n);
54 return 1;
55 } /* else not a number; must be something */
56 luaL_checkany(L, 1); 58 luaL_checkany(L, 1);
59 if (lua_isnumber(L, 1)) {
60 lua_pushnumber(L, lua_tonumber(L, 1));
61 return 1;
62 }
57 } 63 }
58 else { 64 else {
59 size_t l; 65 const char *s1 = luaL_checkstring(L, 1);
60 const char *s = luaL_checklstring(L, 1, &l); 66 char *s2;
61 const char *e = s + l; /* end point for 's' */ 67 unsigned long n;
62 int base = luaL_checkint(L, 2);
63 int neg = 0;
64 luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); 68 luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
65 s += strspn(s, SPACECHARS); /* skip initial spaces */ 69 n = strtoul(s1, &s2, base);
66 if (*s == '-') { s++; neg = 1; } /* handle signal */ 70 if (s1 != s2) { /* at least one valid digit? */
67 else if (*s == '+') s++; 71 while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */
68 if (isalnum((unsigned char)*s)) { 72 if (*s2 == '\0') { /* no invalid trailing characters? */
69 lua_Number n = 0; 73 lua_pushnumber(L, (lua_Number)n);
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);
80 return 1; 74 return 1;
81 } /* else not a number */ 75 }
82 } /* else not a number */ 76 }
83 } 77 }
84 lua_pushnil(L); /* not a number */ 78 lua_pushnil(L); /* else not a number */
85 return 1; 79 return 1;
86} 80}
87 81
@@ -115,26 +109,61 @@ static int luaB_setmetatable (lua_State *L) {
115 luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, 109 luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
116 "nil or table expected"); 110 "nil or table expected");
117 if (luaL_getmetafield(L, 1, "__metatable")) 111 if (luaL_getmetafield(L, 1, "__metatable"))
118 return luaL_error(L, "cannot change a protected metatable"); 112 luaL_error(L, "cannot change a protected metatable");
119 lua_settop(L, 2); 113 lua_settop(L, 2);
120 lua_setmetatable(L, 1); 114 lua_setmetatable(L, 1);
121 return 1; 115 return 1;
122} 116}
123 117
124 118
125static int luaB_rawequal (lua_State *L) { 119static void getfunc (lua_State *L, int opt) {
126 luaL_checkany(L, 1); 120 if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
127 luaL_checkany(L, 2); 121 else {
128 lua_pushboolean(L, lua_rawequal(L, 1, 2)); 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);
129 return 1; 141 return 1;
130} 142}
131 143
132 144
133static int luaB_rawlen (lua_State *L) { 145static int luaB_setfenv (lua_State *L) {
134 int t = lua_type(L, 1); 146 luaL_checktype(L, 2, LUA_TTABLE);
135 luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, 147 getfunc(L, 0);
136 "table or string expected"); 148 lua_pushvalue(L, 2);
137 lua_pushinteger(L, lua_rawlen(L, 1)); 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) {
164 luaL_checkany(L, 1);
165 luaL_checkany(L, 2);
166 lua_pushboolean(L, lua_rawequal(L, 1, 2));
138 return 1; 167 return 1;
139} 168}
140 169
@@ -157,29 +186,32 @@ static int luaB_rawset (lua_State *L) {
157} 186}
158 187
159 188
189static int luaB_gcinfo (lua_State *L) {
190 lua_pushinteger(L, lua_getgccount(L));
191 return 1;
192}
193
194
160static int luaB_collectgarbage (lua_State *L) { 195static int luaB_collectgarbage (lua_State *L) {
161 static const char *const opts[] = {"stop", "restart", "collect", 196 static const char *const opts[] = {"stop", "restart", "collect",
162 "count", "step", "setpause", "setstepmul", 197 "count", "step", "setpause", "setstepmul", NULL};
163 "setmajorinc", "isrunning", "generational", "incremental", NULL};
164 static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, 198 static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
165 LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, 199 LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL};
166 LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; 200 int o = luaL_checkoption(L, 1, "collect", opts);
167 int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
168 int ex = luaL_optint(L, 2, 0); 201 int ex = luaL_optint(L, 2, 0);
169 int res = lua_gc(L, o, ex); 202 int res = lua_gc(L, optsnum[o], ex);
170 switch (o) { 203 switch (optsnum[o]) {
171 case LUA_GCCOUNT: { 204 case LUA_GCCOUNT: {
172 int b = lua_gc(L, LUA_GCCOUNTB, 0); 205 int b = lua_gc(L, LUA_GCCOUNTB, 0);
173 lua_pushnumber(L, res + ((lua_Number)b/1024)); 206 lua_pushnumber(L, res + ((lua_Number)b/1024));
174 lua_pushinteger(L, b); 207 return 1;
175 return 2;
176 } 208 }
177 case LUA_GCSTEP: case LUA_GCISRUNNING: { 209 case LUA_GCSTEP: {
178 lua_pushboolean(L, res); 210 lua_pushboolean(L, res);
179 return 1; 211 return 1;
180 } 212 }
181 default: { 213 default: {
182 lua_pushinteger(L, res); 214 lua_pushnumber(L, res);
183 return 1; 215 return 1;
184 } 216 }
185 } 217 }
@@ -193,23 +225,6 @@ static int luaB_type (lua_State *L) {
193} 225}
194 226
195 227
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
213static int luaB_next (lua_State *L) { 228static int luaB_next (lua_State *L) {
214 luaL_checktype(L, 1, LUA_TTABLE); 229 luaL_checktype(L, 1, LUA_TTABLE);
215 lua_settop(L, 2); /* create a 2nd argument if there isn't one */ 230 lua_settop(L, 2); /* create a 2nd argument if there isn't one */
@@ -223,7 +238,11 @@ static int luaB_next (lua_State *L) {
223 238
224 239
225static int luaB_pairs (lua_State *L) { 240static int luaB_pairs (lua_State *L) {
226 return pairsmeta(L, "__pairs", 0, luaB_next); 241 luaL_checktype(L, 1, LUA_TTABLE);
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;
227} 246}
228 247
229 248
@@ -233,25 +252,23 @@ static int ipairsaux (lua_State *L) {
233 i++; /* next value */ 252 i++; /* next value */
234 lua_pushinteger(L, i); 253 lua_pushinteger(L, i);
235 lua_rawgeti(L, 1, i); 254 lua_rawgeti(L, 1, i);
236 return (lua_isnil(L, -1)) ? 1 : 2; 255 return (lua_isnil(L, -1)) ? 0 : 2;
237} 256}
238 257
239 258
240static int luaB_ipairs (lua_State *L) { 259static int luaB_ipairs (lua_State *L) {
241 return pairsmeta(L, "__ipairs", 1, ipairsaux); 260 luaL_checktype(L, 1, LUA_TTABLE);
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;
242} 265}
243 266
244 267
245static int load_aux (lua_State *L, int status, int envidx) { 268static int load_aux (lua_State *L, int status) {
246 if (status == LUA_OK) { 269 if (status == 0) /* 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 }
252 return 1; 270 return 1;
253 } 271 else {
254 else { /* error (message is on top of the stack) */
255 lua_pushnil(L); 272 lua_pushnil(L);
256 lua_insert(L, -2); /* put before error message */ 273 lua_insert(L, -2); /* put before error message */
257 return 2; /* return nil plus error message */ 274 return 2; /* return nil plus error message */
@@ -259,28 +276,18 @@ static int load_aux (lua_State *L, int status, int envidx) {
259} 276}
260 277
261 278
262static int luaB_loadfile (lua_State *L) { 279static int luaB_loadstring (lua_State *L) {
263 const char *fname = luaL_optstring(L, 1, NULL); 280 size_t l;
264 const char *mode = luaL_optstring(L, 2, NULL); 281 const char *s = luaL_checklstring(L, 1, &l);
265 int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ 282 const char *chunkname = luaL_optstring(L, 2, s);
266 int status = luaL_loadfilex(L, fname, mode); 283 return load_aux(L, luaL_loadbuffer(L, s, l, chunkname));
267 return load_aux(L, status, env);
268} 284}
269 285
270 286
271/* 287static int luaB_loadfile (lua_State *L) {
272** {====================================================== 288 const char *fname = luaL_optstring(L, 1, NULL);
273** Generic Read function 289 return load_aux(L, luaL_loadfile(L, fname));
274** ======================================================= 290}
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 291
285 292
286/* 293/*
@@ -290,66 +297,66 @@ static int luaB_loadfile (lua_State *L) {
290** reserved slot inside the stack. 297** reserved slot inside the stack.
291*/ 298*/
292static const char *generic_reader (lua_State *L, void *ud, size_t *size) { 299static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
293 (void)(ud); /* not used */ 300 (void)ud; /* to avoid warnings */
294 luaL_checkstack(L, 2, "too many nested functions"); 301 luaL_checkstack(L, 2, "too many nested functions");
295 lua_pushvalue(L, 1); /* get function */ 302 lua_pushvalue(L, 1); /* get function */
296 lua_call(L, 0, 1); /* call it */ 303 lua_call(L, 0, 1); /* call it */
297 if (lua_isnil(L, -1)) { 304 if (lua_isnil(L, -1)) {
298 lua_pop(L, 1); /* pop result */
299 *size = 0; 305 *size = 0;
300 return NULL; 306 return NULL;
301 } 307 }
302 else if (!lua_isstring(L, -1)) 308 else if (lua_isstring(L, -1)) {
303 luaL_error(L, "reader function must return a string"); 309 lua_replace(L, 3); /* save string in a reserved stack slot */
304 lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ 310 return lua_tolstring(L, 3, size);
305 return lua_tolstring(L, RESERVEDSLOT, size); 311 }
312 else luaL_error(L, "reader function must return a string");
313 return NULL; /* to avoid warnings */
306} 314}
307 315
308 316
309static int luaB_load (lua_State *L) { 317static int luaB_load (lua_State *L) {
310 int status; 318 int status;
311 size_t l; 319 const char *cname = luaL_optstring(L, 2, "=(load)");
312 const char *s = lua_tolstring(L, 1, &l); 320 luaL_checktype(L, 1, LUA_TFUNCTION);
313 const char *mode = luaL_optstring(L, 3, "bt"); 321 lua_settop(L, 3); /* function, eventual name, plus one reserved slot */
314 int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ 322 status = lua_load(L, generic_reader, NULL, cname);
315 if (s != NULL) { /* loading a string? */ 323 return load_aux(L, status);
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;
333} 324}
334 325
335 326
336static int luaB_dofile (lua_State *L) { 327static int luaB_dofile (lua_State *L) {
337 const char *fname = luaL_optstring(L, 1, NULL); 328 const char *fname = luaL_optstring(L, 1, NULL);
338 lua_settop(L, 1); 329 int n = lua_gettop(L);
339 if (luaL_loadfile(L, fname) != LUA_OK) 330 if (luaL_loadfile(L, fname) != 0) lua_error(L);
340 return lua_error(L); 331 lua_call(L, 0, LUA_MULTRET);
341 lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); 332 return lua_gettop(L) - n;
342 return dofilecont(L);
343} 333}
344 334
345 335
346static int luaB_assert (lua_State *L) { 336static int luaB_assert (lua_State *L) {
337 luaL_checkany(L, 1);
347 if (!lua_toboolean(L, 1)) 338 if (!lua_toboolean(L, 1))
348 return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); 339 return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
349 return lua_gettop(L); 340 return lua_gettop(L);
350} 341}
351 342
352 343
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
353static int luaB_select (lua_State *L) { 360static int luaB_select (lua_State *L) {
354 int n = lua_gettop(L); 361 int n = lua_gettop(L);
355 if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { 362 if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
@@ -366,50 +373,75 @@ static int luaB_select (lua_State *L) {
366} 373}
367 374
368 375
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
388static int luaB_pcall (lua_State *L) { 376static int luaB_pcall (lua_State *L) {
389 int status; 377 int status;
390 luaL_checkany(L, 1); 378 luaL_checkany(L, 1);
391 lua_pushnil(L); 379 status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
392 lua_insert(L, 1); /* create space for status result */ 380 lua_pushboolean(L, (status == 0));
393 status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont); 381 lua_insert(L, 1);
394 return finishpcall(L, (status == LUA_OK)); 382 return lua_gettop(L); /* return status + all results */
395} 383}
396 384
397 385
398static int luaB_xpcall (lua_State *L) { 386static int luaB_xpcall (lua_State *L) {
399 int status; 387 int status;
400 int n = lua_gettop(L); 388 luaL_checkany(L, 2);
401 luaL_argcheck(L, n >= 2, 2, "value expected"); 389 lua_settop(L, 2);
402 lua_pushvalue(L, 1); /* exchange function... */ 390 lua_insert(L, 1); /* put error function under function to be called */
403 lua_copy(L, 2, 1); /* ...and error handler */ 391 status = lua_pcall(L, 0, LUA_MULTRET, 1);
404 lua_replace(L, 2); 392 lua_pushboolean(L, (status == 0));
405 status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont); 393 lua_replace(L, 1);
406 return finishpcall(L, (status == LUA_OK)); 394 return lua_gettop(L); /* return status + all results */
407} 395}
408 396
409 397
410static int luaB_tostring (lua_State *L) { 398static int luaB_tostring (lua_State *L) {
411 luaL_checkany(L, 1); 399 luaL_checkany(L, 1);
412 luaL_tolstring(L, 1, NULL); 400 if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */
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);
413 return 1; 445 return 1;
414} 446}
415 447
@@ -419,40 +451,207 @@ static const luaL_Reg base_funcs[] = {
419 {"collectgarbage", luaB_collectgarbage}, 451 {"collectgarbage", luaB_collectgarbage},
420 {"dofile", luaB_dofile}, 452 {"dofile", luaB_dofile},
421 {"error", luaB_error}, 453 {"error", luaB_error},
454 {"gcinfo", luaB_gcinfo},
455 {"getfenv", luaB_getfenv},
422 {"getmetatable", luaB_getmetatable}, 456 {"getmetatable", luaB_getmetatable},
423 {"ipairs", luaB_ipairs},
424 {"loadfile", luaB_loadfile}, 457 {"loadfile", luaB_loadfile},
425 {"load", luaB_load}, 458 {"load", luaB_load},
426#if defined(LUA_COMPAT_LOADSTRING) 459 {"loadstring", luaB_loadstring},
427 {"loadstring", luaB_load},
428#endif
429 {"next", luaB_next}, 460 {"next", luaB_next},
430 {"pairs", luaB_pairs},
431 {"pcall", luaB_pcall}, 461 {"pcall", luaB_pcall},
462#if 0
432 {"print", luaB_print}, 463 {"print", luaB_print},
464#endif
433 {"rawequal", luaB_rawequal}, 465 {"rawequal", luaB_rawequal},
434 {"rawlen", luaB_rawlen},
435 {"rawget", luaB_rawget}, 466 {"rawget", luaB_rawget},
436 {"rawset", luaB_rawset}, 467 {"rawset", luaB_rawset},
437 {"select", luaB_select}, 468 {"select", luaB_select},
469 {"setfenv", luaB_setfenv},
438 {"setmetatable", luaB_setmetatable}, 470 {"setmetatable", luaB_setmetatable},
439 {"tonumber", luaB_tonumber}, 471 {"tonumber", luaB_tonumber},
440 {"tostring", luaB_tostring}, 472 {"tostring", luaB_tostring},
441 {"type", luaB_type}, 473 {"type", luaB_type},
474 {"unpack", luaB_unpack},
442 {"xpcall", luaB_xpcall}, 475 {"xpcall", luaB_xpcall},
443 {NULL, NULL} 476 {NULL, NULL}
444}; 477};
445 478
446 479
447LUAMOD_API int luaopen_base (lua_State *L) { 480/*
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) {
448 /* set global _G */ 631 /* set global _G */
449 lua_pushglobaltable(L); 632 lua_pushvalue(L, LUA_GLOBALSINDEX);
450 lua_pushglobaltable(L); 633 lua_setglobal(L, "_G");
451 lua_setfield(L, -2, "_G");
452 /* open lib into global table */ 634 /* open lib into global table */
453 luaL_setfuncs(L, base_funcs, 0); 635 luaL_register(L, "_G", base_funcs);
454 lua_pushliteral(L, LUA_VERSION); 636 lua_pushliteral(L, LUA_VERSION);
455 lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ 637 lua_setglobal(L, "_VERSION"); /* set global _VERSION */
456 return 1; 638 /* `ipairs' and `pairs' need auxliliary functions as upvalues */
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;
457} 656}
458 657