lm_message_node.c
author Myhailo Danylenko <isbear@ukrpost.net>
Sat, 21 Feb 2009 16:10:28 +0200
changeset 8 951f92c66821
parent 7 5db1448eb857
child 11 a8c6460d612b
permissions -rw-r--r--
Path method


#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 llm_message_node_bless_lua (lua_State *L)
{
	luaL_argcheck (L, lua_islightuserdata (L, 1), 1, "loudmouth message node lightuserdata expected");
	llm_message_node_bless (L, lua_touserdata (L, 1));
	return 1;
}

/// message_node:name
/// Gets a name of message node.
/// R: string
int llm_message_node_name (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 llm_message_node_next (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	LmMessageNode *next = node->next;
	if (next)
		llm_message_node_bless (L, next);
	else
		lua_pushnil (L);
	return 1;
}

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

/// message_node:children
/// Gets first child node (raw access used).
/// R: lm message node object or nil
int llm_message_node_children (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	LmMessageNode *child = node->children;
	if (child)
		llm_message_node_bless (L, child);
	else
		lua_pushnil (L);
	return 1;
}

/// message_node:parent
/// Gets parent message node.
/// R: lm message node object or nil
int llm_message_node_parent (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	LmMessageNode *parent = node->parent;
	if (parent)
		llm_message_node_bless (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 llm_message_node_value (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.
/// A: string (name), string (optional value)
/// R: lm message node object or nil
int llm_message_node_child (lua_State *L)
{
	LmMessageNode *node = luaL_checkLmMessageNode (L, 1);
	const char *name = luaL_checkstring (L, 2);
	LmMessageNode *child;

	if (lua_gettop (L) > 2) // Add
		child = lm_message_node_add_child (node, name,
						   luaL_checkstring (L, 3));
	else { // Get
		child = lm_message_node_get_child (node, name);
		if (!child) {
			lua_pushnil (L);
			return 1;
		}
	}
	llm_message_node_bless (L, child);
	// XXX lm_message_node_unref (child);
	return 1;
}

/// 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 llm_message_node_find_child (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 {
		llm_message_node_bless (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 llm_message_node_raw (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 llm_message_node_attribute (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 llm_message_node_xml (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 llm_message_node_path (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;
		}
	}
	llm_message_node_bless (L, node);
	// XXX lm_message_node_unref (child);
	return 1;
}

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

static int llm_message_node_gc (lua_State *L)
{
	llm_message_node_t *object = luaL_checklm_message_node (L, 1);
	D ("Message node %X gc called", (int) object);
	lm_message_node_unref (object->message_node);
	return 0;
}

static const luaL_Reg llm_message_node_reg_f[] = {
	{ "bless", llm_message_node_bless_lua },
	{ NULL,    NULL                       },
};

static const luaL_Reg llm_message_node_reg_m[] = {
	{ "name",       llm_message_node_name       },
	{ "next",       llm_message_node_next       },
	{ "prev",       llm_message_node_prev       },
	{ "children",   llm_message_node_children   },
	{ "parent",     llm_message_node_parent     },
	{ "value",      llm_message_node_value      },
	{ "child",      llm_message_node_child      },
	{ "find_child", llm_message_node_find_child },
	{ "attribute",  llm_message_node_attribute  },
	{ "raw",        llm_message_node_raw        },
	{ "xml",        llm_message_node_xml        },
	{ "path",       llm_message_node_path       },
	{ "pointer",    llm_message_node_pointer    },
	{ "__gc",       llm_message_node_gc         },
	{ NULL,         NULL                        },
};

int luaopen_lm_message_node (lua_State *L)
{
	luaL_newmetatable (L, "loudmouth.message_node");
	lua_pushstring (L, "__index");
	lua_pushvalue (L, -2);
	lua_settable (L, -3);
	luaL_register (L, NULL, llm_message_node_reg_m);
	lua_pop (L, 1);
	luaL_register (L, "lm.message_node", llm_message_node_reg_f);
	return 1;
}