瀏覽代碼

Compilable version

git-svn-id: https://klish.googlecode.com/svn/trunk@426 0eaa4687-2ee9-07dd-09d9-bcdd2d2dd5fb
Serj Kalichev 13 年之前
父節點
當前提交
fec195c244

+ 1 - 1
clish/callback_script.c

@@ -22,7 +22,7 @@
 
 /*--------------------------------------------------------- */
 bool_t clish_script_callback(clish_context_t *context,
-	const char *script, char ** out)
+	const char *script, char **out)
 {
 	clish_shell_t *this = context->shell;
 	const clish_command_t *cmd = context->cmd;

+ 8 - 8
clish/command.h

@@ -42,15 +42,14 @@ clish_command_diff(const clish_command_t * cmd1, const clish_command_t * cmd2);
 /*-----------------
  * methods
  *----------------- */
-void clish_command_delete(clish_command_t * instance);
-void
-clish_command_insert_param(clish_command_t * instance, clish_param_t * param);
-int clish_command_help(const clish_command_t * instance, clish_help_t *help,
-	const char *viewid, const char *line, size_t *max_width);
-void clish_command_dump(const clish_command_t * instance);
+void clish_command_delete(clish_command_t *instance);
+void clish_command_insert_param(clish_command_t *instance,
+	clish_param_t *param);
+int clish_command_help(const clish_command_t *instance);
+void clish_command_dump(const clish_command_t *instance);
 
 /*-----------------
- * attributes 
+ * attributes
  *----------------- */
 const char *clish_command__get_name(const clish_command_t * instance);
 const char *clish_command__get_suffix(const clish_command_t * instance);
@@ -59,7 +58,8 @@ const char *clish_command__get_detail(const clish_command_t * instance);
 const char *clish_command__get_builtin(const clish_command_t * instance);
 const char *clish_command__get_escape_chars(const clish_command_t * instance);
 const clish_param_t *clish_command__get_args(const clish_command_t * instance);
-char *clish_command__get_action(const clish_command_t * instance, void *context);
+char *clish_command__get_action(const clish_command_t *instance);
+char *clish_command__expand_action(const clish_command_t *instance, void *context);
 clish_view_t *clish_command__get_view(const clish_command_t * instance);
 char *clish_command__get_viewid(const clish_command_t *instance, void *context);
 const unsigned clish_command__get_param_count(const clish_command_t * instance);

+ 10 - 56
clish/command/command.c

@@ -24,7 +24,7 @@ clish_command_init(clish_command_t * this, const char *name, const char *text,
 	/* initialise the node part */
 	this->name = lub_string_dup(name);
 	this->text = lub_string_dup(text);
-	this->var_expand_fn = fn;
+	this->var_expand_fn = fn ? fn : clish_var_expand_default;
 
 	/* Be a good binary tree citizen */
 	lub_bintree_node_init(&this->bt_node);
@@ -207,61 +207,9 @@ void clish_command_insert_param(clish_command_t * this, clish_param_t * param)
 }
 
 /*--------------------------------------------------------- */
-int clish_command_help(const clish_command_t * this, clish_help_t *help,
-	const char * viewid, const char * line, size_t *max_width)
+int clish_command_help(const clish_command_t *this)
 {
-	const char *name = clish_command__get_name(this);
-	unsigned index = lub_argv_wordcount(line);
-	unsigned idx = lub_argv_wordcount(name);
-	lub_argv_t *argv;
-	clish_pargv_t *last, *pargv;
-	unsigned i;
-	unsigned cnt = 0;
-	clish_pargv_status_t status = CLISH_LINE_OK;
-
-	/* Empty line */
-	if (0 == index)
-		return -1;
-
-	if (line[strlen(line) - 1] != ' ')
-		index--;
-
-	argv = lub_argv_new(line, 0);
-
-	/* get the parameter definition */
-	last = clish_pargv_create();
-	pargv = clish_pargv_create();
-	status = clish_pargv_parse(pargv, this, viewid, this->paramv,
-		argv, &idx, last, index);
-	clish_pargv_delete(pargv);
-	cnt = clish_pargv__get_count(last);
-
-	/* Calculate the longest name */
-	for (i = 0; i < cnt; i++) {
-		const clish_param_t *param;
-		const char *name;
-		unsigned clen = 0;
-
-		param = clish_pargv__get_param(last, i);
-		if (CLISH_PARAM_SUBCOMMAND == clish_param__get_mode(param))
-			name = clish_param__get_value(param);
-		else
-			name = clish_ptype__get_text(clish_param__get_ptype(param));
-		if (name)
-			clen = strlen(name);
-		if (max_width && (clen > *max_width))
-			*max_width = clen;
-		clish_param_help(param, help);
-	}
-	clish_pargv_delete(last);
-	lub_argv_delete(argv);
-
-	/* It's a completed command */
-	if (CLISH_LINE_OK == status)
-		return 0;
-
-	/* Incompleted command */
-	return -1;
+	return 0;
 }
 
 /*--------------------------------------------------------- */
@@ -335,7 +283,13 @@ void clish_command__set_detail(clish_command_t * this, const char *detail)
 }
 
 /*--------------------------------------------------------- */
-char *clish_command__get_action(const clish_command_t * this, void *context)
+char *clish_command__get_action(const clish_command_t *this)
+{
+	return this->action;
+}
+
+/*--------------------------------------------------------- */
+char *clish_command__expand_action(const clish_command_t *this, void *context)
 {
 	return this->var_expand_fn(this->action, context);
 }

+ 3 - 3
clish/nspace/nspace.c

@@ -30,8 +30,8 @@ static void clish_nspace_init(clish_nspace_t * this, clish_view_t * view)
 
 	/* initialise the tree of commands links for this nspace */
 	lub_bintree_init(&this->tree,
-		 clish_command_bt_offset(),
-		 clish_command_bt_compare, clish_command_bt_getkey);
+		clish_command_bt_offset(),
+		clish_command_bt_compare, clish_command_bt_getkey);
 }
 
 /*--------------------------------------------------------- */
@@ -67,7 +67,7 @@ clish_command_t * clish_nspace_create_prefix_cmd(clish_nspace_t * this,
 		this->prefix_cmd = NULL;
 	}
 
-	return (this->prefix_cmd = clish_command_new(name, help));
+	return (this->prefix_cmd = clish_command_new(name, help, NULL));
 }
 
 /*--------------------------------------------------------- */

+ 1 - 1
clish/param/param.c

@@ -23,7 +23,7 @@ static void clish_param_init(clish_param_t *this, const char *name,
 	this->name = lub_string_dup(name);
 	this->text = lub_string_dup(text);
 	this->ptype = ptype;
-	this->var_expand_fn = fn;
+	this->var_expand_fn = fn ? fn : clish_var_expand_default;
 
 	/* set up defaults */
 	this->defval = NULL;

+ 11 - 13
clish/pargv.h

@@ -34,28 +34,26 @@ typedef struct clish_parg_s clish_parg_t;
 /*-----------------
  * meta functions
  *----------------- */
-clish_pargv_t *clish_pargv_new(const clish_command_t * cmd,
-	const char *viewid,
-	const char *line,
-	size_t offset,
-	clish_pargv_status_t * status);
+clish_pargv_t *clish_pargv_new(void);
 /*-----------------
  * methods
  *----------------- */
-clish_pargv_t *clish_pargv_create(void);
 void clish_pargv_delete(clish_pargv_t * instance);
 const clish_parg_t *clish_pargv_find_arg(clish_pargv_t * instance,
 	const char *name);
 int clish_pargv_insert(clish_pargv_t * instance,
 	const clish_param_t * param, const char *value);
-clish_pargv_status_t clish_pargv_parse(clish_pargv_t * instance,
+clish_pargv_status_t clish_pargv_analyze(clish_pargv_t *instance,
+	const clish_command_t * cmd,
+	void *context,
+	const char *line,
+	size_t offset);
+clish_pargv_status_t clish_pargv_parse(clish_pargv_t *instance,
 	const clish_command_t * cmd,
-	const char *viewid,
-	clish_paramv_t * paramv,
-	const lub_argv_t * argv,
-	unsigned *idx,
-	clish_pargv_t * last,
-	unsigned need_index);
+	void *context,
+	clish_paramv_t *paramv,
+	const lub_argv_t *argv,
+	unsigned *idx, clish_pargv_t *last, unsigned need_index);
 void clish_pargv_dump(const clish_pargv_t * instance);
 /*-----------------
  * attributes 

+ 13 - 38
clish/pargv/pargv.c

@@ -322,21 +322,7 @@ clish_pargv_status_t clish_pargv_parse(clish_pargv_t * this,
 }
 
 /*--------------------------------------------------------- */
-static clish_pargv_status_t clish_pargv_init(clish_pargv_t * this,
-	const clish_command_t * cmd, const char *viewid,
-	const lub_argv_t * argv)
-{
-	unsigned idx = lub_argv_wordcount(clish_command__get_name(cmd));
-
-	this->pargc = 0;
-
-	return clish_pargv_parse(this, cmd, viewid,
-		clish_command__get_paramv(cmd),
-		argv, &idx, NULL, 0);
-}
-
-/*--------------------------------------------------------- */
-clish_pargv_t *clish_pargv_create(void)
+clish_pargv_t *clish_pargv_new(void)
 {
 	clish_pargv_t *this;
 
@@ -348,36 +334,25 @@ clish_pargv_t *clish_pargv_create(void)
 }
 
 /*--------------------------------------------------------- */
-clish_pargv_t *clish_pargv_new(const clish_command_t * cmd,
-	const char *viewid,
+clish_pargv_status_t clish_pargv_analyze(clish_pargv_t *this,
+	const clish_command_t *cmd,
+	void *context,
 	const char *line,
-	size_t offset,
-	clish_pargv_status_t * status)
+	size_t offset)
 {
-	clish_pargv_t *this = NULL;
 	lub_argv_t *argv = NULL;
+	unsigned int idx;
+	clish_pargv_status_t status;
 
-	if (!cmd || !line)
-		return NULL;
-
-	this = clish_pargv_create();
-	if (!this)
-		return NULL;
-
+	assert(cmd);
+	idx = lub_argv_wordcount(clish_command__get_name(cmd));
 	argv = lub_argv_new(line, offset);
-	*status = clish_pargv_init(this, cmd, viewid, argv);
+	status = clish_pargv_parse(this, cmd, context,
+		clish_command__get_paramv(cmd),
+		argv, &idx, NULL, 0);
 	lub_argv_delete(argv);
-	switch (*status) {
-	case CLISH_LINE_OK:
-		break;
-	default:
-		/* commit suicide */
-		clish_pargv_delete(this);
-		this = NULL;
-		break;
-	}
 
-	return this;
+	return status;
 }
 
 /*--------------------------------------------------------- */

+ 1 - 2
clish/shell.h

@@ -307,8 +307,7 @@ clish_ptype_t *clish_shell_find_create_ptype(clish_shell_t * instance,
 	clish_ptype_preprocess_e preprocess);
 int clish_shell_xml_read(clish_shell_t * instance, const char *filename);
 void clish_shell_help(clish_shell_t * instance, const char *line);
-bool_t clish_shell_execute(clish_shell_t * instance,
-	const clish_command_t * cmd, clish_pargv_t * pargv, char ** out);
+bool_t clish_shell_execute(clish_context_t *context, char **out);
 bool_t clish_shell_line(clish_shell_t * instance, const char *prompt,
 	const clish_command_t ** cmd, clish_pargv_t ** pargv, const char *str);
 bool_t clish_shell_forceline(clish_shell_t *instance, const char *line, char ** out);

+ 1 - 1
clish/shell/private.h

@@ -90,7 +90,7 @@ bool_t clish_shell_pop_file(clish_shell_t * instance);
 
 clish_view_t *clish_shell_find_view(clish_shell_t * instance, const char *name);
 void clish_shell_insert_view(clish_shell_t * instance, clish_view_t * view);
-clish_pargv_status_t clish_shell_parse(const clish_shell_t * instance,
+clish_pargv_status_t clish_shell_parse(clish_shell_t * instance,
 	const char *line, const clish_command_t ** cmd, clish_pargv_t ** pargv);
 char *clish_shell_word_generator(clish_shell_t * instance,
 	const char *line, unsigned offset, unsigned state);

+ 10 - 6
clish/shell/shell_command.c

@@ -82,11 +82,12 @@ void clish_shell_param_generator(clish_shell_t *this, lub_argv_t *matches,
 	unsigned idx = lub_argv_wordcount(name);
 	/* get the index of the current parameter */
 	unsigned index = lub_argv_wordcount(line) - idx;
+	clish_context_t context;
 
 	if ((0 != index) || (offset && line[offset - 1] == ' ')) {
 		lub_argv_t *argv = lub_argv_new(line, 0);
-		clish_pargv_t *pargv = clish_pargv_create();
-		clish_pargv_t *completion_pargv = clish_pargv_create();
+		clish_pargv_t *pargv = clish_pargv_new();
+		clish_pargv_t *completion = clish_pargv_new();
 		unsigned completion_index = 0;
 		const clish_param_t *param = NULL;
 
@@ -95,13 +96,16 @@ void clish_shell_param_generator(clish_shell_t *this, lub_argv_t *matches,
 			index--;
 
 		/* Parse command line to get completion pargv's */
-		clish_pargv_parse(pargv, cmd, this->viewid,
+		context.shell = this;
+		context.cmd = cmd;
+		context.pargv = pargv;
+		clish_pargv_parse(pargv, cmd, &context,
 			clish_command__get_paramv(cmd),
-			argv, &idx, completion_pargv, index + idx);
+			argv, &idx, completion, index + idx);
 		clish_pargv_delete(pargv);
 		lub_argv_delete(argv);
 
-		while ((param = clish_pargv__get_param(completion_pargv,
+		while ((param = clish_pargv__get_param(completion,
 			completion_index++))) {
 			char *result;
 			/* The param is args so it has no completion */
@@ -121,7 +125,7 @@ void clish_shell_param_generator(clish_shell_t *this, lub_argv_t *matches,
 			if ((ptype = clish_param__get_ptype(param)))
 				clish_ptype_word_generator(ptype, matches, text);
 		}
-		clish_pargv_delete(completion_pargv);
+		clish_pargv_delete(completion);
 	}
 
 	lub_string_free(text);

+ 9 - 10
clish/shell/shell_execute.c

@@ -57,8 +57,7 @@ static bool_t clish_close(const clish_shell_t * shell, const lub_argv_t * argv)
  thread. Whether the script continues after command, but not script, 
  errors depends on the value of the stop_on_error flag.
 */
-static bool_t
-clish_source_internal(const clish_shell_t * shell,
+static bool_t clish_source_internal(const clish_shell_t * shell,
 	const lub_argv_t * argv, bool_t stop_on_error)
 {
 	bool_t result = BOOL_FALSE;
@@ -177,10 +176,11 @@ void clish_shell_cleanup_script(void *script)
 }
 
 /*----------------------------------------------------------- */
-bool_t
-clish_shell_execute(clish_shell_t * this,
-	const clish_command_t * cmd, clish_pargv_t * pargv, char ** out)
+bool_t clish_shell_execute(clish_context_t *context, char **out)
 {
+	clish_shell_t *this = context->shell;
+	const clish_command_t *cmd = context->cmd;
+	clish_pargv_t *pargv = context->pargv;
 	bool_t result = BOOL_TRUE;
 	const char *builtin;
 	char *script;
@@ -265,7 +265,7 @@ clish_shell_execute(clish_shell_t * this,
 
 	/* Execute ACTION */
 	builtin = clish_command__get_builtin(cmd);
-	script = clish_command__get_action(cmd, this->viewid, pargv);
+	script = clish_command__expand_action(cmd, context);
 	/* account for thread cancellation whilst running a script */
 	pthread_cleanup_push((void (*)(void *))clish_shell_cleanup_script,
 		script);
@@ -290,7 +290,7 @@ clish_shell_execute(clish_shell_t * this,
 			lub_argv_delete(argv);
 	} else if (script) {
 		/* now get the client to interpret the resulting script */
-		result = this->client_hooks->script_fn(this, cmd, script, out);
+		result = this->client_hooks->script_fn(context, script, out);
 	}
 	pthread_cleanup_pop(1);
 
@@ -311,7 +311,7 @@ clish_shell_execute(clish_shell_t * this,
 
 	/* Call config callback */
 	if ((BOOL_TRUE == result) && this->client_hooks->config_fn)
-		this->client_hooks->config_fn(this, cmd, pargv);
+		this->client_hooks->config_fn(context);
 
 	/* Unlock the lockfile */
 	if (lock_fd != -1) {
@@ -322,8 +322,7 @@ clish_shell_execute(clish_shell_t * this,
 	/* Move into the new view */
 	if (BOOL_TRUE == result) {
 		clish_view_t *view = clish_command__get_view(cmd);
-		char *viewid = clish_command__get_viewid(cmd,
-			this->viewid, pargv);
+		char *viewid = clish_command__get_viewid(cmd, context);
 		if (view) {
 			/* Save the current config PWD */
 			char *line = clish_shell__get_line(cmd, pargv);

+ 65 - 3
clish/shell/shell_help.c

@@ -13,7 +13,7 @@
 /*
  * Provide a detailed list of the possible command completions
  */
-static void available_commands(clish_shell_t * this,
+static void available_commands(clish_shell_t *this,
 	clish_help_t *help, const char *line, size_t *max_width)
 {
 	const clish_command_t *cmd;
@@ -37,6 +37,69 @@ static void available_commands(clish_shell_t * this,
 	}
 }
 
+/*--------------------------------------------------------- */
+static int available_params(clish_shell_t *this,
+	clish_help_t *help, const clish_command_t *cmd,
+	const char *line, size_t *max_width)
+{
+	unsigned index = lub_argv_wordcount(line);
+	unsigned idx = lub_argv_wordcount(clish_command__get_name(cmd));
+	lub_argv_t *argv;
+	clish_pargv_t *completion, *pargv;
+	unsigned i;
+	unsigned cnt = 0;
+	clish_pargv_status_t status = CLISH_LINE_OK;
+	clish_context_t context;
+
+	/* Empty line */
+	if (0 == index)
+		return -1;
+
+	if (line[strlen(line) - 1] != ' ')
+		index--;
+
+	argv = lub_argv_new(line, 0);
+
+	/* get the parameter definition */
+	completion = clish_pargv_new();
+	pargv = clish_pargv_new();
+	context.shell = this;
+	context.cmd = cmd;
+	context.pargv = pargv;
+	status = clish_pargv_parse(pargv, cmd, &context,
+		clish_command__get_paramv(cmd),
+		argv, &idx, completion, index);
+	clish_pargv_delete(pargv);
+	cnt = clish_pargv__get_count(completion);
+
+	/* Calculate the longest name */
+	for (i = 0; i < cnt; i++) {
+		const clish_param_t *param;
+		const char *name;
+		unsigned clen = 0;
+
+		param = clish_pargv__get_param(completion, i);
+		if (CLISH_PARAM_SUBCOMMAND == clish_param__get_mode(param))
+			name = clish_param__get_value(param);
+		else
+			name = clish_ptype__get_text(clish_param__get_ptype(param));
+		if (name)
+			clen = strlen(name);
+		if (max_width && (clen > *max_width))
+			*max_width = clen;
+		clish_param_help(param, help);
+	}
+	clish_pargv_delete(completion);
+	lub_argv_delete(argv);
+
+	/* It's a completed command */
+	if (CLISH_LINE_OK == status)
+		return 0;
+
+	/* Incompleted command */
+	return -1;
+}
+
 /*--------------------------------------------------------- */
 void clish_shell_help(clish_shell_t *this, const char *line)
 {
@@ -58,8 +121,7 @@ void clish_shell_help(clish_shell_t *this, const char *line)
 	if (cmd) {
 		size_t width = 0;
 		int status;
-		status = clish_command_help(cmd, &help, this->viewid,
-			line, &width);
+		status = available_params(this, &help, cmd, line, &width);
 		if (width > max_width)
 			max_width = width;
 		/* Add <cr> if command is completed */

+ 3 - 3
clish/shell/shell_new.c

@@ -61,7 +61,7 @@ static void clish_shell_init(clish_shell_t * this,
 		CLISH_PTYPE_REGEXP, CLISH_PTYPE_NONE);
 	assert(tmp_ptype);
 	this->param_depth = clish_param_new("__cur_depth",
-		"Current depth", tmp_ptype);
+		"Current depth", tmp_ptype, clish_shell_expand);
 	clish_param__set_hidden(this->param_depth, BOOL_TRUE);
 	/* Current pwd */
 	tmp_ptype = clish_shell_find_create_ptype(this,
@@ -69,7 +69,7 @@ static void clish_shell_init(clish_shell_t * this,
 		CLISH_PTYPE_REGEXP, CLISH_PTYPE_NONE);
 	assert(tmp_ptype);
 	this->param_pwd = clish_param_new("__cur_pwd",
-		"Current path", tmp_ptype);
+		"Current path", tmp_ptype, clish_shell_expand);
 	clish_param__set_hidden(this->param_pwd, BOOL_TRUE);
 	/* Interactive */
 	tmp_ptype = clish_shell_find_create_ptype(this,
@@ -77,7 +77,7 @@ static void clish_shell_init(clish_shell_t * this,
 		CLISH_PTYPE_REGEXP, CLISH_PTYPE_NONE);
 	assert(tmp_ptype);
 	this->param_interactive = clish_param_new("__interactive",
-		"Interactive flag", tmp_ptype);
+		"Interactive flag", tmp_ptype, clish_shell_expand);
 	clish_param__set_hidden(this->param_interactive, BOOL_TRUE);
 
 	/* Push non-NULL istream */

+ 17 - 5
clish/shell/shell_parse.c

@@ -9,15 +9,27 @@
 
 /*----------------------------------------------------------- */
 clish_pargv_status_t clish_shell_parse(
-	const clish_shell_t * this, const char *line,
-	const clish_command_t ** cmd, clish_pargv_t ** pargv)
+	clish_shell_t *this, const char *line,
+	const clish_command_t **ret_cmd, clish_pargv_t **pargv)
 {
 	clish_pargv_status_t result = CLISH_BAD_CMD;
+	clish_context_t context;
+	const clish_command_t *cmd;
+
+	*ret_cmd = cmd = clish_shell_resolve_command(this, line);
+	if (!cmd)
+		return result;
 
-	*cmd = clish_shell_resolve_command(this, line);
 	/* Now construct the parameters for the command */
-	if (*cmd)
-		*pargv = clish_pargv_new(*cmd, this->viewid, line, 0, &result);
+	*pargv = clish_pargv_new();
+	context.shell = this;
+	context.cmd = cmd;
+	context.pargv = *pargv;
+	result = clish_pargv_analyze(*pargv, cmd, &context, line, 0);
+	if (CLISH_LINE_OK != result) {
+		clish_pargv_delete(*pargv);
+		*pargv = NULL;
+	}
 	if (*pargv) {
 		char str[100];
 		char * tmp;

+ 6 - 2
clish/shell/shell_startup.c

@@ -7,16 +7,20 @@
 #include "lub/string.h"
 
 /*----------------------------------------------------------- */
-bool_t clish_shell_startup(clish_shell_t * this)
+bool_t clish_shell_startup(clish_shell_t *this)
 {
 	const char *banner;
+	clish_context_t context;
 
 	assert(this->startup);
 	banner = clish_command__get_detail(this->startup);
 	if (banner)
 		tinyrl_printf(this->tinyrl, "%s\n", banner);
+	context.shell = this;
+	context.cmd = this->startup;
+	context.pargv = NULL;
 
-	return clish_shell_execute(this, this->startup, NULL, NULL);
+	return clish_shell_execute(&context, NULL);
 }
 
 /*----------------------------------------------------------- */

+ 14 - 14
clish/shell/shell_tinyrl.c

@@ -366,12 +366,12 @@ void clish_shell_tinyrl_delete(tinyrl_t * this)
 }
 
 /*-------------------------------------------------------- */
-bool_t clish_shell_execline(clish_shell_t *this, const char *line, char ** out)
+bool_t clish_shell_execline(clish_shell_t *this, const char *line, char **out)
 {
 	char *prompt = NULL;
 	const clish_view_t *view;
 	char *str;
-	clish_context_t con;
+	clish_context_t context;
 	tinyrl_history_t *history;
 	int lerror = 0;
 
@@ -383,21 +383,21 @@ bool_t clish_shell_execline(clish_shell_t *this, const char *line, char ** out)
 	}
 
 	/* Set up the context for tinyrl */
-	con.cmd = NULL;
-	con.pargv = NULL;
-	con.shell = this;
+	context.cmd = NULL;
+	context.pargv = NULL;
+	context.shell = this;
 
 	/* Obtain the prompt */
 	view = clish_shell__get_view(this);
 	assert(view);
-	prompt = clish_view__get_prompt(view, &con);
+	prompt = clish_view__get_prompt(view, &context);
 	assert(prompt);
 
 	/* Push the specified line or interactive line */
 	if (line)
-		str = tinyrl_forceline(this->tinyrl, prompt, &con, line);
+		str = tinyrl_forceline(this->tinyrl, prompt, &context, line);
 	else
-		str = tinyrl_readline(this->tinyrl, prompt, &con);
+		str = tinyrl_readline(this->tinyrl, prompt, &context);
 	lerror = errno;
 	lub_string_free(prompt);
 	if (!str) {
@@ -426,17 +426,17 @@ bool_t clish_shell_execline(clish_shell_t *this, const char *line, char ** out)
 	free(str);
 
 	/* Execute the provided command */
-	if (con.cmd && con.pargv) {
-		if (!clish_shell_execute(this, con.cmd, con.pargv, out)) {
+	if (context.cmd && context.pargv) {
+		if (!clish_shell_execute(&context, out)) {
 			this->state = SHELL_STATE_SCRIPT_ERROR;
-			if (con.pargv)
-				clish_pargv_delete(con.pargv);
+			if (context.pargv)
+				clish_pargv_delete(context.pargv);
 			return BOOL_FALSE;
 		}
 	}
 
-	if (con.pargv)
-		clish_pargv_delete(con.pargv);
+	if (context.pargv)
+		clish_pargv_delete(context.pargv);
 
 	return BOOL_TRUE;
 }

+ 5 - 3
clish/shell/shell_tinyxml.cpp

@@ -266,7 +266,8 @@ process_command(clish_shell_t * shell, TiXmlElement * element, void *parent)
 			CLISH_PTYPE_REGEXP,
 			CLISH_PTYPE_NONE);
 		assert(tmp);
-		param = clish_param_new(args_name, args_help, tmp);
+		param = clish_param_new(args_name, args_help, tmp,
+			clish_shell_expand);
 		clish_command__set_args(cmd, param);
 	}
 	// define the view which this command changes to
@@ -374,7 +375,7 @@ process_param(clish_shell_t * shell, TiXmlElement * element, void *parent)
 				CLISH_PTYPE_NONE);
 			assert(tmp);
 		}
-		param = clish_param_new(name, help, tmp);
+		param = clish_param_new(name, help, tmp, clish_shell_expand);
 
 		/* If prefix is set clish will emulate old optional
 		 * command syntax over newer optional command mechanism.
@@ -396,7 +397,8 @@ process_param(clish_shell_t * shell, TiXmlElement * element, void *parent)
 					ptype_name, "Option", "[^\\]+",
 					CLISH_PTYPE_REGEXP, CLISH_PTYPE_NONE);
 			assert(tmp);
-			opt_param = clish_param_new(prefix, help, tmp);
+			opt_param = clish_param_new(prefix, help, tmp,
+				clish_shell_expand);
 			clish_param__set_mode(opt_param,
 					      CLISH_PARAM_SUBCOMMAND);
 			clish_param__set_optional(opt_param, BOOL_TRUE);

+ 4 - 1
clish/shell/shell_var.c

@@ -265,13 +265,16 @@ char *clish_shell__get_line(const clish_command_t *cmd, clish_pargv_t *pargv)
 /*--------------------------------------------------------- */
 char *clish_shell_expand_var(const char *name, void *context)
 {
-	clish_shell_context_t *this = (clish_context_t *)context;
+	clish_context_t *this = (clish_context_t *)context;
 	char *result = NULL;
 	const char *tmp = NULL;
 	const char *escape_chars = NULL;
 	char *string = NULL;
 	assert(name);
 
+	if (!this)
+		return lub_string_dup(name);
+
 	/* try and substitute a parameter value */
 	if (this && this->pargv) {
 		const clish_parg_t *parg =

+ 1 - 0
clish/var.h

@@ -7,6 +7,7 @@
 typedef struct clish_var_s clish_var_t;
 
 typedef char *clish_var_expand_fn_t(const char *str, void *context);
+char *clish_var_expand_default(const char *str, void *context);
 
 /*=====================================
  * VAR INTERFACE

+ 7 - 0
clish/var/var.c

@@ -42,6 +42,13 @@ int clish_var_bt_compare(const void *clientnode, const void *clientkey)
 	return strcmp(this->name, key);
 }
 
+/*-------------------------------------------------------- */
+clish_var_expand_fn_t clish_var_expand_default;
+inline char *clish_var_expand_default(const char *str, void *context)
+{
+	return lub_string_dup(str);
+}
+
 /*-------------------------------------------------------- */
 void clish_var_bt_getkey(const void *clientnode, lub_bintree_key_t * key)
 {

+ 4 - 6
clish/view/view.c

@@ -47,7 +47,7 @@ static void clish_view_init(clish_view_t * this, const char *name, const char *p
 	this->nspacev = NULL;
 	this->depth = 0;
 	this->restore = CLISH_RESTORE_NONE;
-	this->var_expand_fn = fn;
+	this->var_expand_fn = fn ? fn : clish_var_expand_default;
 
 	/* Be a good binary tree citizen */
 	lub_bintree_node_init(&this->bt_node);
@@ -124,7 +124,8 @@ clish_command_t *clish_view_new_command(clish_view_t * this,
 	const char *name, const char *help)
 {
 	/* allocate the memory for a new parameter definition */
-	clish_command_t *cmd = clish_command_new(name, help);
+	clish_command_t *cmd = clish_command_new(name, help,
+		this->var_expand_fn);
 	assert(cmd);
 
 	/* if this is a command other than the startup command... */
@@ -189,8 +190,7 @@ clish_command_t *clish_view_resolve_command(clish_view_t * this,
 	clish_command_t *result = clish_view_resolve_prefix(this, line, inherit);
 
 	if (result) {
-		char *action = clish_command__get_action(result, NULL, NULL);
-		if (!action && (NULL == clish_command__get_builtin(result)) &&
+		if (!clish_command__get_action(result) && (NULL == clish_command__get_builtin(result)) &&
 			(CLISH_CONFIG_NONE == clish_command__get_cfg_op(result)) &&
 			(NULL == clish_command__get_view(result))) {
 			/* if this doesn't do anything we've
@@ -198,8 +198,6 @@ clish_command_t *clish_view_resolve_command(clish_view_t * this,
 			 */
 			result = NULL;
 		}
-		/* cleanup */
-		lub_string_free(action);
 	}
 	return result;
 }