/*
   +----------------------------------------------------------------------+
   | All rights reserved                                                  |
   |                                                                      |
   | Redistribution and use in source and binary forms, with or without   |
   | modification, are permitted provided that the following conditions   |
   | are met:                                                             |
   |                                                                      |
   | 1. Redistributions of source code must retain the above copyright    |
   |    notice, this list of conditions and the following disclaimer.     |
   | 2. Redistributions in binary form must reproduce the above copyright |
   |    notice, this list of conditions and the following disclaimer in   |
   |    the documentation and/or other materials provided with the        |
   |    distribution.                                                     |
   | 3. The names of the authors may not be used to endorse or promote    |
   |    products derived from this software without specific prior        |
   |    written permission.                                               |
   |                                                                      |
   | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
   | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
   | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
   | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE       |
   | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,  |
   | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
   | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;     |
   | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER     |
   | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT   |
   | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN    |
   | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE      |
   | POSSIBILITY OF SUCH DAMAGE.                                          |
   +----------------------------------------------------------------------+
   | Authors: rsk <rsky0711@gmail.com>                                    |
   +----------------------------------------------------------------------+
*/

/* $ Id: $ */

#define PHP_MECAB_MODULE_VERSION "0.0.3-dev"

#include "php_mecab.h"
#include "php_mecab_private.h"

/* {{{ Resource entries and destructors */

/* for php_mecab_t */
static int le_mecab;
static void php_mecab_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
	php_mecab_real_dtor((php_mecab_t *)(rsrc->ptr) TSRMLS_CC);
}
static void php_mecab_real_dtor(php_mecab_t *mecab TSRMLS_DC)
{
	if (mecab->ptr) {
		mecab_destroy((mecab_t *)(mecab->ptr));
	}
	if (mecab->str) {
		efree(mecab->str);
	}
	efree(mecab);
}

/* for php_mecab_node_t */
static int le_mecab_node;
static void php_mecab_node_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
	php_mecab_node_real_dtor((php_mecab_node_t *)(rsrc->ptr) TSRMLS_CC);
}
static void php_mecab_node_real_dtor(php_mecab_node_t *node TSRMLS_DC)
{
	efree(node);
}

/* for mecab_path_t */
static int le_mecab_path;
static void php_mecab_path_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
	return;
}

/* }}} Resource entries and destructors */


/* {{{ Class definitions */
#ifdef ZEND_ENGINE_2

/* redefine PHP_ME_MAPPING macro */
#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 2)
#undef  PHP_ME_MAPPING
#define PHP_ME_MAPPING(name, func_name, arg_types, flags) ZEND_ME_MAPPING(name, func_name, arg_types)
#endif

static zend_class_entry *mecab_tagger_ce = NULL;
static zend_class_entry *mecab_node_ce = NULL;
static zend_class_entry *mecab_path_ce = NULL;

/* {{{ Class MeCab_Tagger */

/* {{{ Methods */

static zend_function_entry MeCab_Tagger_methods[] = {
	/* MeCab API wrappers */
	PHP_ME_MAPPING(__construct,    mecab_new,                NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
	PHP_ME_MAPPING(__destruct,     mecab_destroy,            NULL, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
	PHP_ME_MAPPING(parse,          mecab_sparse_tostr,       NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(parseToString,  mecab_sparse_tostr,       NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(parseToNode,    mecab_sparse_tonode,      NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(parseNBest,     mecab_nbest_sparse_tostr, NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(parseNBestInit, mecab_nbest_init,         NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(next,           mecab_nbest_next_tostr,   NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(nextNode,       mecab_nbest_next_tonode,  NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(formatNode,     mecab_format_node,        NULL, ZEND_ACC_PUBLIC)
	{ NULL, NULL, NULL }
};

/* }}} Methods */

static void class_init_MeCab_Tagger(void)
{
	zend_class_entry ce;

	INIT_CLASS_ENTRY(ce, "MeCab_Tagger", MeCab_Tagger_methods);
	mecab_tagger_ce = zend_register_internal_class(&ce TSRMLS_CC);

	/* {{{ Property registration */

	zend_declare_property_null(mecab_tagger_ce, "mecab", strlen("mecab"), ZEND_ACC_PRIVATE TSRMLS_CC);

	/* }}} Property registration */

}

/* }}} Class MeCab_Tagger */

/* {{{ Class MeCab_Node */

/* {{{ Methods */

static zend_function_entry MeCab_Node_methods[] = {
	/* Constructor */
	PHP_ME(MeCab_Node, __construct, NULL, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1)
	/* Overloading implementations */
	PHP_ME(MeCab_Node, __get,   arginfo_mecab_magic_getter, ZEND_ACC_PUBLIC)
	PHP_ME(MeCab_Node, __isset, arginfo_mecab_magic_getter, ZEND_ACC_PUBLIC)
#endif
	/* Iterator implementations */
	PHP_ME_MAPPING(current,     mecab_node_current,       NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(key,         mecab_node_key,           NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(valid,       mecab_node_valid,         NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(rewind,      mecab_node_rewind,        NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(next,        mecab_node_next,          NULL, ZEND_ACC_PUBLIC)
	/* Dumper */
	PHP_ME_MAPPING(toArray,     mecab_node_toarray,       NULL, ZEND_ACC_PUBLIC)
	/* Getters */
	PHP_ME_MAPPING(getPrev,     mecab_node_get_prev,      NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getNext,     mecab_node_get_next,      NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getENext,    mecab_node_get_enext,     NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getBNext,    mecab_node_get_bnext,     NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getRPath,    mecab_node_get_rpath,     NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getLPath,    mecab_node_get_lpath,     NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getSurface,  mecab_node_get_surface,   NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getFeature,  mecab_node_get_feature,   NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getId,       mecab_node_get_id,        NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getLength,   mecab_node_get_length,    NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getRLength,  mecab_node_get_rlength,   NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getRcAttr,   mecab_node_get_rcattr,    NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getLcAttr,   mecab_node_get_lcattr,    NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getPosId,    mecab_node_get_posid,     NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getCharType, mecab_node_get_char_type, NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getStat,     mecab_node_get_stat,      NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getIsBest,   mecab_node_get_isbest,    NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getAlpha,    mecab_node_get_alpha,     NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getBeta,     mecab_node_get_beta,      NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getProb,     mecab_node_get_prob,      NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getWCost,    mecab_node_get_wcost,     NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getCost,     mecab_node_get_cost,      NULL, ZEND_ACC_PUBLIC)
	{ NULL, NULL, NULL }
};

/* }}} Methods */

static void class_init_MeCab_Node(void)
{
	zend_class_entry ce;
	
	INIT_CLASS_ENTRY(ce, "MeCab_Node", MeCab_Node_methods);
	mecab_node_ce = zend_register_internal_class(&ce TSRMLS_CC);
#ifdef HAVE_SPL
	zend_class_implements(mecab_node_ce TSRMLS_CC, 1, zend_ce_iterator);
#endif
	
	/* {{{ Property registration */
	
	zend_declare_property_null(mecab_node_ce, "node", strlen("node"), ZEND_ACC_PRIVATE TSRMLS_CC);
	
	/* }}} Property registration */
}

/* }}} Class MeCab_Node */

/* {{{ Class MeCab_Path */

/* {{{ Methods */

static zend_function_entry MeCab_Path_methods[] = {
	/* Constructor */
	PHP_ME(MeCab_Path, __construct, NULL, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1)
	/* Overloading implementations */
	PHP_ME(MeCab_Path, __get,   arginfo_mecab_magic_getter, ZEND_ACC_PUBLIC)
	PHP_ME(MeCab_Path, __isset, arginfo_mecab_magic_getter, ZEND_ACC_PUBLIC)
#endif
	/* Getters */
	PHP_ME_MAPPING(getRNext, mecab_path_get_rnext, NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getLNext, mecab_path_get_lnext, NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getRNode, mecab_path_get_rnode, NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getLNode, mecab_path_get_lnode, NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getProb,  mecab_path_get_prob,  NULL, ZEND_ACC_PUBLIC)
	PHP_ME_MAPPING(getCost,  mecab_path_get_cost,  NULL, ZEND_ACC_PUBLIC)
	{ NULL, NULL, NULL }
};

/* }}} Methods */

static void class_init_MeCab_Path(void)
{
	zend_class_entry ce;
	
	INIT_CLASS_ENTRY(ce, "MeCab_Path", MeCab_Path_methods);
	mecab_path_ce = zend_register_internal_class(&ce TSRMLS_CC);
	
	/* {{{ Property registration */
	
	zend_declare_property_null(mecab_path_ce, "path", strlen("path"), ZEND_ACC_PRIVATE TSRMLS_CC);
	
	/* }}} Property registration */
}

/* }}} Class MeCab_Path */
#endif
/* }}} Class definitions */


/* {{{ mecab_functions[] */
function_entry mecab_functions[] = {
	/* MeCab API wrappers */
	PHP_FE(mecab_new,                NULL)
	PHP_FE(mecab_destroy,            NULL)
	PHP_FE(mecab_sparse_tostr,       NULL)
	PHP_FE(mecab_sparse_tonode,      NULL)
	PHP_FE(mecab_nbest_sparse_tostr, NULL)
	PHP_FE(mecab_nbest_init,         NULL)
	PHP_FE(mecab_nbest_next_tostr,   NULL)
	PHP_FE(mecab_nbest_next_tonode,  NULL)
	PHP_FE(mecab_format_node,        NULL)
	/* Dumper for mecab_node */
	PHP_FE(mecab_node_toarray,      NULL)
	/* Iterator implementations for mecab_node */
	PHP_FE(mecab_node_current,       NULL)
	PHP_FE(mecab_node_key,           NULL)
	PHP_FE(mecab_node_valid,         NULL)
	PHP_FE(mecab_node_rewind,        NULL)
	PHP_FE(mecab_node_next,          NULL)
	/* Getters for mecab_node */
	PHP_FE(mecab_node_get_prev,      NULL)
	PHP_FE(mecab_node_get_next,      NULL)
	PHP_FE(mecab_node_get_enext,     NULL)
	PHP_FE(mecab_node_get_bnext,     NULL)
	PHP_FE(mecab_node_get_rpath,     NULL)
	PHP_FE(mecab_node_get_lpath,     NULL)
	PHP_FE(mecab_node_get_surface,   NULL)
	PHP_FE(mecab_node_get_feature,   NULL)
	PHP_FE(mecab_node_get_id,        NULL)
	PHP_FE(mecab_node_get_length,    NULL)
	PHP_FE(mecab_node_get_rlength,   NULL)
	PHP_FE(mecab_node_get_rcattr,    NULL)
	PHP_FE(mecab_node_get_lcattr,    NULL)
	PHP_FE(mecab_node_get_posid,     NULL)
	PHP_FE(mecab_node_get_char_type, NULL)
	PHP_FE(mecab_node_get_stat,      NULL)
	PHP_FE(mecab_node_get_isbest,    NULL)
	PHP_FE(mecab_node_get_alpha,     NULL)
	PHP_FE(mecab_node_get_beta,      NULL)
	PHP_FE(mecab_node_get_prob,      NULL)
	PHP_FE(mecab_node_get_wcost,     NULL)
	PHP_FE(mecab_node_get_cost,      NULL)
	/* Getters for mecab_path */
	PHP_FE(mecab_path_get_rnext,     NULL)
	PHP_FE(mecab_path_get_lnext,     NULL)
	PHP_FE(mecab_path_get_rnode,     NULL)
	PHP_FE(mecab_path_get_lnode,     NULL)
	PHP_FE(mecab_path_get_prob,      NULL)
	PHP_FE(mecab_path_get_cost,      NULL)
	{ NULL, NULL, NULL }
};
/* }}} */


/* {{{ mecab_module_entry */
zend_module_entry mecab_module_entry = {
	STANDARD_MODULE_HEADER,
	"mecab",
	mecab_functions,
	PHP_MINIT(mecab),
	PHP_MSHUTDOWN(mecab),
	PHP_RINIT(mecab),
	PHP_RSHUTDOWN(mecab),
	PHP_MINFO(mecab),
	PHP_MECAB_MODULE_VERSION,
	STANDARD_MODULE_PROPERTIES
};
/* }}} */


#ifdef COMPILE_DL_MECAB
ZEND_GET_MODULE(mecab)
#endif


/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(mecab)
{
	REGISTER_LONG_CONSTANT("MECAB_NOR_NODE", MECAB_NOR_NODE, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("MECAB_UNK_NODE", MECAB_UNK_NODE, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("MECAB_BOS_NODE", MECAB_BOS_NODE, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("MECAB_EOS_NODE", MECAB_EOS_NODE, CONST_PERSISTENT | CONST_CS);
	le_mecab = zend_register_list_destructors_ex(php_mecab_dtor, NULL, "mecab", module_number);
	le_mecab_node = zend_register_list_destructors_ex(php_mecab_node_dtor, NULL, "mecab_node", module_number);
	le_mecab_path = zend_register_list_destructors_ex(php_mecab_path_dtor, NULL, "mecab_path", module_number);
#ifdef ZEND_ENGINE_2
	class_init_MeCab_Tagger();
	class_init_MeCab_Node();
	class_init_MeCab_Path();
#endif
	return SUCCESS;
}
/* }}} */


/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(mecab)
{
	return SUCCESS;
}
/* }}} */


/* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(mecab)
{
	return SUCCESS;
}
/* }}} */


/* {{{ PHP_RSHUTDOWN_FUNCTION */
PHP_RSHUTDOWN_FUNCTION(mecab)
{
	return SUCCESS;
}
/* }}} */


/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(mecab)
{
	php_info_print_table_start();
	php_info_print_table_header(2, "MeCab Support", "enabled");
#ifdef PHP_MECAB_VERSION_STRING
	php_info_print_table_row(2, "MeCab Library Version", PHP_MECAB_VERSION_STRING);
#else
	php_info_print_table_row(2, "MeCab Library Version", "unknown");
#endif
	php_info_print_table_row(2, "Module Version", PHP_MECAB_MODULE_VERSION);
	php_info_print_table_end();
}
/* }}} */


/* {{{ php_mecab_node_instantiate */
static zval *php_mecab_node_instantiate(zval *obj, php_mecab_node_t *node TSRMLS_DC)
{
#ifdef ZEND_ENGINE_2
	/* initialize mecab_node resource */
	zval *rsrc;
	MAKE_STD_ZVAL(rsrc);
	ZEND_REGISTER_RESOURCE(rsrc, node, le_mecab_node);
	
	/* create an instance of MeCab_Node */
	if (!obj) {
		ALLOC_ZVAL(obj);
	}
	Z_TYPE_P(obj) = IS_OBJECT;
	object_init_ex(obj, mecab_node_ce);
	obj->refcount = 1;
	obj->is_ref = 1;
	zend_update_property(mecab_node_ce, obj, "node", strlen("node"), rsrc TSRMLS_CC);
	
	/* reduce refcount */
	zval_ptr_dtor(&rsrc);
#endif
	return obj;
}
/* }}} php_mecab_node_instantiate */


/* {{{ php_mecab_node_get_sibling */
static zval *php_mecab_node_get_sibling(zval *zv, php_mecab_node_t *node, const char *rel, zend_bool is_obj TSRMLS_DC)
{
	/* initialize  */
	php_mecab_node_t *sbl = NULL;
	if (!zv) {
		MAKE_STD_ZVAL(zv);
	}
	
	/* scan */
	PHP_MECAB_NODE_INIT(sbl);
	if (!strcmp(rel, "prev") && node->ptr->prev) {
		sbl->ptr = node->ptr->prev;
	} else if (!strcmp(rel, "next") && node->ptr->next) {
		sbl->ptr = node->ptr->next;
	} else if (!strcmp(rel, "enext") && node->ptr->enext) {
		sbl->ptr = node->ptr->enext;
	} else if (!strcmp(rel, "bnext") && node->ptr->bnext) {
		sbl->ptr = node->ptr->bnext;
	} else {
		efree(sbl);
		sbl = NULL;
		if (!strcmp(rel, "prev") || !strcmp(rel, "next") || !strcmp(rel, "enext") || !strcmp(rel, "bnext")) {
			ZVAL_NULL(zv);
		} else {
			ZVAL_FALSE(zv);
		}
	}
	
	/* set return value */
	if (sbl != NULL) {
		sbl->valid = 1;
		if (is_obj) {
			php_mecab_node_instantiate(zv, sbl TSRMLS_CC);
		} else {
			ZEND_REGISTER_RESOURCE(zv, sbl, le_mecab_node);
		}
	}
	
	return zv;
}
/* }}} php_mecab_node_get_sibling */


/* {{{ php_mecab_node_get_path */
static zval *php_mecab_node_get_path(zval *zv, php_mecab_node_t *node, const char *rel, zend_bool is_obj TSRMLS_DC)
{
	/* initialize  */
	mecab_path_t *path = NULL;
	if (!zv) {
		MAKE_STD_ZVAL(zv);
	}
	
	/* scan */
	if (!strcmp(rel, "rpath") && node->ptr->rpath) {
		path = node->ptr->rpath;
	} else if (!strcmp(rel, "lpath") && node->ptr->lpath) {
		path = node->ptr->lpath;
	} else {
		if (!strcmp(rel, "rpath") || !strcmp(rel, "lpath")) {
			ZVAL_NULL(zv);
		} else {
			ZVAL_FALSE(zv);
		}
	}
	
	/* set return value */
	if (path != NULL) {
		if (is_obj) {
			php_mecab_path_instantiate(zv, path TSRMLS_CC);
		} else {
			ZEND_REGISTER_RESOURCE(zv, path, le_mecab_path);
		}
	}
	
	return zv;
}
/* }}} php_mecab_node_get_path */


/* {{{ php_mecab_path_instantiate */
static zval *php_mecab_path_instantiate(zval *obj, mecab_path_t *path TSRMLS_DC)
{
#ifdef ZEND_ENGINE_2
	/* initialize mecab_path resource */
	zval *rsrc;
	MAKE_STD_ZVAL(rsrc);
	ZEND_REGISTER_RESOURCE(rsrc, path, le_mecab_path);
	
	/* create an instance of MeCab_Node */
	if (!obj) {
		ALLOC_ZVAL(obj);
	}
	Z_TYPE_P(obj) = IS_OBJECT;
	object_init_ex(obj, mecab_path_ce);
	obj->refcount = 1;
	obj->is_ref = 1;
	zend_update_property(mecab_path_ce, obj, "path", strlen("path"), rsrc TSRMLS_CC);
	
	/* reduce refcount */
	zval_ptr_dtor(&rsrc);
#endif
	return obj;
}
/* }}} php_mecab_path_instantiate */


/* {{{ php_mecab_path_get_sibling */
static zval *php_mecab_path_get_sibling(zval *zv, mecab_path_t *path, const char *rel, zend_bool is_obj TSRMLS_DC)
{
	/* initialize  */
	mecab_path_t *sbl = NULL;
	if (!zv) {
		MAKE_STD_ZVAL(zv);
	}
	
	/* scan */
	if (!strcmp(rel, "rnext") && path->rnext) {
		sbl = path->rnext;
	} else if (!strcmp(rel, "lnext") && path->lnext) {
		sbl = path->lnext;
	} else {
		if (!strcmp(rel, "rnext") || !strcmp(rel, "lnext")) {
			ZVAL_NULL(zv);
		} else {
			ZVAL_FALSE(zv);
		}
	}
	
	/* set return value */
	if (sbl != NULL) {
		if (is_obj) {
			php_mecab_path_instantiate(zv, sbl TSRMLS_CC);
		} else {
			ZEND_REGISTER_RESOURCE(zv, sbl, le_mecab_path);
		}
	}
	
	return zv;
}
/* }}} php_mecab_path_get_sibling */


/* {{{ php_mecab_path_get_node */
static zval *php_mecab_path_get_node(zval *zv, mecab_path_t *path, const char *rel, zend_bool is_obj TSRMLS_DC)
{
	/* initialize  */
	php_mecab_node_t *node = NULL;
	if (!zv) {
		MAKE_STD_ZVAL(zv);
	}
	
	/* scan */
	PHP_MECAB_NODE_INIT(node);
	if (!strcmp(rel, "rnode") && path->rnode) {
		node->ptr = path->rnode;
	} else if (!strcmp(rel, "lnode") && path->lnode) {
		node->ptr = path->lnode;
	} else {
		efree(node);
		node = NULL;
		if (!strcmp(rel, "rnode") || !strcmp(rel, "lnode")) {
			ZVAL_NULL(zv);
		} else {
			ZVAL_FALSE(zv);
		}
	}
	
	/* set return value */
	if (node != NULL) {
		node->valid = 1;
		if (is_obj) {
			php_mecab_node_instantiate(zv, node TSRMLS_CC);
		} else {
			ZEND_REGISTER_RESOURCE(zv, node, le_mecab_node);
		}
	}
	
	return zv;
}
/* }}} php_mecab_path_get_node */


/* {{{ Functions */

/* {{{ proto resource mecab mecab_new(mixed arg); */
/**
 * resource mecab mecab_new(mixed arg)
 * object MeCab_Tagger MeCab_Tagger::__construct(mixed arg)
 *
 * Create new tagger resource of MeCab.
 *
 * @param	array|string	$arg	The analysis/output options. (optional)
 *									The values is same to command line options.
 *									The detail is found in the web site and/or the manpage of MeCab.
 * @return	resource mecab	A tagger resource of MeCab.
 */
PHP_FUNCTION(mecab_new)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *zmecab = NULL;
	php_mecab_t *mecab = NULL;
	
	/* declaration of the arguments */
	zval *arg = NULL;
	
	/* declaration of the hash */
	HashTable *hash = NULL;
	unsigned long h_idx = 0;
	char *h_key = NULL;
	zval **h_entry = NULL;
	
	/* declaration of the local variables */
	char *m_arg0 = "mecab";
	int m_argc = 0;
	char **m_argv = NULL;
	char *m_args = NULL;
	size_t z_size = 0;
	unsigned char z_type = IS_NULL;
	
	/* parse arguments */
	if (ZEND_NUM_ARGS() > 0) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
			return;
		}
		z_type = Z_TYPE_P(arg);
	}
	
	/* initialize php_mecab_t */
	PHP_MECAB_TAGGER_INIT(mecab);
	
	switch (z_type) {
	  /* invalid type of argument */
	  case IS_OBJECT:
	  case IS_RESOURCE:
		efree(mecab);
		php_error(E_WARNING, "First argument is expected to be a string or an array, '%s' was given", zend_zval_type_name(arg));
		RETURN_FALSE;
		
	  /* parameters were given as an array */
	  case IS_ARRAY:
	  case IS_CONSTANT_ARRAY:
		hash = Z_ARRVAL_P(arg);
		zend_hash_internal_pointer_reset(hash);
		m_argv = (char **)emalloc(sizeof(char *) * (zend_hash_num_elements(hash) + 1) * 2);
		m_argv[m_argc++] = m_arg0;
		while (zend_hash_get_current_data(hash, (void **)&h_entry) == SUCCESS) {
			convert_to_string_ex(h_entry);
			switch (zend_hash_get_current_key(hash, &h_key, &h_idx, 0)) {
			  case HASH_KEY_IS_STRING:
				m_argv[m_argc++] = h_key;
				m_argv[m_argc++] = Z_STRVAL_PP(h_entry);
				break;
			  case HASH_KEY_IS_LONG:
				m_argv[m_argc++] = Z_STRVAL_PP(h_entry);
				break;
			}
			zend_hash_move_forward(hash);
		}
		m_argv[m_argc] = NULL;
		mecab->ptr = mecab_new(m_argc, m_argv);
		efree(m_argv);
		break;
		
	  /* parameter was not given or null */
	  case IS_NULL:
		mecab->ptr = mecab_new2(m_arg0);
		break;
		
	  /* parameter was given as a string or an other scalar type */
	  default:
		convert_to_string_ex(&arg);
		z_size = Z_STRLEN_P(arg);
		if (z_size == 0) {
			mecab->ptr = mecab_new2(m_args);
		} else {
			z_size = sizeof(char) * (strlen(m_arg0) + 1 + z_size);
			spprintf(&m_args, z_size, "%s %s", m_arg0, Z_STRVAL_P(arg));
			mecab->ptr = mecab_new2(m_args);
			efree(m_args);
		}
	}
	
	/* on error */
	if (mecab->ptr == NULL) {
		efree(mecab);
		php_error(E_WARNING, "%s", mecab_strerror(NULL));
		RETURN_FALSE;
	}
	
#ifdef ZEND_ENGINE_2
	if (obj) {
		/* set the property to the MeCab resource */
		MAKE_STD_ZVAL(zmecab);
		ZEND_REGISTER_RESOURCE(zmecab, mecab, le_mecab);
		zend_update_property(mecab_tagger_ce, obj, "mecab", strlen("mecab"), zmecab TSRMLS_CC);
		zval_ptr_dtor(&zmecab);
	} else {
#endif
		/* set return value to the MeCab resource */
		ZEND_REGISTER_RESOURCE(return_value, mecab, le_mecab);
#ifdef ZEND_ENGINE_2
	}
#endif
}
/* }}} mecab_new */


/* {{{ proto void mecab_destroy(resource mecab mecab); */
/**
 * void mecab mecab_destroy(resource mecab mecab)
 * void MeCab_Tagger MeCab_Tagger::__destruct()
 *
 * Free the tagger.
 *
 * @param	resource mecab	$mecab	The tagger resource of MeCab.
 * @return	void
 */
PHP_FUNCTION(mecab_destroy)
{
	/* declaration of the arguments */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *zmecab = NULL;

	/* parse the arguments */
	if (obj) {
		zmecab = zend_read_property(mecab_tagger_ce, obj, "mecab", strlen("mecab"), 0 TSRMLS_CC);
	} else {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zmecab) == FAILURE) {
			return;
		}
	}
	
	/* free the resource */
	FREE_RESOURCE(zmecab);
}
/* }}} mecab_destroy */


/* {{{ proto string mecab_sparse_tostr(resource mecab mecab, string str[, int len[, int olen]]); */
/**
 * string mecab_sparse_tostr(resource mecab mecab, string str[, int len[, int olen]])
 * string MeCab_Tagger::parse(string str[, int len[, int olen]])
 * string MeCab_Tagger::parseToString(string str[, int len[, int olen]])
 *
 * Get the parse result as a string.
 *
 * @param	resource mecab	$mecab	The tagger resource of MeCab.
 * @param	string	$str	The parse target.
 * @param	int	$len	The maximum length that can be analyzed. (optional)
 * @param	int	$olen	The limit length of the output buffer. (optional)
 * @return	string	The parse result.
 *					If output buffer has overflowed, returns false.
 */
PHP_FUNCTION(mecab_sparse_tostr)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *zmecab = NULL;
	php_mecab_t *mecab = NULL;
	
	/* declaration of the arguments */
	const char *str = NULL;
	size_t str_len = 0;
	size_t len = 0;
	size_t olen = 0;
	
	/* declaration of the local variables */
	size_t ilen = 0;
	char *ostr = NULL;
	zend_bool ostr_alloced = 0;
	
	/* parse the arguments */
	if (obj) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll",
				&str, &str_len, &len, &olen) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_OBJECT(mecab, zmecab, obj);
	} else {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|ll",
				&zmecab, &str, &str_len, &len, &olen) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_ZVAL(mecab, zmecab);
	}
	
	/* call mecab_sparse_tostr() */
	PHP_MECAB_TAGGER_UPDATE(mecab, str, str_len);
	ilen = (len > str_len) ? len : str_len;
	if (olen == 0) {
		ostr = (char *)mecab_sparse_tostr2(mecab->ptr, mecab->str, ilen);
	} else {
		ostr = (char *)emalloc(olen + 1);
		ostr = mecab_sparse_tostr3(mecab->ptr, mecab->str, ilen, ostr, olen);
		ostr_alloced = 1;
	}
	
	/* set return value */
	if (ostr == NULL) {
		php_error(E_WARNING, "%s", mecab_strerror(mecab->ptr));
		ZVAL_BOOL(return_value, 0);
	} else {
		ZVAL_STRING(return_value, ostr, 1);
	}
	
	/* free */
	if (ostr_alloced) {
		efree(ostr);
	}
}
/* }}} mecab_sparse_tostr */


/* {{{ proto resource mecab_node mecab_sparse_tonode(resource mecab mecab, string str[, int len]); */
/**
 * resource mecab_node mecab_sparse_tonode(resource mecab mecab, string str[, int len])
 * object MeCab_Node MeCab_Tagger::parseToNode(string str[, int len])
 *
 * Get the parse result as a node.
 *
 * @param	resource mecab	$mecab	The tagger resource of MeCab.
 * @param	string	$str	The parse target.
 * @param	int	$len	The maximum length that can be analyzed. (optional)
 * @return	resource mecab_node	The result node of given string.
 */
PHP_FUNCTION(mecab_sparse_tonode)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *zmecab = NULL;
	php_mecab_t *mecab = NULL;
	
	/* declaration of the arguments */
	const char *str = NULL;
	size_t str_len = 0;
	size_t len = 0;
	
	/* declaration of the local variables */
	mecab_node_t *res = NULL;
	php_mecab_node_t *node = NULL;
	
	/* parse the arguments */
	if (obj) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
				&str, &str_len, &len) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_OBJECT(mecab, zmecab, obj);
	} else {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l",
				&zmecab, &str, &str_len, &len) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_ZVAL(mecab, zmecab);
	}
	
	/* call mecab_sparse_tonode() */
	PHP_MECAB_TAGGER_UPDATE(mecab, str, str_len);
	res = mecab_sparse_tonode2(mecab->ptr, mecab->str, ((len > str_len) ? len : str_len));
	if (res == NULL) {
		php_error(E_WARNING, "%s", mecab_strerror(mecab->ptr));
		RETURN_FALSE;
	}
	
	/* set return value */
	PHP_MECAB_NODE_SETUP(node, res);
	if (obj) {
		php_mecab_node_instantiate(return_value, node TSRMLS_CC);
	} else {
		ZEND_REGISTER_RESOURCE(return_value, node, le_mecab_node);
	}
}
/* }}} mecab_sparse_tonode */


/* {{{ proto string mecab_nbest_sparse_tostr(resource mecab mecab, int n, string str[, int len[, int olen]]); */
/**
 * string mecab_nbest_sparse_tostr(resource mecab mecab, int n, string str[, int len[, int olen]])
 * string MeCab_Tagger::parseNBest(int n, string str[, int len[, int olen]])
 *
 * Get the N-Best list as a string.
 *
 * @param	resource mecab	$mecab	The tagger resource of MeCab.
 * @param	int	$n	The number of the result list.
 * @param	string	$str	The parse target.
 * @param	int	$len	The maximum length that can be analyzed. (optional)
 * @param	int	$olen	The maximum length of the output. (optional)
 * @return	string	The N-Best list.
 *					If output buffer has overflowed, returns false.
 */
PHP_FUNCTION(mecab_nbest_sparse_tostr)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *zmecab = NULL;
	php_mecab_t *mecab = NULL;
	
	/* declaration of the arguments */
	long n = 0;
	const char *str = NULL;
	size_t str_len = 0;
	size_t len = 0;
	size_t olen = 0;
	
	/* declaration of the local variables */
	size_t ilen = 0;
	char *ostr = NULL;
	zend_bool ostr_alloced = 1;
	
	/* parse the arguments */
	if (obj) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls|ll",
				&n, &str, &str_len, &len, &olen) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_OBJECT(mecab, zmecab, obj);
	} else {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rls|ll",
				&zmecab, &n, &str, &str_len, &len, &olen) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_ZVAL(mecab, zmecab);
	}
	
	/* call mecab_nbest_sparse_tostr() */
	PHP_MECAB_TAGGER_UPDATE(mecab, str, str_len);
	ilen = (len > str_len) ? len : str_len;
	if (olen == 0) {
		ostr = (char *)mecab_nbest_sparse_tostr2(mecab->ptr, n, mecab->str, ilen);
	} else {
		ostr = (char *)emalloc(olen + 1);
		ostr = mecab_nbest_sparse_tostr3(mecab->ptr, n, mecab->str, ilen, ostr, olen);
		ostr_alloced = 1;
	}
	
	/* set return value */
	if (ostr == NULL) {
		php_error(E_WARNING, "%s", mecab_strerror(mecab->ptr));
		ZVAL_BOOL(return_value, 0);
	} else {
		ZVAL_STRING(return_value, ostr, 1);
	}
	
	/* free */
	if (ostr_alloced) {
		efree(ostr);
	}
}
/* }}} mecab_nbest_sparse_tostr */


/* {{{ proto bool mecab_nbest_init(resource mecab mecab, string str[, int len]); */
/**
 * bool mecab_nbest_init(resource mecab mecab, string str[, int len])
 * bool MeCab_Tagger::parseNBestInit(string str[, int len])
 *
 * Initialize the N-Best list.
 *
 * @param	resource mecab	$mecab	The tagger resource of MeCab.
 * @param	string	$str	The parse target.
 * @param	int	$len	The maximum length that can be analyzed. (optional)
 * @return	bool	True if succeeded to initilalize, otherwise returns false.
 */
PHP_FUNCTION(mecab_nbest_init)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *zmecab = NULL;
	php_mecab_t *mecab = NULL;
	
	/* declaration of the arguments */
	const char *str = NULL;
	size_t str_len = 0;
	size_t len = 0;
	
	/* declaration of the local variables */
	int result = 0;
	
	/* parse the arguments */
	if (obj) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
				&str, &str_len, &len) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_OBJECT(mecab, zmecab, obj);
	} else {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l",
				&zmecab, &str, &str_len, &len) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_ZVAL(mecab, zmecab);
	}
	
	/* call mecab_nbest_init() */
	PHP_MECAB_TAGGER_UPDATE(mecab, str, str_len);
	result = mecab_nbest_init2(mecab->ptr, mecab->str, ((len > str_len) ? len : str_len));
	if (result == 0) {
		php_error(E_WARNING, "%s", mecab_strerror(mecab->ptr));
		RETURN_FALSE;
	}
	RETURN_TRUE;
}
/* }}} mecab_nbest_init */


/* {{{ proto string mecab_nbest_next_tostr(resource mecab mecab[, int olen]); */
/**
 * string mecab_nbest_next_tostr(resource mecab mecab[, int olen])
 * string MeCab_Tagger::next([int olen]])
 *
 * Get the next result of N-Best as a string.
 *
 * @param	resource mecab	$mecab	The tagger resource of MeCab.
 * @param	int	$olen	The maximum length of the output. (optional)
 * @return	string	The parse result of the next pointer.
 *					If there are no more results, returns false.
 *					Also returns false if output buffer has overflowed.
 */
PHP_FUNCTION(mecab_nbest_next_tostr)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *zmecab = NULL;
	php_mecab_t *mecab = NULL;
	
	/* declaration of the arguments */
	size_t olen = 0;
	
	/* declaration of the local variables */
	char *ostr = NULL;
	zend_bool ostr_alloced = 0;
	const char *what = NULL;
	
	/* parse the arguments */
	if (obj) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &olen) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_OBJECT(mecab, zmecab, obj);
	} else {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zmecab, &olen) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_ZVAL(mecab, zmecab);
	}
	
	/* call mecab_nbest_sparse_tostr() */
	if (olen == 0) {
		ostr = (char *)mecab_nbest_next_tostr(mecab->ptr);
	} else {
		ostr = (char *)emalloc(olen + 1);
		ostr = mecab_nbest_next_tostr2(mecab->ptr, ostr, olen);
		ostr_alloced = 1;
	}
	
	/* set return value */
	if (ostr == NULL) {
		if ((what = mecab_strerror(mecab->ptr)) != NULL && !strstr((char *)what, "no more results")) {
			php_error(E_WARNING, "%s", what);
		}
		ZVAL_BOOL(return_value, 0);
	} else {
		ZVAL_STRING(return_value, ostr, 1);
	}
	
	/* free */
	if (ostr_alloced) {
		efree(ostr);
	}
}
/* }}} mecab_nbest_next_tostr */


/* {{{ proto resource mecab_node mecab_nbest_next_tonode(resource mecab mecab); */
/**
 * resource mecab_node mecab_nbest_next_tonode(resource mecab mecab)
 * object MeCab_Node MeCab_Tagger::nextNode(void)
 *
 * Get the next result of N-Best as a node.
 *
 * @param	resource mecab	$mecab	The tagger resource of MeCab.
 * @return	resource mecab_node	The result node of the next pointer.
 *								If there are no more results, returns false.
 */
PHP_FUNCTION(mecab_nbest_next_tonode)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *zmecab = NULL;
	php_mecab_t *mecab = NULL;
	
	/* declaration of the local variables */
	mecab_node_t *res = NULL;
	php_mecab_node_t *node = NULL;
	const char *what = NULL;
	
	/* parse the arguments */
	if (obj) {
		if (ZEND_NUM_ARGS() != 0) {
			WRONG_PARAM_COUNT;
		}
		PHP_MECAB_TAGGER_FROM_OBJECT(mecab, zmecab, obj);
	} else {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zmecab) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_ZVAL(mecab, zmecab);
	}
	
	/* call mecab_nbest_next_tonode() */
	res = mecab_nbest_next_tonode(mecab->ptr);
	if (res == NULL) {
		if ((what = mecab_strerror(mecab->ptr)) != NULL && !strstr((char *)what, "no more results")) {
			php_error(E_WARNING, "%s", what);
		}
		RETURN_FALSE;
	}
	
	/* set return value */
	PHP_MECAB_NODE_SETUP(node, res);
	if (obj) {
		php_mecab_node_instantiate(return_value, node TSRMLS_CC);
	} else {
		ZEND_REGISTER_RESOURCE(return_value, node, le_mecab_node);
	}
}
/* }}} mecab_nbest_next_tonode */


/* {{{ proto string mecab_format_node(resource mecab mecab); */
/**
 * string mecab_format_node(resource mecab mecab, resource mecab_node node)
 * string MeCab_Tagger::formatNode(object MeCab_Node node)
 *
 * Format a node to string.
 * The format is specified by "-O" option or --{node|unk|bos|eos}-format=STR.
 * The detail is found in the web site and/or the manpage of MeCab.
 *
 * @param	resource mecab	$mecab	The tagger resource of MeCab.
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	string	The formatted string.
 */
PHP_FUNCTION(mecab_format_node)
{
	/* declaration of the resources */
	zval *m_obj = PHP_MECAB_THIS_OBJ;
	zval *n_obj = NULL;
	zval *zmecab = NULL;
	zval *znode = NULL;
	php_mecab_t *mecab = NULL;
	php_mecab_node_t *node = NULL;
	
	/* declaration of the local variables */
	const char *fmt = NULL;
	
	/* parse the arguments */
#ifdef ZEND_ENGINE_2
	if (m_obj) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &n_obj, mecab_node_ce) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_OBJECT(mecab, zmecab, m_obj);
		PHP_MECAB_NODE_FROM_OBJECT(node, znode, n_obj);
	} else {
#endif
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &zmecab, &znode) == FAILURE) {
			return;
		}
		PHP_MECAB_TAGGER_FROM_ZVAL(mecab, zmecab);
		PHP_MECAB_NODE_FROM_ZVAL(node, znode);
#ifdef ZEND_ENGINE_2
	}
#endif
	
	/* call mecab_format_node() */
	fmt = mecab_format_node(mecab->ptr, node->ptr);
	if (fmt == NULL) {
		php_error(E_WARNING, "%s", mecab_strerror(mecab->ptr));
		RETURN_FALSE;
	}
	
	/* set return value */
	ZVAL_STRING(return_value, (char *)fmt, 1);
}
/* }}} mecab_format_node */


/* {{{ proto array mecab_node_toarray(resource mecab_node node[, bool dump_all]); */
/**
 * array mecab_node_toarray(resource mecab_node node)
 * array MeCab_Node::toArray(void)
 *
 * Get all elements of the node as an associated array.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @param	bool	$dump_all	Whether dump all related nodes and paths or not.
 * @return	array	All elements of the node.
 */
PHP_FUNCTION(mecab_node_toarray)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *znode = NULL;
	php_mecab_node_t *node = NULL;
	zend_bool is_obj = 0;
	
	/* declaration of the arguments */
	zend_bool dump_all = 0;
	
	/* parse the arguments */
	if (obj) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &dump_all) == FAILURE) {
			return;
		}
		PHP_MECAB_NODE_FROM_OBJECT(node, znode, obj);
		is_obj = 1;
	} else {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|b", &znode, &dump_all) == FAILURE) {
			return;
		}
		PHP_MECAB_NODE_FROM_ZVAL(node, znode);
	}
	
	/* initialize */
	array_init(return_value);
	
	/* assign siblings and paths */
	if (dump_all) {
		zval *prev  = php_mecab_node_get_sibling(NULL, node, "prev", is_obj TSRMLS_CC);
		zval *next  = php_mecab_node_get_sibling(NULL, node, "next", is_obj TSRMLS_CC);
		zval *enext = php_mecab_node_get_sibling(NULL, node, "enext", is_obj TSRMLS_CC);
		zval *bnext = php_mecab_node_get_sibling(NULL, node, "bnext", is_obj TSRMLS_CC);
		zval *rpath = php_mecab_node_get_path(NULL, node, "rpath", is_obj TSRMLS_CC);
		zval *lpath = php_mecab_node_get_path(NULL, node, "lpath", is_obj TSRMLS_CC);
		add_assoc_zval(return_value, "prev",  prev);
		add_assoc_zval(return_value, "next",  next);
		add_assoc_zval(return_value, "enext", enext);
		add_assoc_zval(return_value, "bnext", bnext);
		add_assoc_zval(return_value, "rpath", rpath);
		add_assoc_zval(return_value, "lpath", lpath);
	}
	
	/* assign node info */
	add_assoc_stringl(return_value, "surface",   node->ptr->surface, (int)(node->ptr->length), 1);
	add_assoc_string(return_value,  "feature",   node->ptr->feature, 1);
	add_assoc_long(return_value,    "id",        (long)(node->ptr->id));
	add_assoc_long(return_value,    "length",    (long)(node->ptr->length));
	add_assoc_long(return_value,    "rlength",   (long)(node->ptr->rlength));
	add_assoc_long(return_value,    "rcAttr",    (long)(node->ptr->rcAttr));
	add_assoc_long(return_value,    "lcAttr",    (long)(node->ptr->lcAttr));
	add_assoc_long(return_value,    "posid",     (long)(node->ptr->posid));
	add_assoc_long(return_value,    "char_type", (long)(node->ptr->char_type));
	add_assoc_long(return_value,    "stat",      (long)(node->ptr->stat));
	add_assoc_bool(return_value,    "isbest",    (long)(node->ptr->isbest));
	add_assoc_double(return_value,  "alpha",     (double)(node->ptr->alpha));
	add_assoc_double(return_value,  "beta",      (double)(node->ptr->beta));
	add_assoc_double(return_value,  "prob",      (double)(node->ptr->prob));
	add_assoc_long(return_value,    "wcost",     (long)(node->ptr->wcost));
	add_assoc_long(return_value,    "cost",      (long)(node->ptr->cost));
}
/* }}} mecab_node_toarray */


/* {{{ proto resource mecab_node mecab_node_current(resource mecab_node node); */
/**
 * resource mecab_node mecab_node_current(resource mecab_node node)
 * object MeCab_Node MeCab_Node::current(void)
 *
 * [Iterator implementation]
 * Return the current element.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @param	resource mecab_node	Just a copy of given resource.
 */
PHP_FUNCTION(mecab_node_current)
{
	PHP_MECAB_NODE_GETTER_VARS;
#ifdef ZEND_ENGINE_2
	if (obj) {
		RETURN_ZVAL(obj, 1, 0);
	} else {
#endif
		PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
		ZEND_REGISTER_RESOURCE(return_value, node, le_mecab_node);
#ifdef ZEND_ENGINE_2
	}
#endif
}
/* }}} current */


/* {{{ proto int mecab_node_key(resource mecab_node); */
/**
 * int mecab_node_key(resource mecab_node)
 * int MeCab_Node::key(void)
 *
 * [Iterator implementation]
 * Return the key of the current element.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The cumulative cost of the node.
 */
PHP_FUNCTION(mecab_node_key)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->id));
}
/* }}} mecab_node_key */


/* {{{ proto bool mecab_node_valid(resource mecab_node); */
/**
 * bool mecab_node_valid(resource mecab_node)
 * bool MeCab_Node::valid(void)
 *
 * [Iterator implementation]
 * Check if there is a current element after calls to rewind() or next().
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	bool	True if there is an element after the current element, otherwise returns false.
 */
PHP_FUNCTION(mecab_node_valid)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_BOOL(node->valid);
}
/* }}} mecab_node_valid */


/* {{{ proto bool mecab_node_rewind(resource mecab_node node); */
/**
 * bool mecab_node_rewind(resource mecab_node node)
 * bool MeCab_Node::rewind(void)
 *
 * [Iterator implementation]
 * Set the node pointer to the beginning.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	bool	Always true.
 */
PHP_FUNCTION(mecab_node_rewind)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	while (node->ptr->prev) {
		node->ptr = node->ptr->prev;
	}
	node->valid = 1;
	RETURN_TRUE;
}
/* }}} mecab_node_rewind */


/* {{{ proto bool mecab_node_next(resource mecab_node node); */
/**
 * bool mecab_node_next(resource mecab_node node)
 * bool MeCab_Node::next(void)
 *
 * [Iterator implementation]
 * Set the node pointer to the next.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	bool	False if current position is the end, otherwise returns true.
 */
PHP_FUNCTION(mecab_node_next)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	if (node->ptr->next) {
		node->ptr = node->ptr->next;
		node->valid = 1;
		RETURN_TRUE;
	}
	node->valid = 0;
	RETURN_FALSE;
}
/* }}} mecab_node_next */


/* {{{ proto resource mecab_node mecab_node_get_prev(resource mecab_node node); */
/**
 * resource mecab_node mecab_node_get_prev(resource mecab_node node)
 * object MeCab_Node MeCab_Node::getPrev(void)
 *
 * Get the previous node.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	resource mecab_node	The previous node.
 *								If the given node is the first one, returns FALSE.
 */
PHP_FUNCTION(mecab_node_get_prev)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	php_mecab_node_get_sibling(return_value, node, "prev", is_obj TSRMLS_CC);
}
/* }}} mecab_node_get_prev */


/* {{{ proto resource mecab_node mecab_node_get_next(resource mecab_node node); */
/**
 * resource mecab_node mecab_node_get_next(resource mecab_node node)
 * object MeCab_Node MeCab_Node::getNext(void)
 *
 * Get the next node.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	resource mecab_node	The next node.
 *								If the given node is the last one, returns FALSE.
 */
PHP_FUNCTION(mecab_node_get_next)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	php_mecab_node_get_sibling(return_value, node, "next", is_obj TSRMLS_CC);
}
/* }}} mecab_node_get_next */


/* {{{ proto resource mecab_node mecab_node_get_enext(resource mecab_node node); */
/**
 * resource mecab_node mecab_node_get_enext(resource mecab_node node)
 * object MeCab_Node MeCab_Node::getENext(void)
 *
 * Get the enext node.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	resource mecab_node	The next node which has same end point as the given node.
 *								If there is no `enext' node, returns false.
 */
PHP_FUNCTION(mecab_node_get_enext)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	php_mecab_node_get_sibling(return_value, node, "enext", is_obj TSRMLS_CC);
}
/* }}} mecab_node_get_enext */


/* {{{ proto resource mecab_node mecab_node_get_bnext(resource mecab_node node); */
/**
 * resource mecab_node mecab_node_get_bnext(resource mecab_node node)
 * object MeCab_Node MeCab_Node::getBNext(void)
 *
 * Get the bnext node.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	resource mecab_node	The next node which has same beggining point as the given one.
 *								If there is no `bnext' node, returns false.
 */
PHP_FUNCTION(mecab_node_get_bnext)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	php_mecab_node_get_sibling(return_value, node, "bnext", is_obj TSRMLS_CC);
}
/* }}} mecab_node_get_bnext */


/* {{{ proto resource mecab_path mecab_node_get_rpath(resource mecab_node node); */
/**
 * resource mecab_path mecab_node_get_rpath(resource mecab_node node)
 * object MeCab_Path MeCab_Node::getRPath(void)
 *
 * Get the rpath.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	resource mecab_path	The next node which has same end point as the given node.
 *								If there is no `rpath' node, returns false.
 */
PHP_FUNCTION(mecab_node_get_rpath)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	php_mecab_node_get_path(return_value, node, "rpath", is_obj TSRMLS_CC);
}
/* }}} mecab_node_get_rpath */


/* {{{ proto resource mecab_path mecab_node_get_lpath(resource mecab_node node); */
/**
 * resource mecab_path mecab_node_get_lpath(resource mecab_node node)
 * object MeCab_Path MeCab_Node::getLPath(void)
 *
 * Get the lpath.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	resource mecab_path	The next node which has same beggining point as the given one.
 *								If there is no `lpath' node, returns false.
 */
PHP_FUNCTION(mecab_node_get_lpath)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	php_mecab_node_get_path(return_value, node, "lpath", is_obj TSRMLS_CC);
}
/* }}} mecab_node_get_lpath */


/* {{{ proto string mecab_node_get_surface(resource mecab_node node); */
/**
 * string mecab_node_get_surface(resource mecab_node node)
 * string MeCab_Node::getSurface(void)
 *
 * Get the surface.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	string	The surface of the node.
 */
PHP_FUNCTION(mecab_node_get_surface)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_STRINGL(node->ptr->surface, (int)(node->ptr->length), 1);
}
/* }}} mecab_node_get_surface */


/* {{{ proto string mecab_node_get_feature(resource mecab_node node); */
/**
 * string mecab_node_get_feature(resource mecab_node node)
 * string MeCab_Node::getFeature(void)
 *
 * Get the feature.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	string	The feature of the node.
 */
PHP_FUNCTION(mecab_node_get_feature)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_STRING(node->ptr->feature, 1);
}
/* }}} mecab_node_get_feature */


/* {{{ proto int mecab_node_get_id(resource mecab_node node); */
/**
 * int mecab_node_get_id(resource mecab_node node)
 * int MeCab_Node::getId(void)
 *
 * Get the ID.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The ID of the node.
 */
PHP_FUNCTION(mecab_node_get_id)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->id));
}
/* }}} mecab_node_get_id */


/* {{{ proto int mecab_node_get_length(resource mecab_node node); */
/**
 * int mecab_node_get_length(resource mecab_node node)
 * int MeCab_Node::getLength(void)
 *
 * Get the length of the surface.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The length of the surface of the node.
 */
PHP_FUNCTION(mecab_node_get_length)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->length));
}
/* }}} mecab_node_get_length */


/* {{{ proto int mecab_node_get_rlength(resource mecab_node node); */
/**
 * int mecab_node_get_rlength(resource mecab_node node)
 * int MeCab_Node::getRLength(void)
 *
 * Get the length of the surface and its leading whitespace.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The length of the surface and its leading whitespace of the node.
 */
PHP_FUNCTION(mecab_node_get_rlength)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->rlength));
}
/* }}} mecab_node_get_rlength */


/* {{{ proto int mecab_node_get_rcattr(resource mecab_node node); */
/**
 * int mecab_node_get_rcattr(resource mecab_node node)
 * int MeCab_Node::getRcAttr(void)
 *
 * Get the ID of the right context.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The ID of the right context.
 */
PHP_FUNCTION(mecab_node_get_rcattr)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->rcAttr));
}
/* }}} mecab_node_get_rcattr */


/* {{{ proto int mecab_node_get_lcattr(resource mecab_node node); */
/**
 * int mecab_node_get_lcattr(resource mecab_node node)
 * int MeCab_Node::getLcAttr(void)
 *
 * Get the ID of the left context.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The ID of the left context.
 */
PHP_FUNCTION(mecab_node_get_lcattr)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->lcAttr));
}
/* }}} mecab_node_get_lcattr */


/* {{{ proto int mecab_node_get_posid(resource mecab_node node); */
/**
 * int mecab_node_get_posid(resource mecab_node node)
 * int MeCab_Node::getPosId(void)
 *
 * Get the ID of the Part-of-Speech.
 * (node->posid is not used in MeCab-0.90)
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The ID of the Part-of-Speech.
 *				Currently, always returns 0.
 */
PHP_FUNCTION(mecab_node_get_posid)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->posid));
}
/* }}} mecab_node_get_posid */


/* {{{ proto int mecab_node_get_char_type(resource mecab_node node); */
/**
 * int mecab_node_get_char_type(resource mecab_node node)
 * int MeCab_Node::getCharType(void)
 *
 * Get the type of the character.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The type of the character.
 */
PHP_FUNCTION(mecab_node_get_char_type)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->char_type));
}
/* }}} mecab_node_get_char_type */


/* {{{ proto int mecab_node_get_stat(resource mecab_node node); */
/**
 * int mecab_node_get_stat(resource mecab_node node)
 * int MeCab_Node::getStat(void)
 *
 * Get the status.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The status of the node.
 *				The return value is one of the following:
 *					MECAB_NOR_NODE (0:Normal)
 *					MECAB_UNK_NODE (1:Unknown)
 *					MECAB_BOS_NODE (2:Beginning-of-Sentence)
 *					MECAB_EOS_NODE (3:End-of-Sentence)
 */
PHP_FUNCTION(mecab_node_get_stat)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->stat));
}
/* }}} mecab_node_get_stat */


/* {{{ proto bool mecab_node_get_isbest(resource mecab_node node); */
/**
 * bool mecab_node_get_isbest(resource mecab_node node)
 * bool MeCab_Node::getIsBest(void)
 *
 * Determine whether the node is the best solution.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	bool	True if the node is the best, otherwise returns false.
 */
PHP_FUNCTION(mecab_node_get_isbest)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_BOOL((long)(node->ptr->isbest));
}
/* }}} mecab_node_get_isbest */


/* {{{ proto double mecab_node_get_alpha(resource mecab_node node); */
/**
 * double mecab_node_get_alpha(resource mecab_node node)
 * double MeCab_Node::getAlpha(void)
 *
 * Get the forward log probability.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	double	The forward log probability of the node.
 */
PHP_FUNCTION(mecab_node_get_alpha)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_DOUBLE((double)(node->ptr->alpha));
}
/* }}} mecab_node_get_alpha */


/* {{{ proto double mecab_node_get_beta(resource mecab_node node); */
/**
 * double mecab_node_get_beta(resource mecab_node node)
 * double MeCab_Node::getBeta(void)
 *
 * Get the backward log probability.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	double	The backward log probability of the node.
 */
PHP_FUNCTION(mecab_node_get_beta)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_DOUBLE((double)(node->ptr->beta));
}
/* }}} mecab_node_get_beta */


/* {{{ proto double mecab_node_get_prob(resource mecab_node node); */
/**
 * double mecab_node_get_prob(resource mecab_node node)
 * double MeCab_Node::getProb(void)
 *
 * Get the marginal probability.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	double	The marginal probability of the node.
 */
PHP_FUNCTION(mecab_node_get_prob)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_DOUBLE((double)(node->ptr->prob));
}
/* }}} mecab_node_get_prob */


/* {{{ proto int mecab_node_get_wcost(resource mecab_node node); */
/**
 * int mecab_node_get_wcost(resource mecab_node node)
 * int MeCab_Node::getWCost(void)
 *
 * Get the word arising cost.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The word arising cost of the node.
 */
PHP_FUNCTION(mecab_node_get_wcost)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->wcost));
}
/* }}} mecab_node_get_wcost */


/* {{{ proto int mecab_node_get_cost(resource mecab_node node); */
/**
 * int mecab_node_get_cost(resource mecab_node node)
 * int MeCab_Node::getCost(void)
 *
 * Get the cumulative cost.
 *
 * @param	resource mecab_node	$node	The node of the source string.
 * @return	int	The cumulative cost of the node.
 */
PHP_FUNCTION(mecab_node_get_cost)
{
	PHP_MECAB_NODE_GETTER_VARS;
	PHP_MECAB_NODE_FROM_ARG1(node, znode, obj);
	RETURN_LONG((long)(node->ptr->cost));
}
/* }}} mecab_node_get_cost */


/* {{{ proto resource mecab_path mecab_path_get_rnext(resource mecab_path path); */
/**
 * resource mecab_path mecab_path_get_rnext(resource mecab_path path)
 * object MeCab_Path MeCab_Path::getRNext(void)
 *
 * Get the rnext path.
 *
 * @param	resource mecab_path	$path	The path of the source string.
 * @return	resource mecab_path	The rnext path.
 *								If the given path is the first one, returns FALSE.
 */
PHP_FUNCTION(mecab_path_get_rnext)
{
	PHP_MECAB_PATH_GETTER_VARS;
	PHP_MECAB_PATH_FROM_ARG1(path, zpath, obj);
	php_mecab_path_get_sibling(return_value, path, "rnext", is_obj TSRMLS_CC);
}
/* }}} mecab_path_get_rnext */


/* {{{ proto resource mecab_path mecab_path_get_lnext(resource mecab_path path); */
/**
 * resource mecab_path mecab_path_get_lnext(resource mecab_path path)
 * object MeCab_Path MeCab_Path::getLNext(void)
 *
 * Get the lnext path.
 *
 * @param	resource mecab_path	$path	The path of the source string.
 * @return	resource mecab_path	The lnext path.
 *								If the given path is the last one, returns FALSE.
 */
PHP_FUNCTION(mecab_path_get_lnext)
{
	PHP_MECAB_PATH_GETTER_VARS;
	PHP_MECAB_PATH_FROM_ARG1(path, zpath, obj);
	php_mecab_path_get_sibling(return_value, path, "lnext", is_obj TSRMLS_CC);
}
/* }}} mecab_path_get_lnext */


/* {{{ proto resource mecab_node mecab_path_get_rnode(resource mecab_path path); */
/**
 * resource mecab_node mecab_path_get_rnode(resource mecab_path path)
 * object MeCab_Node MeCab_Path::getRNode(void)
 *
 * Get the rnode.
 *
 * @param	resource mecab_path	$path	The path of the source string.
 * @return	resource mecab_node	The next path which has same end point as the given path.
 *								If there is no `rnode' path, returns false.
 */
PHP_FUNCTION(mecab_path_get_rnode)
{
	PHP_MECAB_PATH_GETTER_VARS;
	PHP_MECAB_PATH_FROM_ARG1(path, zpath, obj);
	php_mecab_path_get_node(return_value, path, "rnode", is_obj TSRMLS_CC);
}
/* }}} mecab_path_get_rnode */


/* {{{ proto resource mecab_node mecab_path_get_lnode(resource mecab_path path); */
/**
 * resource mecab_node mecab_path_get_lnode(resource mecab_path path)
 * object MeCab_Node MeCab_Path::getLNode(void)
 *
 * Get the lnode.
 *
 * @param	resource mecab_path	$path	The path of the source string.
 * @return	resource mecab_node	The next path which has same beggining point as the given one.
 *								If there is no `lnode' path, returns false.
 */
PHP_FUNCTION(mecab_path_get_lnode)
{
	PHP_MECAB_PATH_GETTER_VARS;
	PHP_MECAB_PATH_FROM_ARG1(path, zpath, obj);
	php_mecab_path_get_node(return_value, path, "lnode", is_obj TSRMLS_CC);
}
/* }}} mecab_path_get_lnode */


/* {{{ proto double mecab_path_get_prob(resource mecab_path path); */
/**
 * double mecab_path_get_prob(resource mecab_path path)
 * double MeCab_Path::getProb(void)
 *
 * Get the marginal probability.
 *
 * @param	resource mecab_path	$path	The path of the source string.
 * @return	double	The marginal probability of the path.
 */
PHP_FUNCTION(mecab_path_get_prob)
{
	PHP_MECAB_PATH_GETTER_VARS;
	PHP_MECAB_PATH_FROM_ARG1(path, zpath, obj);
	RETURN_DOUBLE((double)(path->prob));
}
/* }}} mecab_path_get_prob */


/* {{{ proto int mecab_path_get_cost(resource mecab_path path); */
/**
 * int mecab_path_get_cost(resource mecab_path path)
 * int MeCab_Path::getCost(void)
 *
 * Get the cumulative cost.
 *
 * @param	resource mecab_path	$path	The path of the source string.
 * @return	int	The cumulative cost of the path.
 */
PHP_FUNCTION(mecab_path_get_cost)
{
	PHP_MECAB_PATH_GETTER_VARS;
	PHP_MECAB_PATH_FROM_ARG1(path, zpath, obj);
	RETURN_LONG((long)(path->cost));
}
/* }}} mecab_node_get_cost */

/* }}} Functions */

#ifdef ZEND_ENGINE_2
/* {{{ Methods */

/* {{{ Methods of Class MeCab_Node*/

/* {{{ proto object MeCab_Node __construct(void); */
/**
 * object MeCab_Node MeCab_Node::__construct(void)
 *
 * Create MeCab_Node object.
 *
 * @access	private
 * @igore
 */
PHP_METHOD(MeCab_Node, __construct)
{
	return;
}
/* }}} __construct */

#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1)

/* {{{ proto mixed __get(string name); */
/**
 * mixed MeCab_Node::__get(string name)
 *
 * [Overloading implementation]
 * A magick getter.
 *
 * @param	string	$name	The name of property.
 * @return	mixed	The value of the property.
 *					If there is not a named property, causes E_NOTICE error and returns false.
 * @access	public
 * @ignore
 */
PHP_METHOD(MeCab_Node, __get)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *znode = NULL;
	php_mecab_node_t *node = NULL;
	
	/* declaration of the arguments */
	char *name = NULL;
	int name_len = 0;
	
	/* parse the arguments */
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
		return;
	}
	
	/* fetch resource */
	PHP_MECAB_NODE_FROM_OBJECT(node, znode, obj);
	
	/* check for given property name */
	if (!strcmp(name, "prev") || !strcmp(name, "next") || !strcmp(name, "enext") || !strcmp(name, "bnext")) {
		php_mecab_node_get_sibling(return_value, node, name, 1 TSRMLS_CC);
		return;
	}
	if (!strcmp(name, "rpath") || !strcmp(name, "lpath")) {
		php_mecab_node_get_path(return_value, node, name, 1 TSRMLS_CC);
		return;
	}
	if (!strcmp(name, "surface"))   RETURN_STRINGL(node->ptr->surface, (int)(node->ptr->length), 1);
	if (!strcmp(name, "feature"))   RETURN_STRING(node->ptr->feature, 1);
	if (!strcmp(name, "id"))        RETURN_LONG((long)(node->ptr->id));
	if (!strcmp(name, "length"))    RETURN_LONG((long)(node->ptr->length));
	if (!strcmp(name, "rlength"))   RETURN_LONG((long)(node->ptr->rlength));
	if (!strcmp(name, "rcAttr"))    RETURN_LONG((long)(node->ptr->rcAttr));
	if (!strcmp(name, "lcAttr"))    RETURN_LONG((long)(node->ptr->lcAttr));
	if (!strcmp(name, "posid"))     RETURN_LONG((long)(node->ptr->posid));
	if (!strcmp(name, "char_type")) RETURN_LONG((long)(node->ptr->char_type));
	if (!strcmp(name, "stat"))      RETURN_LONG((long)(node->ptr->stat));
	if (!strcmp(name, "isbest"))    RETURN_BOOL((long)(node->ptr->isbest));
	if (!strcmp(name, "alpha"))     RETURN_DOUBLE((double)(node->ptr->alpha));
	if (!strcmp(name, "beta"))      RETURN_DOUBLE((double)(node->ptr->beta));
	if (!strcmp(name, "prob"))      RETURN_DOUBLE((double)(node->ptr->prob));
	if (!strcmp(name, "wcost"))     RETURN_LONG((long)(node->ptr->wcost));
	if (!strcmp(name, "cost"))      RETURN_LONG((long)(node->ptr->cost));
	
	/* when going to fetch undefined property */
	php_error(E_NOTICE, "Undefined property");
	RETURN_NULL();
}
/* }}} __get */


/* {{{ proto bool __isset(string name); */
/**
 * bool MeCab_Node::__isset(string name)
 *
 * [Overloading implementation]
 * Determine whether there is a named property.
 *
 * @param	string	$name	The name of property.
 * @return	bool	True if there is a named property, otherwise returns false.
 * @access	public
 * @ignore
 */
PHP_METHOD(MeCab_Node, __isset)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *znode = NULL;
	php_mecab_node_t *node = NULL;
	
	/* declaration of the arguments */
	char *name = NULL;
	int name_len = 0;
	
	/* parse the arguments */
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
		return;
	}
	
	/* fetch resource */
	PHP_MECAB_NODE_FROM_OBJECT(node, znode, obj);
	
	/* check for given property name */
	if (
			(!strcmp(name, "prev") && node->ptr->prev) ||
			(!strcmp(name, "next") && node->ptr->next) ||
			(!strcmp(name, "enext") && node->ptr->enext) ||
			(!strcmp(name, "bnext") && node->ptr->bnext) ||
			(!strcmp(name, "rpath") && node->ptr->rpath) ||
			(!strcmp(name, "lpath") && node->ptr->lpath) ||
			!strcmp(name, "surface") ||
			!strcmp(name, "feature") ||
			!strcmp(name, "id") ||
			!strcmp(name, "length") ||
			!strcmp(name, "rlength") ||
			!strcmp(name, "rcAttr") ||
			!strcmp(name, "lcAttr") ||
			!strcmp(name, "posid") ||
			!strcmp(name, "char_type") ||
			!strcmp(name, "stat") ||
			!strcmp(name, "isbest") ||
			!strcmp(name, "alpha") ||
			!strcmp(name, "beta") ||
			!strcmp(name, "prob") ||
			!strcmp(name, "wcost") ||
			!strcmp(name, "cost"))
	{
		RETURN_TRUE;
	}
	RETURN_FALSE;
}
/* }}} __isset */

#endif /* Overloading */

/* }}} Methods of Class MeCab_Node */

/* {{{ Methods of Class MeCab_Path*/

/* {{{ proto object MeCab_Path __construct(void); */
/**
 * object MeCab_Path MeCab_Path::__construct(void)
 *
 * Create MeCab_Path object.
 *
 * @access	private
 * @igore
 */
PHP_METHOD(MeCab_Path, __construct)
{
	return;
}
/* }}} __construct */

#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1)

/* {{{ proto mixed __get(string name); */
/**
 * mixed MeCab_Path::__get(string name)
 *
 * [Overloading implementation]
 * A magick getter.
 *
 * @param	string	$name	The name of property.
 * @return	mixed	The value of the property.
 *					If there is not a named property, causes E_NOTICE error and returns false.
 * @access	public
 * @ignore
 */
PHP_METHOD(MeCab_Path, __get)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *zpath = NULL;
	mecab_path_t *path = NULL;
	
	/* declaration of the arguments */
	char *name = NULL;
	int name_len = 0;
	
	/* parse the arguments */
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
		return;
	}
	
	/* fetch resource */
	PHP_MECAB_PATH_FROM_OBJECT(path, zpath, obj);
	
	/* check for given property name */
	if (!strcmp(name, "rnext") || !strcmp(name, "lnext")) {
		php_mecab_path_get_sibling(return_value, path, name, 1 TSRMLS_CC);
		return;
	}
	if (!strcmp(name, "rnode") || !strcmp(name, "lnode")) {
		php_mecab_path_get_node(return_value, path, name, 1 TSRMLS_CC);
		return;
	}
	if (!strcmp(name, "prob")) RETURN_DOUBLE((double)(path->prob));
	if (!strcmp(name, "cost")) RETURN_LONG((long)(path->cost));
	
	/* when going to fetch undefined property */
	php_error(E_NOTICE, "Undefined property");
	RETURN_NULL();
}
/* }}} __get */


/* {{{ proto bool __isset(string name); */
/**
 * bool MeCab_Path::__isset(string name)
 *
 * [Overloading implementation]
 * Determine whether there is a named property.
 *
 * @param	string	$name	The name of property.
 * @return	bool	True if there is a named property, otherwise returns false.
 * @access	public
 * @ignore
 */
PHP_METHOD(MeCab_Path, __isset)
{
	/* declaration of the resources */
	zval *obj = PHP_MECAB_THIS_OBJ;
	zval *zpath = NULL;
	mecab_path_t *path = NULL;
	
	/* declaration of the arguments */
	char *name = NULL;
	int name_len = 0;
	
	/* parse the arguments */
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
		return;
	}
	
	/* fetch resource */
	PHP_MECAB_PATH_FROM_OBJECT(path, zpath, obj);
		
	/* check for given property name */
	if (
			(!strcmp(name, "rnext") && path->rnext) ||
			(!strcmp(name, "lnext") && path->lnext) ||
			(!strcmp(name, "rnode") && path->rnode) ||
			(!strcmp(name, "lnode") && path->lnode) ||
			!strcmp(name, "prob") ||
			!strcmp(name, "cost"))
	{
		RETURN_TRUE;
	}
	RETURN_FALSE;
}
/* }}} __isset */

#endif /* Overloading */

/* }}} Methods of Class MeCab_Path */

/* }}} Methods */
#endif /* PHP5 */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */


syntax highlighted by Code2HTML, v. 0.9.1