diff options
Diffstat (limited to 'apps/plugins/lua/lbaselib.c')
-rw-r--r-- | apps/plugins/lua/lbaselib.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/apps/plugins/lua/lbaselib.c b/apps/plugins/lua/lbaselib.c new file mode 100644 index 0000000000..008e3629fe --- /dev/null +++ b/apps/plugins/lua/lbaselib.c | |||
@@ -0,0 +1,657 @@ | |||
1 | /* | ||
2 | ** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $ | ||
3 | ** Basic library | ||
4 | ** See Copyright Notice in lua.h | ||
5 | */ | ||
6 | |||
7 | |||
8 | |||
9 | #include <ctype.h> | ||
10 | #include <stdio.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <string.h> | ||
13 | |||
14 | #define lbaselib_c | ||
15 | #define LUA_LIB | ||
16 | |||
17 | #include "lua.h" | ||
18 | |||
19 | #include "lauxlib.h" | ||
20 | #include "lualib.h" | ||
21 | |||
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 | ||
32 | static int luaB_print (lua_State *L) { | ||
33 | int n = lua_gettop(L); /* number of arguments */ | ||
34 | int i; | ||
35 | lua_getglobal(L, "tostring"); | ||
36 | for (i=1; i<=n; i++) { | ||
37 | const char *s; | ||
38 | lua_pushvalue(L, -1); /* function to be called */ | ||
39 | lua_pushvalue(L, i); /* value to print */ | ||
40 | lua_call(L, 1, 1); | ||
41 | s = lua_tostring(L, -1); /* get result */ | ||
42 | if (s == NULL) | ||
43 | return luaL_error(L, LUA_QL("tostring") " must return a string to " | ||
44 | LUA_QL("print")); | ||
45 | if (i>1) fputs("\t", stdout); | ||
46 | fputs(s, stdout); | ||
47 | lua_pop(L, 1); /* pop result */ | ||
48 | } | ||
49 | fputs("\n", stdout); | ||
50 | return 0; | ||
51 | } | ||
52 | #endif | ||
53 | |||
54 | |||
55 | static int luaB_tonumber (lua_State *L) { | ||
56 | int base = luaL_optint(L, 2, 10); | ||
57 | if (base == 10) { /* standard conversion */ | ||
58 | luaL_checkany(L, 1); | ||
59 | if (lua_isnumber(L, 1)) { | ||
60 | lua_pushnumber(L, lua_tonumber(L, 1)); | ||
61 | return 1; | ||
62 | } | ||
63 | } | ||
64 | else { | ||
65 | const char *s1 = luaL_checkstring(L, 1); | ||
66 | char *s2; | ||
67 | unsigned long n; | ||
68 | luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); | ||
69 | n = strtoul(s1, &s2, base); | ||
70 | if (s1 != s2) { /* at least one valid digit? */ | ||
71 | while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ | ||
72 | if (*s2 == '\0') { /* no invalid trailing characters? */ | ||
73 | lua_pushnumber(L, (lua_Number)n); | ||
74 | return 1; | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | lua_pushnil(L); /* else not a number */ | ||
79 | return 1; | ||
80 | } | ||
81 | |||
82 | |||
83 | static int luaB_error (lua_State *L) { | ||
84 | int level = luaL_optint(L, 2, 1); | ||
85 | lua_settop(L, 1); | ||
86 | if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ | ||
87 | luaL_where(L, level); | ||
88 | lua_pushvalue(L, 1); | ||
89 | lua_concat(L, 2); | ||
90 | } | ||
91 | return lua_error(L); | ||
92 | } | ||
93 | |||
94 | |||
95 | static int luaB_getmetatable (lua_State *L) { | ||
96 | luaL_checkany(L, 1); | ||
97 | if (!lua_getmetatable(L, 1)) { | ||
98 | lua_pushnil(L); | ||
99 | return 1; /* no metatable */ | ||
100 | } | ||
101 | luaL_getmetafield(L, 1, "__metatable"); | ||
102 | return 1; /* returns either __metatable field (if present) or metatable */ | ||
103 | } | ||
104 | |||
105 | |||
106 | static int luaB_setmetatable (lua_State *L) { | ||
107 | int t = lua_type(L, 2); | ||
108 | luaL_checktype(L, 1, LUA_TTABLE); | ||
109 | luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, | ||
110 | "nil or table expected"); | ||
111 | if (luaL_getmetafield(L, 1, "__metatable")) | ||
112 | luaL_error(L, "cannot change a protected metatable"); | ||
113 | lua_settop(L, 2); | ||
114 | lua_setmetatable(L, 1); | ||
115 | return 1; | ||
116 | } | ||
117 | |||
118 | |||
119 | static 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 | |||
135 | static 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 | |||
145 | static 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 | |||
163 | static 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)); | ||
167 | return 1; | ||
168 | } | ||
169 | |||
170 | |||
171 | static int luaB_rawget (lua_State *L) { | ||
172 | luaL_checktype(L, 1, LUA_TTABLE); | ||
173 | luaL_checkany(L, 2); | ||
174 | lua_settop(L, 2); | ||
175 | lua_rawget(L, 1); | ||
176 | return 1; | ||
177 | } | ||
178 | |||
179 | static int luaB_rawset (lua_State *L) { | ||
180 | luaL_checktype(L, 1, LUA_TTABLE); | ||
181 | luaL_checkany(L, 2); | ||
182 | luaL_checkany(L, 3); | ||
183 | lua_settop(L, 3); | ||
184 | lua_rawset(L, 1); | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | |||
189 | static int luaB_gcinfo (lua_State *L) { | ||
190 | lua_pushinteger(L, lua_getgccount(L)); | ||
191 | return 1; | ||
192 | } | ||
193 | |||
194 | |||
195 | static int luaB_collectgarbage (lua_State *L) { | ||
196 | static const char *const opts[] = {"stop", "restart", "collect", | ||
197 | "count", "step", "setpause", "setstepmul", NULL}; | ||
198 | static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, | ||
199 | LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; | ||
200 | int o = luaL_checkoption(L, 1, "collect", opts); | ||
201 | int ex = luaL_optint(L, 2, 0); | ||
202 | int res = lua_gc(L, optsnum[o], ex); | ||
203 | switch (optsnum[o]) { | ||
204 | case LUA_GCCOUNT: { | ||
205 | int b = lua_gc(L, LUA_GCCOUNTB, 0); | ||
206 | lua_pushnumber(L, res + ((lua_Number)b/1024)); | ||
207 | return 1; | ||
208 | } | ||
209 | case LUA_GCSTEP: { | ||
210 | lua_pushboolean(L, res); | ||
211 | return 1; | ||
212 | } | ||
213 | default: { | ||
214 | lua_pushnumber(L, res); | ||
215 | return 1; | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | |||
220 | |||
221 | static int luaB_type (lua_State *L) { | ||
222 | luaL_checkany(L, 1); | ||
223 | lua_pushstring(L, luaL_typename(L, 1)); | ||
224 | return 1; | ||
225 | } | ||
226 | |||
227 | |||
228 | static int luaB_next (lua_State *L) { | ||
229 | luaL_checktype(L, 1, LUA_TTABLE); | ||
230 | lua_settop(L, 2); /* create a 2nd argument if there isn't one */ | ||
231 | if (lua_next(L, 1)) | ||
232 | return 2; | ||
233 | else { | ||
234 | lua_pushnil(L); | ||
235 | return 1; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | |||
240 | static int luaB_pairs (lua_State *L) { | ||
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; | ||
246 | } | ||
247 | |||
248 | |||
249 | static int ipairsaux (lua_State *L) { | ||
250 | int i = luaL_checkint(L, 2); | ||
251 | luaL_checktype(L, 1, LUA_TTABLE); | ||
252 | i++; /* next value */ | ||
253 | lua_pushinteger(L, i); | ||
254 | lua_rawgeti(L, 1, i); | ||
255 | return (lua_isnil(L, -1)) ? 0 : 2; | ||
256 | } | ||
257 | |||
258 | |||
259 | static int luaB_ipairs (lua_State *L) { | ||
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; | ||
265 | } | ||
266 | |||
267 | |||
268 | static int load_aux (lua_State *L, int status) { | ||
269 | if (status == 0) /* OK? */ | ||
270 | return 1; | ||
271 | else { | ||
272 | lua_pushnil(L); | ||
273 | lua_insert(L, -2); /* put before error message */ | ||
274 | return 2; /* return nil plus error message */ | ||
275 | } | ||
276 | } | ||
277 | |||
278 | |||
279 | static 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 | |||
287 | static int luaB_loadfile (lua_State *L) { | ||
288 | const char *fname = luaL_optstring(L, 1, NULL); | ||
289 | return load_aux(L, luaL_loadfile(L, fname)); | ||
290 | } | ||
291 | |||
292 | |||
293 | /* | ||
294 | ** Reader for generic `load' function: `lua_load' uses the | ||
295 | ** stack for internal stuff, so the reader cannot change the | ||
296 | ** stack top. Instead, it keeps its resulting string in a | ||
297 | ** reserved slot inside the stack. | ||
298 | */ | ||
299 | static const char *generic_reader (lua_State *L, void *ud, size_t *size) { | ||
300 | (void)ud; /* to avoid warnings */ | ||
301 | luaL_checkstack(L, 2, "too many nested functions"); | ||
302 | lua_pushvalue(L, 1); /* get function */ | ||
303 | lua_call(L, 0, 1); /* call it */ | ||
304 | if (lua_isnil(L, -1)) { | ||
305 | *size = 0; | ||
306 | return NULL; | ||
307 | } | ||
308 | else if (lua_isstring(L, -1)) { | ||
309 | lua_replace(L, 3); /* save string in a reserved stack slot */ | ||
310 | return lua_tolstring(L, 3, size); | ||
311 | } | ||
312 | else luaL_error(L, "reader function must return a string"); | ||
313 | return NULL; /* to avoid warnings */ | ||
314 | } | ||
315 | |||
316 | |||
317 | static int luaB_load (lua_State *L) { | ||
318 | int status; | ||
319 | const char *cname = luaL_optstring(L, 2, "=(load)"); | ||
320 | luaL_checktype(L, 1, LUA_TFUNCTION); | ||
321 | lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ | ||
322 | status = lua_load(L, generic_reader, NULL, cname); | ||
323 | return load_aux(L, status); | ||
324 | } | ||
325 | |||
326 | |||
327 | static int luaB_dofile (lua_State *L) { | ||
328 | const char *fname = luaL_optstring(L, 1, NULL); | ||
329 | int n = lua_gettop(L); | ||
330 | if (luaL_loadfile(L, fname) != 0) lua_error(L); | ||
331 | lua_call(L, 0, LUA_MULTRET); | ||
332 | return lua_gettop(L) - n; | ||
333 | } | ||
334 | |||
335 | |||
336 | static int luaB_assert (lua_State *L) { | ||
337 | luaL_checkany(L, 1); | ||
338 | if (!lua_toboolean(L, 1)) | ||
339 | return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); | ||
340 | return lua_gettop(L); | ||
341 | } | ||
342 | |||
343 | |||
344 | static 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 | |||
360 | static int luaB_select (lua_State *L) { | ||
361 | int n = lua_gettop(L); | ||
362 | if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { | ||
363 | lua_pushinteger(L, n-1); | ||
364 | return 1; | ||
365 | } | ||
366 | else { | ||
367 | int i = luaL_checkint(L, 1); | ||
368 | if (i < 0) i = n + i; | ||
369 | else if (i > n) i = n; | ||
370 | luaL_argcheck(L, 1 <= i, 1, "index out of range"); | ||
371 | return n - i; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | |||
376 | static int luaB_pcall (lua_State *L) { | ||
377 | int status; | ||
378 | luaL_checkany(L, 1); | ||
379 | status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); | ||
380 | lua_pushboolean(L, (status == 0)); | ||
381 | lua_insert(L, 1); | ||
382 | return lua_gettop(L); /* return status + all results */ | ||
383 | } | ||
384 | |||
385 | |||
386 | static int luaB_xpcall (lua_State *L) { | ||
387 | int status; | ||
388 | luaL_checkany(L, 2); | ||
389 | lua_settop(L, 2); | ||
390 | lua_insert(L, 1); /* put error function under function to be called */ | ||
391 | status = lua_pcall(L, 0, LUA_MULTRET, 1); | ||
392 | lua_pushboolean(L, (status == 0)); | ||
393 | lua_replace(L, 1); | ||
394 | return lua_gettop(L); /* return status + all results */ | ||
395 | } | ||
396 | |||
397 | |||
398 | static int luaB_tostring (lua_State *L) { | ||
399 | luaL_checkany(L, 1); | ||
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 | |||
423 | static 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; | ||
446 | } | ||
447 | |||
448 | |||
449 | static const luaL_Reg base_funcs[] = { | ||
450 | {"assert", luaB_assert}, | ||
451 | {"collectgarbage", luaB_collectgarbage}, | ||
452 | {"dofile", luaB_dofile}, | ||
453 | {"error", luaB_error}, | ||
454 | {"gcinfo", luaB_gcinfo}, | ||
455 | {"getfenv", luaB_getfenv}, | ||
456 | {"getmetatable", luaB_getmetatable}, | ||
457 | {"loadfile", luaB_loadfile}, | ||
458 | {"load", luaB_load}, | ||
459 | {"loadstring", luaB_loadstring}, | ||
460 | {"next", luaB_next}, | ||
461 | {"pcall", luaB_pcall}, | ||
462 | #if 0 | ||
463 | {"print", luaB_print}, | ||
464 | #endif | ||
465 | {"rawequal", luaB_rawequal}, | ||
466 | {"rawget", luaB_rawget}, | ||
467 | {"rawset", luaB_rawset}, | ||
468 | {"select", luaB_select}, | ||
469 | {"setfenv", luaB_setfenv}, | ||
470 | {"setmetatable", luaB_setmetatable}, | ||
471 | {"tonumber", luaB_tonumber}, | ||
472 | {"tostring", luaB_tostring}, | ||
473 | {"type", luaB_type}, | ||
474 | {"unpack", luaB_unpack}, | ||
475 | {"xpcall", luaB_xpcall}, | ||
476 | {NULL, NULL} | ||
477 | }; | ||
478 | |||
479 | |||
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 | |||
491 | static const char *const statnames[] = | ||
492 | {"running", "suspended", "normal", "dead"}; | ||
493 | |||
494 | static 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 | |||
514 | static 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 | |||
522 | static 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 | |||
547 | static 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 | |||
565 | static 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 | |||
580 | static 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 | |||
590 | static int luaB_cowrap (lua_State *L) { | ||
591 | luaB_cocreate(L); | ||
592 | lua_pushcclosure(L, luaB_auxwrap, 1); | ||
593 | return 1; | ||
594 | } | ||
595 | |||
596 | |||
597 | static int luaB_yield (lua_State *L) { | ||
598 | return lua_yield(L, lua_gettop(L)); | ||
599 | } | ||
600 | |||
601 | |||
602 | static 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 | |||
609 | static 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 | |||
622 | static 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 | |||
630 | static void base_open (lua_State *L) { | ||
631 | /* set global _G */ | ||
632 | lua_pushvalue(L, LUA_GLOBALSINDEX); | ||
633 | lua_setglobal(L, "_G"); | ||
634 | /* open lib into global table */ | ||
635 | luaL_register(L, "_G", base_funcs); | ||
636 | lua_pushliteral(L, LUA_VERSION); | ||
637 | lua_setglobal(L, "_VERSION"); /* set global _VERSION */ | ||
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 | |||
652 | LUALIB_API int luaopen_base (lua_State *L) { | ||
653 | base_open(L); | ||
654 | luaL_register(L, LUA_COLIBNAME, co_funcs); | ||
655 | return 2; | ||
656 | } | ||
657 | |||