[4.0] Use strip (instead of eu-strip) to support --strip-debug of *.so at build time
[platform/upstream/rpm.git] / rpmio / rpmlua.c
1 #include "system.h"
2
3 #ifdef  WITH_LUA
4 #include <lua.h>
5 #include <lualib.h>
6 #include <lauxlib.h>
7 #include <lposix.h>
8 #include <lrexlib.h>
9
10 #ifndef lua_open
11 #define lua_open()      luaL_newstate()
12 #endif
13
14 #ifndef lua_strlen
15 #define lua_strlen(L,i) lua_rawlen(L, (i))
16 #endif
17
18 #ifndef lua_pushglobaltable
19 #define lua_pushglobaltable(L)  lua_pushvalue(L, LUA_GLOBALSINDEX)
20 #endif
21
22 #include <unistd.h>
23 #include <assert.h>
24
25 #include <rpm/rpmio.h>
26 #include <rpm/rpmmacro.h>
27 #include <rpm/rpmlog.h>
28 #include <rpm/rpmurl.h>
29 #include <rpm/rpmfileutil.h>
30 #include <rpm/rpmbase64.h>
31 #include "rpmio/rpmhook.h"
32
33 #define _RPMLUA_INTERNAL
34 #include "rpmio/rpmlua.h"
35
36 #include "debug.h"
37
38 #define INITSTATE(_lua, lua) \
39     rpmlua lua = _lua ? _lua : \
40             (globalLuaState ? globalLuaState : \
41                         \
42                         (globalLuaState = rpmluaNew()) \
43                         \
44             )
45
46 struct rpmluapb_s {
47     size_t alloced;
48     size_t used;
49     char *buf;
50     rpmluapb next;
51 };
52
53 static rpmlua globalLuaState = NULL;
54
55 static int luaopen_rpm(lua_State *L);
56 static int rpm_print(lua_State *L);
57
58 rpmlua rpmluaGetGlobalState(void)
59 {
60     INITSTATE(NULL, lua);
61     return lua;
62 }
63
64 rpmlua rpmluaNew()
65 {
66     rpmlua lua = (rpmlua) xcalloc(1, sizeof(*lua));
67     struct stat st;
68     const luaL_Reg *lib;
69     char *initlua = rpmGenPath(rpmConfigDir(), "init.lua", NULL);
70    
71     static const luaL_Reg extlibs[] = {
72         {"posix", luaopen_posix},
73         {"rex", luaopen_rex},
74         {"rpm", luaopen_rpm},
75         {"os",  luaopen_rpm_os},
76         {NULL, NULL},
77     };
78     
79     lua_State *L = lua_open();
80     luaL_openlibs(L);
81     lua->L = L;
82
83     for (lib = extlibs; lib->name; lib++) {
84         lua_pushcfunction(L, lib->func);
85         lua_pushstring(L, lib->name);
86         lua_call(L, 1, 0);
87         lua_settop(L, 0);
88     }
89 #ifndef LUA_GLOBALSINDEX
90     lua_pushglobaltable(L);
91 #endif
92     lua_pushliteral(L, "LUA_PATH");
93     lua_pushfstring(L, "%s/%s", rpmConfigDir(), "/lua/?.lua");
94 #ifdef LUA_GLOBALSINDEX
95     lua_rawset(L, LUA_GLOBALSINDEX);
96 #else
97     lua_settable(L, -3);
98 #endif
99     lua_pushliteral(L, "print");
100     lua_pushcfunction(L, rpm_print);
101 #ifdef LUA_GLOBALSINDEX
102     lua_rawset(L, LUA_GLOBALSINDEX);
103 #else
104     lua_settable(L, -3);
105 #endif
106 #ifndef LUA_GLOBALSINDEX
107     lua_pop(L, 1);
108 #endif
109     rpmluaSetData(lua, "lua", lua);
110     if (stat(initlua, &st) != -1)
111         (void)rpmluaRunScriptFile(lua, initlua);
112     free(initlua);
113     return lua;
114 }
115
116 rpmlua rpmluaFree(rpmlua lua)
117 {
118     if (lua) {
119         if (lua->L) lua_close(lua->L);
120         free(lua->printbuf);
121         free(lua);
122         if (lua == globalLuaState) globalLuaState = NULL;
123     }
124     return NULL;
125 }
126
127 void rpmluaSetData(rpmlua _lua, const char *key, const void *data)
128 {
129     INITSTATE(_lua, lua);
130     lua_State *L = lua->L;
131     lua_pushliteral(L, "rpm_");
132     lua_pushstring(L, key);
133     lua_concat(L, 2);
134     if (data == NULL)
135         lua_pushnil(L);
136     else
137         lua_pushlightuserdata(L, (void *)data);
138     lua_rawset(L, LUA_REGISTRYINDEX);
139 }
140
141 static void *getdata(lua_State *L, const char *key)
142 {
143     void *ret = NULL;
144     lua_pushliteral(L, "rpm_");
145     lua_pushstring(L, key);
146     lua_concat(L, 2);
147     lua_rawget(L, LUA_REGISTRYINDEX);
148     if (lua_islightuserdata(L, -1))
149         ret = lua_touserdata(L, -1);
150     lua_pop(L, 1);
151     return ret;
152 }
153
154 void *rpmluaGetData(rpmlua _lua, const char *key)
155 {
156     INITSTATE(_lua, lua);
157     return getdata(lua->L, key);
158 }
159
160 void rpmluaPushPrintBuffer(rpmlua _lua)
161 {
162     INITSTATE(_lua, lua);
163     rpmluapb prbuf = xcalloc(1, sizeof(*prbuf));
164     prbuf->buf = NULL;
165     prbuf->alloced = 0;
166     prbuf->used = 0;
167     prbuf->next = lua->printbuf;
168
169     lua->printbuf = prbuf;
170 }
171
172 char *rpmluaPopPrintBuffer(rpmlua _lua)
173 {
174     INITSTATE(_lua, lua);
175     rpmluapb prbuf = lua->printbuf;
176     char *ret = NULL;
177
178     if (prbuf) {
179         ret = prbuf->buf;
180         lua->printbuf = prbuf->next;
181         free(prbuf);
182     }
183     
184     return ret;
185 }
186
187 static int pushvar(lua_State *L, rpmluavType type, void *value)
188 {
189     int ret = 0;
190     switch (type) {
191         case RPMLUAV_NIL:
192             lua_pushnil(L);
193             break;
194         case RPMLUAV_STRING:
195             lua_pushstring(L, *((char **)value));
196             break;
197         case RPMLUAV_NUMBER:
198             lua_pushnumber(L, *((double *)value));
199             break;
200         default:
201             ret = -1;
202             break;
203     }
204     return ret;
205 }
206
207 void rpmluaSetVar(rpmlua _lua, rpmluav var)
208 {
209     INITSTATE(_lua, lua);
210     lua_State *L = lua->L;
211     if (var->listmode && lua->pushsize > 0) {
212         if (var->keyType != RPMLUAV_NUMBER || var->key.num == (double)0) {
213             var->keyType = RPMLUAV_NUMBER;
214             var->key.num = (double) luaL_getn(L, -1);
215         }
216         var->key.num++;
217     }
218     if (!var->listmode || lua->pushsize > 0) {
219         if (lua->pushsize == 0)
220             lua_pushglobaltable(L);
221         if (pushvar(L, var->keyType, &var->key) != -1) {
222             if (pushvar(L, var->valueType, &var->value) != -1)
223                 lua_rawset(L, -3);
224             else
225                 lua_pop(L, 1);
226         }
227         if (lua->pushsize == 0)
228             lua_pop(L, 1);
229     }
230 }
231
232 static void popvar(lua_State *L, rpmluavType *type, void *value)
233 {
234     switch (lua_type(L, -1)) {
235     case LUA_TSTRING:
236         *type = RPMLUAV_STRING;
237         *((const char **)value) = lua_tostring(L, -1);
238         break;
239     case LUA_TNUMBER:
240         *type = RPMLUAV_NUMBER;
241         *((double *)value) = lua_tonumber(L, -1);
242         break;
243     default:
244         *type = RPMLUAV_NIL;
245         *((void **)value) = NULL;
246         break;
247     }
248     lua_pop(L, 1);
249 }
250
251 void rpmluaGetVar(rpmlua _lua, rpmluav var)
252 {
253     INITSTATE(_lua, lua);
254     lua_State *L = lua->L;
255     if (!var->listmode) {
256         if (lua->pushsize == 0)
257             lua_pushglobaltable(L);
258         if (pushvar(L, var->keyType, &var->key) != -1) {
259             lua_rawget(L, -2);
260             popvar(L, &var->valueType, &var->value);
261         }
262         if (lua->pushsize == 0)
263             lua_pop(L, 1);
264     } else if (lua->pushsize > 0) {
265         (void) pushvar(L, var->keyType, &var->key);
266         if (lua_next(L, -2) != 0)
267             popvar(L, &var->valueType, &var->value);
268     }
269 }
270
271 #define FINDKEY_RETURN 0
272 #define FINDKEY_CREATE 1
273 #define FINDKEY_REMOVE 2
274 static int findkey(lua_State *L, int oper, const char *key, va_list va)
275 {
276     char *buf;
277     const char *s, *e;
278     int ret = 0;
279     int blen;
280
281     blen = vsnprintf(NULL, 0, key, va);
282     if (blen <= 0) {
283         return -1;
284     }
285
286     buf = xmalloc(blen + 1);
287     vsnprintf(buf, blen + 1, key, va);
288
289     s = e = buf;
290     lua_pushglobaltable(L);
291     for (;;) {
292         if (*e == '\0' || *e == '.') {
293             if (e != s) {
294                 lua_pushlstring(L, s, e-s);
295                 switch (oper) {
296                 case FINDKEY_REMOVE:
297                     if (*e == '\0') {
298                         lua_pushnil(L);
299                         lua_rawset(L, -3);
300                         lua_pop(L, 1);
301                         break;
302                     }
303                 case FINDKEY_RETURN:
304                     lua_rawget(L, -2);
305                     lua_remove(L, -2);
306                     break;
307                 case FINDKEY_CREATE:
308                     lua_rawget(L, -2);
309                     if (!lua_istable(L, -1)) {
310                         lua_pop(L, 1);
311                         lua_newtable(L);
312                         lua_pushlstring(L, s, e-s);
313                         lua_pushvalue(L, -2);
314                         lua_rawset(L, -4);
315                     }
316                     lua_remove(L, -2);
317                     break;
318                 }
319             }
320             if (*e == '\0')
321                 break;
322             if (!lua_istable(L, -1)) {
323                 lua_pop(L, 1);
324                 ret = -1;
325                 break;
326             }
327             s = e+1;
328         }
329         e++;
330     }
331     free(buf);
332
333     return ret;
334 }
335
336 void rpmluaDelVar(rpmlua _lua, const char *key, ...)
337 {
338     INITSTATE(_lua, lua);
339     va_list va;
340     va_start(va, key);
341     (void) findkey(lua->L, FINDKEY_REMOVE, key, va);
342     va_end(va);
343 }
344
345 int rpmluaVarExists(rpmlua _lua, const char *key, ...)
346 {
347     INITSTATE(_lua, lua);
348     lua_State *L = lua->L;
349     int ret = 0;
350     va_list va;
351     va_start(va, key);
352     if (findkey(L, FINDKEY_RETURN, key, va) == 0) {
353         if (!lua_isnil(L, -1))
354             ret = 1;
355         lua_pop(L, 1);
356     }
357     va_end(va);
358     return ret;
359 }
360
361 void rpmluaPushTable(rpmlua _lua, const char *key, ...)
362 {
363     INITSTATE(_lua, lua);
364     va_list va;
365     va_start(va, key);
366     (void) findkey(lua->L, FINDKEY_CREATE, key, va);
367     lua->pushsize++;
368     va_end(va);
369 }
370
371 void rpmluaPop(rpmlua _lua)
372 {
373     INITSTATE(_lua, lua);
374     assert(lua->pushsize > 0);
375     lua->pushsize--;
376     lua_pop(lua->L, 1);
377 }
378
379 rpmluav rpmluavNew(void)
380 {
381     rpmluav var = (rpmluav) xcalloc(1, sizeof(*var));
382     return var;
383 }
384
385 rpmluav rpmluavFree(rpmluav var)
386 {
387     free(var);
388     return NULL;
389 }
390
391 void rpmluavSetListMode(rpmluav var, int flag)
392 {
393     var->listmode = flag;
394     var->keyType = RPMLUAV_NIL;
395 }
396
397 void rpmluavSetKey(rpmluav var, rpmluavType type, const void *value)
398 {
399     var->keyType = type;
400     switch (type) {
401         case RPMLUAV_NUMBER:
402             var->key.num = *((double *)value);
403             break;
404         case RPMLUAV_STRING:
405             var->key.str = (char *)value;
406             break;
407         default:
408             break;
409     }
410 }
411
412 void rpmluavSetValue(rpmluav var, rpmluavType type, const void *value)
413 {
414     var->valueType = type;
415     switch (type) {
416         case RPMLUAV_NUMBER:
417             var->value.num = *((const double *)value);
418             break;
419         case RPMLUAV_STRING:
420             var->value.str = (const char *)value;
421             break;
422         default:
423             break;
424     }
425 }
426
427 void rpmluavGetKey(rpmluav var, rpmluavType *type, void **value)
428 {
429     *type = var->keyType;
430     switch (var->keyType) {
431         case RPMLUAV_NUMBER:
432             *((double **)value) = &var->key.num;
433             break;
434         case RPMLUAV_STRING:
435             *((const char **)value) = var->key.str;
436             break;
437         default:
438             break;
439     }
440 }
441
442 void rpmluavGetValue(rpmluav var, rpmluavType *type, void **value)
443 {
444     *type = var->valueType;
445     switch (var->valueType) {
446         case RPMLUAV_NUMBER:
447             *((double **)value) = &var->value.num;
448             break;
449         case RPMLUAV_STRING:
450             *((const char **)value) = var->value.str;
451             break;
452         default:
453             break;
454     }
455 }
456
457 void rpmluavSetKeyNum(rpmluav var, double value)
458 {
459     rpmluavSetKey(var, RPMLUAV_NUMBER, &value);
460 }
461
462 void rpmluavSetValueNum(rpmluav var, double value)
463 {
464     rpmluavSetValue(var, RPMLUAV_NUMBER, &value);
465 }
466
467 double rpmluavGetKeyNum(rpmluav var)
468 {
469     rpmluavType type;
470     void *value;
471     rpmluavGetKey(var, &type, &value);
472     if (type == RPMLUAV_NUMBER)
473         return *((double *)value);
474     return (double) 0;
475 }
476
477 double rpmluavGetValueNum(rpmluav var)
478 {
479     rpmluavType type;
480     void *value;
481     rpmluavGetValue(var, &type, &value);
482     if (type == RPMLUAV_NUMBER)
483         return *((double *)value);
484     return (double) 0;
485 }
486
487 int rpmluavKeyIsNum(rpmluav var)
488 {
489     return (var->keyType == RPMLUAV_NUMBER) ? 1 : 0;
490 }
491
492 int rpmluavValueIsNum(rpmluav var)
493 {
494     return (var->valueType == RPMLUAV_NUMBER) ? 1 : 0;
495 }
496
497 int rpmluaCheckScript(rpmlua _lua, const char *script, const char *name)
498 {
499     INITSTATE(_lua, lua);
500     lua_State *L = lua->L;
501     int ret = 0;
502     if (name == NULL)
503         name = "<lua>";
504     if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
505         rpmlog(RPMLOG_ERR,
506                 _("invalid syntax in lua scriptlet: %s\n"),
507                   lua_tostring(L, -1));
508         ret = -1;
509     }
510     lua_pop(L, 1); /* Error or chunk. */
511     return ret;
512 }
513
514 int rpmluaRunScript(rpmlua _lua, const char *script, const char *name)
515 {
516     INITSTATE(_lua, lua);
517     lua_State *L = lua->L;
518     int ret = 0;
519     if (name == NULL)
520         name = "<lua>";
521     if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
522         rpmlog(RPMLOG_ERR, _("invalid syntax in lua script: %s\n"),
523                  lua_tostring(L, -1));
524         lua_pop(L, 1);
525         ret = -1;
526     } else if (lua_pcall(L, 0, 0, 0) != 0) {
527         rpmlog(RPMLOG_ERR, _("lua script failed: %s\n"),
528                  lua_tostring(L, -1));
529         lua_pop(L, 1);
530         ret = -1;
531     }
532     return ret;
533 }
534
535 int rpmluaRunScriptFile(rpmlua _lua, const char *filename)
536 {
537     INITSTATE(_lua, lua);
538     lua_State *L = lua->L;
539     int ret = 0;
540     if (luaL_loadfile(L, filename) != 0) {
541         rpmlog(RPMLOG_ERR, _("invalid syntax in lua file: %s\n"),
542                  lua_tostring(L, -1));
543         lua_pop(L, 1);
544         ret = -1;
545     } else if (lua_pcall(L, 0, 0, 0) != 0) {
546         rpmlog(RPMLOG_ERR, _("lua script failed: %s\n"),
547                  lua_tostring(L, -1));
548         lua_pop(L, 1);
549         ret = -1;
550     }
551     return ret;
552 }
553
554 /* From lua.c */
555 static int rpmluaReadline(lua_State *L, const char *prompt)
556 {
557    static char buffer[1024];
558    if (prompt) {
559       (void) fputs(prompt, stdout);
560       (void) fflush(stdout);
561    }
562    if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
563       return 0;  /* read fails */
564    } else {
565       lua_pushstring(L, buffer);
566       return 1;
567    }
568 }
569
570 /* Based on lua.c */
571 static void _rpmluaInteractive(lua_State *L)
572 {
573    (void) fputs("\n", stdout);
574    printf("RPM Interactive %s Interpreter\n", LUA_VERSION);
575    for (;;) {
576       int rc = 0;
577
578       if (rpmluaReadline(L, "> ") == 0)
579          break;
580       if (lua_tostring(L, -1)[0] == '=') {
581          (void) lua_pushfstring(L, "print(%s)", lua_tostring(L, -1)+1);
582          lua_remove(L, -2);
583       }
584       for (;;) {
585          rc = luaL_loadbuffer(L, lua_tostring(L, -1),
586                               lua_strlen(L, -1), "<lua>");
587          if (rc == LUA_ERRSYNTAX &&
588              strstr(lua_tostring(L, -1), "near `<eof>'") != NULL) {
589             if (rpmluaReadline(L, ">> ") == 0)
590                break;
591             lua_remove(L, -2); /* Remove error */
592             lua_concat(L, 2);
593             continue;
594          }
595          break;
596       }
597       if (rc == 0)
598          rc = lua_pcall(L, 0, 0, 0);
599       if (rc != 0) {
600          fprintf(stderr, "%s\n", lua_tostring(L, -1));
601          lua_pop(L, 1);
602       }
603       lua_pop(L, 1); /* Remove line */
604    }
605    (void) fputs("\n", stdout);
606 }
607
608 void rpmluaInteractive(rpmlua _lua)
609 {
610     INITSTATE(_lua, lua);
611     _rpmluaInteractive(lua->L);
612 }
613
614 /* ------------------------------------------------------------------ */
615 /* Lua API */
616
617 static int rpm_b64encode(lua_State *L)
618 {
619     const char *str = luaL_checkstring(L, 1);
620     size_t len = lua_strlen(L, 1);
621     int linelen = -1;
622     if (lua_gettop(L) == 2)
623         linelen = luaL_checkinteger(L, 2);
624     if (str && len) {
625         char *data = rpmBase64Encode(str, len, linelen);
626         lua_pushstring(L, data);
627         free(data);
628     }
629     return 1;
630 }
631
632 static int rpm_b64decode(lua_State *L)
633 {
634     const char *str = luaL_checkstring(L, 1);
635     if (str) {
636         void *data = NULL;
637         size_t len = 0;
638         if (rpmBase64Decode(str, &data, &len) == 0) {
639             lua_pushlstring(L, data, len);
640         } else {
641             lua_pushnil(L);
642         }
643         free(data);
644     }
645     return 1;
646 }
647
648 static int rpm_expand(lua_State *L)
649 {
650     const char *str = luaL_checkstring(L, 1);
651     char *val = rpmExpand(str, NULL);
652     lua_pushstring(L, val);
653     free(val);
654     return 1;
655 }
656
657 static int rpm_define(lua_State *L)
658 {
659     const char *str = luaL_checkstring(L, 1);
660     (void) rpmDefineMacro(NULL, str, 0);
661     return 0;
662 }
663
664 static int rpm_interactive(lua_State *L)
665 {
666     _rpmluaInteractive(L);
667     return 0;
668 }
669
670 typedef struct rpmluaHookData_s {
671     lua_State *L;
672     int funcRef;
673     int dataRef;
674 } * rpmluaHookData;
675
676 static int rpmluaHookWrapper(rpmhookArgs args, void *data)
677 {
678     rpmluaHookData hookdata = (rpmluaHookData)data;
679     lua_State *L = hookdata->L;
680     int ret = 0;
681     int i;
682     lua_rawgeti(L, LUA_REGISTRYINDEX, hookdata->funcRef);
683     lua_newtable(L);
684     for (i = 0; i != args->argc; i++) {
685         switch (args->argt[i]) {
686             case 's':
687                 lua_pushstring(L, args->argv[i].s);
688                 lua_rawseti(L, -2, i+1);
689                 break;
690             case 'i':
691                 lua_pushnumber(L, (lua_Number)args->argv[i].i);
692                 lua_rawseti(L, -2, i+1);
693                 break;
694             case 'f':
695                 lua_pushnumber(L, (lua_Number)args->argv[i].f);
696                 lua_rawseti(L, -2, i+1);
697                 break;
698             case 'p':
699                 lua_pushlightuserdata(L, args->argv[i].p);
700                 lua_rawseti(L, -2, i+1);
701                 break;
702             default:
703                 (void) luaL_error(L, "unsupported type '%c' as "
704                               "a hook argument\n", args->argt[i]);
705                 break;
706         }
707     }
708     if (lua_pcall(L, 1, 1, 0) != 0) {
709         rpmlog(RPMLOG_ERR, _("lua hook failed: %s\n"),
710                  lua_tostring(L, -1));
711         lua_pop(L, 1);
712     } else {
713         if (lua_isnumber(L, -1))
714             ret = (int)lua_tonumber(L, -1);
715         lua_pop(L, 1);
716     }
717     return ret;
718 }
719
720 static int rpm_register(lua_State *L)
721 {
722     if (!lua_isstring(L, 1)) {
723         (void) luaL_argerror(L, 1, "hook name expected");
724     } else if (!lua_isfunction(L, 2)) {
725         (void) luaL_argerror(L, 2, "function expected");
726     } else {
727         rpmluaHookData hookdata =
728             lua_newuserdata(L, sizeof(struct rpmluaHookData_s));
729         lua_pushvalue(L, -1);
730         hookdata->dataRef = luaL_ref(L, LUA_REGISTRYINDEX);
731         lua_pushvalue(L, 2);
732         hookdata->funcRef = luaL_ref(L, LUA_REGISTRYINDEX);
733         hookdata->L = L;
734         rpmhookRegister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
735         return 1;
736     }
737     return 0;
738 }
739
740 static int rpm_unregister(lua_State *L)
741 {
742     if (!lua_isstring(L, 1)) {
743         (void) luaL_argerror(L, 1, "hook name expected");
744     } else if (!lua_isuserdata(L, 2)) {
745         (void) luaL_argerror(L, 2, "hook information expected");
746     } else {
747         rpmluaHookData hookdata = (rpmluaHookData)lua_touserdata(L, 2);
748         luaL_unref(L, LUA_REGISTRYINDEX, hookdata->funcRef);
749         luaL_unref(L, LUA_REGISTRYINDEX, hookdata->dataRef);
750         rpmhookUnregister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
751     }
752     return 0;
753 }
754
755 static int rpm_call(lua_State *L)
756 {
757     if (!lua_isstring(L, 1)) {
758         (void) luaL_argerror(L, 1, "hook name expected");
759     } else {
760         rpmhookArgs args = rpmhookArgsNew(lua_gettop(L)-1);
761         const char *name = lua_tostring(L, 1);
762         char *argt = (char *)xmalloc(args->argc+1);
763         int i;
764         for (i = 0; i != args->argc; i++) {
765             switch (lua_type(L, i+1)) {
766                 case LUA_TNIL:
767                     argt[i] = 'p';
768                     args->argv[i].p = NULL;
769                     break;
770                 case LUA_TNUMBER: {
771                     float f = (float)lua_tonumber(L, i+1);
772                     if (f == (int)f) {
773                         argt[i] = 'i';
774                         args->argv[i].i = (int)f;
775                     } else {
776                         argt[i] = 'f';
777                         args->argv[i].f = f;
778                     }
779                 }   break;
780                 case LUA_TSTRING:
781                     argt[i] = 's';
782                     args->argv[i].s = lua_tostring(L, i+1);
783                     break;
784                 case LUA_TUSERDATA:
785                 case LUA_TLIGHTUSERDATA:
786                     argt[i] = 'p';
787                     args->argv[i].p = lua_touserdata(L, i+1);
788                     break;
789                 default:
790                     (void) luaL_error(L, "unsupported Lua type passed to hook");
791                     argt[i] = 'p';
792                     args->argv[i].p = NULL;
793                     break;
794             }
795         }
796         args->argt = argt;
797         rpmhookCallArgs(name, args);
798         free(argt);
799         (void) rpmhookArgsFree(args);
800     }
801     return 0;
802 }
803
804 /* Based on luaB_print. */
805 static int rpm_print (lua_State *L)
806 {
807     rpmlua lua = (rpmlua)getdata(L, "lua");
808     int n = lua_gettop(L);  /* number of arguments */
809     int i;
810     if (!lua) return 0;
811     lua_getglobal(L, "tostring");
812     for (i = 1; i <= n; i++) {
813         const char *s;
814         lua_pushvalue(L, -1);  /* function to be called */
815         lua_pushvalue(L, i);   /* value to print */
816         lua_call(L, 1, 1);
817         s = lua_tostring(L, -1);  /* get result */
818         if (s == NULL)
819             return luaL_error(L, "`tostring' must return a string to `print'");
820         if (lua->printbuf) {
821             rpmluapb prbuf = lua->printbuf;
822             int sl = lua_strlen(L, -1);
823             if (prbuf->used+sl+1 > prbuf->alloced) {
824                 prbuf->alloced += sl+512;
825                 prbuf->buf = xrealloc(prbuf->buf, prbuf->alloced);
826             }
827             if (i > 1)
828                 prbuf->buf[prbuf->used++] = '\t';
829             memcpy(prbuf->buf+prbuf->used, s, sl+1);
830             prbuf->used += sl;
831         } else {
832             if (i > 1)
833                 (void) fputs("\t", stdout);
834             (void) fputs(s, stdout);
835         }
836         lua_pop(L, 1);  /* pop result */
837     }
838     if (!lua->printbuf) {
839         (void) fputs("\n", stdout);
840     } else {
841         rpmluapb prbuf = lua->printbuf;
842         if (prbuf->used+1 > prbuf->alloced) {
843             prbuf->alloced += 512;
844             prbuf->buf = xrealloc(prbuf->buf, prbuf->alloced);
845         }
846         prbuf->buf[prbuf->used] = '\0';
847     }
848     return 0;
849 }
850
851 static const luaL_Reg rpmlib[] = {
852     {"b64encode", rpm_b64encode},
853     {"b64decode", rpm_b64decode},
854     {"expand", rpm_expand},
855     {"define", rpm_define},
856     {"register", rpm_register},
857     {"unregister", rpm_unregister},
858     {"call", rpm_call},
859     {"interactive", rpm_interactive},
860     {NULL, NULL}
861 };
862
863 static int luaopen_rpm(lua_State *L)
864 {
865     lua_pushglobaltable(L);
866     luaL_openlib(L, "rpm", rpmlib, 0);
867     return 0;
868 }
869 #endif  /* WITH_LUA */
870