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