rpmio/rpmlua.c

Go to the documentation of this file.
00001 /*@-bounds -realcompare -sizeoftype -protoparammatch @*/
00002 #include "system.h"
00003 
00004 #ifdef  WITH_LUA
00005 #include <rpmio.h>
00006 #include <rpmmacro.h>
00007 #include <rpmerr.h>
00008 #include <rpmurl.h>
00009 #include <rpmhook.h>
00010 
00011 #include <lua.h>
00012 #include <lualib.h>
00013 #include <lauxlib.h>
00014 #include <lposix.h>
00015 #include <lrexlib.h>
00016 
00017 #include <unistd.h>
00018 #include <assert.h>
00019 
00020 #define _RPMLUA_INTERNAL
00021 #include "rpmlua.h"
00022 
00023 #include "debug.h"
00024 
00025 #if !defined(HAVE_VSNPRINTF)
00026 static inline int vsnprintf(char * buf, /*@unused@*/ int nb,
00027                             const char * fmt, va_list ap)
00028 {
00029     return vsprintf(buf, fmt, ap);
00030 }
00031 #endif
00032 
00033 #define INITSTATE(_lua, lua) \
00034     rpmlua lua = _lua ? _lua : \
00035             (globalLuaState ? globalLuaState : \
00036                         /*@-mods@*/ \
00037                         (globalLuaState = rpmluaNew()) \
00038                         /*@=mods@*/ \
00039             )
00040 
00041 /*@only@*/ /*@unchecked@*/ /*@null@*/
00042 static rpmlua globalLuaState = NULL;
00043 
00044 static int luaopen_rpm(lua_State *L)
00045         /*@modifies L @*/;
00046 static int rpm_print(lua_State *L)
00047         /*@globals fileSystem @*/
00048         /*@modifies L, fileSystem @*/;
00049 
00050 rpmlua rpmluaNew()
00051 {
00052     rpmlua lua = (rpmlua) xcalloc(1, sizeof(*lua));
00053     lua_State *L = lua_open();
00054     struct stat st;
00055     /*@-readonlytrans@*/
00056     /*@observer@*/ /*@unchecked@*/
00057     static const luaL_reg lualibs[] = {
00058         {"base", luaopen_base},
00059         {"table", luaopen_table},
00060         {"io", luaopen_io},
00061         {"string", luaopen_string},
00062         {"debug", luaopen_debug},
00063         {"loadlib", luaopen_loadlib},
00064         {"posix", luaopen_posix},
00065         {"rex", luaopen_rex},
00066         {"rpm", luaopen_rpm},
00067         {NULL, NULL},
00068     };
00069     /*@observer@*/ /*@unchecked@*/
00070     const luaL_reg *lib = lualibs;
00071     /*@=readonlytrans@*/
00072 
00073     lua->L = L;
00074     for (; lib->name; lib++) {
00075 /*@-noeffectuncon@*/
00076         (void) lib->func(L);
00077 /*@=noeffectuncon@*/
00078         lua_settop(L, 0);
00079     }
00080     lua_pushliteral(L, "LUA_PATH");
00081     lua_pushstring(L, RPMCONFIGDIR "/lua/?.lua");
00082     lua_rawset(L, LUA_GLOBALSINDEX);
00083     lua_pushliteral(L, "print");
00084     lua_pushcfunction(L, rpm_print);
00085     lua_rawset(L, LUA_GLOBALSINDEX);
00086     rpmluaSetData(lua, "lua", lua);
00087     if (stat(RPMCONFIGDIR "/init.lua", &st) != -1)
00088         (void)rpmluaRunScriptFile(lua, RPMCONFIGDIR "/init.lua");
00089     return lua;
00090 }
00091 
00092 void *rpmluaFree(rpmlua lua)
00093 {
00094     if (lua) {
00095         if (lua->L) lua_close(lua->L);
00096         free(lua->printbuf);
00097         free(lua);
00098     }
00099     return NULL;
00100 }
00101 
00102 void rpmluaSetData(rpmlua _lua, const char *key, const void *data)
00103 {
00104     INITSTATE(_lua, lua);
00105     lua_State *L = lua->L;
00106     lua_pushliteral(L, "rpm_");
00107     lua_pushstring(L, key);
00108     lua_concat(L, 2);
00109     if (data == NULL)
00110         lua_pushnil(L);
00111     else
00112         lua_pushlightuserdata(L, (void *)data);
00113     lua_rawset(L, LUA_REGISTRYINDEX);
00114 }
00115 
00116 static void *getdata(lua_State *L, const char *key)
00117         /*@modifies L @*/
00118 {
00119     void *ret = NULL;
00120     lua_pushliteral(L, "rpm_");
00121     lua_pushstring(L, key);
00122     lua_concat(L, 2);
00123     lua_rawget(L, LUA_REGISTRYINDEX);
00124 /*@-branchstate@*/
00125     if (lua_islightuserdata(L, -1))
00126         ret = lua_touserdata(L, -1);
00127 /*@=branchstate@*/
00128     lua_pop(L, 1);
00129     return ret;
00130 }
00131 
00132 void *rpmluaGetData(rpmlua _lua, const char *key)
00133 {
00134     INITSTATE(_lua, lua);
00135     return getdata(lua->L, key);
00136 }
00137 
00138 void rpmluaSetPrintBuffer(rpmlua _lua, int flag)
00139 {
00140     INITSTATE(_lua, lua);
00141     lua->storeprint = flag;
00142     free(lua->printbuf);
00143     lua->printbuf = NULL;
00144     lua->printbufsize = 0;
00145 }
00146 
00147 const char *rpmluaGetPrintBuffer(rpmlua _lua)
00148 {
00149     INITSTATE(_lua, lua);
00150     return lua->printbuf;
00151 }
00152 
00153 static int pushvar(lua_State *L, rpmluavType type, void *value)
00154         /*@modifies L @*/
00155 {
00156     int ret = 0;
00157     switch (type) {
00158         case RPMLUAV_NIL:
00159             lua_pushnil(L);
00160             break;
00161         case RPMLUAV_STRING:
00162             lua_pushstring(L, *((char **)value));
00163             break;
00164         case RPMLUAV_NUMBER:
00165             lua_pushnumber(L, *((double *)value));
00166             break;
00167         default:
00168             ret = -1;
00169             break;
00170     }
00171     return ret;
00172 }
00173 
00174 void rpmluaSetVar(rpmlua _lua, rpmluav var)
00175 {
00176     INITSTATE(_lua, lua);
00177     lua_State *L = lua->L;
00178     if (var->listmode && lua->pushsize > 0) {
00179         if (var->keyType != RPMLUAV_NUMBER || var->key.num == (double)0) {
00180             var->keyType = RPMLUAV_NUMBER;
00181             var->key.num = (double) luaL_getn(L, -1);
00182         }
00183         var->key.num++;
00184     }
00185     if (!var->listmode || lua->pushsize > 0) {
00186         if (lua->pushsize == 0)
00187             lua_pushvalue(L, LUA_GLOBALSINDEX);
00188         if (pushvar(L, var->keyType, &var->key) != -1) {
00189             if (pushvar(L, var->valueType, &var->value) != -1)
00190                 lua_rawset(L, -3);
00191             else
00192                 lua_pop(L, 1);
00193         }
00194         if (lua->pushsize == 0)
00195             lua_pop(L, 1);
00196     }
00197 }
00198 
00199 static void popvar(lua_State *L, rpmluavType *type, void *value)
00200         /*@modifies L, *type, *value @*/
00201 {
00202     switch (lua_type(L, -1)) {
00203     case LUA_TSTRING:
00204         *type = RPMLUAV_STRING;
00205 /*@-observertrans -dependenttrans @*/
00206         *((const char **)value) = lua_tostring(L, -1);
00207 /*@=observertrans =dependenttrans @*/
00208         break;
00209     case LUA_TNUMBER:
00210         *type = RPMLUAV_NUMBER;
00211         *((double *)value) = lua_tonumber(L, -1);
00212         break;
00213     default:
00214         *type = RPMLUAV_NIL;
00215         *((void **)value) = NULL;
00216         break;
00217     }
00218     lua_pop(L, 1);
00219 }
00220 
00221 void rpmluaGetVar(rpmlua _lua, rpmluav var)
00222 {
00223     INITSTATE(_lua, lua);
00224     lua_State *L = lua->L;
00225     if (!var->listmode) {
00226         if (lua->pushsize == 0)
00227             lua_pushvalue(L, LUA_GLOBALSINDEX);
00228         if (pushvar(L, var->keyType, &var->key) != -1) {
00229             lua_rawget(L, -2);
00230             popvar(L, &var->valueType, &var->value);
00231         }
00232         if (lua->pushsize == 0)
00233             lua_pop(L, 1);
00234     } else if (lua->pushsize > 0) {
00235         (void) pushvar(L, var->keyType, &var->key);
00236         if (lua_next(L, -2) != 0)
00237             popvar(L, &var->valueType, &var->value);
00238     }
00239 }
00240 
00241 #define FINDKEY_RETURN 0
00242 #define FINDKEY_CREATE 1
00243 #define FINDKEY_REMOVE 2
00244 static int findkey(lua_State *L, int oper, const char *key, va_list va)
00245         /*@modifies L @*/
00246 {
00247     char buf[BUFSIZ];
00248     const char *s, *e;
00249     int ret = 0;
00250     (void) vsnprintf(buf, BUFSIZ, key, va);
00251     s = e = buf;
00252     lua_pushvalue(L, LUA_GLOBALSINDEX);
00253     for (;;) {
00254         if (*e == '\0' || *e == '.') {
00255             if (e != s) {
00256                 lua_pushlstring(L, s, e-s);
00257                 switch (oper) {
00258                 case FINDKEY_REMOVE:
00259                     if (*e == '\0') {
00260                         lua_pushnil(L);
00261                         lua_rawset(L, -3);
00262                         lua_pop(L, 1);
00263                         /*@switchbreak@*/ break;
00264                     }
00265                     /*@fallthrough@*/
00266                 case FINDKEY_RETURN:
00267                     lua_rawget(L, -2);
00268                     lua_remove(L, -2);
00269                     /*@switchbreak@*/ break;
00270                 case FINDKEY_CREATE:
00271                     lua_rawget(L, -2);
00272                     if (!lua_istable(L, -1)) {
00273                         lua_pop(L, 1);
00274                         lua_newtable(L);
00275                         lua_pushlstring(L, s, e-s);
00276                         lua_pushvalue(L, -2);
00277                         lua_rawset(L, -4);
00278                     }
00279                     lua_remove(L, -2);
00280                     /*@switchbreak@*/ break;
00281                 }
00282             }
00283             if (*e == '\0')
00284                 break;
00285             if (!lua_istable(L, -1)) {
00286                 lua_pop(L, 1);
00287                 ret = -1;
00288                 break;
00289             }
00290             s = e+1;
00291         }
00292         e++;
00293     }
00294 
00295     return ret;
00296 }
00297 
00298 void rpmluaDelVar(rpmlua _lua, const char *key, ...)
00299 {
00300     INITSTATE(_lua, lua);
00301     va_list va;
00302     va_start(va, key);
00303     (void) findkey(lua->L, FINDKEY_REMOVE, key, va);
00304     va_end(va);
00305 }
00306 
00307 int rpmluaVarExists(rpmlua _lua, const char *key, ...)
00308 {
00309     INITSTATE(_lua, lua);
00310     lua_State *L = lua->L;
00311     int ret = 0;
00312     va_list va;
00313     va_start(va, key);
00314     if (findkey(L, FINDKEY_RETURN, key, va) == 0) {
00315         if (!lua_isnil(L, -1))
00316             ret = 1;
00317         lua_pop(L, 1);
00318     }
00319     va_end(va);
00320     return ret;
00321 }
00322 
00323 void rpmluaPushTable(rpmlua _lua, const char *key, ...)
00324 {
00325     INITSTATE(_lua, lua);
00326     va_list va;
00327     va_start(va, key);
00328     (void) findkey(lua->L, FINDKEY_CREATE, key, va);
00329     lua->pushsize++;
00330     va_end(va);
00331 }
00332 
00333 void rpmluaPop(rpmlua _lua)
00334 {
00335     INITSTATE(_lua, lua);
00336     assert(lua->pushsize > 0);
00337     lua->pushsize--;
00338     lua_pop(lua->L, 1);
00339 }
00340 
00341 rpmluav rpmluavNew(void)
00342 {
00343     rpmluav var = (rpmluav) xcalloc(1, sizeof(*var));
00344     return var;
00345 }
00346 
00347 void *rpmluavFree(rpmluav var)
00348 {
00349     free(var);
00350     return NULL;
00351 }
00352 
00353 void rpmluavSetListMode(rpmluav var, int flag)
00354 {
00355     var->listmode = flag;
00356     var->keyType = RPMLUAV_NIL;
00357 }
00358 
00359 void rpmluavSetKey(rpmluav var, rpmluavType type, const void *value)
00360 {
00361     var->keyType = type;
00362 /*@-assignexpose -branchstate -temptrans @*/
00363     switch (type) {
00364         case RPMLUAV_NUMBER:
00365             var->key.num = *((double *)value);
00366             break;
00367         case RPMLUAV_STRING:
00368             var->key.str = (char *)value;
00369             break;
00370         default:
00371             break;
00372     }
00373 /*@=assignexpose =branchstate =temptrans @*/
00374 }
00375 
00376 void rpmluavSetValue(rpmluav var, rpmluavType type, const void *value)
00377 {
00378     var->valueType = type;
00379 /*@-assignexpose -branchstate -temptrans @*/
00380     switch (type) {
00381         case RPMLUAV_NUMBER:
00382             var->value.num = *((const double *)value);
00383             break;
00384         case RPMLUAV_STRING:
00385             var->value.str = (const char *)value;
00386             break;
00387         default:
00388             break;
00389     }
00390 /*@=assignexpose =branchstate =temptrans @*/
00391 }
00392 
00393 void rpmluavGetKey(rpmluav var, rpmluavType *type, void **value)
00394 {
00395     *type = var->keyType;
00396 /*@-onlytrans@*/
00397     switch (var->keyType) {
00398         case RPMLUAV_NUMBER:
00399             *((double **)value) = &var->key.num;
00400             break;
00401         case RPMLUAV_STRING:
00402             *((const char **)value) = var->key.str;
00403             break;
00404         default:
00405             break;
00406     }
00407 /*@=onlytrans@*/
00408 }
00409 
00410 void rpmluavGetValue(rpmluav var, rpmluavType *type, void **value)
00411 {
00412     *type = var->valueType;
00413 /*@-onlytrans@*/
00414     switch (var->valueType) {
00415         case RPMLUAV_NUMBER:
00416             *((double **)value) = &var->value.num;
00417             break;
00418         case RPMLUAV_STRING:
00419             *((const char **)value) = var->value.str;
00420             break;
00421         default:
00422             break;
00423     }
00424 /*@=onlytrans@*/
00425 }
00426 
00427 void rpmluavSetKeyNum(rpmluav var, double value)
00428 {
00429     rpmluavSetKey(var, RPMLUAV_NUMBER, &value);
00430 }
00431 
00432 void rpmluavSetValueNum(rpmluav var, double value)
00433 {
00434     rpmluavSetValue(var, RPMLUAV_NUMBER, &value);
00435 }
00436 
00437 double rpmluavGetKeyNum(rpmluav var)
00438 {
00439     rpmluavType type;
00440     void *value;
00441     rpmluavGetKey(var, &type, &value);
00442     if (type == RPMLUAV_NUMBER)
00443         return *((double *)value);
00444     return (double) 0;
00445 }
00446 
00447 double rpmluavGetValueNum(rpmluav var)
00448 {
00449     rpmluavType type;
00450     void *value;
00451     rpmluavGetValue(var, &type, &value);
00452     if (type == RPMLUAV_NUMBER)
00453         return *((double *)value);
00454     return (double) 0;
00455 }
00456 
00457 int rpmluavKeyIsNum(rpmluav var)
00458 {
00459     return (var->keyType == RPMLUAV_NUMBER) ? 1 : 0;
00460 }
00461 
00462 int rpmluavValueIsNum(rpmluav var)
00463 {
00464     return (var->valueType == RPMLUAV_NUMBER) ? 1 : 0;
00465 }
00466 
00467 int rpmluaCheckScript(rpmlua _lua, const char *script, const char *name)
00468 {
00469     INITSTATE(_lua, lua);
00470     lua_State *L = lua->L;
00471     int ret = 0;
00472 /*@-branchstate@*/
00473     if (name == NULL)
00474         name = "<lua>";
00475 /*@=branchstate@*/
00476     if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
00477         rpmError(RPMERR_SCRIPT,
00478                 _("invalid syntax in lua scriptlet: %s\n"),
00479                   lua_tostring(L, -1));
00480         ret = -1;
00481     }
00482     lua_pop(L, 1); /* Error or chunk. */
00483     return ret;
00484 }
00485 
00486 int rpmluaRunScript(rpmlua _lua, const char *script, const char *name)
00487 {
00488     INITSTATE(_lua, lua);
00489     lua_State *L = lua->L;
00490     int ret = 0;
00491 /*@-branchstate@*/
00492     if (name == NULL)
00493         name = "<lua>";
00494 /*@=branchstate@*/
00495     if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
00496         rpmError(RPMERR_SCRIPT, _("invalid syntax in lua script: %s\n"),
00497                  lua_tostring(L, -1));
00498         lua_pop(L, 1);
00499         ret = -1;
00500     } else if (lua_pcall(L, 0, 0, 0) != 0) {
00501         rpmError(RPMERR_SCRIPT, _("lua script failed: %s\n"),
00502                  lua_tostring(L, -1));
00503         lua_pop(L, 1);
00504         ret = -1;
00505     }
00506     return ret;
00507 }
00508 
00509 int rpmluaRunScriptFile(rpmlua _lua, const char *filename)
00510 {
00511     INITSTATE(_lua, lua);
00512     lua_State *L = lua->L;
00513     int ret = 0;
00514     if (luaL_loadfile(L, filename) != 0) {
00515         rpmError(RPMERR_SCRIPT, _("invalid syntax in lua file: %s\n"),
00516                  lua_tostring(L, -1));
00517         lua_pop(L, 1);
00518         ret = -1;
00519     } else if (lua_pcall(L, 0, 0, 0) != 0) {
00520         rpmError(RPMERR_SCRIPT, _("lua script failed: %s\n"),
00521                  lua_tostring(L, -1));
00522         lua_pop(L, 1);
00523         ret = -1;
00524     }
00525     return ret;
00526 }
00527 
00528 /* From lua.c */
00529 static int rpmluaReadline(lua_State *L, const char *prompt)
00530         /*@globals fileSystem @*/
00531         /*@modifies L, fileSystem @*/
00532 {
00533    static char buffer[1024];
00534    if (prompt) {
00535       (void) fputs(prompt, stdout);
00536       (void) fflush(stdout);
00537    }
00538    if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
00539       return 0;  /* read fails */
00540    } else {
00541       lua_pushstring(L, buffer);
00542       return 1;
00543    }
00544 }
00545 
00546 /* Based on lua.c */
00547 static void _rpmluaInteractive(lua_State *L)
00548         /*@globals fileSystem @*/
00549         /*@modifies L, fileSystem @*/
00550 {
00551    (void) fputs("\n", stdout);
00552    printf("RPM Interactive %s Interpreter\n", LUA_VERSION);
00553    for (;;) {
00554       int rc = 0;
00555 
00556       if (rpmluaReadline(L, "> ") == 0)
00557          break;
00558       if (lua_tostring(L, -1)[0] == '=') {
00559 /*@-evalorder@*/
00560          (void) lua_pushfstring(L, "print(%s)", lua_tostring(L, -1)+1);
00561 /*@=evalorder@*/
00562          lua_remove(L, -2);
00563       }
00564       for (;;) {
00565 /*@-evalorder@*/
00566          rc = luaL_loadbuffer(L, lua_tostring(L, -1),
00567                               lua_strlen(L, -1), "<lua>");
00568 /*@=evalorder@*/
00569          if (rc == LUA_ERRSYNTAX &&
00570              strstr(lua_tostring(L, -1), "near `<eof>'") != NULL) {
00571             if (rpmluaReadline(L, ">> ") == 0)
00572                /*@innerbreak@*/ break;
00573             lua_remove(L, -2); /* Remove error */
00574             lua_concat(L, 2);
00575             /*@innercontinue@*/ continue;
00576          }
00577          /*@innerbreak@*/ break;
00578       }
00579       if (rc == 0)
00580          rc = lua_pcall(L, 0, 0, 0);
00581       if (rc != 0) {
00582          fprintf(stderr, "%s\n", lua_tostring(L, -1));
00583          lua_pop(L, 1);
00584       }
00585       lua_pop(L, 1); /* Remove line */
00586    }
00587    (void) fputs("\n", stdout);
00588 }
00589 
00590 /*@-mods@*/
00591 void rpmluaInteractive(rpmlua _lua)
00592 {
00593     INITSTATE(_lua, lua);
00594     _rpmluaInteractive(lua->L);
00595 }
00596 /*@=mods@*/
00597 
00598 /* ------------------------------------------------------------------ */
00599 /* Lua API */
00600 
00601 static int rpm_expand(lua_State *L)
00602         /*@globals rpmGlobalMacroContext, h_errno @*/
00603         /*@modifies L, rpmGlobalMacroContext @*/
00604 {
00605     const char *str = luaL_checkstring(L, 1);
00606     lua_pushstring(L, rpmExpand(str, NULL));
00607     return 1;
00608 }
00609 
00610 static int rpm_define(lua_State *L)
00611         /*@globals rpmGlobalMacroContext, h_errno @*/
00612         /*@modifies L, rpmGlobalMacroContext @*/
00613 {
00614     const char *str = luaL_checkstring(L, 1);
00615     (void) rpmDefineMacro(NULL, str, 0);
00616     return 0;
00617 }
00618 
00619 static int rpm_interactive(lua_State *L)
00620         /*@globals fileSystem @*/
00621         /*@modifies L, fileSystem @*/
00622 {
00623     _rpmluaInteractive(L);
00624     return 0;
00625 }
00626 
00627 typedef struct rpmluaHookData_s {
00628 /*@shared@*/
00629     lua_State *L;
00630     int funcRef;
00631     int dataRef;
00632 } * rpmluaHookData;
00633 
00634 static int rpmluaHookWrapper(rpmhookArgs args, void *data)
00635     /*@*/
00636 {
00637     rpmluaHookData hookdata = (rpmluaHookData)data;
00638     lua_State *L = hookdata->L;
00639     int ret = 0;
00640     int i;
00641     lua_rawgeti(L, LUA_REGISTRYINDEX, hookdata->funcRef);
00642     lua_newtable(L);
00643     for (i = 0; i != args->argc; i++) {
00644         switch (args->argt[i]) {
00645             case 's':
00646                 lua_pushstring(L, args->argv[i].s);
00647                 lua_rawseti(L, -2, i+1);
00648                 /*@switchbreak@*/ break;
00649             case 'i':
00650                 lua_pushnumber(L, (lua_Number)args->argv[i].i);
00651                 lua_rawseti(L, -2, i+1);
00652                 /*@switchbreak@*/ break;
00653             case 'f':
00654                 lua_pushnumber(L, (lua_Number)args->argv[i].f);
00655                 lua_rawseti(L, -2, i+1);
00656                 /*@switchbreak@*/ break;
00657             case 'p':
00658                 lua_pushlightuserdata(L, args->argv[i].p);
00659                 lua_rawseti(L, -2, i+1);
00660                 /*@switchbreak@*/ break;
00661             default:
00662                 (void) luaL_error(L, "unsupported type '%c' as "
00663                               "a hook argument\n", args->argt[i]);
00664                 /*@switchbreak@*/ break;
00665         }
00666     }
00667     if (lua_pcall(L, 1, 1, 0) != 0) {
00668         rpmError(RPMERR_SCRIPT, _("lua hook failed: %s\n"),
00669                  lua_tostring(L, -1));
00670         lua_pop(L, 1);
00671     } else {
00672         if (lua_isnumber(L, -1))
00673             ret = (int)lua_tonumber(L, -1);
00674         lua_pop(L, 1);
00675     }
00676     return ret;
00677 }
00678 
00679 static int rpm_register(lua_State *L)
00680         /*@globals internalState @*/
00681         /*@modifies L, internalState @*/
00682 {
00683     if (!lua_isstring(L, 1)) {
00684         (void) luaL_argerror(L, 1, "hook name expected");
00685     } else if (!lua_isfunction(L, 2)) {
00686         (void) luaL_argerror(L, 2, "function expected");
00687     } else {
00688         rpmluaHookData hookdata =
00689             lua_newuserdata(L, sizeof(struct rpmluaHookData_s));
00690         lua_pushvalue(L, -1);
00691         hookdata->dataRef = luaL_ref(L, LUA_REGISTRYINDEX);
00692         lua_pushvalue(L, 2);
00693         hookdata->funcRef = luaL_ref(L, LUA_REGISTRYINDEX);
00694 /*@-temptrans@*/
00695         hookdata->L = L;
00696 /*@=temptrans@*/
00697         rpmhookRegister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
00698         return 1;
00699     }
00700     return 0;
00701 }
00702 
00703 static int rpm_unregister(lua_State *L)
00704         /*@modifies L @*/
00705 {
00706     if (!lua_isstring(L, 1)) {
00707         (void) luaL_argerror(L, 1, "hook name expected");
00708     } else if (!lua_islightuserdata(L, 2)) {
00709         (void) luaL_argerror(L, 2, "hook information expected");
00710     } else {
00711         rpmluaHookData hookdata = (rpmluaHookData)lua_touserdata(L, 2);
00712         luaL_unref(L, LUA_REGISTRYINDEX, hookdata->funcRef);
00713         luaL_unref(L, LUA_REGISTRYINDEX, hookdata->dataRef);
00714         rpmhookUnregister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
00715     }
00716     return 0;
00717 }
00718 
00719 static int rpm_call(lua_State *L)
00720         /*@globals internalState @*/
00721         /*@modifies L, internalState @*/
00722 {
00723     if (!lua_isstring(L, 1)) {
00724         (void) luaL_argerror(L, 1, "hook name expected");
00725     } else {
00726         rpmhookArgs args = rpmhookArgsNew(lua_gettop(L)-1);
00727         const char *name = lua_tostring(L, 1);
00728         char *argt = (char *)xmalloc(args->argc+1);
00729         int i;
00730         for (i = 0; i != args->argc; i++) {
00731             switch (lua_type(L, i+1)) {
00732                 case LUA_TNIL:
00733                     argt[i] = 'p';
00734                     args->argv[i].p = NULL;
00735                     /*@switchbreak@*/ break;
00736                 case LUA_TNUMBER: {
00737                     float f = (float)lua_tonumber(L, i+1);
00738 /*@+relaxtypes@*/
00739                     if (f == (int)f) {
00740                         argt[i] = 'i';
00741                         args->argv[i].i = (int)f;
00742                     } else {
00743                         argt[i] = 'f';
00744                         args->argv[i].f = f;
00745                     }
00746 /*@=relaxtypes@*/
00747                 }   /*@switchbreak@*/ break;
00748                 case LUA_TSTRING:
00749                     argt[i] = 's';
00750                     args->argv[i].s = lua_tostring(L, i+1);
00751                     /*@switchbreak@*/ break;
00752                 case LUA_TUSERDATA:
00753                 case LUA_TLIGHTUSERDATA:
00754                     argt[i] = 'p';
00755                     args->argv[i].p = lua_touserdata(L, i+1);
00756                     /*@switchbreak@*/ break;
00757                 default:
00758                     (void) luaL_error(L, "unsupported Lua type passed to hook");
00759                     argt[i] = 'p';
00760                     args->argv[i].p = NULL;
00761                     /*@switchbreak@*/ break;
00762             }
00763         }
00764 /*@-compdef -kepttrans -usereleased @*/
00765         args->argt = argt;
00766         rpmhookCallArgs(name, args);
00767         free(argt);
00768         (void) rpmhookArgsFree(args);
00769 /*@=compdef =kepttrans =usereleased @*/
00770     }
00771     return 0;
00772 }
00773 
00774 /* Based on luaB_print. */
00775 static int rpm_print (lua_State *L)
00776         /*@globals fileSystem @*/
00777         /*@modifies L, fileSystem @*/
00778 {
00779     rpmlua lua = (rpmlua)getdata(L, "lua");
00780     int n = lua_gettop(L);  /* number of arguments */
00781     int i;
00782     if (!lua) return 0;
00783     lua_getglobal(L, "tostring");
00784     for (i = 1; i <= n; i++) {
00785         const char *s;
00786         lua_pushvalue(L, -1);  /* function to be called */
00787         lua_pushvalue(L, i);   /* value to print */
00788         lua_call(L, 1, 1);
00789         s = lua_tostring(L, -1);  /* get result */
00790         if (s == NULL)
00791             return luaL_error(L, "`tostring' must return a string to `print'");
00792         if (lua->storeprint) {
00793             int sl = lua_strlen(L, -1);
00794             if (lua->printbufused+sl+1 > lua->printbufsize) {
00795                 lua->printbufsize += sl+512;
00796                 lua->printbuf = xrealloc(lua->printbuf, lua->printbufsize);
00797             }
00798             if (i > 1)
00799                 lua->printbuf[lua->printbufused++] = '\t';
00800             memcpy(lua->printbuf+lua->printbufused, s, sl+1);
00801             lua->printbufused += sl;
00802         } else {
00803             if (i > 1)
00804                 (void) fputs("\t", stdout);
00805             (void) fputs(s, stdout);
00806         }
00807         lua_pop(L, 1);  /* pop result */
00808     }
00809     lua_pop(L, 1);
00810     if (!lua->storeprint) {
00811         (void) fputs("\n", stdout);
00812     } else {
00813         if (lua->printbufused+1 >= lua->printbufsize) {
00814             lua->printbufsize += 512;
00815             lua->printbuf = xrealloc(lua->printbuf, lua->printbufsize);
00816         }
00817         lua->printbuf[lua->printbufused++] = '\n';
00818         lua->printbuf[lua->printbufused] = '\0';
00819     }
00820     return 0;
00821 }
00822 
00823 /*@-readonlytrans@*/
00824 /*@observer@*/ /*@unchecked@*/
00825 static const luaL_reg rpmlib[] = {
00826     {"expand", rpm_expand},
00827     {"define", rpm_define},
00828     {"register", rpm_register},
00829     {"unregister", rpm_unregister},
00830     {"call", rpm_call},
00831     {"interactive", rpm_interactive},
00832     {NULL, NULL}
00833 };
00834 /*@=readonlytrans@*/
00835 
00836 static int luaopen_rpm(lua_State *L)
00837         /*@modifies L @*/
00838 {
00839     lua_pushvalue(L, LUA_GLOBALSINDEX);
00840     luaL_openlib(L, "rpm", rpmlib, 0);
00841     return 0;
00842 }
00843 #endif  /* WITH_LUA */
00844 
00845 /*@=bounds =realcompare =sizeoftype =protoparammatch @*/

Generated on Tue Feb 19 22:26:37 2008 for rpm by  doxygen 1.5.1