lm_message_node.c
author Myhailo Danylenko <isbear@ukrpost.net>
Wed, 20 Jul 2011 14:35:13 +0300
changeset 45 1fcec4b012a7
parent 39 c5a487f2fd7f
child 54 6bef2082e5f9
permissions -rw-r--r--
Fix warnings


/* Copyright 2009 Myhailo Danylenko

This file is part of lua-lm.

lua-lm is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#include <lua.h>
#include <lauxlib.h>
#include <loudmouth/loudmouth.h>

#include "config.h"
#include "lm_types.h"

/// lm.message_node
/// Object, representing xml node of the message.
/// Cannot be created directly, only as a part of message tree.

/// lm.message_node.bless
/// Blesses given pointer to lm message node object.
/// A: lightuserdata (C lm message node object)
/// R: lm message node object
static int bless_lua_lm_node (lua_State *L)
{
	luaL_argcheck (L, lua_islightuserdata (L, 1), 1, "loudmouth message node lightuserdata expected");
	bless_lm_node (L, lua_touserdata (L, 1));
	return 1;
}

/// message_node:name
/// Gets a name of message node.
/// R: string
int name_lm_node (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	lua_pushstring (L, node->name);
	return 1;
}

/// message_node:next
/// Gets next message node.
/// R: lm message node object or nil
int next_lm_node (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	LmMessageNode *next = node->next;
	if (next)
		bless_lm_node (L, next);
	else
		lua_pushnil (L);
	return 1;
}

/// message_node:prev
/// Gets previous message node.
/// R: lm message node object or nil
int prev_lm_node (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	LmMessageNode *prev = node->prev;
	if (prev)
		bless_lm_node (L, prev);
	else
		lua_pushnil (L);
	return 1;
}

/// message_node:parent
/// Gets parent message node.
/// R: lm message node object or nil
int parent_lm_node (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	LmMessageNode *parent = node->parent;
	if (parent)
		bless_lm_node (L, parent);
	else
		lua_pushnil (L);
	return 1;
}

/// message_node:value
/// Gets or sets a value of message node.
/// A: string (optional value)
/// R: string (if called without arguments) or lm message node object
int value_lm_node (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	if (lua_gettop (L) > 1) { // Set
		const char *value = luaL_checkstring (L, 2);
		lm_message_node_set_value (node, value);
		lua_pop (L, 1);
	} else // Get
		lua_pushstring (L, lm_message_node_get_value (node));
	return 1;
}

/// message_node:child
/// Gets or creates child node object with given name.
/// If name is omitted, first child node is returned.
/// A: string (name, optional), string (optional value)
/// R: lm message node object or nil
int child_lm_node (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	LmMessageNode *child;
	int            top  = lua_gettop (L);
	if (top > 1) {
		const char *name = luaL_checkstring (L, 2);

		if (top > 2) // Add
			child = lm_message_node_add_child (node, name,
							   luaL_checkstring (L, 3));
		else // Get
			child = lm_message_node_get_child (node, name);
	} else
		child = node->children;

	if (child)
		bless_lm_node (L, child);
		// XXX lm_message_node_unref (child); // may be necessary on _get/_add'ed nodes
	else
		lua_pushnil (L);
	return 1;
}

static int children_iterator_lm_node (lua_State *L)
{
	const char    *name = lua_tostring (L, lua_upvalueindex (1));
	LmMessageNode *node;
	if (lua_type (L, 2) == LUA_TUSERDATA) {
		node = luaL_checkLmMessageNode (L, 2);
		node = node -> next;
	} else {
		node = luaL_checkLmMessageNode (L, 1);
		node = node -> children;
	}

	if (name)
		while (node && g_strcmp0 (node -> name, name))
			node = node -> next;

	if (node)
		bless_lm_node (L, node);
		// XXX lm_message_node_unref (child); // may be necessary on _get/_add'ed nodes
	else
		lua_pushnil (L);

	return 1;
}

/// message_node:children
/// Returns iterator over child nodes of given node. Optionally filters childs by name.
/// A: string (name, optional)
/// R: iterator function, lm message node object, nil
int children_lm_node (lua_State *L)
{
	if (lua_type (L, 2) != LUA_TSTRING)
		lua_pushnil (L);

	lua_pushcclosure (L, children_iterator_lm_node, 1);
	lua_pushvalue (L, 1);
	lua_pushnil (L);
	
	return 3;
}

/// message_node:find_child
/// Searches for node with a given name over all node subtree.
/// A: string (name)
/// R: lm message node object or nil
int find_child_lm_node (lua_State *L)
{
	LmMessageNode *node  = luaL_checkLmMessageNode (L, 1);
	const char    *name  = luaL_checkstring (L, 2);
	LmMessageNode *child;

	child = lm_message_node_get_child (node, name);
	if (!child)
		lua_pushnil (L);
	else {
		bless_lm_node (L, child);
		// XXX lm_message_node_unref (child);
	}
	return 1;
}

/// message_node:raw
/// Gets or sets raw mode flag for node.
/// When set, value of node will not be escaped.
/// A: boolean (optional)
/// V: boolean (if called with no apguments) or lm message node object
int raw_lm_node (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	if (lua_gettop (L) > 1) { // Set
		luaL_checktype (L, 2, LUA_TBOOLEAN);
		lm_message_node_set_raw_mode (node, lua_toboolean (L, 2));
		lua_pop (L, 1);
	} else // Get
		lua_pushboolean (L, lm_message_node_get_raw_mode (node));
	return 1;
}

/// message_node:attribute
/// Gets or sets value of node attribute with a given name.
/// A: string (name), string (optional value)
/// R: string (when called with one aprgument) or lm message node object
int attribute_lm_node (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	const char    *name = luaL_checkstring (L, 2);
	if (lua_gettop (L) > 2) { // Set
		lm_message_node_set_attribute (node, name, luaL_checkstring (L, 3));
		lua_pop (L, 2);
	} else // Get
		lua_pushstring (L, lm_message_node_get_attribute (node, name));
	return 1;
}

/// message_node:xml
/// Returns node representation in xml.
/// R: string
int xml_lm_node (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	lua_pushstring (L, lm_message_node_to_string (node));
	return 1;
}

/// message_node:path
/// Returns node with specified path to it.
/// If any element in a path cannot be found, it returns nil.
/// A: string (node name), ...
/// R: lm message node object or nil
int path_lm_node (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	int i = 1;
	while (i++ < lua_gettop (L)) {
		node = lm_message_node_get_child (node, luaL_checkstring (L, i));
		if (node == NULL) {
			lua_pushnil (L);
			return 1;
		}
	}
	bless_lm_node (L, node);
	// XXX lm_message_node_unref (child);
	return 1;
}

/// message_node:pointer
/// Returns pointer to underlying C structure.
/// R: lightuserdata
static int pointer_lm_node (lua_State *L)
{
	llm_node_t *object = luaL_checklm_node (L, 1);
	lua_pushlightuserdata (L, object->node);
	return 1;
}

static int gc_lm_node (lua_State *L)
{
	llm_node_t *object = luaL_checklm_node (L, 1);
	D ("Message node %p gc called", object);
	lm_message_node_unref (object->node);
	return 0;
}

static const luaL_Reg reg_f_lm_node[] = {
	{ "bless", bless_lua_lm_node },
	{ NULL,    NULL              },
};

static const luaL_Reg reg_m_lm_node[] = {
	{ "name",       name_lm_node       },
	{ "next",       next_lm_node       },
	{ "prev",       prev_lm_node       },
	{ "parent",     parent_lm_node     },
	{ "value",      value_lm_node      },
	{ "child",      child_lm_node      },
	{ "children",   children_lm_node   },
	{ "find_child", find_child_lm_node },
	{ "attribute",  attribute_lm_node  },
	{ "raw",        raw_lm_node        },
	{ "xml",        xml_lm_node        },
	{ "path",       path_lm_node       },
	{ "pointer",    pointer_lm_node    },
	{ "__gc",       gc_lm_node         },
	{ NULL,         NULL               },
};

int luaopen_lm_message_node (lua_State *L)
{
	luaL_newmetatable (L, "loudmouth.message_node");
	lua_pushvalue (L, -1);
	lua_setfield (L, -2, "__index");
	luaL_register (L, NULL, reg_m_lm_node);
	lua_pop (L, 1);
	lua_newtable (L); // XXX we can specify here exact amount of fields
	luaL_register (L, NULL, reg_f_lm_node);
	return 1;
}