diff --git a/legacy/edje/ChangeLog b/legacy/edje/ChangeLog index 9dd1453701..505ce25584 100644 --- a/legacy/edje/ChangeLog +++ b/legacy/edje/ChangeLog @@ -271,3 +271,10 @@ * Unswallow object that are about to be swallowed if necessary. * Add EDJE_ASPECT_PREFER_SOURCE. + +2011-11-07 David Seikel (onefang) + + * Lua: Calling non exstent functions no longer crashes scripts. + This is so that future scripts will still work with old libraries, + and lets us add the "host can provide Lua API" feature soon. + diff --git a/legacy/edje/NEWS b/legacy/edje/NEWS index 1b38efb0b6..875a566b46 100644 --- a/legacy/edje/NEWS +++ b/legacy/edje/NEWS @@ -13,6 +13,7 @@ Improvements: * check existence of group at compile time also. * reduce number of call to stat during edje_object_file_set. * unswallow object about to be swallowed if necessary. + * Lua scripts now more resilient against API changes. Changes since Edje 1.0.0: ------------------------- diff --git a/legacy/edje/src/examples/lua_script.edc b/legacy/edje/src/examples/lua_script.edc index 24e8ebe4ce..2f2ea74757 100644 --- a/legacy/edje/src/examples/lua_script.edc +++ b/legacy/edje/src/examples/lua_script.edc @@ -168,6 +168,14 @@ collections { print(D.text:text()); D.text:show(); + --// Put a few bogus API calls here to test the bogus API protection, + --// If the bogus API protection works, these should get ignored, but everything else runs smoothly. + --// Otherwise, the map is not done, the bubbles are not done, but the timers keep runinng. + bogus.failme(1, "two", D.rect); + temp = bogus.failme2(); + D.text.bogus(); + edje.bogus2(); + --// Fun with maps! D.map = edje.map(4); --// 4 is the only supported map size at the moment. --// These all do the same thing. diff --git a/legacy/edje/src/lib/edje_lua2.c b/legacy/edje/src/lib/edje_lua2.c index 527d1bd8d8..2dbcb081a2 100644 --- a/legacy/edje/src/lib/edje_lua2.c +++ b/legacy/edje/src/lib/edje_lua2.c @@ -3724,25 +3724,80 @@ _elua_text_text(lua_State *L) // Stack usage [ //--------------------------------------------------------------------------// + +// A metatable and functions so that calling non existant API does not crash Lua scripts. + +static int _elua_bogan_nilfunc(lua_State *L); +static int _elua_bogan_index(lua_State *L); + +static const struct luaL_reg _elua_bogan_funcs [] = +{ + {"nilfunc", _elua_bogan_nilfunc}, // Just return a nil. + {"__index", _elua_bogan_index}, // Return the above func. + + {NULL, NULL} // end +}; + +static int +_elua_bogan_nilfunc(lua_State *L) +{ + lua_getglobal(L, "nil"); + return 1; +} + +static int +_elua_bogan_index(lua_State *L) +{ + const char *key; + + key = lua_tostring(L, 2); + LE("%s does not exist!", key); + lua_pushcfunction(L, _elua_bogan_nilfunc); + return 1; +} + +static void +_elua_bogan_protect(lua_State *L) // Stack usage [-3, +3, m] +{ + lua_pushnil(L); // Stack usage [-0, +1, -] + luaL_newmetatable(L, "bogan"); // Stack usage [-0, +1, m] + luaL_register(L, 0, _elua_bogan_funcs); // Stack usage [-1, +1, m] + lua_setmetatable(L, -2); // Stack usage [-1, +0, -] + lua_pop(L, 1); // Stack usage [-1, +0, -] +} + +//--------------------------------------------------------------------------// + // Brain dead inheritance thingy, built for speed. Kinda. Part 1. static void _elua_add_functions(lua_State *L, const char *api, const luaL_Reg *funcs, const char *meta, const char *parent, const char *base) // Stack usage [-3, +5, m] if inheriting [-6, +11, em] { + // Create an api table, fill it full of the methods. luaL_register(L, api, funcs); // Stack usage [-0, +1, m] + // Set the api metatable to the bogan metatable. + luaL_getmetatable(L, "bogan"); // Stack usage [-0, +1, -] + lua_setmetatable(L, -2); // Stack usage [-1, +0, -] + // Creat a meta metatable. luaL_newmetatable(L, meta); // Stack usage [-0, +1, m] + // Put the gc functions in the metatable. luaL_register(L, 0, _elua_edje_gc_funcs); // Stack usage [-1, +1, m] + // Create an __index entry in the metatable, make it point to the api table. lua_pushliteral(L, "__index"); // Stack usage [-0, +1, m] lua_pushvalue(L, -3); // Stack usage [-0, +1, -] lua_rawset(L, -3); // Stack usage [-2, +0, m] + // Later this metatable is used as the metatable for newly created objects of this class. if (base && parent) { // Inherit from base lua_getglobal(L, base); // Stack usage [-0, +1, e] + // Create a new parent metatable. luaL_newmetatable(L, parent); // Stack usage [-0, +1, m] + // Create an __index entry in the metatable, make it point to the base table. lua_pushliteral(L, "__index"); // Stack usage [-0, +1, m] lua_pushvalue(L, -3); // Stack usage [-0, +1, -] lua_rawset(L, -3); // Stack usage [-2, +0, m] + // Set the metatable for the api table to the parent metatable. lua_getglobal(L, api); // Stack usage [-0, +1, e] luaL_getmetatable(L, parent); // Stack usage [-0, +1, -] lua_setmetatable(L, -2); // Stack usage [-1, +0, -] @@ -3850,7 +3905,11 @@ _edje_lua2_script_init(Edje *ed) // Stack usage lua_call(L, 1, 0); // Stack usage [-2, +0, m] } + _elua_bogan_protect(L); // Stack usage [+3, -3, m] + luaL_register(L, _elua_edje_api, _elua_edje_funcs); // Stack usage [-0, +1, m] + luaL_getmetatable(L, "bogan"); // Stack usage [-0, +1, -] + lua_setmetatable(L, -2); // Stack usage [-1, +0, -] luaL_newmetatable(L, _elua_edje_meta); // Stack usage [-0, +1, m] luaL_register(L, 0, _elua_edje_gc_funcs); // Stack usage [-1, +1, m]