isbear@23: isbear@23: /* Copyright 2009 Myhailo Danylenko isbear@23: isbear@23: This file is part of lua-lm. isbear@23: isbear@23: lua-lm is free software: you can redistribute it and/or modify isbear@23: it under the terms of the GNU General Public License as published by isbear@23: the Free Software Foundation, either version 2 of the License, or isbear@23: (at your option) any later version. isbear@23: isbear@23: This program is distributed in the hope that it will be useful, isbear@23: but WITHOUT ANY WARRANTY; without even the implied warranty of isbear@23: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the isbear@23: GNU General Public License for more details. isbear@23: isbear@23: You should have received a copy of the GNU General Public License isbear@23: along with this program. If not, see . */ isbear@0: isbear@0: #include isbear@0: #include isbear@0: #include isbear@0: isbear@6: #include "config.h" isbear@0: #include "lm_types.h" isbear@0: isbear@0: /// lm.message_node isbear@0: /// Object, representing xml node of the message. isbear@0: /// Cannot be created directly, only as a part of message tree. isbear@0: isbear@0: /// lm.message_node.bless isbear@0: /// Blesses given pointer to lm message node object. isbear@0: /// A: lightuserdata (C lm message node object) isbear@0: /// R: lm message node object isbear@11: static int bless_lua_lm_node (lua_State *L) isbear@0: { isbear@0: luaL_argcheck (L, lua_islightuserdata (L, 1), 1, "loudmouth message node lightuserdata expected"); isbear@11: bless_lm_node (L, lua_touserdata (L, 1)); isbear@0: return 1; isbear@0: } isbear@0: isbear@0: /// message_node:name isbear@0: /// Gets a name of message node. isbear@0: /// R: string isbear@11: int name_lm_node (lua_State *L) isbear@0: { isbear@7: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@7: lua_pushstring (L, node->name); isbear@0: return 1; isbear@0: } isbear@0: isbear@0: /// message_node:next isbear@0: /// Gets next message node. isbear@0: /// R: lm message node object or nil isbear@11: int next_lm_node (lua_State *L) isbear@0: { isbear@7: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@7: LmMessageNode *next = node->next; isbear@7: if (next) isbear@11: bless_lm_node (L, next); isbear@0: else isbear@0: lua_pushnil (L); isbear@0: return 1; isbear@0: } isbear@0: isbear@0: /// message_node:prev isbear@0: /// Gets previous message node. isbear@0: /// R: lm message node object or nil isbear@11: int prev_lm_node (lua_State *L) isbear@0: { isbear@7: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@7: LmMessageNode *prev = node->prev; isbear@7: if (prev) isbear@11: bless_lm_node (L, prev); isbear@0: else isbear@0: lua_pushnil (L); isbear@0: return 1; isbear@0: } isbear@0: isbear@0: /// message_node:parent isbear@0: /// Gets parent message node. isbear@0: /// R: lm message node object or nil isbear@11: int parent_lm_node (lua_State *L) isbear@0: { isbear@7: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@7: LmMessageNode *parent = node->parent; isbear@7: if (parent) isbear@11: bless_lm_node (L, parent); isbear@0: else isbear@0: lua_pushnil (L); isbear@0: return 1; isbear@0: } isbear@0: isbear@0: /// message_node:value isbear@0: /// Gets or sets a value of message node. isbear@0: /// A: string (optional value) isbear@6: /// R: string (if called without arguments) or lm message node object isbear@11: int value_lm_node (lua_State *L) isbear@0: { isbear@7: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@0: if (lua_gettop (L) > 1) { // Set isbear@0: const char *value = luaL_checkstring (L, 2); isbear@7: lm_message_node_set_value (node, value); isbear@6: lua_pop (L, 1); isbear@6: } else // Get isbear@7: lua_pushstring (L, lm_message_node_get_value (node)); isbear@6: return 1; isbear@0: } isbear@0: isbear@0: /// message_node:child isbear@0: /// Gets or creates child node object with given name. isbear@14: /// If name is omitted, first child node is returned. isbear@14: /// A: string (name, optional), string (optional value) isbear@0: /// R: lm message node object or nil isbear@11: int child_lm_node (lua_State *L) isbear@0: { isbear@7: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@0: LmMessageNode *child; isbear@14: int top = lua_gettop (L); isbear@14: if (top > 1) { isbear@14: const char *name = luaL_checkstring (L, 2); isbear@0: isbear@14: if (top > 2) // Add isbear@14: child = lm_message_node_add_child (node, name, isbear@14: luaL_checkstring (L, 3)); isbear@14: else // Get isbear@14: child = lm_message_node_get_child (node, name); isbear@14: } else isbear@14: child = node->children; isbear@14: isbear@14: if (child) isbear@14: bless_lm_node (L, child); isbear@14: // XXX lm_message_node_unref (child); // may be necessary on _get/_add'ed nodes isbear@14: else isbear@14: lua_pushnil (L); isbear@0: return 1; isbear@0: } isbear@0: isbear@39: static int children_iterator_lm_node (lua_State *L) isbear@39: { isbear@39: const char *name = lua_tostring (L, lua_upvalueindex (1)); isbear@39: LmMessageNode *node; isbear@39: if (lua_type (L, 2) == LUA_TUSERDATA) { isbear@39: node = luaL_checkLmMessageNode (L, 2); isbear@39: node = node -> next; isbear@39: } else { isbear@39: node = luaL_checkLmMessageNode (L, 1); isbear@39: node = node -> children; isbear@39: } isbear@39: isbear@39: if (name) isbear@39: while (node && g_strcmp0 (node -> name, name)) isbear@39: node = node -> next; isbear@39: isbear@39: if (node) isbear@39: bless_lm_node (L, node); isbear@39: // XXX lm_message_node_unref (child); // may be necessary on _get/_add'ed nodes isbear@39: else isbear@39: lua_pushnil (L); isbear@39: isbear@39: return 1; isbear@39: } isbear@39: isbear@39: /// message_node:children isbear@39: /// Returns iterator over child nodes of given node. Optionally filters childs by name. isbear@39: /// A: string (name, optional) isbear@39: /// R: iterator function, lm message node object, nil isbear@39: int children_lm_node (lua_State *L) isbear@39: { isbear@39: if (lua_type (L, 2) != LUA_TSTRING) isbear@39: lua_pushnil (L); isbear@39: isbear@39: lua_pushcclosure (L, children_iterator_lm_node, 1); isbear@39: lua_pushvalue (L, 1); isbear@39: lua_pushnil (L); isbear@39: isbear@39: return 3; isbear@39: } isbear@39: isbear@0: /// message_node:find_child isbear@0: /// Searches for node with a given name over all node subtree. isbear@0: /// A: string (name) isbear@0: /// R: lm message node object or nil isbear@11: int find_child_lm_node (lua_State *L) isbear@0: { isbear@39: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@39: const char *name = luaL_checkstring (L, 2); isbear@0: LmMessageNode *child; isbear@0: isbear@7: child = lm_message_node_get_child (node, name); isbear@0: if (!child) isbear@0: lua_pushnil (L); isbear@0: else { isbear@11: bless_lm_node (L, child); isbear@0: // XXX lm_message_node_unref (child); isbear@0: } isbear@0: return 1; isbear@0: } isbear@0: isbear@0: /// message_node:raw isbear@0: /// Gets or sets raw mode flag for node. isbear@0: /// When set, value of node will not be escaped. isbear@0: /// A: boolean (optional) isbear@6: /// V: boolean (if called with no apguments) or lm message node object isbear@11: int raw_lm_node (lua_State *L) isbear@0: { isbear@7: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@0: if (lua_gettop (L) > 1) { // Set isbear@0: luaL_checktype (L, 2, LUA_TBOOLEAN); isbear@7: lm_message_node_set_raw_mode (node, lua_toboolean (L, 2)); isbear@6: lua_pop (L, 1); isbear@6: } else // Get isbear@7: lua_pushboolean (L, lm_message_node_get_raw_mode (node)); isbear@6: return 1; isbear@0: } isbear@0: isbear@0: /// message_node:attribute isbear@0: /// Gets or sets value of node attribute with a given name. isbear@0: /// A: string (name), string (optional value) isbear@6: /// R: string (when called with one aprgument) or lm message node object isbear@11: int attribute_lm_node (lua_State *L) isbear@0: { isbear@7: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@39: const char *name = luaL_checkstring (L, 2); isbear@0: if (lua_gettop (L) > 2) { // Set isbear@7: lm_message_node_set_attribute (node, name, luaL_checkstring (L, 3)); isbear@6: lua_pop (L, 2); isbear@6: } else // Get isbear@7: lua_pushstring (L, lm_message_node_get_attribute (node, name)); isbear@6: return 1; isbear@0: } isbear@0: isbear@0: /// message_node:xml isbear@0: /// Returns node representation in xml. isbear@0: /// R: string isbear@11: int xml_lm_node (lua_State *L) isbear@0: { isbear@7: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@7: lua_pushstring (L, lm_message_node_to_string (node)); isbear@0: return 1; isbear@0: } isbear@0: isbear@8: /// message_node:path isbear@8: /// Returns node with specified path to it. isbear@8: /// If any element in a path cannot be found, it returns nil. isbear@8: /// A: string (node name), ... isbear@8: /// R: lm message node object or nil isbear@11: int path_lm_node (lua_State *L) isbear@8: { isbear@8: LmMessageNode *node = luaL_checkLmMessageNode (L, 1); isbear@8: int i = 1; isbear@8: while (i++ < lua_gettop (L)) { isbear@8: node = lm_message_node_get_child (node, luaL_checkstring (L, i)); isbear@8: if (node == NULL) { isbear@8: lua_pushnil (L); isbear@8: return 1; isbear@8: } isbear@8: } isbear@11: bless_lm_node (L, node); isbear@8: // XXX lm_message_node_unref (child); isbear@8: return 1; isbear@8: } isbear@8: isbear@0: /// message_node:pointer isbear@0: /// Returns pointer to underlying C structure. isbear@0: /// R: lightuserdata isbear@11: static int pointer_lm_node (lua_State *L) isbear@0: { isbear@11: llm_node_t *object = luaL_checklm_node (L, 1); isbear@11: lua_pushlightuserdata (L, object->node); isbear@0: return 1; isbear@0: } isbear@0: isbear@11: static int gc_lm_node (lua_State *L) isbear@0: { isbear@11: llm_node_t *object = luaL_checklm_node (L, 1); isbear@38: D ("Message node %p gc called", object); isbear@11: lm_message_node_unref (object->node); isbear@0: return 0; isbear@0: } isbear@0: isbear@11: static const luaL_Reg reg_f_lm_node[] = { isbear@11: { "bless", bless_lua_lm_node }, isbear@12: { NULL, NULL }, isbear@0: }; isbear@0: isbear@11: static const luaL_Reg reg_m_lm_node[] = { isbear@11: { "name", name_lm_node }, isbear@11: { "next", next_lm_node }, isbear@11: { "prev", prev_lm_node }, isbear@11: { "parent", parent_lm_node }, isbear@11: { "value", value_lm_node }, isbear@11: { "child", child_lm_node }, isbear@39: { "children", children_lm_node }, isbear@11: { "find_child", find_child_lm_node }, isbear@11: { "attribute", attribute_lm_node }, isbear@11: { "raw", raw_lm_node }, isbear@11: { "xml", xml_lm_node }, isbear@11: { "path", path_lm_node }, isbear@11: { "pointer", pointer_lm_node }, isbear@11: { "__gc", gc_lm_node }, isbear@12: { NULL, NULL }, isbear@0: }; isbear@0: isbear@0: int luaopen_lm_message_node (lua_State *L) isbear@0: { isbear@0: luaL_newmetatable (L, "loudmouth.message_node"); isbear@19: lua_pushvalue (L, -1); isbear@19: lua_setfield (L, -2, "__index"); isbear@54: luaL_setfuncs (L, reg_m_lm_node, 0); isbear@0: lua_pop (L, 1); isbear@16: lua_newtable (L); // XXX we can specify here exact amount of fields isbear@54: luaL_setfuncs (L, reg_f_lm_node, 0); isbear@0: return 1; isbear@0: } isbear@0: