Removing unwanted "static" attribute in "luaL_reg *lib". Using it
[tools/librpm-tizen.git] / rpmio / rpmlua.c
1 /*@-bounds -realcompare -sizeoftype @*/
2 #include "system.h"
3 #include <rpmio.h>
4 #include <rpmmacro.h>
5 #include <rpmerr.h>
6 #include <rpmurl.h>
7
8 #include <lua.h>
9 #include <lualib.h>
10 #include <lauxlib.h>
11 #include <lposix.h>
12 #include <lrexlib.h>
13
14 #include <unistd.h>
15 #include <assert.h>
16
17 #define _RPMLUA_INTERNAL
18 #include "rpmlua.h"
19
20 #include "debug.h"
21
22 #if !defined(HAVE_VSNPRINTF)
23 static inline int vsnprintf(char * buf, /*@unused@*/ int nb,
24                             const char * fmt, va_list ap)
25 {
26     return vsprintf(buf, fmt, ap);
27 }
28 #endif
29
30 static int luaopen_rpm(lua_State *L)
31         /*@modifies L @*/;
32 static int rpm_print(lua_State *L)
33         /*@globals fileSystem @*/
34         /*@modifies L, fileSystem @*/;
35
36 rpmlua rpmluaNew()
37 {
38     rpmlua lua = (rpmlua) xcalloc(1, sizeof(*lua));
39     lua_State *L = lua_open();
40     /*@-readonlytrans@*/
41     /*@observer@*/ /*@unchecked@*/
42     static const luaL_reg lualibs[] = {
43         {"base", luaopen_base},
44         {"table", luaopen_table},
45         {"io", luaopen_io},
46         {"string", luaopen_string},
47         {"debug", luaopen_debug},
48         {"loadlib", luaopen_loadlib},
49         {"posix", luaopen_posix},
50         {"rex", luaopen_rex},
51         {"rpm", luaopen_rpm},
52         {NULL, NULL},
53     };
54     /*@observer@*/ /*@unchecked@*/
55     const luaL_reg *lib = lualibs;
56     /*@=readonlytrans@*/
57
58     lua->L = L;
59     for (; lib->name; lib++) {
60         (void) lib->func(L);
61         lua_settop(L, 0);
62     }
63     lua_pushliteral(L, "LUA_PATH");
64     lua_pushstring(L, RPMCONFIGDIR "/lua/?.lua");
65     lua_rawset(L, LUA_GLOBALSINDEX);
66     lua_pushliteral(L, "print");
67     lua_pushcfunction(L, rpm_print);
68     lua_rawset(L, LUA_GLOBALSINDEX);
69     rpmluaSetData(lua, "lua", lua);
70     return lua;
71 }
72
73 void *rpmluaFree(rpmlua lua)
74 {
75     if (lua) {
76         if (lua->L) lua_close(lua->L);
77         free(lua->printbuf);
78         free(lua);
79     }
80     return NULL;
81 }
82
83 void rpmluaSetData(rpmlua lua, const char *key, const void *data)
84 {
85     lua_State *L = lua->L;
86     lua_pushliteral(L, "rpm_");
87     lua_pushstring(L, key);
88     lua_concat(L, 2);
89     if (data == NULL)
90         lua_pushnil(L);
91     else
92         lua_pushlightuserdata(L, (void *)data);
93     lua_rawset(L, LUA_REGISTRYINDEX);
94 }
95
96 static void *getdata(lua_State *L, const char *key)
97         /*@modifies L @*/
98 {
99     void *ret = NULL;
100     lua_pushliteral(L, "rpm_");
101     lua_pushstring(L, key);
102     lua_concat(L, 2);
103     lua_rawget(L, LUA_REGISTRYINDEX);
104 /*@-branchstate@*/
105     if (lua_islightuserdata(L, -1))
106         ret = lua_touserdata(L, -1);
107 /*@=branchstate@*/
108     lua_pop(L, 1);
109     return ret;
110 }
111
112 void *rpmluaGetData(rpmlua lua, const char *key)
113 {
114     return getdata(lua->L, key);
115 }
116
117 void rpmluaSetPrintBuffer(rpmlua lua, int flag)
118 {
119     lua->storeprint = flag;
120     free(lua->printbuf);
121     lua->printbuf = NULL;
122     lua->printbufsize = 0;
123 }
124
125 const char *rpmluaGetPrintBuffer(rpmlua lua)
126 {
127     return lua->printbuf;
128 }
129
130 static int pushvar(lua_State *L, rpmluavType type, void *value)
131         /*@modifies L @*/
132 {
133     int ret = 0;
134     switch (type) {
135         case RPMLUAV_NIL:
136             lua_pushnil(L);
137             break;
138         case RPMLUAV_STRING:
139             lua_pushstring(L, *((char **)value));
140             break;
141         case RPMLUAV_NUMBER:
142             lua_pushnumber(L, *((double *)value));
143             break;
144         default:
145             ret = -1;
146             break;
147     }
148     return ret;
149 }
150
151 void rpmluaSetVar(rpmlua lua, rpmluav var)
152 {
153     lua_State *L = lua->L;
154     if (var->listmode && lua->pushsize > 0) {
155         if (var->keyType != RPMLUAV_NUMBER || var->key.num == (double)0) {
156             var->keyType = RPMLUAV_NUMBER;
157             var->key.num = (double) luaL_getn(L, -1);
158         }
159         var->key.num++;
160     }
161     if (!var->listmode || lua->pushsize > 0) {
162         if (lua->pushsize == 0)
163             lua_pushvalue(L, LUA_GLOBALSINDEX);
164         if (pushvar(L, var->keyType, &var->key) != -1) {
165             if (pushvar(L, var->valueType, &var->value) != -1)
166                 lua_rawset(L, -3);
167             else
168                 lua_pop(L, 1);
169         }
170         if (lua->pushsize == 0)
171             lua_pop(L, 1);
172     }
173 }
174
175 static void popvar(lua_State *L, rpmluavType *type, void *value)
176         /*@modifies L, *type, *value @*/
177 {
178     switch (lua_type(L, -1)) {
179     case LUA_TSTRING:
180         *type = RPMLUAV_STRING;
181 /*@-observertrans -dependenttrans @*/
182         *((const char **)value) = lua_tostring(L, -1);
183 /*@=observertrans =dependenttrans @*/
184         break;
185     case LUA_TNUMBER:
186         *type = RPMLUAV_NUMBER;
187         *((double *)value) = lua_tonumber(L, -1);
188         break;
189     default:
190         *type = RPMLUAV_NIL;
191         *((void **)value) = NULL;
192         break;
193     }
194     lua_pop(L, 1);
195 }
196
197 void rpmluaGetVar(rpmlua lua, rpmluav var)
198 {
199     lua_State *L = lua->L;
200     if (!var->listmode) {
201         if (lua->pushsize == 0)
202             lua_pushvalue(L, LUA_GLOBALSINDEX);
203         if (pushvar(L, var->keyType, &var->key) != -1) {
204             lua_rawget(L, -2);
205             popvar(L, &var->valueType, &var->value);
206         }
207         if (lua->pushsize == 0)
208             lua_pop(L, 1);
209     } else if (lua->pushsize > 0) {
210         (void) pushvar(L, var->keyType, &var->key);
211         if (lua_next(L, -2) != 0)
212             popvar(L, &var->valueType, &var->value);
213     }
214 }
215
216 #define FINDKEY_RETURN 0
217 #define FINDKEY_CREATE 1
218 #define FINDKEY_REMOVE 2
219 static int findkey(lua_State *L, int oper, const char *key, va_list va)
220         /*@modifies L @*/
221 {
222     char buf[BUFSIZ];
223     const char *s, *e;
224     int ret = 0;
225     (void) vsnprintf(buf, BUFSIZ, key, va);
226     s = e = buf;
227     lua_pushvalue(L, LUA_GLOBALSINDEX);
228     for (;;) {
229         if (*e == '\0' || *e == '.') {
230             if (e != s) {
231                 lua_pushlstring(L, s, e-s);
232                 switch (oper) {
233                 case FINDKEY_REMOVE:
234                     if (*e == '\0') {
235                         lua_pushnil(L);
236                         lua_rawset(L, -3);
237                         lua_pop(L, 1);
238                         /*@switchbreak@*/ break;
239                     }
240                     /*@fallthrough@*/
241                 case FINDKEY_RETURN:
242                     lua_rawget(L, -2);
243                     lua_remove(L, -2);
244                     /*@switchbreak@*/ break;
245                 case FINDKEY_CREATE:
246                     lua_rawget(L, -2);
247                     if (!lua_istable(L, -1)) {
248                         lua_pop(L, 1);
249                         lua_newtable(L);
250                         lua_pushlstring(L, s, e-s);
251                         lua_pushvalue(L, -2);
252                         lua_rawset(L, -4);
253                     }
254                     lua_remove(L, -2);
255                     /*@switchbreak@*/ break;
256                 }
257             }
258             if (*e == '\0')
259                 break;
260             if (!lua_istable(L, -1)) {
261                 lua_pop(L, 1);
262                 ret = -1;
263                 break;
264             }
265             s = e+1;
266         }
267         e++;
268     }
269
270     return ret;
271 }
272
273 void rpmluaDelVar(rpmlua lua, const char *key, ...)
274 {
275     va_list va;
276     va_start(va, key);
277     (void) findkey(lua->L, FINDKEY_REMOVE, key, va);
278     va_end(va);
279 }
280
281 int rpmluaVarExists(rpmlua lua, const char *key, ...)
282 {
283     int ret = 0;
284     va_list va;
285     va_start(va, key);
286     if (findkey(lua->L, FINDKEY_RETURN, key, va) == 0) {
287         if (!lua_isnil(lua->L, -1))
288             ret = 1;
289         lua_pop(lua->L, 1);
290     }
291     va_end(va);
292     return ret;
293 }
294
295 void rpmluaPushTable(rpmlua lua, const char *key, ...)
296 {
297     va_list va;
298     va_start(va, key);
299     (void) findkey(lua->L, FINDKEY_CREATE, key, va);
300     lua->pushsize++;
301     va_end(va);
302 }
303
304 void rpmluaPop(rpmlua lua)
305 {
306     assert(lua->pushsize > 0);
307     lua->pushsize--;
308     lua_pop(lua->L, 1);
309 }
310
311 rpmluav rpmluavNew(void)
312 {
313     rpmluav var = (rpmluav) xcalloc(1, sizeof(*var));
314     return var;
315 }
316
317 void *rpmluavFree(rpmluav var)
318 {
319     free(var);
320     return NULL;
321 }
322
323 void rpmluavSetListMode(rpmluav var, int flag)
324 {
325     var->listmode = flag;
326     var->keyType = RPMLUAV_NIL;
327 }
328
329 void rpmluavSetKey(rpmluav var, rpmluavType type, const void *value)
330 {
331     var->keyType = type;
332 /*@-assignexpose -branchstate -temptrans @*/
333     switch (type) {
334         case RPMLUAV_NUMBER:
335             var->key.num = *((double *)value);
336             break;
337         case RPMLUAV_STRING:
338             var->key.str = (char *)value;
339             break;
340         default:
341             break;
342     }
343 /*@=assignexpose =branchstate =temptrans @*/
344 }
345
346 void rpmluavSetValue(rpmluav var, rpmluavType type, const void *value)
347 {
348     var->valueType = type;
349 /*@-assignexpose -branchstate -temptrans @*/
350     switch (type) {
351         case RPMLUAV_NUMBER:
352             var->value.num = *((const double *)value);
353             break;
354         case RPMLUAV_STRING:
355             var->value.str = (const char *)value;
356             break;
357         default:
358             break;
359     }
360 /*@=assignexpose =branchstate =temptrans @*/
361 }
362
363 void rpmluavGetKey(rpmluav var, rpmluavType *type, void **value)
364 {
365     *type = var->keyType;
366 /*@-onlytrans@*/
367     switch (var->keyType) {
368         case RPMLUAV_NUMBER:
369             *((double **)value) = &var->key.num;
370             break;
371         case RPMLUAV_STRING:
372             *((const char **)value) = var->key.str;
373             break;
374         default:
375             break;
376     }
377 /*@=onlytrans@*/
378 }
379
380 void rpmluavGetValue(rpmluav var, rpmluavType *type, void **value)
381 {
382     *type = var->valueType;
383 /*@-onlytrans@*/
384     switch (var->valueType) {
385         case RPMLUAV_NUMBER:
386             *((double **)value) = &var->value.num;
387             break;
388         case RPMLUAV_STRING:
389             *((const char **)value) = var->value.str;
390             break;
391         default:
392             break;
393     }
394 /*@=onlytrans@*/
395 }
396
397 void rpmluavSetKeyNum(rpmluav var, double value)
398 {
399     rpmluavSetKey(var, RPMLUAV_NUMBER, &value);
400 }
401
402 void rpmluavSetValueNum(rpmluav var, double value)
403 {
404     rpmluavSetValue(var, RPMLUAV_NUMBER, &value);
405 }
406
407 double rpmluavGetKeyNum(rpmluav var)
408 {
409     rpmluavType type;
410     void *value;
411     rpmluavGetKey(var, &type, &value);
412     if (type == RPMLUAV_NUMBER)
413         return *((double *)value);
414     return (double) 0;
415 }
416
417 double rpmluavGetValueNum(rpmluav var)
418 {
419     rpmluavType type;
420     void *value;
421     rpmluavGetValue(var, &type, &value);
422     if (type == RPMLUAV_NUMBER)
423         return *((double *)value);
424     return (double) 0;
425 }
426
427 int rpmluavKeyIsNum(rpmluav var)
428 {
429     return (var->keyType == RPMLUAV_NUMBER) ? 1 : 0;
430 }
431
432 int rpmluavValueIsNum(rpmluav var)
433 {
434     return (var->valueType == RPMLUAV_NUMBER) ? 1 : 0;
435 }
436
437 int rpmluaCheckScript(rpmlua lua, const char *script, const char *name)
438 {
439     lua_State *L = lua->L;
440     int ret = 0;
441 /*@-branchstate@*/
442     if (name == NULL)
443         name = "<lua>";
444 /*@=branchstate@*/
445     if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
446         rpmError(RPMERR_SCRIPT,
447                 _("invalid syntax in lua scriptlet: %s\n"),
448                   lua_tostring(L, -1));
449         ret = -1;
450     }
451     lua_pop(L, 1); /* Error or chunk. */
452     return ret;
453 }
454
455 int rpmluaRunScript(rpmlua lua, const char *script, const char *name)
456 {
457     lua_State *L = lua->L;
458     int ret = 0;
459 /*@-branchstate@*/
460     if (name == NULL)
461         name = "<lua>";
462 /*@=branchstate@*/
463     if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
464         rpmError(RPMERR_SCRIPT, _("invalid syntax in lua script: %s\n"),
465                  lua_tostring(L, -1));
466         lua_pop(L, 1);
467         ret = -1;
468     } else if (lua_pcall(L, 0, 0, 0) != 0) {
469         rpmError(RPMERR_SCRIPT, _("lua script failed: %s\n"),
470                  lua_tostring(L, -1));
471         lua_pop(L, 1);
472         ret = -1;
473     }
474     return ret;
475 }
476
477 /* From lua.c */
478 static int rpmluaReadline(lua_State *L, const char *prompt)
479         /*@globals fileSystem @*/
480         /*@modifies L, fileSystem @*/
481 {
482    static char buffer[1024];
483    if (prompt) {
484       (void) fputs(prompt, stdout);
485       (void) fflush(stdout);
486    }
487    if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
488       return 0;  /* read fails */
489    } else {
490       lua_pushstring(L, buffer);
491       return 1;
492    }
493 }
494
495 /* Based on lua.c */
496 static void _rpmluaInteractive(lua_State *L)
497         /*@globals fileSystem @*/
498         /*@modifies L, fileSystem @*/
499 {
500    (void) fputs("\n", stdout);
501    printf("RPM Interactive %s Interpreter\n", LUA_VERSION);
502    for (;;) {
503       int rc = 0;
504
505       if (rpmluaReadline(L, "> ") == 0)
506          break;
507       if (lua_tostring(L, -1)[0] == '=') {
508 /*@-evalorder@*/
509          (void) lua_pushfstring(L, "print(%s)", lua_tostring(L, -1)+1);
510 /*@=evalorder@*/
511          lua_remove(L, -2);
512       }
513       for (;;) {
514 /*@-evalorder@*/
515          rc = luaL_loadbuffer(L, lua_tostring(L, -1),
516                               lua_strlen(L, -1), "<lua>");
517 /*@=evalorder@*/
518          if (rc == LUA_ERRSYNTAX &&
519              strstr(lua_tostring(L, -1), "near `<eof>'") != NULL) {
520             if (rpmluaReadline(L, ">> ") == 0)
521                /*@innerbreak@*/ break;
522             lua_remove(L, -2); /* Remove error */
523             lua_concat(L, 2);
524             /*@innercontinue@*/ continue;
525          }
526          /*@innerbreak@*/ break;
527       }
528       if (rc == 0)
529          rc = lua_pcall(L, 0, 0, 0);
530       if (rc != 0) {
531          fprintf(stderr, "%s\n", lua_tostring(L, -1));
532          lua_pop(L, 1);
533       }
534       lua_pop(L, 1); /* Remove line */
535    }
536    (void) fputs("\n", stdout);
537 }
538
539 void rpmluaInteractive(rpmlua lua)
540 {
541     _rpmluaInteractive(lua->L);
542 }
543
544 /* ------------------------------------------------------------------ */
545 /* Lua API */
546
547 static int rpm_expand(lua_State *L)
548         /*@globals rpmGlobalMacroContext, h_errno @*/
549         /*@modifies L, rpmGlobalMacroContext @*/
550 {
551     const char *str = luaL_checkstring(L, 1);
552     lua_pushstring(L, rpmExpand(str, NULL));
553     return 1;
554 }
555
556 static int rpm_define(lua_State *L)
557         /*@globals rpmGlobalMacroContext, h_errno @*/
558         /*@modifies L, rpmGlobalMacroContext @*/
559 {
560     const char *str = luaL_checkstring(L, 1);
561     (void) rpmDefineMacro(NULL, str, 0);
562     return 0;
563 }
564
565 static int rpm_interactive(lua_State *L)
566         /*@globals fileSystem @*/
567         /*@modifies L, fileSystem @*/
568 {
569     _rpmluaInteractive(L);
570     return 0;
571 }
572
573 /* Based on luaB_print. */
574 static int rpm_print (lua_State *L)
575         /*@globals fileSystem @*/
576         /*@modifies L, fileSystem @*/
577 {
578     rpmlua lua = (rpmlua)getdata(L, "lua");
579     int n = lua_gettop(L);  /* number of arguments */
580     int i;
581     if (!lua) return 0;
582     lua_getglobal(L, "tostring");
583     for (i = 1; i <= n; i++) {
584         const char *s;
585         lua_pushvalue(L, -1);  /* function to be called */
586         lua_pushvalue(L, i);   /* value to print */
587         lua_call(L, 1, 1);
588         s = lua_tostring(L, -1);  /* get result */
589         if (s == NULL)
590             return luaL_error(L, "`tostring' must return a string to `print'");
591         if (lua->storeprint) {
592             int sl = lua_strlen(L, -1);
593             if (lua->printbufused+sl+1 > lua->printbufsize) {
594                 lua->printbufsize += sl+512;
595                 lua->printbuf = xrealloc(lua->printbuf, lua->printbufsize);
596             }
597             if (i > 1)
598                 lua->printbuf[lua->printbufused++] = '\t';
599             memcpy(lua->printbuf+lua->printbufused, s, sl+1);
600             lua->printbufused += sl;
601         } else {
602             if (i > 1)
603                 (void) fputs("\t", stdout);
604             (void) fputs(s, stdout);
605         }
606         lua_pop(L, 1);  /* pop result */
607     }
608     lua_pop(L, 1);
609     if (!lua->storeprint) {
610         (void) fputs("\n", stdout);
611     } else {
612         if (lua->printbufused+1 >= lua->printbufsize) {
613             lua->printbufsize += 512;
614             lua->printbuf = xrealloc(lua->printbuf, lua->printbufsize);
615         }
616         lua->printbuf[lua->printbufused++] = '\n';
617         lua->printbuf[lua->printbufused] = '\0';
618     }
619     return 0;
620 }
621
622 /*@-readonlytrans@*/
623 /*@observer@*/ /*@unchecked@*/
624 static const luaL_reg rpmlib[] = {
625     {"expand", rpm_expand},
626     {"define", rpm_define},
627     {"interactive", rpm_interactive},
628     {NULL, NULL}
629 };
630 /*@=readonlytrans@*/
631
632 static int luaopen_rpm(lua_State *L)
633         /*@modifies L @*/
634 {
635     lua_pushvalue(L, LUA_GLOBALSINDEX);
636     luaL_openlib(L, "rpm", rpmlib, 0);
637     return 0;
638 }
639 /*@=bounds =realcompare =sizeoftype @*/