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