cf45ff1abeaf159febf8bafa117f6efee76ff771
[olsrd.git] / lib / tas / src / lua / lauxlib.c
1
2 /*
3 ** $Id: lauxlib.c,v 1.100 2003/04/07 14:35:00 roberto Exp $
4 ** Auxiliary functions for building Lua libraries
5 ** See Copyright Notice in lua.h
6 */
7
8
9 #include <ctype.h>
10 #include <errno.h>
11 #include <stdarg.h>
12 #include <stdio.h>
13 #include <string.h>
14
15
16 /* This file uses only the official API of Lua.
17 ** Any function declared here could be written as an application function.
18 */
19
20 #define lauxlib_c
21
22 #include "lua.h"
23
24 #include "lauxlib.h"
25
26
27 /* number of prereserved references (for internal use) */
28 #define RESERVED_REFS   2
29
30 /* reserved references */
31 #define FREELIST_REF    1       /* free list of references */
32 #define ARRAYSIZE_REF   2       /* array sizes */
33
34
35 /* convert a stack index to positive */
36 #define abs_index(L, i)         ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
37                                         lua_gettop(L) + (i) + 1)
38
39
40 /*
41 ** {======================================================
42 ** Error-report functions
43 ** =======================================================
44 */
45
46
47 LUALIB_API int
48 luaL_argerror(lua_State * L, int narg, const char *extramsg)
49 {
50   lua_Debug ar;
51   lua_getstack(L, 0, &ar);
52   lua_getinfo(L, "n", &ar);
53   if (strcmp(ar.namewhat, "method") == 0) {
54     narg--;                     /* do not count `self' */
55     if (narg == 0)              /* error is in the self argument itself? */
56       luaL_error(L, "calling `%s' on bad self (%s)", ar.name, extramsg);
57   }
58   if (ar.name == NULL)
59     ar.name = "?";
60   luaL_error(L, "bad argument #%d to `%s' (%s)", narg, ar.name, extramsg);
61 }
62
63
64 LUALIB_API int
65 luaL_typerror(lua_State * L, int narg, const char *tname)
66 {
67   const char *msg = lua_pushfstring(L, "%s expected, got %s",
68                                     tname, lua_typename(L, lua_type(L, narg)));
69   luaL_argerror(L, narg, msg);
70 }
71
72
73 static void tag_error(lua_State * L, int narg, int tag) __attribute__ ((noreturn));
74 static void
75 tag_error(lua_State * L, int narg, int tag)
76 {
77   luaL_typerror(L, narg, lua_typename(L, tag));
78 }
79
80
81 LUALIB_API void
82 luaL_where(lua_State * L, int level)
83 {
84   lua_Debug ar;
85   if (lua_getstack(L, level, &ar)) {    /* check function at level */
86     lua_getinfo(L, "Snl", &ar); /* get info about it */
87     if (ar.currentline > 0) {   /* is there info? */
88       lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
89       return;
90     }
91   }
92   lua_pushliteral(L, "");       /* else, no information available... */
93 }
94
95
96 LUALIB_API int
97 luaL_error(lua_State * L, const char *fmt, ...)
98 {
99   va_list argp;
100   va_start(argp, fmt);
101   luaL_where(L, 1);
102   lua_pushvfstring(L, fmt, argp);
103   va_end(argp);
104   lua_concat(L, 2);
105   lua_error(L);
106 }
107
108 /* }====================================================== */
109
110
111 LUALIB_API int
112 luaL_findstring(const char *name, const char *const list[])
113 {
114   int i;
115   for (i = 0; list[i]; i++)
116     if (strcmp(list[i], name) == 0)
117       return i;
118   return -1;                    /* name not found */
119 }
120
121
122 LUALIB_API int
123 luaL_newmetatable(lua_State * L, const char *tname)
124 {
125   lua_pushstring(L, tname);
126   lua_rawget(L, LUA_REGISTRYINDEX);     /* get registry.name */
127   if (!lua_isnil(L, -1))        /* name already in use? */
128     return 0;                   /* leave previous value on top, but return 0 */
129   lua_pop(L, 1);
130   lua_newtable(L);              /* create metatable */
131   lua_pushstring(L, tname);
132   lua_pushvalue(L, -2);
133   lua_rawset(L, LUA_REGISTRYINDEX);     /* registry.name = metatable */
134   lua_pushvalue(L, -1);
135   lua_pushstring(L, tname);
136   lua_rawset(L, LUA_REGISTRYINDEX);     /* registry[metatable] = name */
137   return 1;
138 }
139
140
141 LUALIB_API void
142 luaL_getmetatable(lua_State * L, const char *tname)
143 {
144   lua_pushstring(L, tname);
145   lua_rawget(L, LUA_REGISTRYINDEX);
146 }
147
148
149 LUALIB_API void *
150 luaL_checkudata(lua_State * L, int ud, const char *tname)
151 {
152   const char *tn;
153   if (!lua_getmetatable(L, ud))
154     return NULL;                /* no metatable? */
155   lua_rawget(L, LUA_REGISTRYINDEX);     /* get registry[metatable] */
156   tn = lua_tostring(L, -1);
157   if (tn && (strcmp(tn, tname) == 0)) {
158     lua_pop(L, 1);
159     return lua_touserdata(L, ud);
160   } else {
161     lua_pop(L, 1);
162     return NULL;
163   }
164 }
165
166
167 LUALIB_API void
168 luaL_checkstack(lua_State * L, int space, const char *mes)
169 {
170   if (!lua_checkstack(L, space))
171     luaL_error(L, "stack overflow (%s)", mes);
172 }
173
174
175 LUALIB_API void
176 luaL_checktype(lua_State * L, int narg, int t)
177 {
178   if (lua_type(L, narg) != t)
179     tag_error(L, narg, t);
180 }
181
182
183 LUALIB_API void
184 luaL_checkany(lua_State * L, int narg)
185 {
186   if (lua_type(L, narg) == LUA_TNONE)
187     luaL_argerror(L, narg, "value expected");
188 }
189
190
191 LUALIB_API const char *
192 luaL_checklstring(lua_State * L, int narg, size_t * len)
193 {
194   const char *s = lua_tostring(L, narg);
195   if (!s)
196     tag_error(L, narg, LUA_TSTRING);
197   if (len)
198     *len = lua_strlen(L, narg);
199   return s;
200 }
201
202
203 LUALIB_API const char *
204 luaL_optlstring(lua_State * L, int narg, const char *def, size_t * len)
205 {
206   if (lua_isnoneornil(L, narg)) {
207     if (len)
208       *len = (def ? strlen(def) : 0);
209     return def;
210   } else
211     return luaL_checklstring(L, narg, len);
212 }
213
214
215 LUALIB_API lua_Number
216 luaL_checknumber(lua_State * L, int narg)
217 {
218   lua_Number d = lua_tonumber(L, narg);
219   if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
220     tag_error(L, narg, LUA_TNUMBER);
221   return d;
222 }
223
224
225 LUALIB_API lua_Number
226 luaL_optnumber(lua_State * L, int narg, lua_Number def)
227 {
228   if (lua_isnoneornil(L, narg))
229     return def;
230   else
231     return luaL_checknumber(L, narg);
232 }
233
234
235 LUALIB_API int
236 luaL_getmetafield(lua_State * L, int obj, const char *event)
237 {
238   if (!lua_getmetatable(L, obj))        /* no metatable? */
239     return 0;
240   lua_pushstring(L, event);
241   lua_rawget(L, -2);
242   if (lua_isnil(L, -1)) {
243     lua_pop(L, 2);              /* remove metatable and metafield */
244     return 0;
245   } else {
246     lua_remove(L, -2);          /* remove only metatable */
247     return 1;
248   }
249 }
250
251
252 LUALIB_API int
253 luaL_callmeta(lua_State * L, int obj, const char *event)
254 {
255   obj = abs_index(L, obj);
256   if (!luaL_getmetafield(L, obj, event))        /* no metafield? */
257     return 0;
258   lua_pushvalue(L, obj);
259   lua_call(L, 1, 1);
260   return 1;
261 }
262
263
264 LUALIB_API void
265 luaL_openlib(lua_State * L, const char *libname, const luaL_reg * l, int nup)
266 {
267   if (libname) {
268     lua_pushstring(L, libname);
269     lua_gettable(L, LUA_GLOBALSINDEX);  /* check whether lib already exists */
270     if (lua_isnil(L, -1)) {     /* no? */
271       lua_pop(L, 1);
272       lua_newtable(L);          /* create it */
273       lua_pushstring(L, libname);
274       lua_pushvalue(L, -2);
275       lua_settable(L, LUA_GLOBALSINDEX);        /* register it with given name */
276     }
277     lua_insert(L, -(nup + 1));  /* move library table to below upvalues */
278   }
279   for (; l->name; l++) {
280     int i;
281     lua_pushstring(L, l->name);
282     for (i = 0; i < nup; i++)   /* copy upvalues to the top */
283       lua_pushvalue(L, -(nup + 1));
284     lua_pushcclosure(L, l->func, nup);
285     lua_settable(L, -(nup + 3));
286   }
287   lua_pop(L, nup);              /* remove upvalues */
288 }
289
290
291
292 /*
293 ** {======================================================
294 ** getn-setn: size for arrays
295 ** =======================================================
296 */
297
298 static int
299 checkint(lua_State * L, int topop)
300 {
301   int n = lua_tonumber(L, -1);
302   if (n == 0 && !lua_isnumber(L, -1))
303     n = -1;
304   lua_pop(L, topop);
305   return n;
306 }
307
308
309 static void
310 getsizes(lua_State * L)
311 {
312   lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF);
313   if (lua_isnil(L, -1)) {       /* no `size' table? */
314     lua_pop(L, 1);              /* remove nil */
315     lua_newtable(L);            /* create it */
316     lua_pushvalue(L, -1);       /* `size' will be its own metatable */
317     lua_setmetatable(L, -2);
318     lua_pushliteral(L, "__mode");
319     lua_pushliteral(L, "k");
320     lua_rawset(L, -3);          /* metatable(N).__mode = "k" */
321     lua_pushvalue(L, -1);
322     lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF);   /* store in register */
323   }
324 }
325
326
327 void
328 luaL_setn(lua_State * L, int t, int n)
329 {
330   t = abs_index(L, t);
331   lua_pushliteral(L, "n");
332   lua_rawget(L, t);
333   if (checkint(L, 1) >= 0) {    /* is there a numeric field `n'? */
334     lua_pushliteral(L, "n");    /* use it */
335     lua_pushnumber(L, (lua_Number) n);
336     lua_rawset(L, t);
337   } else {                      /* use `sizes' */
338     getsizes(L);
339     lua_pushvalue(L, t);
340     lua_pushnumber(L, (lua_Number) n);
341     lua_rawset(L, -3);          /* sizes[t] = n */
342     lua_pop(L, 1);              /* remove `sizes' */
343   }
344 }
345
346
347 int
348 luaL_getn(lua_State * L, int t)
349 {
350   int n;
351   t = abs_index(L, t);
352   lua_pushliteral(L, "n");      /* try t.n */
353   lua_rawget(L, t);
354   if ((n = checkint(L, 1)) >= 0)
355     return n;
356   getsizes(L);                  /* else try sizes[t] */
357   lua_pushvalue(L, t);
358   lua_rawget(L, -2);
359   if ((n = checkint(L, 2)) >= 0)
360     return n;
361   for (n = 1;; n++) {           /* else must count elements */
362     lua_rawgeti(L, t, n);
363     if (lua_isnil(L, -1))
364       break;
365     lua_pop(L, 1);
366   }
367   lua_pop(L, 1);
368   return n - 1;
369 }
370
371 /* }====================================================== */
372
373
374
375 /*
376 ** {======================================================
377 ** Generic Buffer manipulation
378 ** =======================================================
379 */
380
381
382 #define bufflen(B)      ((B)->p - (B)->buffer)
383 #define bufffree(B)     ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
384
385 #define LIMIT   (LUA_MINSTACK/2)
386
387
388 static int
389 emptybuffer(luaL_Buffer * B)
390 {
391   size_t l = bufflen(B);
392   if (l == 0)
393     return 0;                   /* put nothing on stack */
394   else {
395     lua_pushlstring(B->L, B->buffer, l);
396     B->p = B->buffer;
397     B->lvl++;
398     return 1;
399   }
400 }
401
402
403 static void
404 adjuststack(luaL_Buffer * B)
405 {
406   if (B->lvl > 1) {
407     lua_State *L = B->L;
408     int toget = 1;                     /* number of levels to concat */
409     size_t toplen = lua_strlen(L, -1);
410     do {
411       size_t l = lua_strlen(L, -(toget + 1));
412       if (B->lvl - toget + 1 >= LIMIT || toplen > l) {
413         toplen += l;
414         toget++;
415       } else
416         break;
417     } while (toget < B->lvl);
418     lua_concat(L, toget);
419     B->lvl = B->lvl - toget + 1;
420   }
421 }
422
423
424 LUALIB_API char *
425 luaL_prepbuffer(luaL_Buffer * B)
426 {
427   if (emptybuffer(B))
428     adjuststack(B);
429   return B->buffer;
430 }
431
432
433 LUALIB_API void
434 luaL_addlstring(luaL_Buffer * B, const char *s, size_t l)
435 {
436   while (l--)
437     luaL_putchar(B, *s++);
438 }
439
440
441 LUALIB_API void
442 luaL_addstring(luaL_Buffer * B, const char *s)
443 {
444   luaL_addlstring(B, s, strlen(s));
445 }
446
447
448 LUALIB_API void
449 luaL_pushresult(luaL_Buffer * B)
450 {
451   emptybuffer(B);
452   lua_concat(B->L, B->lvl);
453   B->lvl = 1;
454 }
455
456
457 LUALIB_API void
458 luaL_addvalue(luaL_Buffer * B)
459 {
460   lua_State *L = B->L;
461   size_t vl = lua_strlen(L, -1);
462   if (vl <= bufffree(B)) {      /* fit into buffer? */
463     memcpy(B->p, lua_tostring(L, -1), vl);      /* put it there */
464     B->p += vl;
465     lua_pop(L, 1);              /* remove from stack */
466   } else {
467     if (emptybuffer(B))
468       lua_insert(L, -2);        /* put buffer before new value */
469     B->lvl++;                   /* add new value into B stack */
470     adjuststack(B);
471   }
472 }
473
474
475 LUALIB_API void
476 luaL_buffinit(lua_State * L, luaL_Buffer * B)
477 {
478   B->L = L;
479   B->p = B->buffer;
480   B->lvl = 0;
481 }
482
483 /* }====================================================== */
484
485
486 LUALIB_API int
487 luaL_ref(lua_State * L, int t)
488 {
489   int ref;
490   t = abs_index(L, t);
491   if (lua_isnil(L, -1)) {
492     lua_pop(L, 1);              /* remove from stack */
493     return LUA_REFNIL;          /* `nil' has a unique fixed reference */
494   }
495   lua_rawgeti(L, t, FREELIST_REF);      /* get first free element */
496   ref = lua_tonumber(L, -1);    /* ref = t[FREELIST_REF] */
497   lua_pop(L, 1);                /* remove it from stack */
498   if (ref != 0) {               /* any free element? */
499     lua_rawgeti(L, t, ref);     /* remove it from list */
500     lua_rawseti(L, t, FREELIST_REF);    /* (t[FREELIST_REF] = t[ref]) */
501   } else {                      /* no free elements */
502     ref = luaL_getn(L, t);
503     if (ref < RESERVED_REFS)
504       ref = RESERVED_REFS;      /* skip reserved references */
505     ref++;                      /* create new reference */
506     luaL_setn(L, t, ref);
507   }
508   lua_rawseti(L, t, ref);
509   return ref;
510 }
511
512
513 LUALIB_API void
514 luaL_unref(lua_State * L, int t, int ref)
515 {
516   if (ref >= 0) {
517     t = abs_index(L, t);
518     lua_rawgeti(L, t, FREELIST_REF);
519     lua_rawseti(L, t, ref);     /* t[ref] = t[FREELIST_REF] */
520     lua_pushnumber(L, (lua_Number) ref);
521     lua_rawseti(L, t, FREELIST_REF);    /* t[FREELIST_REF] = ref */
522   }
523 }
524
525
526
527 /*
528 ** {======================================================
529 ** Load functions
530 ** =======================================================
531 */
532
533 typedef struct LoadF {
534   FILE *f;
535   char buff[LUAL_BUFFERSIZE];
536 } LoadF;
537
538
539 static const char *
540 getF(lua_State * L, void *ud, size_t * size)
541 {
542   LoadF *lf = (LoadF *) ud;
543   (void)L;
544   if (feof(lf->f))
545     return NULL;
546   *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f);
547   return (*size > 0) ? lf->buff : NULL;
548 }
549
550
551 static int
552 errfile(lua_State * L, int fnameindex)
553 {
554   const char *filename = lua_tostring(L, fnameindex) + 1;
555   lua_pushfstring(L, "cannot read %s: %s", filename, strerror(errno));
556   lua_remove(L, fnameindex);
557   return LUA_ERRFILE;
558 }
559
560
561 LUALIB_API int
562 luaL_loadfile(lua_State * L, const char *filename)
563 {
564   LoadF lf;
565   int status, readstatus;
566   int c;
567   int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */
568   if (filename == NULL) {
569     lua_pushliteral(L, "=stdin");
570     lf.f = stdin;
571   } else {
572     lua_pushfstring(L, "@%s", filename);
573     lf.f = fopen(filename, "r");
574   }
575   if (lf.f == NULL)
576     return errfile(L, fnameindex);      /* unable to open file */
577   c = ungetc(getc(lf.f), lf.f);
578   if (!(isspace(c) || isprint(c)) && lf.f != stdin) {   /* binary file? */
579     fclose(lf.f);
580     lf.f = fopen(filename, "rb");       /* reopen in binary mode */
581     if (lf.f == NULL)
582       return errfile(L, fnameindex);    /* unable to reopen file */
583   }
584   status = lua_load(L, getF, &lf, lua_tostring(L, -1));
585   readstatus = ferror(lf.f);
586   if (lf.f != stdin)
587     fclose(lf.f);               /* close file (even in case of errors) */
588   if (readstatus) {
589     lua_settop(L, fnameindex);  /* ignore results from `lua_load' */
590     return errfile(L, fnameindex);
591   }
592   lua_remove(L, fnameindex);
593   return status;
594 }
595
596
597 typedef struct LoadS {
598   const char *s;
599   size_t size;
600 } LoadS;
601
602
603 static const char *
604 getS(lua_State * L, void *ud, size_t * size)
605 {
606   LoadS *ls = (LoadS *) ud;
607   (void)L;
608   if (ls->size == 0)
609     return NULL;
610   *size = ls->size;
611   ls->size = 0;
612   return ls->s;
613 }
614
615
616 LUALIB_API int
617 luaL_loadbuffer(lua_State * L, const char *buff, size_t size, const char *name)
618 {
619   LoadS ls;
620   ls.s = buff;
621   ls.size = size;
622   return lua_load(L, getS, &ls, name);
623 }
624
625 /* }====================================================== */
626
627
628 /*
629 ** {======================================================
630 ** compatibility code
631 ** =======================================================
632 */
633
634
635 static void
636 callalert(lua_State * L, int status)
637 {
638   if (status != 0) {
639     lua_getglobal(L, "_ALERT");
640     if (lua_isfunction(L, -1)) {
641       lua_insert(L, -2);
642       lua_call(L, 1, 0);
643     } else {                    /* no _ALERT function; print it on stderr */
644       fprintf(stderr, "%s\n", lua_tostring(L, -2));
645       lua_pop(L, 2);            /* remove error message and _ALERT */
646     }
647   }
648 }
649
650
651 static int
652 aux_do(lua_State * L, int status)
653 {
654   if (status == 0) {            /* parse OK? */
655     status = lua_pcall(L, 0, LUA_MULTRET, 0);   /* call main */
656   }
657   callalert(L, status);
658   return status;
659 }
660
661
662 LUALIB_API int
663 lua_dofile(lua_State * L, const char *filename)
664 {
665   return aux_do(L, luaL_loadfile(L, filename));
666 }
667
668
669 LUALIB_API int
670 lua_dobuffer(lua_State * L, const char *buff, size_t size, const char *name)
671 {
672   return aux_do(L, luaL_loadbuffer(L, buff, size, name));
673 }
674
675
676 LUALIB_API int
677 lua_dostring(lua_State * L, const char *str)
678 {
679   return lua_dobuffer(L, str, strlen(str), str);
680 }
681
682 /* }====================================================== */