diff options
-rw-r--r-- | lauxlib.c | 307 |
1 files changed, 163 insertions, 144 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lauxlib.c,v 1.167 2007/05/15 18:46:12 roberto Exp roberto $ | 2 | ** $Id: lauxlib.c,v 1.168 2007/06/21 13:48:04 roberto Exp roberto $ |
3 | ** Auxiliary functions for building Lua libraries | 3 | ** Auxiliary functions for building Lua libraries |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -25,13 +25,6 @@ | |||
25 | #include "lauxlib.h" | 25 | #include "lauxlib.h" |
26 | 26 | ||
27 | 27 | ||
28 | /* number of prereserved references (for internal use) */ | ||
29 | #define RESERVED_REFS 1 /* only FREELIST_REF is reserved */ | ||
30 | |||
31 | #define FREELIST_REF 1 /* free list of references */ | ||
32 | |||
33 | |||
34 | |||
35 | /* convert a stack index to positive */ | 28 | /* convert a stack index to positive */ |
36 | #define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ | 29 | #define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ |
37 | lua_gettop(L) + (i) + 1) | 30 | lua_gettop(L) + (i) + 1) |
@@ -43,7 +36,6 @@ | |||
43 | ** ======================================================= | 36 | ** ======================================================= |
44 | */ | 37 | */ |
45 | 38 | ||
46 | |||
47 | LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { | 39 | LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { |
48 | lua_Debug ar; | 40 | lua_Debug ar; |
49 | if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ | 41 | if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ |
@@ -100,18 +92,11 @@ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { | |||
100 | /* }====================================================== */ | 92 | /* }====================================================== */ |
101 | 93 | ||
102 | 94 | ||
103 | LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, | 95 | /* |
104 | const char *const lst[]) { | 96 | ** {====================================================== |
105 | const char *name = (def) ? luaL_optstring(L, narg, def) : | 97 | ** Userdata's metatable manipulation |
106 | luaL_checkstring(L, narg); | 98 | ** ======================================================= |
107 | int i; | 99 | */ |
108 | for (i=0; lst[i]; i++) | ||
109 | if (strcmp(lst[i], name) == 0) | ||
110 | return i; | ||
111 | return luaL_argerror(L, narg, | ||
112 | lua_pushfstring(L, "invalid option " LUA_QS, name)); | ||
113 | } | ||
114 | |||
115 | 100 | ||
116 | LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { | 101 | LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { |
117 | lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ | 102 | lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ |
@@ -146,6 +131,27 @@ LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { | |||
146 | return p; | 131 | return p; |
147 | } | 132 | } |
148 | 133 | ||
134 | /* }====================================================== */ | ||
135 | |||
136 | |||
137 | /* | ||
138 | ** {====================================================== | ||
139 | ** Argument check functions | ||
140 | ** ======================================================= | ||
141 | */ | ||
142 | |||
143 | LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, | ||
144 | const char *const lst[]) { | ||
145 | const char *name = (def) ? luaL_optstring(L, narg, def) : | ||
146 | luaL_checkstring(L, narg); | ||
147 | int i; | ||
148 | for (i=0; lst[i]; i++) | ||
149 | if (strcmp(lst[i], name) == 0) | ||
150 | return i; | ||
151 | return luaL_argerror(L, narg, | ||
152 | lua_pushfstring(L, "invalid option " LUA_QS, name)); | ||
153 | } | ||
154 | |||
149 | 155 | ||
150 | LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { | 156 | LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { |
151 | if (!lua_checkstack(L, space)) | 157 | if (!lua_checkstack(L, space)) |
@@ -209,128 +215,7 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, | |||
209 | return luaL_opt(L, luaL_checkinteger, narg, def); | 215 | return luaL_opt(L, luaL_checkinteger, narg, def); |
210 | } | 216 | } |
211 | 217 | ||
212 | 218 | /* }====================================================== */ | |
213 | LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { | ||
214 | if (!lua_getmetatable(L, obj)) /* no metatable? */ | ||
215 | return 0; | ||
216 | lua_pushstring(L, event); | ||
217 | lua_rawget(L, -2); | ||
218 | if (lua_isnil(L, -1)) { | ||
219 | lua_pop(L, 2); /* remove metatable and metafield */ | ||
220 | return 0; | ||
221 | } | ||
222 | else { | ||
223 | lua_remove(L, -2); /* remove only metatable */ | ||
224 | return 1; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | |||
229 | LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { | ||
230 | obj = abs_index(L, obj); | ||
231 | if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ | ||
232 | return 0; | ||
233 | lua_pushvalue(L, obj); | ||
234 | lua_call(L, 1, 1); | ||
235 | return 1; | ||
236 | } | ||
237 | |||
238 | |||
239 | LUALIB_API const char *luaL_tostring (lua_State *L, int idx) { | ||
240 | if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ | ||
241 | switch (lua_type(L, idx)) { | ||
242 | case LUA_TNUMBER: | ||
243 | return lua_pushstring(L, lua_tostring(L, idx)); | ||
244 | case LUA_TSTRING: | ||
245 | lua_pushvalue(L, idx); | ||
246 | break; | ||
247 | case LUA_TBOOLEAN: | ||
248 | return lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); | ||
249 | case LUA_TNIL: | ||
250 | return lua_pushliteral(L, "nil"); | ||
251 | default: | ||
252 | return lua_pushfstring(L, "%s: %p", luaL_typename(L, idx), | ||
253 | lua_topointer(L, idx)); | ||
254 | } | ||
255 | } | ||
256 | return lua_tostring(L, -1); | ||
257 | } | ||
258 | |||
259 | |||
260 | static int libsize (const luaL_Reg *l) { | ||
261 | int size = 0; | ||
262 | for (; l->name; l++) size++; | ||
263 | return size; | ||
264 | } | ||
265 | |||
266 | |||
267 | LUALIB_API void luaL_register (lua_State *L, const char *libname, | ||
268 | const luaL_Reg *l) { | ||
269 | if (libname) { | ||
270 | int size = libsize(l); | ||
271 | /* check whether lib already exists */ | ||
272 | luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); | ||
273 | lua_getfield(L, -1, libname); /* get _LOADED[libname] */ | ||
274 | if (!lua_istable(L, -1)) { /* not found? */ | ||
275 | lua_pop(L, 1); /* remove previous result */ | ||
276 | /* try global variable (and create one if it does not exist) */ | ||
277 | if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) | ||
278 | luaL_error(L, "name conflict for module " LUA_QS, libname); | ||
279 | lua_pushvalue(L, -1); | ||
280 | lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ | ||
281 | } | ||
282 | lua_remove(L, -2); /* remove _LOADED table */ | ||
283 | } | ||
284 | for (; l->name; l++) { | ||
285 | lua_pushcfunction(L, l->func); | ||
286 | lua_setfield(L, -2, l->name); | ||
287 | } | ||
288 | } | ||
289 | |||
290 | |||
291 | LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, | ||
292 | const char *r) { | ||
293 | const char *wild; | ||
294 | size_t l = strlen(p); | ||
295 | luaL_Buffer b; | ||
296 | luaL_buffinit(L, &b); | ||
297 | while ((wild = strstr(s, p)) != NULL) { | ||
298 | luaL_addlstring(&b, s, wild - s); /* push prefix */ | ||
299 | luaL_addstring(&b, r); /* push replacement in place of pattern */ | ||
300 | s = wild + l; /* continue after `p' */ | ||
301 | } | ||
302 | luaL_addstring(&b, s); /* push last suffix */ | ||
303 | luaL_pushresult(&b); | ||
304 | return lua_tostring(L, -1); | ||
305 | } | ||
306 | |||
307 | |||
308 | LUALIB_API const char *luaL_findtable (lua_State *L, int idx, | ||
309 | const char *fname, int szhint) { | ||
310 | const char *e; | ||
311 | lua_pushvalue(L, idx); | ||
312 | do { | ||
313 | e = strchr(fname, '.'); | ||
314 | if (e == NULL) e = fname + strlen(fname); | ||
315 | lua_pushlstring(L, fname, e - fname); | ||
316 | lua_rawget(L, -2); | ||
317 | if (lua_isnil(L, -1)) { /* no such field? */ | ||
318 | lua_pop(L, 1); /* remove this nil */ | ||
319 | lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ | ||
320 | lua_pushlstring(L, fname, e - fname); | ||
321 | lua_pushvalue(L, -2); | ||
322 | lua_settable(L, -4); /* set new table into field */ | ||
323 | } | ||
324 | else if (!lua_istable(L, -1)) { /* field has a non-table value? */ | ||
325 | lua_pop(L, 2); /* remove table and value */ | ||
326 | return fname; /* return problematic part of the name */ | ||
327 | } | ||
328 | lua_remove(L, -2); /* remove previous table */ | ||
329 | fname = e + 1; | ||
330 | } while (*e == '.'); | ||
331 | return NULL; | ||
332 | } | ||
333 | |||
334 | 219 | ||
335 | 220 | ||
336 | /* | 221 | /* |
@@ -429,6 +314,18 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { | |||
429 | /* }====================================================== */ | 314 | /* }====================================================== */ |
430 | 315 | ||
431 | 316 | ||
317 | /* | ||
318 | ** {====================================================== | ||
319 | ** Reference system | ||
320 | ** ======================================================= | ||
321 | */ | ||
322 | |||
323 | /* number of prereserved references (for internal use) */ | ||
324 | #define RESERVED_REFS 1 /* only FREELIST_REF is reserved */ | ||
325 | |||
326 | #define FREELIST_REF 1 /* free list of references */ | ||
327 | |||
328 | |||
432 | LUALIB_API int luaL_ref (lua_State *L, int t) { | 329 | LUALIB_API int luaL_ref (lua_State *L, int t) { |
433 | int ref; | 330 | int ref; |
434 | t = abs_index(L, t); | 331 | t = abs_index(L, t); |
@@ -464,6 +361,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { | |||
464 | } | 361 | } |
465 | } | 362 | } |
466 | 363 | ||
364 | /* }====================================================== */ | ||
467 | 365 | ||
468 | 366 | ||
469 | /* | 367 | /* |
@@ -572,9 +470,130 @@ LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { | |||
572 | return luaL_loadbuffer(L, s, strlen(s), s); | 470 | return luaL_loadbuffer(L, s, strlen(s), s); |
573 | } | 471 | } |
574 | 472 | ||
473 | /* }====================================================== */ | ||
575 | 474 | ||
576 | 475 | ||
577 | /* }====================================================== */ | 476 | |
477 | LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { | ||
478 | if (!lua_getmetatable(L, obj)) /* no metatable? */ | ||
479 | return 0; | ||
480 | lua_pushstring(L, event); | ||
481 | lua_rawget(L, -2); | ||
482 | if (lua_isnil(L, -1)) { | ||
483 | lua_pop(L, 2); /* remove metatable and metafield */ | ||
484 | return 0; | ||
485 | } | ||
486 | else { | ||
487 | lua_remove(L, -2); /* remove only metatable */ | ||
488 | return 1; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | |||
493 | LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { | ||
494 | obj = abs_index(L, obj); | ||
495 | if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ | ||
496 | return 0; | ||
497 | lua_pushvalue(L, obj); | ||
498 | lua_call(L, 1, 1); | ||
499 | return 1; | ||
500 | } | ||
501 | |||
502 | |||
503 | LUALIB_API const char *luaL_tostring (lua_State *L, int idx) { | ||
504 | if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ | ||
505 | switch (lua_type(L, idx)) { | ||
506 | case LUA_TNUMBER: | ||
507 | return lua_pushstring(L, lua_tostring(L, idx)); | ||
508 | case LUA_TSTRING: | ||
509 | lua_pushvalue(L, idx); | ||
510 | break; | ||
511 | case LUA_TBOOLEAN: | ||
512 | return lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); | ||
513 | case LUA_TNIL: | ||
514 | return lua_pushliteral(L, "nil"); | ||
515 | default: | ||
516 | return lua_pushfstring(L, "%s: %p", luaL_typename(L, idx), | ||
517 | lua_topointer(L, idx)); | ||
518 | } | ||
519 | } | ||
520 | return lua_tostring(L, -1); | ||
521 | } | ||
522 | |||
523 | |||
524 | static int libsize (const luaL_Reg *l) { | ||
525 | int size = 0; | ||
526 | for (; l->name; l++) size++; | ||
527 | return size; | ||
528 | } | ||
529 | |||
530 | |||
531 | LUALIB_API void luaL_register (lua_State *L, const char *libname, | ||
532 | const luaL_Reg *l) { | ||
533 | if (libname) { | ||
534 | int size = libsize(l); | ||
535 | /* check whether lib already exists */ | ||
536 | luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); | ||
537 | lua_getfield(L, -1, libname); /* get _LOADED[libname] */ | ||
538 | if (!lua_istable(L, -1)) { /* not found? */ | ||
539 | lua_pop(L, 1); /* remove previous result */ | ||
540 | /* try global variable (and create one if it does not exist) */ | ||
541 | if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) | ||
542 | luaL_error(L, "name conflict for module " LUA_QS, libname); | ||
543 | lua_pushvalue(L, -1); | ||
544 | lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ | ||
545 | } | ||
546 | lua_remove(L, -2); /* remove _LOADED table */ | ||
547 | } | ||
548 | for (; l->name; l++) { | ||
549 | lua_pushcfunction(L, l->func); | ||
550 | lua_setfield(L, -2, l->name); | ||
551 | } | ||
552 | } | ||
553 | |||
554 | |||
555 | LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, | ||
556 | const char *r) { | ||
557 | const char *wild; | ||
558 | size_t l = strlen(p); | ||
559 | luaL_Buffer b; | ||
560 | luaL_buffinit(L, &b); | ||
561 | while ((wild = strstr(s, p)) != NULL) { | ||
562 | luaL_addlstring(&b, s, wild - s); /* push prefix */ | ||
563 | luaL_addstring(&b, r); /* push replacement in place of pattern */ | ||
564 | s = wild + l; /* continue after `p' */ | ||
565 | } | ||
566 | luaL_addstring(&b, s); /* push last suffix */ | ||
567 | luaL_pushresult(&b); | ||
568 | return lua_tostring(L, -1); | ||
569 | } | ||
570 | |||
571 | |||
572 | LUALIB_API const char *luaL_findtable (lua_State *L, int idx, | ||
573 | const char *fname, int szhint) { | ||
574 | const char *e; | ||
575 | lua_pushvalue(L, idx); | ||
576 | do { | ||
577 | e = strchr(fname, '.'); | ||
578 | if (e == NULL) e = fname + strlen(fname); | ||
579 | lua_pushlstring(L, fname, e - fname); | ||
580 | lua_rawget(L, -2); | ||
581 | if (lua_isnil(L, -1)) { /* no such field? */ | ||
582 | lua_pop(L, 1); /* remove this nil */ | ||
583 | lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ | ||
584 | lua_pushlstring(L, fname, e - fname); | ||
585 | lua_pushvalue(L, -2); | ||
586 | lua_settable(L, -4); /* set new table into field */ | ||
587 | } | ||
588 | else if (!lua_istable(L, -1)) { /* field has a non-table value? */ | ||
589 | lua_pop(L, 2); /* remove table and value */ | ||
590 | return fname; /* return problematic part of the name */ | ||
591 | } | ||
592 | lua_remove(L, -2); /* remove previous table */ | ||
593 | fname = e + 1; | ||
594 | } while (*e == '.'); | ||
595 | return NULL; | ||
596 | } | ||
578 | 597 | ||
579 | 598 | ||
580 | static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { | 599 | static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { |