+/* luci.cutil.instanceof(object, class) */
+static int luci_instanceof(lua_State *L) {
+ int stat = 0;
+
+ luaL_checkany(L, 1);
+ luaL_checkany(L, 2);
+
+ if (lua_getmetatable(L, 1)) {
+ /* get parent class */
+ lua_getfield(L, -1, "__index");
+ while (lua_istable(L, -1)) {
+ /* parent class == class */
+ if (lua_equal(L, -1, 2)) {
+ stat = 1;
+ break;
+ }
+
+ /* remove last metatable */
+ lua_remove(L, -2);
+
+ /* get metatable of parent class */
+ if (lua_getmetatable(L, -1)) {
+ /* remove last parent class */
+ lua_remove(L, -2);
+
+ /* get next parent class */
+ lua_getfield(L, -1, "__index");
+ } else {
+ break;
+ }
+ }
+ }
+
+ lua_pushboolean(L, stat);
+ return 1;
+}
+
+
+/* luci.cutil.pcdata(obj) */
+static int luci_pcdata(lua_State *L) {
+ if (lua_isnone(L, 1)) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ /* Discard anything else */
+ lua_settop(L, 1);
+
+ /* tostring(obj) */
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_insert(L, 1);
+ lua_call(L, 1, 1);
+
+ /* pattern */
+ lua_pushvalue(L, lua_upvalueindex(2));
+
+ /* repl */
+ lua_pushvalue(L, lua_upvalueindex(3));
+
+ /* get gsub function */
+ lua_getfield(L, -3, "gsub");
+ lua_insert(L, 1);
+
+ /* tostring(obj):gsub(pattern, repl) */
+ lua_call(L, 3, 1);
+ return 1;
+}
+
+
+/* Registration helper for luci.cutil.pcdata */
+static void luci__register_pcdata(lua_State *L) {
+ /* tostring */
+ lua_getfield(L, LUA_GLOBALSINDEX, "tostring");
+
+ /* pattern */
+ lua_pushliteral(L, "[&\"'<>]");
+
+ /* repl */
+ lua_createtable(L, 0, 5);
+
+ lua_pushliteral(L, "&");
+ lua_setfield(L, -2, "&");
+ lua_pushliteral(L, """);
+ lua_setfield(L, -2, "\"");
+ lua_pushliteral(L, "'");
+ lua_setfield(L, -2, "'");
+ lua_pushliteral(L, "<");
+ lua_setfield(L, -2, "<");
+ lua_pushliteral(L, ">");
+ lua_setfield(L, -2, ">");
+
+ /* register function */
+ lua_pushcclosure(L, luci_pcdata, 3);
+ lua_setfield(L, -2, "pcdata");
+}