1
0
Переглянути джерело

The spawn API refactoring.

git-svn-id: https://klish.googlecode.com/svn/trunk@238 0eaa4687-2ee9-07dd-09d9-bcdd2d2dd5fb
Serj Kalichev 14 роки тому
батько
коміт
7f452f368d

+ 16 - 6
bin/clish.cpp

@@ -20,29 +20,39 @@ clish_shell_hooks_t my_hooks =
 //---------------------------------------------------------
 int main(int argc, const char **argv)
 {
+	bool_t running;
 	int result = -1;
-	clish_context_t * context;
+	clish_shell_t * shell;
 
-	context = clish_context_new(&my_hooks, NULL, stdin, stdout);
-	if (!context) {
+	shell = clish_shell_new(&my_hooks, NULL, stdin, stdout);
+	if (!shell) {
 		fprintf(stderr, "Cannot run clish.\n");
 		return -1;
 	}
+	/* Load the XML files */
+	clish_shell_load_files(shell);
+	/* Execute startup */
+	running = clish_shell_startup(shell);
+	if (!running) {
+		fprintf(stderr, "Cannot startup clish.\n");
+		clish_shell_delete(shell);
+		return -1;
+	}
 
 	if(argc > 1) {
 		int i = 1;
 		while(argc--) {
 			/* run the commands in the file */
-			result = clish_context_spawn_from_file(context,
+			result = clish_shell_spawn_from_file(shell,
 				NULL, argv[i++]);
 		}
 	} else {
 		/* spawn the shell */
-		result = clish_context_spawn_and_wait(context, NULL);
+		result = clish_shell_spawn_and_wait(shell, NULL);
 	}
 
 	/* Cleanup */
-	clish_context_free(context);
+	clish_shell_delete(shell);
 
 	return result ? 0 : -1;
  }

+ 26 - 31
clish/shell.h

@@ -27,7 +27,10 @@
 #define CLISH_LOCK_PATH "/tmp/clish.lock"
 #define CLISH_LOCK_WAIT 20
 
-_BEGIN_C_DECL typedef struct clish_shell_s clish_shell_t;
+typedef struct clish_context_s clish_context_t;
+typedef struct clish_shell_s clish_shell_t;
+
+_BEGIN_C_DECL 
 
 /*=====================================
  * SHELL INTERFACE
@@ -235,6 +238,8 @@ typedef struct {
 /*-----------------
  * meta functions
  *----------------- */
+
+#if 0
 int clish_shell_spawn_and_wait(const clish_shell_hooks_t * hooks, void *cookie);
  /**
   * This operation causes a separate (POSIX) thread of execution to 
@@ -274,9 +279,10 @@ bool_t clish_shell_spawn(
          * a callback by invoking clish_shell__get_client_cookie()
          */
 				void *cookie);
+#endif
 
 clish_shell_t *clish_shell_new(const clish_shell_hooks_t * hooks,
-			       void *cookie, FILE * istream, FILE * ostream);
+	void *cookie, FILE * istream, FILE * ostream);
 /*-----------------
  * methods
  *----------------- */
@@ -286,24 +292,22 @@ clish_shell_t *clish_shell_new(const clish_shell_hooks_t * hooks,
 bool_t clish_shell_startup(clish_shell_t * instance);
 void clish_shell_delete(clish_shell_t * instance);
 clish_view_t *clish_shell_find_create_view(clish_shell_t * instance,
-					   const char *name,
-					   const char *prompt);
+	const char *name,
+	const char *prompt);
 clish_ptype_t *clish_shell_find_create_ptype(clish_shell_t * instance,
-					     const char *name,
-					     const char *text,
-					     const char *pattern,
-					     clish_ptype_method_e method,
-					     clish_ptype_preprocess_e
-					     preprocess);
+	const char *name,
+	const char *text,
+	const char *pattern,
+	clish_ptype_method_e method,
+	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);
-bool_t clish_shell_readline(clish_shell_t * instance, const char *prompt,
-	const clish_command_t ** cmd, clish_pargv_t ** pargv);
-bool_t clish_shell_forceline(clish_shell_t * instance, const char *prompt,
-	const clish_command_t ** cmd, clish_pargv_t ** pargv, const char * str);
+bool_t clish_shell_execute(clish_shell_t * instance,
+	const clish_command_t * cmd, clish_pargv_t * pargv);
+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);
+bool_t clish_shell_readline(clish_shell_t *instance);
 void clish_shell_set_context(clish_shell_t * instance, const char *viewname);
 void clish_shell_dump(clish_shell_t * instance);
 void clish_shell_close(clish_shell_t * instance);
@@ -333,23 +337,14 @@ FILE *clish_shell__get_ostream(const clish_shell_t * instance);
 void clish_shell__set_lockfile(clish_shell_t * instance, const char * path);
 char * clish_shell__get_lockfile(clish_shell_t * instance);
 
-/* Context */
-typedef struct clish_context_s clish_context_t;
-
-clish_context_t * clish_context_new(const clish_shell_hooks_t * hooks,
-	void *cookie, FILE * istream, FILE * ostream);
-void clish_context_free(clish_context_t *instance);
-bool_t clish_context_forceline(clish_context_t *instance, const char *line);
-bool_t clish_context_readline(clish_context_t *instance);
-
-int clish_context_spawn(clish_context_t * context,
+int clish_shell_spawn(clish_shell_t * instance,
 	const pthread_attr_t * attr);
-int clish_context_wait(clish_context_t * context);
-int clish_context_spawn_and_wait(clish_context_t * context,
+int clish_shell_wait(clish_shell_t * instance);
+int clish_shell_spawn_and_wait(clish_shell_t * instance,
 	const pthread_attr_t * attr);
-bool_t clish_context_spawn_from_file(clish_context_t * context,
+bool_t clish_shell_spawn_from_file(clish_shell_t * instance,
 	const pthread_attr_t * attr, const char *filename);
-
+void clish_shell_load_files(clish_shell_t * instance);
 
 _END_C_DECL
 #endif				/* _clish_shell_h */

+ 13 - 17
clish/shell/private.h

@@ -8,22 +8,10 @@
 #include "tinyrl/tinyrl.h"
 
 /*-------------------------------------
- * PRIVATE TYPES 
+ * PRIVATE TYPES
  *------------------------------------- */
 
 /*-------------------------------------------------------- */
-/* 
- * The context structure is used to simplify the cleanup of 
- * a CLI session when a thread is cancelled.
- */
-struct clish_context_s {
-	pthread_t pthread;
-	const clish_shell_hooks_t *hooks;
-	void *cookie;
-	clish_shell_t *shell;
-	clish_pargv_t *pargv;
-	char *prompt;
-};
 
 typedef enum {
 	SHELL_STATE_INITIALISING,
@@ -55,6 +43,16 @@ typedef struct {
 	char *viewid;
 } clish_shell_pwd_t;
 
+/* 
+ * The context structure
+ */
+struct clish_context_s {
+	clish_pargv_t *completion_pargv;
+	unsigned completion_index;
+	unsigned completion_pindex;
+	clish_shell_iterator_t iter; /* used for iterating commands */
+};
+
 struct clish_shell_s {
 	lub_bintree_t view_tree;	/* Maintain a tree of views      */
 	lub_bintree_t ptype_tree;	/* Maintain a tree of ptypes     */
@@ -63,7 +61,6 @@ struct clish_shell_s {
 	clish_view_t *global;	/* Reference to the global view. */
 	clish_view_t *view;	/* Reference to the current view. */
 	clish_command_t *startup;	/* This is the startup command   */
-	clish_shell_iterator_t iter;	/* used for iterating commands */
 	shell_state_t state;	/* The current state               */
 	char *overview;		/* Overview text for this shell.  */
 	char *viewid;		/* The current view ID string     */
@@ -72,12 +69,11 @@ struct clish_shell_s {
 	clish_shell_pwd_t **cfg_pwdv;	/* Levels for the config file structure */
 	unsigned cfg_pwdc;
 	konf_client_t *client;
-	clish_pargv_t *completion_pargv;
-	unsigned completion_index;
-	unsigned completion_pindex;
 	clish_param_t *param_depth;
 	clish_param_t *param_pwd;
 	char * lockfile;
+	pthread_t pthread;
+	clish_context_t context;
 };
 
 /**

+ 14 - 14
clish/shell/shell_command_generator.c

@@ -74,22 +74,22 @@ static char *clish_shell_param_generator(clish_shell_t * this,
 			}
 			argv = lub_argv_new(line, 0);
 			idx = lub_argv_wordcount(name);
-			if (this->completion_pargv) {
-				clish_pargv_delete(this->completion_pargv);
-				this->completion_pargv = NULL;
+			if (this->context.completion_pargv) {
+				clish_pargv_delete(this->context.completion_pargv);
+				this->context.completion_pargv = NULL;
 			}
-			this->completion_pargv = clish_pargv_create();
+			this->context.completion_pargv = clish_pargv_create();
 			pargv = clish_pargv_create();
 			clish_pargv_parse(pargv, cmd, clish_command__get_paramv(cmd),
-				argv, &idx, this->completion_pargv, index + idx);
+				argv, &idx, this->context.completion_pargv, index + idx);
 			clish_pargv_delete(pargv);
 			lub_argv_delete(argv);
-			this->completion_index = 0;
-			this->completion_pindex = 0;
+			this->context.completion_index = 0;
+			this->context.completion_pindex = 0;
 		}
 
-		while ((param = clish_pargv__get_param(this->completion_pargv,
-			this->completion_index++))) {
+		while ((param = clish_pargv__get_param(this->context.completion_pargv,
+			this->context.completion_index++))) {
 
 			if (param == clish_command__get_args(cmd)) {
 				/* The param is args so it has no format */
@@ -106,11 +106,11 @@ static char *clish_shell_param_generator(clish_shell_t * this,
 				/* The common param. Let ptype do the work */
 				if (ptype = clish_param__get_ptype(param)) {
 					result = clish_ptype_word_generator(ptype, text, 
-						this->completion_pindex++);
+						this->context.completion_pindex++);
 					if (!result)
-						this->completion_pindex = 0;
+						this->context.completion_pindex = 0;
 					else
-						this->completion_index--;
+						this->context.completion_index--;
 				} else {
 					result = NULL;
 				}
@@ -126,8 +126,8 @@ static char *clish_shell_param_generator(clish_shell_t * this,
 	}
 
 	if (!result) {
-		clish_pargv_delete(this->completion_pargv);
-		this->completion_pargv = NULL;
+		clish_pargv_delete(this->context.completion_pargv);
+		this->context.completion_pargv = NULL;
 		/* make sure we reset the line state */
 //		tinyrl_crlf(this->tinyrl);
 //		tinyrl_reset_line_state(this->tinyrl);

+ 6 - 4
clish/shell/shell_delete.c

@@ -55,16 +55,18 @@ static void clish_shell_fini(clish_shell_t * this)
 	this->cfg_pwdc = 0;
 	this->cfg_pwdv = NULL;
 	konf_client_free(this->client);
-	if (this->completion_pargv) {
-		clish_pargv_delete(this->completion_pargv);
-		this->completion_pargv = NULL;
-	}
 
 	/* Free internal params */
 	clish_param_delete(this->param_depth);
 	clish_param_delete(this->param_pwd);
 
 	lub_string_free(this->lockfile);
+
+	/* Clear the context */
+	if (this->context.completion_pargv) {
+		clish_pargv_delete(this->context.completion_pargv);
+		this->context.completion_pargv = NULL;
+	}
 }
 
 /*--------------------------------------------------------- */

+ 7 - 12
clish/shell/shell_execute.c

@@ -193,7 +193,7 @@ 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)
+	const clish_command_t * cmd, clish_pargv_t * pargv)
 {
 	bool_t result = BOOL_TRUE;
 	const char *builtin;
@@ -262,7 +262,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__get_action(cmd, this->viewid, pargv);
 	/* account for thread cancellation whilst running a script */
 	pthread_cleanup_push((void (*)(void *))clish_shell_cleanup_script,
 		script);
@@ -297,7 +297,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(this, cmd, pargv);
 
 	/* Unlock the lockfile */
 	if (lock_fd != -1) {
@@ -309,10 +309,10 @@ clish_shell_execute(clish_shell_t * this,
 	if (BOOL_TRUE == result) {
 		clish_view_t *view = clish_command__get_view(cmd);
 		char *viewid = clish_command__get_viewid(cmd,
-			this->viewid, *pargv);
+			this->viewid, pargv);
 		if (NULL != view) {
 			/* Save the current config PWD */
-			char *line = clish_variable__get_line(cmd, *pargv);
+			char *line = clish_variable__get_line(cmd, pargv);
 			clish_shell__set_pwd(this,
 				clish_command__get_depth(cmd),
 				line, this->view, this->viewid);
@@ -327,18 +327,13 @@ clish_shell_execute(clish_shell_t * this,
 		}
 	}
 
-	if (NULL != *pargv) {
-		clish_pargv_delete(*pargv);
-		*pargv = NULL;
-	}
-
 	return result;
 }
 
 /*----------------------------------------------------------- */
 /*
- Find out the previous view in the stack and go to it
-*/
+ * Find out the previous view in the stack and go to it
+ */
 static bool_t clish_nested_up(const clish_shell_t * shell, const lub_argv_t * argv)
 {
 	clish_shell_t *this = (clish_shell_t *) shell;

+ 1 - 1
clish/shell/shell_getfirst_command.c

@@ -9,7 +9,7 @@ const clish_command_t *clish_shell_getfirst_command(clish_shell_t * this,
 						    clish_nspace_visibility_t
 						    field)
 {
-	clish_shell_iterator_init(&this->iter, field);
+	clish_shell_iterator_init(&this->context.iter, field);
 
 	/* find the first command for which this is a prefix */
 	return clish_shell_getnext_command(this, line);

+ 1 - 1
clish/shell/shell_getnext_command.c

@@ -7,7 +7,7 @@
 const clish_command_t *clish_shell_getnext_command(clish_shell_t * this,
 						   const char *line)
 {
-	return clish_shell_find_next_completion(this, line, &this->iter);
+	return clish_shell_find_next_completion(this, line, &this->context.iter);
 }
 
 /*--------------------------------------------------------- */

+ 4 - 2
clish/shell/shell_new.c

@@ -37,13 +37,11 @@ clish_shell_init(clish_shell_t * this,
 	this->startup = NULL;
 	this->state = SHELL_STATE_INITIALISING;
 	this->overview = NULL;
-	clish_shell_iterator_init(&this->iter, CLISH_NSPACE_NONE);
 	this->tinyrl = clish_shell_tinyrl_new(istream, ostream, 0);
 	this->current_file = NULL;
 	this->cfg_pwdv = NULL;
 	this->cfg_pwdc = 0;
 	this->client = konf_client_new(KONFD_SOCKET_PATH);
-	this->completion_pargv = NULL;
 	this->lockfile = lub_string_dup(CLISH_LOCK_PATH);
 
 	/* Create internal ptypes and params */
@@ -63,6 +61,10 @@ clish_shell_init(clish_shell_t * this,
 	this->param_pwd = clish_param_new("__cur_pwd",
 		"Current path", tmp_ptype);
 	clish_param__set_hidden(this->param_pwd, BOOL_TRUE);
+
+	/* Initialize context */
+	this->context.completion_pargv = NULL;
+	clish_shell_iterator_init(&this->context.iter, CLISH_NSPACE_NONE);
 }
 
 /*-------------------------------------------------------- */

+ 18 - 120
clish/shell/shell_spawn.c

@@ -114,7 +114,7 @@ void clish_shell_load_files(clish_shell_t * this)
 /*
  * This is invoked when the thread ends or is cancelled.
  */
-static void clish_shell_cleanup(clish_context_t * context)
+static void clish_shell_thread_cleanup(clish_shell_t * this)
 {
 #ifdef __vxworks
 	int last_state;
@@ -135,15 +135,14 @@ static void clish_shell_cleanup(clish_context_t * context)
  */
 static void *clish_shell_thread(void *arg)
 {
-	clish_context_t *context = arg;
 	bool_t running = BOOL_TRUE;
-	clish_shell_t *this = context->shell;
+	clish_shell_t *this = arg;
 	int last_type;
 
 	/* make sure we can only be cancelled at controlled points */
 	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_type);
 	/* register a cancellation handler */
-	pthread_cleanup_push((void (*)(void *))clish_shell_cleanup, context);
+	pthread_cleanup_push((void (*)(void *))clish_shell_thread_cleanup, this);
 
 	/*
 	 * Check the shell isn't closing down
@@ -168,7 +167,7 @@ static void *clish_shell_thread(void *arg)
 			/* only bother to read the next line if there hasn't been a script error */
 			if (this->state != SHELL_STATE_SCRIPT_ERROR) {
 				/* get input from the user */
-				running = clish_context_readline(context);
+				running = clish_shell_readline(this);
 				/*
 				 * what we do now depends on whether we are set up to
 				 * stop on error on not.
@@ -198,54 +197,53 @@ static void *clish_shell_thread(void *arg)
 }
 
 /*-------------------------------------------------------- */
-int clish_context_spawn(clish_context_t * context,
+int clish_shell_spawn(clish_shell_t * this,
 	const pthread_attr_t * attr)
 {
-	if (!context)
+	if (!this)
 		return -1;
 
-	return pthread_create(&context->pthread,
-		attr, clish_shell_thread, context);
+	return pthread_create(&this->pthread,
+		attr, clish_shell_thread, this);
 }
 
 /*-------------------------------------------------------- */
-int clish_context_wait(clish_context_t * context)
+int clish_shell_wait(clish_shell_t * this)
 {
 	void *result = NULL;
 
-	if (!context)
+	if (!this)
 		return BOOL_FALSE;
-	(void)pthread_join(context->pthread, &result);
+	(void)pthread_join(this->pthread, &result);
 
 	return result ? BOOL_TRUE : BOOL_FALSE;
 }
 
 /*-------------------------------------------------------- */
-int clish_context_spawn_and_wait(clish_context_t * context,
+int clish_shell_spawn_and_wait(clish_shell_t * this,
 	const pthread_attr_t * attr)
 {
-	if (clish_context_spawn(context, attr) < 0)
+	if (clish_shell_spawn(this, attr) < 0)
 		return -1;
-	return clish_context_wait(context);
+	return clish_shell_wait(this);
 }
 
 /*-------------------------------------------------------- */
-bool_t clish_context_spawn_from_file(clish_context_t * context,
+bool_t clish_shell_spawn_from_file(clish_shell_t * this,
 	const pthread_attr_t * attr, const char *filename)
 {
 	bool_t result = BOOL_FALSE;
 	FILE *file;
-	clish_shell_t *this;
 
-	if (!context || !filename)
+	if (!this || !filename)
 		return result;
-	this = context->shell;
+
 	file = fopen(filename, "r");
 	if (NULL == file)
 		return result;
 	tinyrl__set_istream(this->tinyrl, file);
 	/* spawn the thread and wait for it to exit */
-	result = clish_context_spawn_and_wait(context, attr) ?
+	result = clish_shell_spawn_and_wait(this, attr) ?
 		BOOL_TRUE : BOOL_FALSE;
 	fclose(file);
 
@@ -253,103 +251,3 @@ bool_t clish_context_spawn_from_file(clish_context_t * context,
 }
 
 /*-------------------------------------------------------- */
-clish_context_t * clish_context_new(const clish_shell_hooks_t * hooks,
-	void *cookie, FILE * istream, FILE * ostream)
-{
-	bool_t running;
-	clish_context_t *this = malloc(sizeof(clish_context_t));
-	if (!this)
-		return NULL;
-
-	this->hooks = hooks;
-	this->cookie = cookie;
-	this->shell = NULL;
-	this->prompt = NULL;
-	this->pargv = NULL;
-
-	/* Create a shell */
-	this->shell = clish_shell_new(this->hooks, this->cookie,
-		istream, ostream);
-	/* Load the XML files */
-	clish_shell_load_files(this->shell);
-	/* Execute startup */
-	running = clish_shell_startup(this->shell);
-	if (!running) {
-		clish_context_free(this);
-		return NULL;
-	}
-
-	return this;
-}
-
-/*-------------------------------------------------------- */
-void clish_context_free(clish_context_t *this)
-{
-	if (this->shell) {
-		/* Clean shell */
-		clish_shell_delete(this->shell);
-		this->shell = NULL;
-	}
-	if (this->pargv) {
-		clish_pargv_delete(this->pargv);
-		this->pargv = NULL;
-	}
-	if (this->prompt) {
-		lub_string_free(this->prompt);
-		this->prompt = NULL;
-	}
-
-	free(this);
-}
-
-/*-------------------------------------------------------- */
-static bool_t _clish_context_line(clish_context_t *context, const char *line)
-{
-	const clish_command_t *cmd;
-	const clish_view_t *view;
-	bool_t running = BOOL_TRUE;
-	clish_shell_t *this;
-
-	if (!context)
-		return BOOL_FALSE;
-	this = context->shell;
-
-	/* obtain the prompt */
-	view = clish_shell__get_view(this);
-	assert(view);
-
-	context->prompt = clish_view__get_prompt(view,
-		clish_shell__get_viewid(this));
-	assert(context->prompt);
-
-	if (line) {
-		/* push the specified line */
-		running = clish_shell_forceline(this, context->prompt,
-			&cmd, &context->pargv, line);
-	} else {
-		running = clish_shell_readline(this, context->prompt,
-			&cmd, &context->pargv);
-	}
-	lub_string_free(context->prompt);
-	context->prompt = NULL;
-
-	if (running && cmd && context->pargv)
-	/* execute the provided command */
-		return clish_shell_execute(this, cmd, &context->pargv);
-
-	return running;
-}
-
-/*-------------------------------------------------------- */
-bool_t clish_context_forceline(clish_context_t *context, const char *line)
-{
-	return _clish_context_line(context, line);
-}
-
-/*-------------------------------------------------------- */
-bool_t clish_context_readline(clish_context_t *context)
-{
-	return _clish_context_line(context, NULL);
-}
-
-/*-------------------------------------------------------- */

+ 1 - 2
clish/shell/shell_startup.c

@@ -8,7 +8,6 @@
 bool_t clish_shell_startup(clish_shell_t * this)
 {
 	const char *banner;
-	clish_pargv_t *dummy = NULL;
 
 	assert(this->startup);
 
@@ -17,7 +16,7 @@ bool_t clish_shell_startup(clish_shell_t * this)
 	if (NULL != banner) {
 		tinyrl_printf(this->tinyrl, "%s\n", banner);
 	}
-	return clish_shell_execute(this, this->startup, &dummy);
+	return clish_shell_execute(this, this->startup, NULL);
 }
 
 /*----------------------------------------------------------- */

+ 45 - 7
clish/shell/shell_tinyrl.c

@@ -357,7 +357,7 @@ void clish_shell_tinyrl_delete(tinyrl_t * this)
 }
 
 /*-------------------------------------------------------- */
-static bool_t shell_readline(clish_shell_t * this, const char *prompt,
+bool_t clish_shell_line(clish_shell_t * this, const char *prompt,
 	const clish_command_t ** cmd, clish_pargv_t ** pargv, const char *str)
 {
 	char *line = NULL;
@@ -398,17 +398,55 @@ static bool_t shell_readline(clish_shell_t * this, const char *prompt,
 }
 
 /*-------------------------------------------------------- */
-bool_t clish_shell_readline(clish_shell_t * this, const char *prompt,
-	const clish_command_t ** cmd, clish_pargv_t ** pargv)
+bool_t clish_shell_execline(clish_shell_t *this, const char *line)
 {
-	return shell_readline(this, prompt, cmd, pargv, NULL);
+	const clish_command_t *cmd;
+	char *prompt = NULL;
+	clish_pargv_t *pargv = NULL;
+	const clish_view_t *view;
+	bool_t running = BOOL_TRUE;
+
+	if (!this)
+		return BOOL_FALSE;
+
+	/* obtain the prompt */
+	view = clish_shell__get_view(this);
+	assert(view);
+
+	prompt = clish_view__get_prompt(view,
+		clish_shell__get_viewid(this));
+	assert(prompt);
+
+	if (line) {
+		/* push the specified line */
+		running = clish_shell_line(this, prompt,
+			&cmd, &pargv, line);
+	} else {
+		running = clish_shell_line(this, prompt,
+			&cmd, &pargv, NULL);
+	}
+	lub_string_free(prompt);
+
+	/* execute the provided command */
+	if (running && cmd && pargv)
+		running = clish_shell_execute(this, cmd, pargv);
+
+	if (NULL != pargv)
+		clish_pargv_delete(pargv);
+
+	return running;
 }
 
 /*-------------------------------------------------------- */
-bool_t clish_shell_forceline(clish_shell_t * this, const char *prompt,
-	const clish_command_t ** cmd, clish_pargv_t ** pargv, const char *str)
+bool_t clish_shell_forceline(clish_shell_t *this, const char *line)
+{
+	return clish_shell_execline(this, line);
+}
+
+/*-------------------------------------------------------- */
+bool_t clish_shell_readline(clish_shell_t *this)
 {
-	return shell_readline(this, prompt, cmd, pargv, str);
+	return clish_shell_execline(this, NULL);
 }
 
 /*-------------------------------------------------------- */