* #36737: switch back to svn repo, remove assert in sip_transaction.c
diff --git a/jni/pjproject-android/.svn/pristine/f2/f27613836326d2dd313bbd5924c8a5abcb4695dd.svn-base b/jni/pjproject-android/.svn/pristine/f2/f27613836326d2dd313bbd5924c8a5abcb4695dd.svn-base
new file mode 100644
index 0000000..94d14c5
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f2/f27613836326d2dd313bbd5924c8a5abcb4695dd.svn-base
@@ -0,0 +1,1353 @@
+/* $Id$ */

+/*

+ * Copyright (C) 2010 Teluu Inc. (http://www.teluu.com)

+ *

+ * This program 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, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#include <pjlib-util/cli_imp.h>

+#include <pj/assert.h>

+#include <pj/errno.h>

+#include <pj/except.h>

+#include <pj/hash.h>

+#include <pj/os.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pjlib-util/errno.h>

+#include <pjlib-util/scanner.h>

+#include <pjlib-util/xml.h>

+

+#define CMD_HASH_TABLE_SIZE 63	/* Hash table size */

+

+#define CLI_CMD_CHANGE_LOG  30000

+#define CLI_CMD_EXIT        30001

+

+#define MAX_CMD_HASH_NAME_LENGTH PJ_CLI_MAX_CMDBUF

+#define MAX_CMD_ID_LENGTH 16

+

+#if 1

+    /* Enable some tracing */

+    #define THIS_FILE   "cli.c"

+    #define TRACE_(arg)	PJ_LOG(3,arg)

+#else

+    #define TRACE_(arg)

+#endif

+

+/**

+ * This structure describes the full specification of a CLI command. A CLI

+ * command mainly consists of the name of the command, zero or more arguments,

+ * and a callback function to be called to execute the command.

+ *

+ * Application can create this specification by forming an XML document and

+ * calling pj_cli_add_cmd_from_xml() to instantiate the spec. A sample XML

+ * document containing a command spec is as follows:

+ *

+ \verbatim

+  <CMD name='makecall' id='101' sc='m,mc' desc='Make outgoing call'>

+      <ARGS>

+	  <ARG name='target' type='text' desc='The destination'/>

+      </ARGS>

+  </CMD>

+ \endverbatim

+ */

+struct pj_cli_cmd_spec

+{

+    /**

+     * To make list of child cmds.

+     */

+    PJ_DECL_LIST_MEMBER(struct pj_cli_cmd_spec);

+

+    /**

+     * Command ID assigned to this command by the application during command

+     * creation. If this value is PJ_CLI_CMD_ID_GROUP (-2), then this is

+     * a command group and it can't be executed.

+     */

+    pj_cli_cmd_id id;

+

+    /**

+     * The command name.

+     */

+    pj_str_t name;

+

+    /**

+     * The full description of the command.

+     */

+    pj_str_t desc;

+

+    /**

+     * Number of optional shortcuts

+     */

+    unsigned sc_cnt;

+

+    /**

+     * Optional array of shortcuts, if any. Shortcut is a short name version

+     * of the command. If the command doesn't have any shortcuts, this

+     * will be initialized to NULL.

+     */

+    pj_str_t *sc;

+

+    /**

+     * The command handler, to be executed when a command matching this command

+     * specification is invoked by the end user. The value may be NULL if this

+     * is a command group.

+     */

+    pj_cli_cmd_handler handler;

+

+    /**

+     * Number of arguments.

+     */

+    unsigned arg_cnt;

+

+    /**

+     * Array of arguments.

+     */

+    pj_cli_arg_spec *arg;

+

+    /**

+     * Child commands, if any. A command will only have subcommands if it is

+     * a group. If the command doesn't have subcommands, this field will be

+     * initialized with NULL.

+     */

+    pj_cli_cmd_spec *sub_cmd;

+};

+

+struct pj_cli_t

+{

+    pj_pool_t	       *pool;           /* Pool to allocate memory from */

+    pj_cli_cfg          cfg;            /* CLI configuration */

+    pj_cli_cmd_spec     root;           /* Root of command tree structure */

+    pj_cli_front_end    fe_head;        /* List of front-ends */

+    pj_hash_table_t    *cmd_name_hash;  /* Command name hash table, this will 

+					   include the command name and shortcut 

+					   as hash key */

+    pj_hash_table_t    *cmd_id_hash;    /* Command id hash table */

+

+    pj_bool_t           is_quitting;

+    pj_bool_t           is_restarting;

+};

+

+/**

+ * Reserved command id constants.

+ */

+typedef enum pj_cli_std_cmd_id

+{

+    /**

+     * Constant to indicate an invalid command id.

+     */

+    PJ_CLI_INVALID_CMD_ID = -1,

+

+    /**

+     * A special command id to indicate that a command id denotes

+     * a command group.

+     */

+    PJ_CLI_CMD_ID_GROUP = -2

+

+} pj_cli_std_cmd_id;

+

+/**

+ * This describes the type of an argument (pj_cli_arg_spec).

+ */

+typedef enum pj_cli_arg_type

+{

+    /**

+     * Unformatted string.

+     */

+    PJ_CLI_ARG_TEXT,

+

+    /**

+     * An integral number.

+     */

+    PJ_CLI_ARG_INT,

+

+    /**

+     * Choice type

+    */

+    PJ_CLI_ARG_CHOICE

+

+} pj_cli_arg_type;

+

+struct arg_type

+{

+    const pj_str_t msg;

+} arg_type[3] = 

+{

+    {{"Text", 4}},

+    {{"Int", 3}},

+    {{"Choice", 6}}

+};

+

+/**

+ * This structure describe the specification of a command argument.

+ */

+struct pj_cli_arg_spec

+{

+    /**

+     * Argument id

+     */

+    pj_cli_arg_id id;

+

+    /**

+     * Argument name.

+     */

+    pj_str_t name;

+

+    /**

+     * Helpful description of the argument. This text will be used when

+     * displaying help texts for the command/argument.

+     */

+    pj_str_t desc;

+

+    /**

+     * Argument type, which will be used for rendering the argument and

+     * to perform basic validation against an input value.

+     */

+    pj_cli_arg_type type;

+

+    /**

+     * Argument status

+     */

+    pj_bool_t optional;

+

+    /**

+     * Validate choice values

+     */

+    pj_bool_t validate;

+

+    /**

+     * Static Choice Values count

+     */

+    unsigned stat_choice_cnt; 

+

+    /**

+     * Static Choice Values

+     */

+    pj_cli_arg_choice_val *stat_choice_val; 

+

+    /**

+     * Argument callback to get the valid values

+     */

+    pj_cli_get_dyn_choice get_dyn_choice;

+

+};

+

+/**

+ * This describe the parse mode of the command line

+ */

+typedef enum pj_cli_parse_mode {

+    PARSE_NONE,

+    PARSE_COMPLETION,	/* Complete the command line */

+    PARSE_NEXT_AVAIL,   /* Find the next available command line */

+    PARSE_EXEC		/* Exec the command line */

+} pj_cli_parse_mode;

+

+/** 

+ * This is used to get the matched command/argument from the 

+ * command/argument structure.

+ * 

+ * @param sess		The session on which the command is execute on.

+ * @param cmd		The active command.

+ * @param cmd_val	The command value to match.

+ * @param argc		The number of argument that the 

+ *			current active command have.

+ * @param pool		The memory pool to allocate memory.

+ * @param get_cmd	Set true to search matching command from sub command.

+ * @param parse_mode	The parse mode.

+ * @param p_cmd		The command that mathes the command value.

+ * @param info		The output information containing any hints for 

+ *			matching command/arg.

+ * @return		This function return the status of the 

+ *			matching process.Please see the return value

+ * 			of pj_cli_sess_parse() for possible return values.

+ */

+static pj_status_t get_available_cmds(pj_cli_sess *sess,

+				      pj_cli_cmd_spec *cmd, 

+				      pj_str_t *cmd_val,

+				      unsigned argc,

+				      pj_pool_t *pool,

+				      pj_bool_t get_cmd,

+				      pj_cli_parse_mode parse_mode,

+				      pj_cli_cmd_spec **p_cmd,

+				      pj_cli_exec_info *info);

+

+PJ_DEF(pj_cli_cmd_id) pj_cli_get_cmd_id(const pj_cli_cmd_spec *cmd)

+{

+    return cmd->id;

+}

+

+PJ_DEF(void) pj_cli_cfg_default(pj_cli_cfg *param)

+{

+    pj_assert(param);

+    pj_bzero(param, sizeof(*param));

+    pj_strset2(&param->name, "");

+}

+

+PJ_DEF(void) pj_cli_exec_info_default(pj_cli_exec_info *param)

+{

+    pj_assert(param);

+    pj_bzero(param, sizeof(*param));

+    param->err_pos = -1;

+    param->cmd_id = PJ_CLI_INVALID_CMD_ID;

+    param->cmd_ret = PJ_SUCCESS;

+}

+

+PJ_DEF(void) pj_cli_write_log(pj_cli_t *cli,

+                              int level,

+                              const char *buffer,

+                              int len)

+{

+    struct pj_cli_front_end *fe;

+

+    pj_assert(cli);

+

+    fe = cli->fe_head.next;

+    while (fe != &cli->fe_head) {

+        if (fe->op && fe->op->on_write_log)

+            (*fe->op->on_write_log)(fe, level, buffer, len);

+        fe = fe->next;

+    }

+}

+

+PJ_DEF(void) pj_cli_sess_write_msg(pj_cli_sess *sess,                               

+				   const char *buffer,

+				   pj_size_t len)

+{

+    struct pj_cli_front_end *fe;

+

+    pj_assert(sess);

+

+    fe = sess->fe;

+    if (fe->op && fe->op->on_write_log)

+        (*fe->op->on_write_log)(fe, 0, buffer, len);

+}

+

+/* Command handler */

+static pj_status_t cmd_handler(pj_cli_cmd_val *cval)

+{

+    unsigned level;

+

+    switch(cval->cmd->id) {

+    case CLI_CMD_CHANGE_LOG:

+        level = pj_strtoul(&cval->argv[1]);

+        if (!level && cval->argv[1].slen > 0 && (cval->argv[1].ptr[0] < '0' ||

+            cval->argv[1].ptr[0] > '9'))

+	{

+            return PJ_CLI_EINVARG;

+	}

+        cval->sess->log_level = level;

+        return PJ_SUCCESS;

+    case CLI_CMD_EXIT:

+        pj_cli_sess_end_session(cval->sess);

+        return PJ_CLI_EEXIT;

+    default:

+        return PJ_SUCCESS;

+    }

+}

+

+PJ_DEF(pj_status_t) pj_cli_create(pj_cli_cfg *cfg,

+                                  pj_cli_t **p_cli)

+{

+    pj_pool_t *pool;

+    pj_cli_t *cli;    

+    unsigned i;

+

+    /* This is an example of the command structure */

+    char* cmd_xmls[] = {

+     "<CMD name='log' id='30000' sc='' desc='Change log level'>"

+     "    <ARG name='level' type='int' optional='0' desc='Log level'/>"

+     "</CMD>",     

+     "<CMD name='exit' id='30001' sc='' desc='Exit session'>"     

+     "</CMD>",

+    };

+

+    PJ_ASSERT_RETURN(cfg && cfg->pf && p_cli, PJ_EINVAL);

+

+    pool = pj_pool_create(cfg->pf, "cli", PJ_CLI_POOL_SIZE, 

+                          PJ_CLI_POOL_INC, NULL);

+    if (!pool)

+        return PJ_ENOMEM;

+    cli = PJ_POOL_ZALLOC_T(pool, struct pj_cli_t);

+

+    pj_memcpy(&cli->cfg, cfg, sizeof(*cfg));

+    cli->pool = pool;

+    pj_list_init(&cli->fe_head);

+

+    cli->cmd_name_hash = pj_hash_create(pool, CMD_HASH_TABLE_SIZE);

+    cli->cmd_id_hash = pj_hash_create(pool, CMD_HASH_TABLE_SIZE);

+

+    cli->root.sub_cmd = PJ_POOL_ZALLOC_T(pool, pj_cli_cmd_spec);

+    pj_list_init(cli->root.sub_cmd);

+

+    /* Register some standard commands. */

+    for (i = 0; i < sizeof(cmd_xmls)/sizeof(cmd_xmls[0]); i++) {

+        pj_str_t xml = pj_str(cmd_xmls[i]);

+

+        if (pj_cli_add_cmd_from_xml(cli, NULL, &xml, 

+				    &cmd_handler, NULL, NULL) != PJ_SUCCESS) 

+	{

+            TRACE_((THIS_FILE, "Failed to add command #%d", i));

+	}

+    }

+

+    *p_cli = cli;

+

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_cli_cfg*) pj_cli_get_param(pj_cli_t *cli)

+{

+    PJ_ASSERT_RETURN(cli, NULL);

+

+    return &cli->cfg;

+}

+

+PJ_DEF(void) pj_cli_register_front_end(pj_cli_t *cli,

+                                       pj_cli_front_end *fe)

+{

+    pj_list_push_back(&cli->fe_head, fe);

+}

+

+PJ_DEF(void) pj_cli_quit(pj_cli_t *cli, pj_cli_sess *req,

+			 pj_bool_t restart)

+{

+    pj_cli_front_end *fe;

+

+    pj_assert(cli);

+    if (cli->is_quitting)

+	return;

+

+    cli->is_quitting = PJ_TRUE;

+    cli->is_restarting = restart;

+

+    fe = cli->fe_head.next;

+    while (fe != &cli->fe_head) {

+        if (fe->op && fe->op->on_quit)

+            (*fe->op->on_quit)(fe, req);

+        fe = fe->next;

+    }

+}

+

+PJ_DEF(pj_bool_t) pj_cli_is_quitting(pj_cli_t *cli)

+{

+    PJ_ASSERT_RETURN(cli, PJ_FALSE);

+

+    return cli->is_quitting;

+}

+

+PJ_DEF(pj_bool_t) pj_cli_is_restarting(pj_cli_t *cli)

+{

+    PJ_ASSERT_RETURN(cli, PJ_FALSE);

+

+    return cli->is_restarting;

+}

+

+PJ_DEF(void) pj_cli_destroy(pj_cli_t *cli)

+{

+    pj_cli_front_end *fe;

+

+    if (!cli)

+	return;

+

+    if (!pj_cli_is_quitting(cli))

+        pj_cli_quit(cli, NULL, PJ_FALSE);

+

+    fe = cli->fe_head.next;

+    while (fe != &cli->fe_head) {

+        pj_list_erase(fe);

+	if (fe->op && fe->op->on_destroy)

+	    (*fe->op->on_destroy)(fe);

+

+        fe = cli->fe_head.next;

+    }

+    cli->is_quitting = PJ_FALSE;

+    pj_pool_release(cli->pool);

+}

+

+PJ_DEF(void) pj_cli_sess_end_session(pj_cli_sess *sess)

+{

+    pj_assert(sess);

+

+    if (sess->op && sess->op->destroy)

+        (*sess->op->destroy)(sess);

+}

+

+/* Syntax error handler for parser. */

+static void on_syntax_error(pj_scanner *scanner)

+{

+    PJ_UNUSED_ARG(scanner);

+    PJ_THROW(PJ_EINVAL);

+}

+

+/* Get the command from the command hash */

+static pj_cli_cmd_spec *get_cmd_name(const pj_cli_t *cli, 

+				     const pj_cli_cmd_spec *group, 

+				     const pj_str_t *cmd)

+{

+    pj_str_t cmd_val;

+    char cmd_ptr[MAX_CMD_HASH_NAME_LENGTH];

+

+    cmd_val.ptr = cmd_ptr;

+    cmd_val.slen = 0;

+

+    if (group) {

+	char cmd_str[MAX_CMD_ID_LENGTH];

+	pj_ansi_sprintf(cmd_str, "%d", group->id);

+	pj_strcat2(&cmd_val, cmd_str);	

+    }

+    pj_strcat(&cmd_val, cmd);

+    return (pj_cli_cmd_spec *)pj_hash_get(cli->cmd_name_hash, cmd_val.ptr, 

+					  (unsigned)cmd_val.slen, NULL);

+}

+

+/* Add command to the command hash */

+static void add_cmd_name(pj_cli_t *cli, pj_cli_cmd_spec *group, 

+			 pj_cli_cmd_spec *cmd, pj_str_t *cmd_name)

+{

+    pj_str_t cmd_val;

+    pj_str_t add_cmd;

+    char cmd_ptr[MAX_CMD_HASH_NAME_LENGTH];

+

+    cmd_val.ptr = cmd_ptr;

+    cmd_val.slen = 0;

+

+    if (group) {

+	char cmd_str[MAX_CMD_ID_LENGTH];

+	pj_ansi_sprintf(cmd_str, "%d", group->id);

+	pj_strcat2(&cmd_val, cmd_str);	

+    }

+    pj_strcat(&cmd_val, cmd_name);

+    pj_strdup(cli->pool, &add_cmd, &cmd_val);

+    

+    pj_hash_set(cli->pool, cli->cmd_name_hash, cmd_val.ptr, 

+		(unsigned)cmd_val.slen, 0, cmd);

+}

+

+/**

+ * This method is to parse and add the choice type 

+ * argument values to command structure.

+ **/

+static pj_status_t add_choice_node(pj_cli_t *cli,

+				   pj_xml_node *xml_node,

+				   pj_cli_arg_spec *arg,

+				   pj_cli_get_dyn_choice get_choice)

+{

+    pj_xml_node *choice_node;

+    pj_xml_node *sub_node;

+    pj_cli_arg_choice_val choice_values[PJ_CLI_MAX_CHOICE_VAL];

+    pj_status_t status = PJ_SUCCESS;

+

+    sub_node = xml_node;

+    arg->type = PJ_CLI_ARG_CHOICE;

+    arg->get_dyn_choice = get_choice;						

+

+    choice_node = sub_node->node_head.next;

+    while (choice_node != (pj_xml_node*)&sub_node->node_head) {

+	pj_xml_attr *choice_attr;

+	unsigned *stat_cnt = &arg->stat_choice_cnt;

+	pj_cli_arg_choice_val *choice_val = &choice_values[*stat_cnt];		     

+	pj_bzero(choice_val, sizeof(*choice_val));

+

+	choice_attr = choice_node->attr_head.next;

+	while (choice_attr != &choice_node->attr_head) {

+	    if (!pj_stricmp2(&choice_attr->name, "value")) {

+		pj_strassign(&choice_val->value, &choice_attr->value);

+	    } else if (!pj_stricmp2(&choice_attr->name, "desc")) {

+		pj_strassign(&choice_val->desc, &choice_attr->value);

+	    }

+	    choice_attr = choice_attr->next;

+	}		

+	if (++(*stat_cnt) >= PJ_CLI_MAX_CHOICE_VAL)

+	    break;

+	choice_node = choice_node->next;

+    }    

+    if (arg->stat_choice_cnt > 0) {

+        unsigned i;

+

+	arg->stat_choice_val = (pj_cli_arg_choice_val *)

+				pj_pool_zalloc(cli->pool, 

+					       arg->stat_choice_cnt *

+					       sizeof(pj_cli_arg_choice_val));

+

+        for (i = 0; i < arg->stat_choice_cnt; i++) {

+	    pj_strdup(cli->pool, &arg->stat_choice_val[i].value, 

+		      &choice_values[i].value);

+            pj_strdup(cli->pool, &arg->stat_choice_val[i].desc, 

+		      &choice_values[i].desc);            

+        }

+    }

+    return status;

+}

+

+/**

+ * This method is to parse and add the argument attribute to command structure.

+ **/

+static pj_status_t add_arg_node(pj_cli_t *cli,

+				pj_xml_node *xml_node,

+				pj_cli_cmd_spec *cmd,

+				pj_cli_arg_spec *arg,

+				pj_cli_get_dyn_choice get_choice)

+{    

+    pj_xml_attr *attr;

+    pj_status_t status = PJ_SUCCESS;

+    pj_xml_node *sub_node = xml_node;

+

+    if (cmd->arg_cnt >= PJ_CLI_MAX_ARGS)

+	return PJ_CLI_ETOOMANYARGS;

+    

+    pj_bzero(arg, sizeof(*arg));

+    attr = sub_node->attr_head.next;

+    arg->optional = PJ_FALSE;

+    arg->validate = PJ_TRUE;

+    while (attr != &sub_node->attr_head) {	

+	if (!pj_stricmp2(&attr->name, "name")) {

+	    pj_strassign(&arg->name, &attr->value);

+	} else if (!pj_stricmp2(&attr->name, "id")) {

+	    arg->id = pj_strtol(&attr->value);

+	} else if (!pj_stricmp2(&attr->name, "type")) {

+	    if (!pj_stricmp2(&attr->value, "text")) {

+		arg->type = PJ_CLI_ARG_TEXT;

+	    } else if (!pj_stricmp2(&attr->value, "int")) {

+		arg->type = PJ_CLI_ARG_INT;

+	    } else if (!pj_stricmp2(&attr->value, "choice")) {

+		/* Get choice value */

+		add_choice_node(cli, xml_node, arg, get_choice);

+	    } 

+	} else if (!pj_stricmp2(&attr->name, "desc")) {

+	    pj_strassign(&arg->desc, &attr->value);

+	} else if (!pj_stricmp2(&attr->name, "optional")) {

+	    if (!pj_strcmp2(&attr->value, "1")) {

+		arg->optional = PJ_TRUE;

+	    }

+	} else if (!pj_stricmp2(&attr->name, "validate")) {

+	    if (!pj_strcmp2(&attr->value, "1")) {

+		arg->validate = PJ_TRUE;

+	    } else {

+		arg->validate = PJ_FALSE;

+	    }	

+	} 

+	attr = attr->next;

+    }

+    cmd->arg_cnt++;

+    return status;

+}

+

+/**

+ * This method is to parse and add the command attribute to command structure.

+ **/

+static pj_status_t add_cmd_node(pj_cli_t *cli,				  

+				pj_cli_cmd_spec *group,					 

+				pj_xml_node *xml_node,

+				pj_cli_cmd_handler handler,

+				pj_cli_cmd_spec **p_cmd,

+				pj_cli_get_dyn_choice get_choice)

+{

+    pj_xml_node *root = xml_node;

+    pj_xml_attr *attr;

+    pj_xml_node *sub_node;

+    pj_cli_cmd_spec *cmd;

+    pj_cli_arg_spec args[PJ_CLI_MAX_ARGS];

+    pj_str_t sc[PJ_CLI_MAX_SHORTCUTS];

+    pj_status_t status = PJ_SUCCESS;

+

+    if (pj_stricmp2(&root->name, "CMD"))

+        return PJ_EINVAL;

+

+    /* Initialize the command spec */

+    cmd = PJ_POOL_ZALLOC_T(cli->pool, struct pj_cli_cmd_spec);

+    

+    /* Get the command attributes */

+    attr = root->attr_head.next;

+    while (attr != &root->attr_head) {

+        if (!pj_stricmp2(&attr->name, "name")) {

+            pj_strltrim(&attr->value);

+            if (!attr->value.slen || 

+		(get_cmd_name(cli, group, &attr->value)))                

+            {

+                return PJ_CLI_EBADNAME;

+            }

+            pj_strdup(cli->pool, &cmd->name, &attr->value);

+        } else if (!pj_stricmp2(&attr->name, "id")) {	    

+	    pj_bool_t is_valid = PJ_FALSE;

+            if (attr->value.slen) {		

+		pj_cli_cmd_id cmd_id = pj_strtol(&attr->value);

+		if (!pj_hash_get(cli->cmd_id_hash, &cmd_id, 

+		                 sizeof(pj_cli_cmd_id), NULL))

+		    is_valid = PJ_TRUE;

+	    } 

+	    if (!is_valid)

+		return PJ_CLI_EBADID;

+            cmd->id = (pj_cli_cmd_id)pj_strtol(&attr->value);

+        } else if (!pj_stricmp2(&attr->name, "sc")) {

+            pj_scanner scanner;

+            pj_str_t str;

+

+            PJ_USE_EXCEPTION;

+

+            pj_scan_init(&scanner, attr->value.ptr, attr->value.slen,

+                         PJ_SCAN_AUTOSKIP_WS, &on_syntax_error);

+

+            PJ_TRY {

+                while (!pj_scan_is_eof(&scanner)) {

+                    pj_scan_get_until_ch(&scanner, ',', &str);

+                    pj_strrtrim(&str);

+                    if (!pj_scan_is_eof(&scanner))

+                        pj_scan_advance_n(&scanner, 1, PJ_TRUE);

+                    if (!str.slen)

+                        continue;

+

+                    if (cmd->sc_cnt >= PJ_CLI_MAX_SHORTCUTS) {

+                        PJ_THROW(PJ_CLI_ETOOMANYARGS);

+                    }

+                    /* Check whether the shortcuts are already used */

+                    if (get_cmd_name(cli, &cli->root, &str)) {

+                        PJ_THROW(PJ_CLI_EBADNAME);

+                    }

+

+                    pj_strassign(&sc[cmd->sc_cnt++], &str);

+                }

+            }

+            PJ_CATCH_ANY {

+                pj_scan_fini(&scanner);

+                return (PJ_GET_EXCEPTION());

+            }

+            PJ_END;

+            

+        } else if (!pj_stricmp2(&attr->name, "desc")) {

+            pj_strdup(cli->pool, &cmd->desc, &attr->value);

+        }

+        attr = attr->next;

+    }

+

+    /* Get the command childs/arguments */

+    sub_node = root->node_head.next;

+    while (sub_node != (pj_xml_node*)&root->node_head) {

+	if (!pj_stricmp2(&sub_node->name, "CMD")) {

+	    status = add_cmd_node(cli, cmd, sub_node, handler, NULL, 

+				  get_choice);

+	    if (status != PJ_SUCCESS)

+		return status;

+	} else if (!pj_stricmp2(&sub_node->name, "ARG")) {

+	    /* Get argument attribute */

+	    status = add_arg_node(cli, sub_node, 

+			          cmd, &args[cmd->arg_cnt], 

+		                  get_choice);

+

+	    if (status != PJ_SUCCESS)

+		return status;

+        }

+        sub_node = sub_node->next;

+    }

+

+    if (!cmd->name.slen)

+        return PJ_CLI_EBADNAME;

+

+    if (!cmd->id)

+        return PJ_CLI_EBADID;

+

+    if (cmd->arg_cnt) {

+        unsigned i;

+

+        cmd->arg = (pj_cli_arg_spec *)pj_pool_zalloc(cli->pool, cmd->arg_cnt *

+                                                     sizeof(pj_cli_arg_spec));

+	

+        for (i = 0; i < cmd->arg_cnt; i++) {

+            pj_strdup(cli->pool, &cmd->arg[i].name, &args[i].name);

+            pj_strdup(cli->pool, &cmd->arg[i].desc, &args[i].desc);

+	    cmd->arg[i].id = args[i].id;

+            cmd->arg[i].type = args[i].type;

+	    cmd->arg[i].optional = args[i].optional;

+	    cmd->arg[i].validate = args[i].validate;

+	    cmd->arg[i].get_dyn_choice = args[i].get_dyn_choice;

+	    cmd->arg[i].stat_choice_cnt = args[i].stat_choice_cnt;

+	    cmd->arg[i].stat_choice_val = args[i].stat_choice_val;

+        }

+    }

+

+    if (cmd->sc_cnt) {

+        unsigned i;

+

+        cmd->sc = (pj_str_t *)pj_pool_zalloc(cli->pool, cmd->sc_cnt *

+                                             sizeof(pj_str_t));

+        for (i = 0; i < cmd->sc_cnt; i++) {

+            pj_strdup(cli->pool, &cmd->sc[i], &sc[i]);	

+	    /** Add shortcut to root command **/

+	    add_cmd_name(cli, &cli->root, cmd, &sc[i]);

+        }

+    }

+    

+    add_cmd_name(cli, group, cmd, &cmd->name);    

+    pj_hash_set(cli->pool, cli->cmd_id_hash, 

+		&cmd->id, sizeof(pj_cli_cmd_id), 0, cmd);

+

+    cmd->handler = handler;

+

+    if (group) {

+	if (!group->sub_cmd) {

+	    group->sub_cmd = PJ_POOL_ALLOC_T(cli->pool, struct pj_cli_cmd_spec);

+	    pj_list_init(group->sub_cmd);

+	}

+        pj_list_push_back(group->sub_cmd, cmd);

+    } else {

+        pj_list_push_back(cli->root.sub_cmd, cmd);

+    }

+

+    if (p_cmd)

+        *p_cmd = cmd;

+

+    return status;

+}

+

+PJ_DEF(pj_status_t) pj_cli_add_cmd_from_xml(pj_cli_t *cli,

+					    pj_cli_cmd_spec *group,

+                                            const pj_str_t *xml,

+                                            pj_cli_cmd_handler handler,

+                                            pj_cli_cmd_spec **p_cmd, 

+					    pj_cli_get_dyn_choice get_choice)

+{ 

+    pj_pool_t *pool;

+    pj_xml_node *root;

+    pj_status_t status = PJ_SUCCESS;

+    

+    PJ_ASSERT_RETURN(cli && xml, PJ_EINVAL);

+

+    /* Parse the xml */

+    pool = pj_pool_create(cli->cfg.pf, "xml", 1024, 1024, NULL);

+    if (!pool)

+        return PJ_ENOMEM;

+

+    root = pj_xml_parse(pool, xml->ptr, xml->slen);

+    if (!root) {

+	TRACE_((THIS_FILE, "Error: unable to parse XML"));

+	pj_pool_release(pool);

+	return PJ_CLI_EBADXML;

+    }    

+    status = add_cmd_node(cli, group, root, handler, p_cmd, get_choice);

+    pj_pool_release(pool);

+    return status;

+}

+

+PJ_DEF(pj_status_t) pj_cli_sess_parse(pj_cli_sess *sess,

+				      char *cmdline,

+				      pj_cli_cmd_val *val,

+				      pj_pool_t *pool,

+				      pj_cli_exec_info *info)

+{    

+    pj_scanner scanner;

+    pj_str_t str;

+    pj_size_t len;    

+    pj_cli_cmd_spec *cmd;

+    pj_cli_cmd_spec *next_cmd;

+    pj_status_t status = PJ_SUCCESS;

+    pj_cli_parse_mode parse_mode = PARSE_NONE;    

+

+    PJ_USE_EXCEPTION;

+

+    PJ_ASSERT_RETURN(sess && cmdline && val, PJ_EINVAL);

+

+    PJ_UNUSED_ARG(pool);

+

+    str.slen = 0;

+    pj_cli_exec_info_default(info);

+

+    /* Set the parse mode based on the latest char. */

+    len = pj_ansi_strlen(cmdline);

+    if (len > 0 && ((cmdline[len - 1] == '\r')||(cmdline[len - 1] == '\n'))) {

+        cmdline[--len] = 0;

+	parse_mode = PARSE_EXEC;

+    } else if (len > 0 && 

+	       (cmdline[len - 1] == '\t' || cmdline[len - 1] == '?')) 

+    {

+	cmdline[--len] = 0;

+	if (len == 0) {

+	    parse_mode = PARSE_NEXT_AVAIL;

+	} else {

+	    if (cmdline[len - 1] == ' ') 

+		parse_mode = PARSE_NEXT_AVAIL;

+	    else 

+		parse_mode = PARSE_COMPLETION;

+	}

+    }

+    val->argc = 0;

+    info->err_pos = 0;

+    cmd = &sess->fe->cli->root;

+    if (len > 0) {

+	pj_scan_init(&scanner, cmdline, len, PJ_SCAN_AUTOSKIP_WS, 

+		     &on_syntax_error);

+	PJ_TRY {

+	    val->argc = 0;	    

+	    while (!pj_scan_is_eof(&scanner)) {

+		info->err_pos = (int)(scanner.curptr - scanner.begin);

+		if (*scanner.curptr == '\'' || *scanner.curptr == '"' ||

+		    *scanner.curptr == '{')

+		{

+		    pj_scan_get_quotes(&scanner, "'\"{", "'\"}", 3, &str);

+		    /* Remove the quotes */

+		    str.ptr++;

+		    str.slen -= 2;

+		} else {

+		    pj_scan_get_until_chr(&scanner, " \t\r\n", &str);

+		}

+		++val->argc;

+		if (val->argc == PJ_CLI_MAX_ARGS)

+		    PJ_THROW(PJ_CLI_ETOOMANYARGS);		

+		

+		status = get_available_cmds(sess, cmd, &str, val->argc-1, 

+					    pool, PJ_TRUE, parse_mode, 

+					    &next_cmd, info);

+

+		if (status != PJ_SUCCESS)

+		    PJ_THROW(status);

+		

+		if (cmd != next_cmd) {

+		    /* Found new command, set it as the active command */

+		    cmd = next_cmd;

+		    val->argc = 1;

+		    val->cmd = cmd;

+		}

+		if (parse_mode == PARSE_EXEC) 

+		    pj_strassign(&val->argv[val->argc-1], &info->hint->name);

+		else 

+		    pj_strassign(&val->argv[val->argc-1], &str);

+

+	    }            

+	    if (!pj_scan_is_eof(&scanner)) 

+		PJ_THROW(PJ_CLI_EINVARG);

+

+	}

+	PJ_CATCH_ANY {

+	    pj_scan_fini(&scanner);

+	    return PJ_GET_EXCEPTION();

+	}

+	PJ_END;

+    } 

+    

+    if ((parse_mode == PARSE_NEXT_AVAIL) || (parse_mode == PARSE_EXEC)) {

+	/* If exec mode, just get the matching argument */

+	status = get_available_cmds(sess, cmd, NULL, val->argc, pool, 

+				    (parse_mode==PARSE_NEXT_AVAIL), 

+				    parse_mode,

+				    NULL, info);

+	if ((status != PJ_SUCCESS) && (status != PJ_CLI_EINVARG)) {

+	    pj_str_t data = pj_str(cmdline);

+	    pj_strrtrim(&data);

+	    data.ptr[data.slen] = ' ';

+	    data.ptr[data.slen+1] = 0;

+

+	    info->err_pos = (int)pj_ansi_strlen(cmdline);

+	}

+    } 

+   

+    val->sess = sess;

+    return status;

+}

+

+PJ_DECL(pj_status_t) pj_cli_sess_exec(pj_cli_sess *sess,

+				      char *cmdline,

+				      pj_pool_t *pool,

+				      pj_cli_exec_info *info)

+{

+    pj_cli_cmd_val val;

+    pj_status_t status;

+    pj_cli_exec_info einfo;

+    pj_str_t cmd;

+

+    PJ_ASSERT_RETURN(sess && cmdline, PJ_EINVAL);

+

+    PJ_UNUSED_ARG(pool);

+

+    cmd.ptr = cmdline;

+    cmd.slen = pj_ansi_strlen(cmdline);

+

+    if (pj_strtrim(&cmd)->slen == 0)

+	return PJ_SUCCESS;

+

+    if (!info)

+        info = &einfo;

+	

+    status = pj_cli_sess_parse(sess, cmdline, &val, pool, info);

+    if (status != PJ_SUCCESS)

+        return status;

+

+    if ((val.argc > 0) && (val.cmd->handler)) {

+        info->cmd_ret = (*val.cmd->handler)(&val);

+        if (info->cmd_ret == PJ_CLI_EINVARG ||

+            info->cmd_ret == PJ_CLI_EEXIT)

+	{

+            return info->cmd_ret;

+	}

+    }

+

+    return PJ_SUCCESS;

+}

+

+static pj_bool_t hint_inserted(const pj_str_t *name, 

+			       const pj_str_t *desc, 

+			       const pj_str_t *type, 

+			       pj_cli_exec_info *info)

+{

+    unsigned i;

+    for(i=0; i<info->hint_cnt; ++i) {

+	pj_cli_hint_info *hint = &info->hint[i];

+	if ((!pj_strncmp(&hint->name, name, hint->name.slen)) &&

+	    (!pj_strncmp(&hint->desc, desc, hint->desc.slen)) &&

+	    (!pj_strncmp(&hint->type, type, hint->type.slen)))

+	{

+	    return PJ_TRUE;

+	}

+    }

+    return PJ_FALSE;

+}

+

+/** This will insert new hint with the option to check for the same 

+    previous entry **/

+static pj_status_t insert_new_hint2(pj_pool_t *pool, 

+				    pj_bool_t unique_insert,

+				    const pj_str_t *name, 

+				    const pj_str_t *desc, 

+				    const pj_str_t *type, 

+				    pj_cli_exec_info *info)

+{

+    pj_cli_hint_info *hint;

+    PJ_ASSERT_RETURN(pool && info, PJ_EINVAL);

+    PJ_ASSERT_RETURN((info->hint_cnt < PJ_CLI_MAX_HINTS), PJ_EINVAL);

+

+    if ((unique_insert) && (hint_inserted(name, desc, type, info)))

+	return PJ_SUCCESS;

+

+    hint = &info->hint[info->hint_cnt];

+

+    pj_strdup(pool, &hint->name, name);

+

+    if (desc && (desc->slen > 0))  {

+	pj_strdup(pool, &hint->desc, desc);

+    } else {

+	hint->desc.slen = 0;

+    }

+    

+    if (type && (type->slen > 0)) {

+	pj_strdup(pool, &hint->type, type);

+    } else {

+	hint->type.slen = 0;

+    }

+

+    ++info->hint_cnt;    

+    return PJ_SUCCESS;

+}

+

+/** This will insert new hint without checking for the same previous entry **/

+static pj_status_t insert_new_hint(pj_pool_t *pool, 

+				   const pj_str_t *name, 

+				   const pj_str_t *desc, 

+				   const pj_str_t *type, 

+				   pj_cli_exec_info *info)

+{        

+    return insert_new_hint2(pool, PJ_FALSE, name, desc, type, info);

+}

+

+/** This will get a complete/exact match of a command from the cmd hash **/

+static pj_status_t get_comp_match_cmds(const pj_cli_t *cli, 

+				       const pj_cli_cmd_spec *group,

+				       const pj_str_t *cmd_val,	

+				       pj_pool_t *pool, 

+				       pj_cli_cmd_spec **p_cmd,

+				       pj_cli_exec_info *info)

+{

+    pj_cli_cmd_spec *cmd;    

+    PJ_ASSERT_RETURN(cli && group && cmd_val && pool && info, PJ_EINVAL);   

+

+    cmd = get_cmd_name(cli, group, cmd_val);

+

+    if (cmd) {

+	pj_status_t status;    

+	status = insert_new_hint(pool, cmd_val, &cmd->desc, NULL, info);

+

+	if (status != PJ_SUCCESS)

+	    return status;

+

+	*p_cmd = cmd;

+    }

+

+    return PJ_SUCCESS;

+}

+

+/** This method will search for any shortcut with pattern match to the input

+    command. This method should be called from root command, as shortcut could

+    only be executed from root **/

+static pj_status_t get_pattern_match_shortcut(const pj_cli_t *cli,

+					      const pj_str_t *cmd_val,

+					      pj_pool_t *pool, 

+					      pj_cli_cmd_spec **p_cmd,

+					      pj_cli_exec_info *info)

+{

+    pj_hash_iterator_t it_buf, *it;

+    pj_status_t status;

+    PJ_ASSERT_RETURN(cli && pool && cmd_val && info, PJ_EINVAL);

+  

+    it = pj_hash_first(cli->cmd_name_hash, &it_buf);

+    while (it) {

+	unsigned i;

+	pj_cli_cmd_spec *cmd = (pj_cli_cmd_spec *)

+			       pj_hash_this(cli->cmd_name_hash, it);

+

+	PJ_ASSERT_RETURN(cmd, PJ_EINVAL);	    

+	

+	for (i=0; i < cmd->sc_cnt; ++i) {

+	    static const pj_str_t SHORTCUT = {"SC", 2};

+	    pj_str_t *sc = &cmd->sc[i];

+	    PJ_ASSERT_RETURN(sc, PJ_EINVAL);

+

+	    if (!pj_strncmp(sc, cmd_val, cmd_val->slen)) {

+		/** Unique hints needed because cmd hash contain command name

+		    and shortcut referencing to the same command **/

+		status = insert_new_hint2(pool, PJ_TRUE, sc, &cmd->desc, 

+					  &SHORTCUT, info);

+		if (status != PJ_SUCCESS)

+		    return status;

+

+		if (p_cmd)

+		    *p_cmd = cmd;

+	    }

+	}

+	

+	it = pj_hash_next(cli->cmd_name_hash, it);

+    }

+

+    return PJ_SUCCESS;

+}

+

+/** This method will search a pattern match to the input command from the child

+    command list of the current/active command. **/

+static pj_status_t get_pattern_match_cmds(pj_cli_cmd_spec *cmd, 

+					  const pj_str_t *cmd_val,				      

+					  pj_pool_t *pool, 

+					  pj_cli_cmd_spec **p_cmd, 

+					  pj_cli_parse_mode parse_mode,

+					  pj_cli_exec_info *info)

+{

+    pj_status_t status;

+    PJ_ASSERT_RETURN(cmd && pool && info && cmd_val, PJ_EINVAL);   

+

+    if (p_cmd)

+	*p_cmd = cmd;

+

+    /* Get matching command */

+    if (cmd->sub_cmd) {

+	pj_cli_cmd_spec *child_cmd = cmd->sub_cmd->next;

+	while (child_cmd != cmd->sub_cmd) {

+	    pj_bool_t found = PJ_FALSE;

+	    if (!pj_strncmp(&child_cmd->name, cmd_val, cmd_val->slen)) {		

+		status = insert_new_hint(pool, &child_cmd->name, 

+					 &child_cmd->desc, NULL, info);

+		if (status != PJ_SUCCESS)

+		    return status;

+

+		found = PJ_TRUE;

+	    }

+	    if (found) {

+		if (parse_mode == PARSE_NEXT_AVAIL) {

+		    /** Only insert shortcut on next available commands mode **/

+		    unsigned i;

+		    for (i=0; i < child_cmd->sc_cnt; ++i) {

+			static const pj_str_t SHORTCUT = {"SC", 2};

+			pj_str_t *sc = &child_cmd->sc[i];

+			PJ_ASSERT_RETURN(sc, PJ_EINVAL);

+

+			status = insert_new_hint(pool, sc, 

+						 &child_cmd->desc, &SHORTCUT, 

+						 info);

+			if (status != PJ_SUCCESS)

+			    return status;

+		    }

+		}

+

+		if (p_cmd)

+		    *p_cmd = child_cmd;			    

+	    }	

+	    child_cmd = child_cmd->next;

+	}

+    }

+    return PJ_SUCCESS;

+}

+

+/** This will match the arguments passed to the command with the argument list

+    of the specified command list. **/

+static pj_status_t get_match_args(pj_cli_sess *sess,

+				  pj_cli_cmd_spec *cmd, 

+				  const pj_str_t *cmd_val,

+				  unsigned argc,

+				  pj_pool_t *pool, 

+				  pj_cli_parse_mode parse_mode,

+				  pj_cli_exec_info *info)

+{

+    pj_cli_arg_spec *arg;

+    pj_status_t status = PJ_SUCCESS;

+

+    PJ_ASSERT_RETURN(cmd && pool && cmd_val && info, PJ_EINVAL);

+

+    if ((argc > cmd->arg_cnt) && (!cmd->sub_cmd)) {

+	if (cmd_val->slen > 0)

+	    return PJ_CLI_ETOOMANYARGS;

+	else

+	    return PJ_SUCCESS;

+    }

+

+    if (cmd->arg_cnt > 0) {

+	arg = &cmd->arg[argc-1];

+	PJ_ASSERT_RETURN(arg, PJ_EINVAL);

+	if (arg->type == PJ_CLI_ARG_CHOICE) {	    

+	    unsigned j;	    	    

+

+	    if ((parse_mode == PARSE_EXEC) && (!arg->validate)) {

+		/* If no validation needed, then insert the values */

+		status = insert_new_hint(pool, cmd_val, NULL, NULL, info);		

+		return status;

+	    }

+

+	    for (j=0; j < arg->stat_choice_cnt; ++j) {

+		pj_cli_arg_choice_val *choice_val = &arg->stat_choice_val[j];		

+    	    

+		PJ_ASSERT_RETURN(choice_val, PJ_EINVAL);		

+    	    

+		if (!pj_strncmp(&choice_val->value, cmd_val, cmd_val->slen)) {		    

+		    status = insert_new_hint(pool, 

+					     &choice_val->value, 

+					     &choice_val->desc, 

+					     &arg_type[PJ_CLI_ARG_CHOICE].msg, 

+					     info);

+		    if (status != PJ_SUCCESS)

+			return status;		    

+		}

+	    }

+	    if (arg->get_dyn_choice) {

+		pj_cli_dyn_choice_param dyn_choice_param;

+		static pj_str_t choice_str = {"choice", 6};

+

+		/* Get the dynamic choice values */	    

+		dyn_choice_param.sess = sess;

+		dyn_choice_param.cmd = cmd;

+		dyn_choice_param.arg_id = arg->id;

+		dyn_choice_param.max_cnt = PJ_CLI_MAX_CHOICE_VAL;

+		dyn_choice_param.pool = pool;

+		dyn_choice_param.cnt = 0;	    

+

+		(*arg->get_dyn_choice)(&dyn_choice_param);

+		for (j=0; j < dyn_choice_param.cnt; ++j) {

+		    pj_cli_arg_choice_val *choice = &dyn_choice_param.choice[j];

+		    if (!pj_strncmp(&choice->value, cmd_val, cmd_val->slen)) {

+			pj_strassign(&info->hint[info->hint_cnt].name, 

+				     &choice->value);

+			pj_strassign(&info->hint[info->hint_cnt].type, 

+				     &choice_str);

+			pj_strassign(&info->hint[info->hint_cnt].desc, 

+				     &choice->desc);

+			if ((++info->hint_cnt) >= PJ_CLI_MAX_HINTS)

+			    break;

+		    }

+		}

+		if ((info->hint_cnt == 0) && (!arg->optional))

+		    return PJ_CLI_EMISSINGARG;

+	    }

+	} else {

+	    if (cmd_val->slen == 0) {

+		if (info->hint_cnt == 0) {

+		    if (!((parse_mode == PARSE_EXEC) && (arg->optional))) {

+			/* For exec mode,no need to insert hint if optional */

+			status = insert_new_hint(pool, 

+						 &arg->name, 

+				  	         &arg->desc, 

+						 &arg_type[arg->type].msg,

+						 info);

+			if (status != PJ_SUCCESS)

+			    return status;

+		    }

+		    if (!arg->optional)

+			return PJ_CLI_EMISSINGARG;

+		} 

+	    } else {

+		return insert_new_hint(pool, cmd_val, NULL, NULL, info);

+	    }

+	}

+    } 

+    return status;

+}

+

+/** This will check for a match of the commands/arguments input. Any match 

+    will be inserted to the hint data. **/

+static pj_status_t get_available_cmds(pj_cli_sess *sess,

+				      pj_cli_cmd_spec *cmd, 

+				      pj_str_t *cmd_val,

+				      unsigned argc,

+				      pj_pool_t *pool,

+				      pj_bool_t get_cmd,

+				      pj_cli_parse_mode parse_mode,

+				      pj_cli_cmd_spec **p_cmd,

+				      pj_cli_exec_info *info)

+{

+    pj_status_t status = PJ_SUCCESS;

+    pj_str_t *prefix;

+    pj_str_t EMPTY_STR = {NULL, 0};

+

+    prefix = cmd_val?(pj_strtrim(cmd_val)):(&EMPTY_STR);

+

+    info->hint_cnt = 0;    

+

+    if (get_cmd) {

+	status = get_comp_match_cmds(sess->fe->cli, cmd, prefix, pool, p_cmd, 

+				     info);

+	if (status != PJ_SUCCESS)

+	    return status;

+	

+	/** If exact match found, then no need to search for pattern match **/

+	if (info->hint_cnt == 0) {

+	    if ((parse_mode != PARSE_NEXT_AVAIL) && 

+		(cmd == &sess->fe->cli->root)) 

+	    {

+		/** Pattern match for shortcut needed on root command only **/

+		status = get_pattern_match_shortcut(sess->fe->cli, prefix, pool,

+						    p_cmd, info);

+

+		if (status != PJ_SUCCESS)

+		    return status;

+	    }

+

+	    status = get_pattern_match_cmds(cmd, prefix, pool, p_cmd, 

+					    parse_mode, info);

+	}

+

+	if (status != PJ_SUCCESS)

+	    return status;

+    }

+

+    if (argc > 0)

+	status = get_match_args(sess, cmd, prefix, argc, 

+			        pool, parse_mode, info);

+

+    if (status == PJ_SUCCESS) {	

+	if (prefix->slen > 0) {

+	    /** If a command entered is not a an empty command, and have a 

+		single match in the command list then it is a valid command **/

+	    if (info->hint_cnt == 0) {

+		status = PJ_CLI_EINVARG;

+	    } else if (info->hint_cnt > 1) {

+		status = PJ_CLI_EAMBIGUOUS;

+	    }

+	} else {

+	    if (info->hint_cnt > 0)

+		status = PJ_CLI_EAMBIGUOUS;

+	}

+    } 

+

+    return status;

+}

+