/* * Generic object newindex metamethod handler. * Lua Stack: ud, key, value */ int object_newindex_handler(lua_State *L) { char sskey[16], *skey; if ((!lua_isstring(L, 2)) || (!lua_isstring(L, 3))){ gr_object_t *ud = toobject(L, 1, NULL, STRICT); skey = agget(ud->p.p, ".attrib"); if (!skey || (strlen(skey) == 0)){ /* Let's create an attrib table on the fly if none exists */ sprintf(sskey, "%p", ud->p.p); skey = agstrdup(sskey); agset(ud->p.p, ".attrib", skey); lua_pushstring(L, skey); /* ud, key, value, skey */ lua_newtable(L); /* ud, key, value, skey, stab */ lua_rawset(L, LUA_REGISTRYINDEX); /* ud, key, value, */ } lua_pushstring(L, skey); /* ud, key, value, skey */ lua_rawget(L, LUA_REGISTRYINDEX); /* ud, key, value, stab */ lua_pushvalue(L, 2); /* ud, key, value, stab, key */ lua_pushvalue(L, 3); /* ud, key, value, stab, key, value */ lua_rawset(L, -3); /* ud, key, value, stab */ lua_pop(L, -1); /* ud, key, value */ return 0; } return setval(L); }
/* * Set a value to a graphviz object attribute */ static int setval(lua_State *L) { gr_object_t *ud = toobject(L, 1, NULL, STRICT); char *key = (char *) luaL_checkstring(L, 2); char *value = (char *) luaL_checkstring(L, 3); return agsafeset(ud->p.p, key, value, NULL); }
/*-------------------------------------------------------------------------*\ * Generic method: type = obj.type(self) * Returns type of a graph object. * Returns the type as string: 'graph', 'node' or 'edge'. * Example: * type = n:type() \*-------------------------------------------------------------------------*/ int get_object_type(lua_State *L) { gr_object_t *ud = toobject(L, 1, NULL, STRICT); lua_pushstring(L, AGTYPE(ud->p.p) == AGGRAPH ? "graph" : AGTYPE(ud->p.p) == AGNODE ? "node" : AGTYPE(ud->p.p) == AGEDGE ? "edge" : "unkown"); return 1; }
/* * Get the value of a graphviz object attribute */ int getval(lua_State *L) { gr_object_t *ud = toobject(L, 1, NULL, STRICT); char *key = (char *) luaL_checkstring(L, 2); char *value = agget(ud->p.p, key); if (!value || strlen(value) == 0){ lua_pushnil(L); return 1; } lua_pushstring(L, value); return 1; }
/* * Generic object index metamethod handler * This closure has 2 upvalues: * 1. table with read members (this is the metatable) * 2. metatable.__metatable contains the methods * Lua stack: ud, key */ int object_index_handler(lua_State *L) { gr_object_t *ud; char *skey; /* Read member lookup in first upvalue */ lua_pushvalue(L, 2); /* ud, key, key */ lua_rawget(L, lua_upvalueindex(1)); /* ud, key, getfunc (member) or nil (method) */ if (!lua_isfunction(L, -1)){ /* Member not found - try methods */ lua_pop(L, 1); /* ud, key */ lua_pushvalue(L, 2); /* ud, key, key */ lua_gettable(L, lua_upvalueindex(2)); /* ud, key, method */ if (lua_isnil(L, -1)){ /* Try generic get method */ if (lua_isstring(L, 2)){ lua_settop(L, 2); /* ud, key */ lua_pushcfunction(L, getval); /* ud, key, gr_get */ lua_pushvalue(L, 1); /* ud, key, gr_get, ud */ lua_pushvalue(L, 2); /* ud, key, gr_get, ud, key */ lua_call(L, 2, 1); /* ud, key, value or nil */ } if (lua_isnil(L, -1)){ /* Try generic storage */ lua_settop(L, 2); /* ud, key */ ud = toobject(L, 1, NULL, STRICT); skey = agget(ud->p.p, ".attrib"); if (skey && strlen(skey) > 0){ lua_pushstring(L, skey); /* ud, key, skey */ lua_rawget(L, LUA_REGISTRYINDEX); /* ud, key, stab */ lua_pushvalue(L, 2); /* ud, key, stab, key */ lua_rawget(L, -2); /* ud, key, stab, value */ lua_remove(L, -2); /* ud, key, value */ } else lua_pushnil(L); /* ud, key, nil */ } } return 1; } /* Call the member's access function */ lua_pushvalue(L, 1); /* ud, key, getfunc, ud */ lua_pushvalue(L, 2); /* ud, key, getfunc, ud, key */ lua_call(L, 2, 1); /* ud, key, value */ return 1; }
/*-------------------------------------------------------------------------*\ * Metamethod: __tostring [boolean] * Return a string presentation of a graph object. * Example: * g == h or g != h with metamethods \*-------------------------------------------------------------------------*/ static int gr_tostring(lua_State *L) { gr_object_t *ud = toobject(L, 1, NULL, NONSTRICT); lua_pushfstring(L, "node: %p (%s)", ud, ud->p.status == ALIVE ? "alive" : "dead"); return 1; }