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"
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()) \
41 static rpmlua globalLuaState = NULL;
43 static int luaopen_rpm(lua_State *L);
44 static int rpm_print(lua_State *L);
46 rpmlua rpmluaGetGlobalState(void)
54 rpmlua lua = (rpmlua) xcalloc(1, sizeof(*lua));
57 char *initlua = rpmGenPath(rpmConfigDir(), "init.lua", NULL);
59 static const luaL_reg extlibs[] = {
60 {"posix", luaopen_posix},
63 {"os", luaopen_rpm_os},
67 lua_State *L = lua_open();
71 for (lib = extlibs; lib->name; lib++) {
72 lua_pushcfunction(L, lib->func);
73 lua_pushstring(L, lib->name);
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);
90 rpmlua rpmluaFree(rpmlua lua)
93 if (lua->L) lua_close(lua->L);
96 if (lua == globalLuaState) globalLuaState = NULL;
101 void rpmluaSetData(rpmlua _lua, const char *key, const void *data)
103 INITSTATE(_lua, lua);
104 lua_State *L = lua->L;
105 lua_pushliteral(L, "rpm_");
106 lua_pushstring(L, key);
111 lua_pushlightuserdata(L, (void *)data);
112 lua_rawset(L, LUA_REGISTRYINDEX);
115 static void *getdata(lua_State *L, const char *key)
118 lua_pushliteral(L, "rpm_");
119 lua_pushstring(L, key);
121 lua_rawget(L, LUA_REGISTRYINDEX);
122 if (lua_islightuserdata(L, -1))
123 ret = lua_touserdata(L, -1);
128 void *rpmluaGetData(rpmlua _lua, const char *key)
130 INITSTATE(_lua, lua);
131 return getdata(lua->L, key);
134 void rpmluaPushPrintBuffer(rpmlua _lua)
136 INITSTATE(_lua, lua);
137 rpmluapb prbuf = xcalloc(1, sizeof(*prbuf));
141 prbuf->next = lua->printbuf;
143 lua->printbuf = prbuf;
146 char *rpmluaPopPrintBuffer(rpmlua _lua)
148 INITSTATE(_lua, lua);
149 rpmluapb prbuf = lua->printbuf;
154 lua->printbuf = prbuf->next;
161 static int pushvar(lua_State *L, rpmluavType type, void *value)
169 lua_pushstring(L, *((char **)value));
172 lua_pushnumber(L, *((double *)value));
181 void rpmluaSetVar(rpmlua _lua, rpmluav var)
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);
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)
201 if (lua->pushsize == 0)
206 static void popvar(lua_State *L, rpmluavType *type, void *value)
208 switch (lua_type(L, -1)) {
210 *type = RPMLUAV_STRING;
211 *((const char **)value) = lua_tostring(L, -1);
214 *type = RPMLUAV_NUMBER;
215 *((double *)value) = lua_tonumber(L, -1);
219 *((void **)value) = NULL;
225 void rpmluaGetVar(rpmlua _lua, rpmluav var)
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) {
234 popvar(L, &var->valueType, &var->value);
236 if (lua->pushsize == 0)
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);
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)
255 blen = vsnprintf(NULL, 0, key, va);
260 buf = xmalloc(blen + 1);
261 vsnprintf(buf, blen + 1, key, va);
264 lua_pushvalue(L, LUA_GLOBALSINDEX);
266 if (*e == '\0' || *e == '.') {
268 lua_pushlstring(L, s, e-s);
283 if (!lua_istable(L, -1)) {
286 lua_pushlstring(L, s, e-s);
287 lua_pushvalue(L, -2);
296 if (!lua_istable(L, -1)) {
310 void rpmluaDelVar(rpmlua _lua, const char *key, ...)
312 INITSTATE(_lua, lua);
315 (void) findkey(lua->L, FINDKEY_REMOVE, key, va);
319 int rpmluaVarExists(rpmlua _lua, const char *key, ...)
321 INITSTATE(_lua, lua);
322 lua_State *L = lua->L;
326 if (findkey(L, FINDKEY_RETURN, key, va) == 0) {
327 if (!lua_isnil(L, -1))
335 void rpmluaPushTable(rpmlua _lua, const char *key, ...)
337 INITSTATE(_lua, lua);
340 (void) findkey(lua->L, FINDKEY_CREATE, key, va);
345 void rpmluaPop(rpmlua _lua)
347 INITSTATE(_lua, lua);
348 assert(lua->pushsize > 0);
353 rpmluav rpmluavNew(void)
355 rpmluav var = (rpmluav) xcalloc(1, sizeof(*var));
359 rpmluav rpmluavFree(rpmluav var)
365 void rpmluavSetListMode(rpmluav var, int flag)
367 var->listmode = flag;
368 var->keyType = RPMLUAV_NIL;
371 void rpmluavSetKey(rpmluav var, rpmluavType type, const void *value)
376 var->key.num = *((double *)value);
379 var->key.str = (char *)value;
386 void rpmluavSetValue(rpmluav var, rpmluavType type, const void *value)
388 var->valueType = type;
391 var->value.num = *((const double *)value);
394 var->value.str = (const char *)value;
401 void rpmluavGetKey(rpmluav var, rpmluavType *type, void **value)
403 *type = var->keyType;
404 switch (var->keyType) {
406 *((double **)value) = &var->key.num;
409 *((const char **)value) = var->key.str;
416 void rpmluavGetValue(rpmluav var, rpmluavType *type, void **value)
418 *type = var->valueType;
419 switch (var->valueType) {
421 *((double **)value) = &var->value.num;
424 *((const char **)value) = var->value.str;
431 void rpmluavSetKeyNum(rpmluav var, double value)
433 rpmluavSetKey(var, RPMLUAV_NUMBER, &value);
436 void rpmluavSetValueNum(rpmluav var, double value)
438 rpmluavSetValue(var, RPMLUAV_NUMBER, &value);
441 double rpmluavGetKeyNum(rpmluav var)
445 rpmluavGetKey(var, &type, &value);
446 if (type == RPMLUAV_NUMBER)
447 return *((double *)value);
451 double rpmluavGetValueNum(rpmluav var)
455 rpmluavGetValue(var, &type, &value);
456 if (type == RPMLUAV_NUMBER)
457 return *((double *)value);
461 int rpmluavKeyIsNum(rpmluav var)
463 return (var->keyType == RPMLUAV_NUMBER) ? 1 : 0;
466 int rpmluavValueIsNum(rpmluav var)
468 return (var->valueType == RPMLUAV_NUMBER) ? 1 : 0;
471 int rpmluaCheckScript(rpmlua _lua, const char *script, const char *name)
473 INITSTATE(_lua, lua);
474 lua_State *L = lua->L;
478 if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
480 _("invalid syntax in lua scriptlet: %s\n"),
481 lua_tostring(L, -1));
484 lua_pop(L, 1); /* Error or chunk. */
488 int rpmluaRunScript(rpmlua _lua, const char *script, const char *name)
490 INITSTATE(_lua, lua);
491 lua_State *L = lua->L;
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));
500 } else if (lua_pcall(L, 0, 0, 0) != 0) {
501 rpmlog(RPMLOG_ERR, _("lua script failed: %s\n"),
502 lua_tostring(L, -1));
509 int rpmluaRunScriptFile(rpmlua _lua, const char *filename)
511 INITSTATE(_lua, lua);
512 lua_State *L = lua->L;
514 if (luaL_loadfile(L, filename) != 0) {
515 rpmlog(RPMLOG_ERR, _("invalid syntax in lua file: %s\n"),
516 lua_tostring(L, -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));
529 static int rpmluaReadline(lua_State *L, const char *prompt)
531 static char buffer[1024];
533 (void) fputs(prompt, stdout);
534 (void) fflush(stdout);
536 if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
537 return 0; /* read fails */
539 lua_pushstring(L, buffer);
545 static void _rpmluaInteractive(lua_State *L)
547 (void) fputs("\n", stdout);
548 printf("RPM Interactive %s Interpreter\n", LUA_VERSION);
552 if (rpmluaReadline(L, "> ") == 0)
554 if (lua_tostring(L, -1)[0] == '=') {
555 (void) lua_pushfstring(L, "print(%s)", lua_tostring(L, -1)+1);
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)
565 lua_remove(L, -2); /* Remove error */
572 rc = lua_pcall(L, 0, 0, 0);
574 fprintf(stderr, "%s\n", lua_tostring(L, -1));
577 lua_pop(L, 1); /* Remove line */
579 (void) fputs("\n", stdout);
582 void rpmluaInteractive(rpmlua _lua)
584 INITSTATE(_lua, lua);
585 _rpmluaInteractive(lua->L);
588 /* ------------------------------------------------------------------ */
591 static int rpm_rpmBase64Encode(lua_State *L)
593 const char *str = luaL_checkstring(L, 1);
594 size_t len = lua_strlen(L, 1);
596 if (lua_gettop(L) == 2)
597 linelen = luaL_checkinteger(L, 2);
599 char *data = rpmBase64Encode(str, len, linelen);
600 lua_pushstring(L, data);
606 static int rpm_rpmBase64Decode(lua_State *L)
608 const char *str = luaL_checkstring(L, 1);
612 if (rpmBase64Decode(str, &data, &len) == 0) {
613 lua_pushlstring(L, data, len);
622 static int rpm_expand(lua_State *L)
624 const char *str = luaL_checkstring(L, 1);
625 char *val = rpmExpand(str, NULL);
626 lua_pushstring(L, val);
631 static int rpm_define(lua_State *L)
633 const char *str = luaL_checkstring(L, 1);
634 (void) rpmDefineMacro(NULL, str, 0);
638 static int rpm_interactive(lua_State *L)
640 _rpmluaInteractive(L);
644 typedef struct rpmluaHookData_s {
650 static int rpmluaHookWrapper(rpmhookArgs args, void *data)
652 rpmluaHookData hookdata = (rpmluaHookData)data;
653 lua_State *L = hookdata->L;
656 lua_rawgeti(L, LUA_REGISTRYINDEX, hookdata->funcRef);
658 for (i = 0; i != args->argc; i++) {
659 switch (args->argt[i]) {
661 lua_pushstring(L, args->argv[i].s);
662 lua_rawseti(L, -2, i+1);
665 lua_pushnumber(L, (lua_Number)args->argv[i].i);
666 lua_rawseti(L, -2, i+1);
669 lua_pushnumber(L, (lua_Number)args->argv[i].f);
670 lua_rawseti(L, -2, i+1);
673 lua_pushlightuserdata(L, args->argv[i].p);
674 lua_rawseti(L, -2, i+1);
677 (void) luaL_error(L, "unsupported type '%c' as "
678 "a hook argument\n", args->argt[i]);
682 if (lua_pcall(L, 1, 1, 0) != 0) {
683 rpmlog(RPMLOG_ERR, _("lua hook failed: %s\n"),
684 lua_tostring(L, -1));
687 if (lua_isnumber(L, -1))
688 ret = (int)lua_tonumber(L, -1);
694 static int rpm_register(lua_State *L)
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");
701 rpmluaHookData hookdata =
702 lua_newuserdata(L, sizeof(struct rpmluaHookData_s));
703 lua_pushvalue(L, -1);
704 hookdata->dataRef = luaL_ref(L, LUA_REGISTRYINDEX);
706 hookdata->funcRef = luaL_ref(L, LUA_REGISTRYINDEX);
708 rpmhookRegister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
714 static int rpm_unregister(lua_State *L)
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");
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);
729 static int rpm_call(lua_State *L)
731 if (!lua_isstring(L, 1)) {
732 (void) luaL_argerror(L, 1, "hook name expected");
734 rpmhookArgs args = rpmhookArgsNew(lua_gettop(L)-1);
735 const char *name = lua_tostring(L, 1);
736 char *argt = (char *)xmalloc(args->argc+1);
738 for (i = 0; i != args->argc; i++) {
739 switch (lua_type(L, i+1)) {
742 args->argv[i].p = NULL;
745 float f = (float)lua_tonumber(L, i+1);
748 args->argv[i].i = (int)f;
756 args->argv[i].s = lua_tostring(L, i+1);
759 case LUA_TLIGHTUSERDATA:
761 args->argv[i].p = lua_touserdata(L, i+1);
764 (void) luaL_error(L, "unsupported Lua type passed to hook");
766 args->argv[i].p = NULL;
771 rpmhookCallArgs(name, args);
773 (void) rpmhookArgsFree(args);
778 /* Based on luaB_print. */
779 static int rpm_print (lua_State *L)
781 rpmlua lua = (rpmlua)getdata(L, "lua");
782 int n = lua_gettop(L); /* number of arguments */
785 lua_getglobal(L, "tostring");
786 for (i = 1; i <= n; i++) {
788 lua_pushvalue(L, -1); /* function to be called */
789 lua_pushvalue(L, i); /* value to print */
791 s = lua_tostring(L, -1); /* get result */
793 return luaL_error(L, "`tostring' must return a string to `print'");
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);
802 prbuf->buf[prbuf->used++] = '\t';
803 memcpy(prbuf->buf+prbuf->used, s, sl+1);
807 (void) fputs("\t", stdout);
808 (void) fputs(s, stdout);
810 lua_pop(L, 1); /* pop result */
812 if (!lua->printbuf) {
813 (void) fputs("\n", stdout);
815 rpmluapb prbuf = lua->printbuf;
816 if (prbuf->used+1 > prbuf->alloced) {
817 prbuf->alloced += 512;
818 prbuf->buf = xrealloc(prbuf->buf, prbuf->alloced);
820 prbuf->buf[prbuf->used] = '\0';
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},
833 {"interactive", rpm_interactive},
837 static int luaopen_rpm(lua_State *L)
839 lua_pushvalue(L, LUA_GLOBALSINDEX);
840 luaL_openlib(L, "rpm", rpmlib, 0);
843 #endif /* WITH_LUA */