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"
21 #define _RPMLUA_INTERNAL
22 #include "rpmio/rpmlua.h"
26 #define INITSTATE(_lua, lua) \
27 rpmlua lua = _lua ? _lua : \
28 (globalLuaState ? globalLuaState : \
30 (globalLuaState = rpmluaNew()) \
34 static rpmlua globalLuaState = NULL;
36 static int luaopen_rpm(lua_State *L);
37 static int rpm_print(lua_State *L);
39 rpmlua rpmluaGetGlobalState(void)
47 rpmlua lua = (rpmlua) xcalloc(1, sizeof(*lua));
50 char *initlua = rpmGenPath(rpmConfigDir(), "init.lua", NULL);
52 static const luaL_reg extlibs[] = {
53 {"posix", luaopen_posix},
56 {"os", luaopen_rpm_os},
60 lua_State *L = lua_open();
64 for (lib = extlibs; lib->name; lib++) {
65 lua_pushcfunction(L, lib->func);
66 lua_pushstring(L, lib->name);
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);
83 rpmlua rpmluaFree(rpmlua lua)
86 if (lua->L) lua_close(lua->L);
89 if (lua == globalLuaState) globalLuaState = NULL;
94 void rpmluaSetData(rpmlua _lua, const char *key, const void *data)
97 lua_State *L = lua->L;
98 lua_pushliteral(L, "rpm_");
99 lua_pushstring(L, key);
104 lua_pushlightuserdata(L, (void *)data);
105 lua_rawset(L, LUA_REGISTRYINDEX);
108 static void *getdata(lua_State *L, const char *key)
111 lua_pushliteral(L, "rpm_");
112 lua_pushstring(L, key);
114 lua_rawget(L, LUA_REGISTRYINDEX);
115 if (lua_islightuserdata(L, -1))
116 ret = lua_touserdata(L, -1);
121 void *rpmluaGetData(rpmlua _lua, const char *key)
123 INITSTATE(_lua, lua);
124 return getdata(lua->L, key);
127 void rpmluaSetPrintBuffer(rpmlua _lua, int flag)
129 INITSTATE(_lua, lua);
130 lua->storeprint = flag;
132 lua->printbuf = NULL;
133 lua->printbufsize = 0;
134 lua->printbufused = 0;
137 const char *rpmluaGetPrintBuffer(rpmlua _lua)
139 INITSTATE(_lua, lua);
140 return lua->printbuf;
143 static int pushvar(lua_State *L, rpmluavType type, void *value)
151 lua_pushstring(L, *((char **)value));
154 lua_pushnumber(L, *((double *)value));
163 void rpmluaSetVar(rpmlua _lua, rpmluav var)
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);
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)
183 if (lua->pushsize == 0)
188 static void popvar(lua_State *L, rpmluavType *type, void *value)
190 switch (lua_type(L, -1)) {
192 *type = RPMLUAV_STRING;
193 *((const char **)value) = lua_tostring(L, -1);
196 *type = RPMLUAV_NUMBER;
197 *((double *)value) = lua_tonumber(L, -1);
201 *((void **)value) = NULL;
207 void rpmluaGetVar(rpmlua _lua, rpmluav var)
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) {
216 popvar(L, &var->valueType, &var->value);
218 if (lua->pushsize == 0)
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);
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)
237 blen = vsnprintf(NULL, 0, key, va);
242 buf = xmalloc(blen + 1);
243 vsnprintf(buf, blen + 1, key, va);
246 lua_pushvalue(L, LUA_GLOBALSINDEX);
248 if (*e == '\0' || *e == '.') {
250 lua_pushlstring(L, s, e-s);
265 if (!lua_istable(L, -1)) {
268 lua_pushlstring(L, s, e-s);
269 lua_pushvalue(L, -2);
278 if (!lua_istable(L, -1)) {
292 void rpmluaDelVar(rpmlua _lua, const char *key, ...)
294 INITSTATE(_lua, lua);
297 (void) findkey(lua->L, FINDKEY_REMOVE, key, va);
301 int rpmluaVarExists(rpmlua _lua, const char *key, ...)
303 INITSTATE(_lua, lua);
304 lua_State *L = lua->L;
308 if (findkey(L, FINDKEY_RETURN, key, va) == 0) {
309 if (!lua_isnil(L, -1))
317 void rpmluaPushTable(rpmlua _lua, const char *key, ...)
319 INITSTATE(_lua, lua);
322 (void) findkey(lua->L, FINDKEY_CREATE, key, va);
327 void rpmluaPop(rpmlua _lua)
329 INITSTATE(_lua, lua);
330 assert(lua->pushsize > 0);
335 rpmluav rpmluavNew(void)
337 rpmluav var = (rpmluav) xcalloc(1, sizeof(*var));
341 rpmluav rpmluavFree(rpmluav var)
347 void rpmluavSetListMode(rpmluav var, int flag)
349 var->listmode = flag;
350 var->keyType = RPMLUAV_NIL;
353 void rpmluavSetKey(rpmluav var, rpmluavType type, const void *value)
358 var->key.num = *((double *)value);
361 var->key.str = (char *)value;
368 void rpmluavSetValue(rpmluav var, rpmluavType type, const void *value)
370 var->valueType = type;
373 var->value.num = *((const double *)value);
376 var->value.str = (const char *)value;
383 void rpmluavGetKey(rpmluav var, rpmluavType *type, void **value)
385 *type = var->keyType;
386 switch (var->keyType) {
388 *((double **)value) = &var->key.num;
391 *((const char **)value) = var->key.str;
398 void rpmluavGetValue(rpmluav var, rpmluavType *type, void **value)
400 *type = var->valueType;
401 switch (var->valueType) {
403 *((double **)value) = &var->value.num;
406 *((const char **)value) = var->value.str;
413 void rpmluavSetKeyNum(rpmluav var, double value)
415 rpmluavSetKey(var, RPMLUAV_NUMBER, &value);
418 void rpmluavSetValueNum(rpmluav var, double value)
420 rpmluavSetValue(var, RPMLUAV_NUMBER, &value);
423 double rpmluavGetKeyNum(rpmluav var)
427 rpmluavGetKey(var, &type, &value);
428 if (type == RPMLUAV_NUMBER)
429 return *((double *)value);
433 double rpmluavGetValueNum(rpmluav var)
437 rpmluavGetValue(var, &type, &value);
438 if (type == RPMLUAV_NUMBER)
439 return *((double *)value);
443 int rpmluavKeyIsNum(rpmluav var)
445 return (var->keyType == RPMLUAV_NUMBER) ? 1 : 0;
448 int rpmluavValueIsNum(rpmluav var)
450 return (var->valueType == RPMLUAV_NUMBER) ? 1 : 0;
453 int rpmluaCheckScript(rpmlua _lua, const char *script, const char *name)
455 INITSTATE(_lua, lua);
456 lua_State *L = lua->L;
460 if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
462 _("invalid syntax in lua scriptlet: %s\n"),
463 lua_tostring(L, -1));
466 lua_pop(L, 1); /* Error or chunk. */
470 int rpmluaRunScript(rpmlua _lua, const char *script, const char *name)
472 INITSTATE(_lua, lua);
473 lua_State *L = lua->L;
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));
482 } else if (lua_pcall(L, 0, 0, 0) != 0) {
483 rpmlog(RPMLOG_ERR, _("lua script failed: %s\n"),
484 lua_tostring(L, -1));
491 int rpmluaRunScriptFile(rpmlua _lua, const char *filename)
493 INITSTATE(_lua, lua);
494 lua_State *L = lua->L;
496 if (luaL_loadfile(L, filename) != 0) {
497 rpmlog(RPMLOG_ERR, _("invalid syntax in lua file: %s\n"),
498 lua_tostring(L, -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));
511 static int rpmluaReadline(lua_State *L, const char *prompt)
513 static char buffer[1024];
515 (void) fputs(prompt, stdout);
516 (void) fflush(stdout);
518 if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
519 return 0; /* read fails */
521 lua_pushstring(L, buffer);
527 static void _rpmluaInteractive(lua_State *L)
529 (void) fputs("\n", stdout);
530 printf("RPM Interactive %s Interpreter\n", LUA_VERSION);
534 if (rpmluaReadline(L, "> ") == 0)
536 if (lua_tostring(L, -1)[0] == '=') {
537 (void) lua_pushfstring(L, "print(%s)", lua_tostring(L, -1)+1);
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)
547 lua_remove(L, -2); /* Remove error */
554 rc = lua_pcall(L, 0, 0, 0);
556 fprintf(stderr, "%s\n", lua_tostring(L, -1));
559 lua_pop(L, 1); /* Remove line */
561 (void) fputs("\n", stdout);
564 void rpmluaInteractive(rpmlua _lua)
566 INITSTATE(_lua, lua);
567 _rpmluaInteractive(lua->L);
570 /* ------------------------------------------------------------------ */
573 static int rpm_b64encode(lua_State *L)
575 const char *str = luaL_checkstring(L, 1);
576 size_t len = lua_strlen(L, 1);
578 if (lua_gettop(L) == 2)
579 linelen = luaL_checkinteger(L, 2);
581 char *data = b64encode(str, len, linelen);
582 lua_pushstring(L, data);
588 static int rpm_b64decode(lua_State *L)
590 const char *str = luaL_checkstring(L, 1);
594 if (b64decode(str, &data, &len) == 0) {
595 lua_pushlstring(L, data, len);
604 static int rpm_expand(lua_State *L)
606 const char *str = luaL_checkstring(L, 1);
607 lua_pushstring(L, rpmExpand(str, NULL));
611 static int rpm_define(lua_State *L)
613 const char *str = luaL_checkstring(L, 1);
614 (void) rpmDefineMacro(NULL, str, 0);
618 static int rpm_interactive(lua_State *L)
620 _rpmluaInteractive(L);
624 typedef struct rpmluaHookData_s {
630 static int rpmluaHookWrapper(rpmhookArgs args, void *data)
632 rpmluaHookData hookdata = (rpmluaHookData)data;
633 lua_State *L = hookdata->L;
636 lua_rawgeti(L, LUA_REGISTRYINDEX, hookdata->funcRef);
638 for (i = 0; i != args->argc; i++) {
639 switch (args->argt[i]) {
641 lua_pushstring(L, args->argv[i].s);
642 lua_rawseti(L, -2, i+1);
645 lua_pushnumber(L, (lua_Number)args->argv[i].i);
646 lua_rawseti(L, -2, i+1);
649 lua_pushnumber(L, (lua_Number)args->argv[i].f);
650 lua_rawseti(L, -2, i+1);
653 lua_pushlightuserdata(L, args->argv[i].p);
654 lua_rawseti(L, -2, i+1);
657 (void) luaL_error(L, "unsupported type '%c' as "
658 "a hook argument\n", args->argt[i]);
662 if (lua_pcall(L, 1, 1, 0) != 0) {
663 rpmlog(RPMLOG_ERR, _("lua hook failed: %s\n"),
664 lua_tostring(L, -1));
667 if (lua_isnumber(L, -1))
668 ret = (int)lua_tonumber(L, -1);
674 static int rpm_register(lua_State *L)
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");
681 rpmluaHookData hookdata =
682 lua_newuserdata(L, sizeof(struct rpmluaHookData_s));
683 lua_pushvalue(L, -1);
684 hookdata->dataRef = luaL_ref(L, LUA_REGISTRYINDEX);
686 hookdata->funcRef = luaL_ref(L, LUA_REGISTRYINDEX);
688 rpmhookRegister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
694 static int rpm_unregister(lua_State *L)
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");
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);
709 static int rpm_call(lua_State *L)
711 if (!lua_isstring(L, 1)) {
712 (void) luaL_argerror(L, 1, "hook name expected");
714 rpmhookArgs args = rpmhookArgsNew(lua_gettop(L)-1);
715 const char *name = lua_tostring(L, 1);
716 char *argt = (char *)xmalloc(args->argc+1);
718 for (i = 0; i != args->argc; i++) {
719 switch (lua_type(L, i+1)) {
722 args->argv[i].p = NULL;
725 float f = (float)lua_tonumber(L, i+1);
728 args->argv[i].i = (int)f;
736 args->argv[i].s = lua_tostring(L, i+1);
739 case LUA_TLIGHTUSERDATA:
741 args->argv[i].p = lua_touserdata(L, i+1);
744 (void) luaL_error(L, "unsupported Lua type passed to hook");
746 args->argv[i].p = NULL;
751 rpmhookCallArgs(name, args);
753 (void) rpmhookArgsFree(args);
758 /* Based on luaB_print. */
759 static int rpm_print (lua_State *L)
761 rpmlua lua = (rpmlua)getdata(L, "lua");
762 int n = lua_gettop(L); /* number of arguments */
765 lua_getglobal(L, "tostring");
766 for (i = 1; i <= n; i++) {
768 lua_pushvalue(L, -1); /* function to be called */
769 lua_pushvalue(L, i); /* value to print */
771 s = lua_tostring(L, -1); /* get result */
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);
781 lua->printbuf[lua->printbufused++] = '\t';
782 memcpy(lua->printbuf+lua->printbufused, s, sl+1);
783 lua->printbufused += sl;
786 (void) fputs("\t", stdout);
787 (void) fputs(s, stdout);
789 lua_pop(L, 1); /* pop result */
791 if (!lua->storeprint) {
792 (void) fputs("\n", stdout);
794 if (lua->printbufused+1 > lua->printbufsize) {
795 lua->printbufsize += 512;
796 lua->printbuf = xrealloc(lua->printbuf, lua->printbufsize);
798 lua->printbuf[lua->printbufused] = '\0';
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},
811 {"interactive", rpm_interactive},
815 static int luaopen_rpm(lua_State *L)
817 lua_pushvalue(L, LUA_GLOBALSINDEX);
818 luaL_openlib(L, "rpm", rpmlib, 0);
821 #endif /* WITH_LUA */