11 #define lua_open() luaL_newstate()
15 #define lua_strlen(L,i) lua_rawlen(L, (i))
18 #ifndef lua_pushglobaltable
19 #define lua_pushglobaltable(L) lua_pushvalue(L, LUA_GLOBALSINDEX)
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"
33 #define _RPMLUA_INTERNAL
34 #include "rpmio/rpmlua.h"
38 #define INITSTATE(_lua, lua) \
39 rpmlua lua = _lua ? _lua : \
40 (globalLuaState ? globalLuaState : \
42 (globalLuaState = rpmluaNew()) \
53 static rpmlua globalLuaState = NULL;
55 static int luaopen_rpm(lua_State *L);
56 static int rpm_print(lua_State *L);
58 rpmlua rpmluaGetGlobalState(void)
66 rpmlua lua = (rpmlua) xcalloc(1, sizeof(*lua));
69 char *initlua = rpmGenPath(rpmConfigDir(), "init.lua", NULL);
71 static const luaL_Reg extlibs[] = {
72 {"posix", luaopen_posix},
75 {"os", luaopen_rpm_os},
79 lua_State *L = lua_open();
83 for (lib = extlibs; lib->name; lib++) {
84 lua_pushcfunction(L, lib->func);
85 lua_pushstring(L, lib->name);
89 #ifndef LUA_GLOBALSINDEX
90 lua_pushglobaltable(L);
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);
99 lua_pushliteral(L, "print");
100 lua_pushcfunction(L, rpm_print);
101 #ifdef LUA_GLOBALSINDEX
102 lua_rawset(L, LUA_GLOBALSINDEX);
106 #ifndef LUA_GLOBALSINDEX
109 rpmluaSetData(lua, "lua", lua);
110 if (stat(initlua, &st) != -1)
111 (void)rpmluaRunScriptFile(lua, initlua);
116 rpmlua rpmluaFree(rpmlua lua)
119 if (lua->L) lua_close(lua->L);
122 if (lua == globalLuaState) globalLuaState = NULL;
127 void rpmluaSetData(rpmlua _lua, const char *key, const void *data)
129 INITSTATE(_lua, lua);
130 lua_State *L = lua->L;
131 lua_pushliteral(L, "rpm_");
132 lua_pushstring(L, key);
137 lua_pushlightuserdata(L, (void *)data);
138 lua_rawset(L, LUA_REGISTRYINDEX);
141 static void *getdata(lua_State *L, const char *key)
144 lua_pushliteral(L, "rpm_");
145 lua_pushstring(L, key);
147 lua_rawget(L, LUA_REGISTRYINDEX);
148 if (lua_islightuserdata(L, -1))
149 ret = lua_touserdata(L, -1);
154 void *rpmluaGetData(rpmlua _lua, const char *key)
156 INITSTATE(_lua, lua);
157 return getdata(lua->L, key);
160 void rpmluaPushPrintBuffer(rpmlua _lua)
162 INITSTATE(_lua, lua);
163 rpmluapb prbuf = xcalloc(1, sizeof(*prbuf));
167 prbuf->next = lua->printbuf;
169 lua->printbuf = prbuf;
172 char *rpmluaPopPrintBuffer(rpmlua _lua)
174 INITSTATE(_lua, lua);
175 rpmluapb prbuf = lua->printbuf;
180 lua->printbuf = prbuf->next;
187 static int pushvar(lua_State *L, rpmluavType type, void *value)
195 lua_pushstring(L, *((char **)value));
198 lua_pushnumber(L, *((double *)value));
207 void rpmluaSetVar(rpmlua _lua, rpmluav var)
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);
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)
227 if (lua->pushsize == 0)
232 static void popvar(lua_State *L, rpmluavType *type, void *value)
234 switch (lua_type(L, -1)) {
236 *type = RPMLUAV_STRING;
237 *((const char **)value) = lua_tostring(L, -1);
240 *type = RPMLUAV_NUMBER;
241 *((double *)value) = lua_tonumber(L, -1);
245 *((void **)value) = NULL;
251 void rpmluaGetVar(rpmlua _lua, rpmluav var)
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) {
260 popvar(L, &var->valueType, &var->value);
262 if (lua->pushsize == 0)
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);
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)
281 blen = vsnprintf(NULL, 0, key, va);
286 buf = xmalloc(blen + 1);
287 vsnprintf(buf, blen + 1, key, va);
290 lua_pushglobaltable(L);
292 if (*e == '\0' || *e == '.') {
294 lua_pushlstring(L, s, e-s);
309 if (!lua_istable(L, -1)) {
312 lua_pushlstring(L, s, e-s);
313 lua_pushvalue(L, -2);
322 if (!lua_istable(L, -1)) {
336 void rpmluaDelVar(rpmlua _lua, const char *key, ...)
338 INITSTATE(_lua, lua);
341 (void) findkey(lua->L, FINDKEY_REMOVE, key, va);
345 int rpmluaVarExists(rpmlua _lua, const char *key, ...)
347 INITSTATE(_lua, lua);
348 lua_State *L = lua->L;
352 if (findkey(L, FINDKEY_RETURN, key, va) == 0) {
353 if (!lua_isnil(L, -1))
361 void rpmluaPushTable(rpmlua _lua, const char *key, ...)
363 INITSTATE(_lua, lua);
366 (void) findkey(lua->L, FINDKEY_CREATE, key, va);
371 void rpmluaPop(rpmlua _lua)
373 INITSTATE(_lua, lua);
374 assert(lua->pushsize > 0);
379 rpmluav rpmluavNew(void)
381 rpmluav var = (rpmluav) xcalloc(1, sizeof(*var));
385 rpmluav rpmluavFree(rpmluav var)
391 void rpmluavSetListMode(rpmluav var, int flag)
393 var->listmode = flag;
394 var->keyType = RPMLUAV_NIL;
397 void rpmluavSetKey(rpmluav var, rpmluavType type, const void *value)
402 var->key.num = *((double *)value);
405 var->key.str = (char *)value;
412 void rpmluavSetValue(rpmluav var, rpmluavType type, const void *value)
414 var->valueType = type;
417 var->value.num = *((const double *)value);
420 var->value.str = (const char *)value;
427 void rpmluavGetKey(rpmluav var, rpmluavType *type, void **value)
429 *type = var->keyType;
430 switch (var->keyType) {
432 *((double **)value) = &var->key.num;
435 *((const char **)value) = var->key.str;
442 void rpmluavGetValue(rpmluav var, rpmluavType *type, void **value)
444 *type = var->valueType;
445 switch (var->valueType) {
447 *((double **)value) = &var->value.num;
450 *((const char **)value) = var->value.str;
457 void rpmluavSetKeyNum(rpmluav var, double value)
459 rpmluavSetKey(var, RPMLUAV_NUMBER, &value);
462 void rpmluavSetValueNum(rpmluav var, double value)
464 rpmluavSetValue(var, RPMLUAV_NUMBER, &value);
467 double rpmluavGetKeyNum(rpmluav var)
471 rpmluavGetKey(var, &type, &value);
472 if (type == RPMLUAV_NUMBER)
473 return *((double *)value);
477 double rpmluavGetValueNum(rpmluav var)
481 rpmluavGetValue(var, &type, &value);
482 if (type == RPMLUAV_NUMBER)
483 return *((double *)value);
487 int rpmluavKeyIsNum(rpmluav var)
489 return (var->keyType == RPMLUAV_NUMBER) ? 1 : 0;
492 int rpmluavValueIsNum(rpmluav var)
494 return (var->valueType == RPMLUAV_NUMBER) ? 1 : 0;
497 int rpmluaCheckScript(rpmlua _lua, const char *script, const char *name)
499 INITSTATE(_lua, lua);
500 lua_State *L = lua->L;
504 if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
506 _("invalid syntax in lua scriptlet: %s\n"),
507 lua_tostring(L, -1));
510 lua_pop(L, 1); /* Error or chunk. */
514 int rpmluaRunScript(rpmlua _lua, const char *script, const char *name)
516 INITSTATE(_lua, lua);
517 lua_State *L = lua->L;
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));
526 } else if (lua_pcall(L, 0, 0, 0) != 0) {
527 rpmlog(RPMLOG_ERR, _("lua script failed: %s\n"),
528 lua_tostring(L, -1));
535 int rpmluaRunScriptFile(rpmlua _lua, const char *filename)
537 INITSTATE(_lua, lua);
538 lua_State *L = lua->L;
540 if (luaL_loadfile(L, filename) != 0) {
541 rpmlog(RPMLOG_ERR, _("invalid syntax in lua file: %s\n"),
542 lua_tostring(L, -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));
555 static int rpmluaReadline(lua_State *L, const char *prompt)
557 static char buffer[1024];
559 (void) fputs(prompt, stdout);
560 (void) fflush(stdout);
562 if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
563 return 0; /* read fails */
565 lua_pushstring(L, buffer);
571 static void _rpmluaInteractive(lua_State *L)
573 (void) fputs("\n", stdout);
574 printf("RPM Interactive %s Interpreter\n", LUA_VERSION);
578 if (rpmluaReadline(L, "> ") == 0)
580 if (lua_tostring(L, -1)[0] == '=') {
581 (void) lua_pushfstring(L, "print(%s)", lua_tostring(L, -1)+1);
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)
591 lua_remove(L, -2); /* Remove error */
598 rc = lua_pcall(L, 0, 0, 0);
600 fprintf(stderr, "%s\n", lua_tostring(L, -1));
603 lua_pop(L, 1); /* Remove line */
605 (void) fputs("\n", stdout);
608 void rpmluaInteractive(rpmlua _lua)
610 INITSTATE(_lua, lua);
611 _rpmluaInteractive(lua->L);
614 /* ------------------------------------------------------------------ */
617 static int rpm_b64encode(lua_State *L)
619 const char *str = luaL_checkstring(L, 1);
620 size_t len = lua_strlen(L, 1);
622 if (lua_gettop(L) == 2)
623 linelen = luaL_checkinteger(L, 2);
625 char *data = rpmBase64Encode(str, len, linelen);
626 lua_pushstring(L, data);
632 static int rpm_b64decode(lua_State *L)
634 const char *str = luaL_checkstring(L, 1);
638 if (rpmBase64Decode(str, &data, &len) == 0) {
639 lua_pushlstring(L, data, len);
648 static int rpm_expand(lua_State *L)
650 const char *str = luaL_checkstring(L, 1);
651 char *val = rpmExpand(str, NULL);
652 lua_pushstring(L, val);
657 static int rpm_define(lua_State *L)
659 const char *str = luaL_checkstring(L, 1);
660 (void) rpmDefineMacro(NULL, str, 0);
664 static int rpm_interactive(lua_State *L)
666 _rpmluaInteractive(L);
670 typedef struct rpmluaHookData_s {
676 static int rpmluaHookWrapper(rpmhookArgs args, void *data)
678 rpmluaHookData hookdata = (rpmluaHookData)data;
679 lua_State *L = hookdata->L;
682 lua_rawgeti(L, LUA_REGISTRYINDEX, hookdata->funcRef);
684 for (i = 0; i != args->argc; i++) {
685 switch (args->argt[i]) {
687 lua_pushstring(L, args->argv[i].s);
688 lua_rawseti(L, -2, i+1);
691 lua_pushnumber(L, (lua_Number)args->argv[i].i);
692 lua_rawseti(L, -2, i+1);
695 lua_pushnumber(L, (lua_Number)args->argv[i].f);
696 lua_rawseti(L, -2, i+1);
699 lua_pushlightuserdata(L, args->argv[i].p);
700 lua_rawseti(L, -2, i+1);
703 (void) luaL_error(L, "unsupported type '%c' as "
704 "a hook argument\n", args->argt[i]);
708 if (lua_pcall(L, 1, 1, 0) != 0) {
709 rpmlog(RPMLOG_ERR, _("lua hook failed: %s\n"),
710 lua_tostring(L, -1));
713 if (lua_isnumber(L, -1))
714 ret = (int)lua_tonumber(L, -1);
720 static int rpm_register(lua_State *L)
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");
727 rpmluaHookData hookdata =
728 lua_newuserdata(L, sizeof(struct rpmluaHookData_s));
729 lua_pushvalue(L, -1);
730 hookdata->dataRef = luaL_ref(L, LUA_REGISTRYINDEX);
732 hookdata->funcRef = luaL_ref(L, LUA_REGISTRYINDEX);
734 rpmhookRegister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
740 static int rpm_unregister(lua_State *L)
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");
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);
755 static int rpm_call(lua_State *L)
757 if (!lua_isstring(L, 1)) {
758 (void) luaL_argerror(L, 1, "hook name expected");
760 rpmhookArgs args = rpmhookArgsNew(lua_gettop(L)-1);
761 const char *name = lua_tostring(L, 1);
762 char *argt = (char *)xmalloc(args->argc+1);
764 for (i = 0; i != args->argc; i++) {
765 switch (lua_type(L, i+1)) {
768 args->argv[i].p = NULL;
771 float f = (float)lua_tonumber(L, i+1);
774 args->argv[i].i = (int)f;
782 args->argv[i].s = lua_tostring(L, i+1);
785 case LUA_TLIGHTUSERDATA:
787 args->argv[i].p = lua_touserdata(L, i+1);
790 (void) luaL_error(L, "unsupported Lua type passed to hook");
792 args->argv[i].p = NULL;
797 rpmhookCallArgs(name, args);
799 (void) rpmhookArgsFree(args);
804 /* Based on luaB_print. */
805 static int rpm_print (lua_State *L)
807 rpmlua lua = (rpmlua)getdata(L, "lua");
808 int n = lua_gettop(L); /* number of arguments */
811 lua_getglobal(L, "tostring");
812 for (i = 1; i <= n; i++) {
814 lua_pushvalue(L, -1); /* function to be called */
815 lua_pushvalue(L, i); /* value to print */
817 s = lua_tostring(L, -1); /* get result */
819 return luaL_error(L, "`tostring' must return a string to `print'");
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);
828 prbuf->buf[prbuf->used++] = '\t';
829 memcpy(prbuf->buf+prbuf->used, s, sl+1);
833 (void) fputs("\t", stdout);
834 (void) fputs(s, stdout);
836 lua_pop(L, 1); /* pop result */
838 if (!lua->printbuf) {
839 (void) fputs("\n", stdout);
841 rpmluapb prbuf = lua->printbuf;
842 if (prbuf->used+1 > prbuf->alloced) {
843 prbuf->alloced += 512;
844 prbuf->buf = xrealloc(prbuf->buf, prbuf->alloced);
846 prbuf->buf[prbuf->used] = '\0';
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},
859 {"interactive", rpm_interactive},
863 static int luaopen_rpm(lua_State *L)
865 lua_pushglobaltable(L);
866 luaL_openlib(L, "rpm", rpmlib, 0);
869 #endif /* WITH_LUA */