Browse Source

Working on syntax error processing.

git-svn-id: https://klish.googlecode.com/svn/trunk@380 0eaa4687-2ee9-07dd-09d9-bcdd2d2dd5fb
Serj Kalichev 13 years ago
parent
commit
de11d61946
5 changed files with 145 additions and 179 deletions
  1. 4 3
      clish/shell.h
  2. 11 13
      clish/shell/shell_help.c
  3. 18 13
      clish/shell/shell_spawn.c
  4. 44 68
      clish/shell/shell_tinyrl.c
  5. 68 82
      tinyrl/tinyrl.c

+ 4 - 3
clish/shell.h

@@ -34,9 +34,10 @@ typedef enum {
 	SHELL_STATE_INITIALISING,
 	SHELL_STATE_READY,
 	SHELL_STATE_HELPING,
-	SHELL_STATE_SCRIPT_ERROR,
-	SHELL_STATE_EOF,
-	SHELL_STATE_SYNTAX_ERROR,
+	SHELL_STATE_SCRIPT_ERROR,/* Script execution error */
+	SHELL_STATE_EOF, /* EOF of input stream */
+	SHELL_STATE_SYNTAX_ERROR, /* Illegal line entered */
+	SHELL_STATE_SYSTEM_ERROR, /* Some internal system error */
 	SHELL_STATE_CLOSING
 } clish_shell_state_t;
 

+ 11 - 13
clish/shell/shell_help.c

@@ -100,24 +100,22 @@ void clish_shell_help(clish_shell_t * this, const char *line)
 		/* we've resolved a particular command */
 		switch (this->state) {
 		case SHELL_STATE_HELPING:
-			{
-				const char *detail =
-				    clish_command__get_detail(cmd);
-				if (NULL != detail) {
-					fprintf(stderr, "%s\n", detail);
-				} else {
-					/* get the command to describe itself */
-					clish_command_help(cmd, this->viewid, line);
-				}
-				break;
-			}
+		{
+			const char *detail =
+				clish_command__get_detail(cmd);
+			if (NULL != detail)
+				fprintf(stderr, "%s\n", detail);
+			else
+				clish_command_help(cmd, this->viewid, line);
+			break;
+		}
 		case SHELL_STATE_READY:
 		case SHELL_STATE_SCRIPT_ERROR:
+		case SHELL_STATE_SYNTAX_ERROR:
 			/* get the command to provide help */
 			clish_command_help(cmd, this->viewid, line);
 			break;
-		case SHELL_STATE_INITIALISING:
-		case SHELL_STATE_CLOSING:
+		default:
 			/* do nothing */
 			break;
 		}

+ 18 - 13
clish/shell/shell_spawn.c

@@ -125,22 +125,27 @@ static bool_t _loop(clish_shell_t * this, bool_t is_thread)
 
 	if (is_thread)
 		pthread_testcancel();
-	/* Loop reading and executing lines until the user quits. */
+	/* Loop reading and executing lines until the user quits */
 	while (running) {
 		/* Get input from the stream */
+		this->state = SHELL_STATE_READY;
 		running = clish_shell_readline(this, NULL);
-		if ((SHELL_STATE_SCRIPT_ERROR == this->state) &&
-			(BOOL_TRUE == tinyrl__get_isatty(this->tinyrl))) {
-			/* interactive session doesn't automatically exit on error */
-			this->state = SHELL_STATE_READY;
-		}
-		if ((BOOL_FALSE == running) ||
-			(this->state == SHELL_STATE_SCRIPT_ERROR)) {
-			/* we've reached the end of a file (or a script error has occured)
-			 * unwind the file stack to see whether 
-			 * we need to exit
-			 */
-			running = clish_shell_pop_file(this);
+		if (!running) {
+			switch (this->state) {
+			case SHELL_STATE_SCRIPT_ERROR:
+			case SHELL_STATE_SYNTAX_ERROR:
+				/* Interactive session doesn't exit on error */
+				if (tinyrl__get_isatty(this->tinyrl) ||
+					!this->current_file->stop_on_error)
+					running = BOOL_TRUE;
+				break;
+			case SHELL_STATE_EOF:
+				/* We've reached the end of a file */
+				running = clish_shell_pop_file(this);
+				break;
+			default:
+				break;
+			}
 		}
 		/* test for cancellation */
 		if (is_thread)

+ 44 - 68
clish/shell/shell_tinyrl.c

@@ -10,6 +10,7 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <string.h>
+#include <errno.h>
 
 #include "tinyrl/tinyrl.h"
 #include "tinyrl/history.h"
@@ -20,7 +21,7 @@
 typedef struct _context context_t;
 struct _context {
 	clish_shell_t *shell;
-	const clish_command_t *command;
+	const clish_command_t *cmd;
 	clish_pargv_t *pargv;
 };
 /*-------------------------------------------------------- */
@@ -269,7 +270,7 @@ static bool_t clish_shell_tinyrl_key_enter(tinyrl_t * this, int key)
 			/* we've got a command so check the syntax */
 			arg_status = clish_shell_parse(context->shell,
 						       line,
-						       &context->command,
+						       &context->cmd,
 						       &context->pargv);
 			switch (arg_status) {
 			case CLISH_LINE_OK:
@@ -311,8 +312,7 @@ static bool_t clish_shell_tinyrl_key_enter(tinyrl_t * this, int key)
 /* This is the completion function provided for CLISH */
 static tinyrl_completion_func_t clish_shell_tinyrl_completion;
 static char **clish_shell_tinyrl_completion(tinyrl_t * this,
-					    const char *line,
-					    unsigned start, unsigned end)
+	const char *line, unsigned start, unsigned end)
 {
 	char **matches;
 
@@ -321,9 +321,7 @@ static char **clish_shell_tinyrl_completion(tinyrl_t * this,
 
 	/* perform the matching */
 	matches = tinyrl_completion(this,
-				    line,
-				    start,
-				    end, clish_shell_tinyrl_word_generator);
+		line, start, end, clish_shell_tinyrl_word_generator);
 	return matches;
 }
 
@@ -347,17 +345,15 @@ static void clish_shell_tinyrl_init(tinyrl_t * this)
 }
 
 /*-------------------------------------------------------- */
-/* 
+/*
  * Create an instance of the specialised class
  */
 tinyrl_t *clish_shell_tinyrl_new(FILE * istream,
-				 FILE * ostream, unsigned stifle)
+	FILE * ostream, unsigned stifle)
 {
 	/* call the parent constructor */
 	tinyrl_t *this = tinyrl_new(istream,
-				    ostream,
-				    stifle,
-				    clish_shell_tinyrl_completion);
+		ostream, stifle, clish_shell_tinyrl_completion);
 	if (NULL != this) {
 		/* now call our own constructor */
 		clish_shell_tinyrl_init(this);
@@ -382,58 +378,26 @@ void clish_shell_tinyrl_delete(tinyrl_t * this)
 	tinyrl_delete(this);
 }
 
-/*-------------------------------------------------------- */
-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;
-	bool_t result = BOOL_FALSE;
-	context_t context;
-	tinyrl_history_t *history;
-
-	/* Set up the context for tinyrl */
-	context.command = NULL;
-	context.pargv = NULL;
-	context.shell = this;
-
-	if (str)
-		line = tinyrl_forceline(this->tinyrl, prompt, &context, str);
-	else
-		line = tinyrl_readline(this->tinyrl, prompt, &context);
-	if (!line)
-		return result;
-
-	/* Deal with the history list */
-	if (tinyrl__get_isatty(this->tinyrl)) {
-		history = tinyrl__get_history(this->tinyrl);
-		tinyrl_history_add(history, line);
-	}
-	/* Let the client know the command line has been entered */
-	if (this->client_hooks->cmd_line_fn)
-		this->client_hooks->cmd_line_fn(this, line);
-	free(line);
-	result = BOOL_TRUE;
-	*cmd = context.command;
-	*pargv = context.pargv;
-
-	return result;
-}
-
 /*-------------------------------------------------------- */
 bool_t clish_shell_execline(clish_shell_t *this, const char *line, char ** out)
 {
-	const clish_command_t *cmd;
 	char *prompt = NULL;
-	clish_pargv_t *pargv = NULL;
 	const clish_view_t *view;
-	bool_t running = BOOL_TRUE;
 	char *str;
-	context_t context;
+	context_t con;
 	tinyrl_history_t *history;
+	int lerror = 0;
 
 	assert(this);
-	if (!line && !tinyrl__get_istream(this->tinyrl))
+	if (!line && !tinyrl__get_istream(this->tinyrl)) {
+		this->state = SHELL_STATE_SYSTEM_ERROR;
 		return BOOL_FALSE;
+	}
+
+	/* Set up the context for tinyrl */
+	con.cmd = NULL;
+	con.pargv = NULL;
+	con.shell = this;
 
 	/* Obtain the prompt */
 	view = clish_shell__get_view(this);
@@ -443,18 +407,26 @@ bool_t clish_shell_execline(clish_shell_t *this, const char *line, char ** out)
 	assert(prompt);
 
 	/* Push the specified line or interactive line */
-	/* Set up the context for tinyrl */
-	context.command = NULL;
-	context.pargv = NULL;
-	context.shell = this;
-
 	if (line)
-		str = tinyrl_forceline(this->tinyrl, prompt, &context, line);
+		str = tinyrl_forceline(this->tinyrl, prompt, &con, line);
 	else
-		str = tinyrl_readline(this->tinyrl, prompt, &context);
+		str = tinyrl_readline(this->tinyrl, prompt, &con);
+	lerror = errno;
 	lub_string_free(prompt);
-	if (!str)
-		return result;
+	if (!str) {
+		switch (lerror) {
+		case ENODATA:
+			this->state = SHELL_STATE_EOF;
+			break;
+		case EBADMSG:
+			this->state = SHELL_STATE_SYNTAX_ERROR;
+			break;
+		default:
+			this->state = SHELL_STATE_SYSTEM_ERROR;
+			break;
+		};
+		return BOOL_FALSE;
+	}
 
 	/* Deal with the history list */
 	if (tinyrl__get_isatty(this->tinyrl)) {
@@ -467,15 +439,19 @@ bool_t clish_shell_execline(clish_shell_t *this, const char *line, char ** out)
 	free(str);
 
 	/* Execute the provided command */
-	if (running && context.command && context.pargv) {
-		if (BOOL_FALSE == clish_shell_execute(this, context.command, context.pargv, out))
+	if (con.cmd && con.pargv) {
+		if (!clish_shell_execute(this, con.cmd, con.pargv, out)) {
 			this->state = SHELL_STATE_SCRIPT_ERROR;
+			if (con.pargv)
+				clish_pargv_delete(con.pargv);
+			return BOOL_FALSE;
+		}
 	}
 
-	if (NULL != pargv)
-		clish_pargv_delete(pargv);
+	if (con.pargv)
+		clish_pargv_delete(con.pargv);
 
-	return running;
+	return BOOL_TRUE;
 }
 
 /*-------------------------------------------------------- */

+ 68 - 82
tinyrl/tinyrl.c

@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <errno.h>
 
 /* POSIX HEADERS */
 #include <unistd.h>
@@ -671,17 +672,14 @@ static char *internal_insertline(tinyrl_t * this, char *buffer)
 
 	/* strip any spurious '\r' or '\n' */
 	p = strchr(buffer, '\r');
-	if (NULL == p) {
+	if (NULL == p)
 		p = strchr(buffer, '\n');
-	}
-	if (NULL != p) {
+	if (NULL != p)
 		*p = '\0';
-	}
 	/* skip any whitespace at the beginning of the line */
 	if (0 == this->point) {
-		while (*s && isspace(*s)) {
+		while (*s && isspace(*s))
 			s++;
-		}
 	}
 	if (*s) {
 		/* append this string to the input buffer */
@@ -695,11 +693,12 @@ static char *internal_insertline(tinyrl_t * this, char *buffer)
 
 /*----------------------------------------------------------------------- */
 static char *internal_readline(tinyrl_t * this,
-			       const char *prompt,
-			       void *context, const char *str)
+	const char *prompt, void *context, const char *str)
 {
 	FILE *istream = tinyrl_vt100__get_istream(this->term);
 	int crlf = 1;		/* Enable crlf if result is NULL */
+	char *result = NULL;
+	int lerrno = 0;
 
 	/* initialise for reading a line */
 	this->done = BOOL_FALSE;
@@ -715,51 +714,42 @@ static char *internal_readline(tinyrl_t * this,
 	if ((BOOL_TRUE == this->isatty) && (!str)) {
 		/* set the terminal into raw input mode */
 		tty_set_raw_mode(this);
-
 		tinyrl_reset_line_state(this);
 
 		while (!this->done) {
 			int key;
 			/* update the display */
 			tinyrl_redisplay(this);
-
 			/* get a key */
 			key = tinyrl_getchar(this);
-
 			/* has the input stream terminated? */
 			if (EOF != key) {
 				/* call the handler for this key */
-				if (BOOL_FALSE ==
-				    this->handlers[key] (this, key)) {
-					/* an issue has occured */
+				if (!this->handlers[key](this, key))
 					tinyrl_ding(this);
-				}
-
-				if (BOOL_TRUE == this->done) {
+				if (this->done) {
 					/*
-					 * If the last character in the line (other than 
+					 * If the last character in the line (other than
 					 * the null) is a space remove it.
 					 */
-					if (this->end
-					    && isspace(this->
-						       line[this->end - 1])) {
+					if (this->end &&
+						isspace(this->line[this->end - 1]))
 						tinyrl_delete_text(this,
-								   this->end -
-								   1,
-								   this->end);
-					}
+							this->end - 1,
+							this->end);
 				}
 			} else {
 				/* time to finish the session */
 				this->done = BOOL_TRUE;
 				this->line = NULL;
+				lerrno = ENODATA;
 			}
 		}
 		/* restores the terminal mode */
 		tty_restore_mode(this);
 	} else {
 		/* This is a non-interactive set of commands */
-		char *s = 0, buffer[80];
+		char *s = NULL, buffer[80];
 		size_t len = sizeof(buffer);
 		char *tmp = NULL;
 
@@ -772,15 +762,15 @@ static char *internal_readline(tinyrl_t * this,
 			s = internal_insertline(this, tmp);
 		} else {
 			while ((sizeof(buffer) == len) &&
-			       (s = fgets(buffer, sizeof(buffer), istream))) {
+				(s = fgets(buffer, sizeof(buffer), istream))) {
 				s = internal_insertline(this, buffer);
-				len = strlen(buffer) + 1;	/* account for the '\0' */
+				len = strlen(buffer) + 1; /* account for the '\0' */
 			}
-			if (s == NULL
-			    || (this->line[0] == '\0' && feof(istream))) {
+			if (!s || (this->line[0] == '\0' && feof(istream))) {
 				/* time to finish the session */
-				this->line = NULL;
 				crlf = 0;
+				this->line = NULL;
+				lerrno = ENODATA;
 			}
 		}
 
@@ -792,12 +782,11 @@ static char *internal_readline(tinyrl_t * this,
 		if (this->line) {
 			if (this->line[0] == '\0') {
 				tinyrl_reset_line_state(this);
-			} /* call the handler for the newline key */
-			else if (BOOL_FALSE ==
-				 this->handlers[KEY_LF] (this, KEY_LF)) {
+			} else if (!this->handlers[KEY_LF](this, KEY_LF)) {
 				/* an issue has occured */
 				tinyrl_ding(this);
 				this->line = NULL;
+				lerrno = EBADMSG;
 			}
 		}
 		if (str)
@@ -808,20 +797,19 @@ static char *internal_readline(tinyrl_t * this,
 	 * we have to duplicate as we may be referencing a
 	 * history entry or our internal buffer
 	 */
-	{
-		char *result = this->line ? lub_string_dup(this->line) : NULL;
+	result = this->line ? lub_string_dup(this->line) : NULL;
 
-		/* free our internal buffer */
-		free(this->buffer);
-		this->buffer = NULL;
+	/* free our internal buffer */
+	free(this->buffer);
+	this->buffer = NULL;
 
-		if (crlf && ((NULL == result) || ('\0' == *result))) {
-			/* make sure we're not left on a prompt line */
-			tinyrl_crlf(this);
+	/* make sure we're not left on a prompt line */
+	if (crlf && ((NULL == result) || ('\0' == *result)))
+		tinyrl_crlf(this);
 
-		}
-		return result;
-	}
+	if (!result)
+		errno = lerrno; /* get saved errno */
+	return result;
 }
 
 /*----------------------------------------------------------------------- */
@@ -846,52 +834,51 @@ char *tinyrl_forceline(tinyrl_t * this,
 bool_t tinyrl_extend_line_buffer(tinyrl_t * this, unsigned len)
 {
 	bool_t result = BOOL_TRUE;
-	if (this->buffer_size < len) {
-		char *new_buffer;
-		size_t new_len = len;
+	char *new_buffer;
+	size_t new_len = len;
 
-		/* 
-		 * What we do depends on whether we are limited by
-		 * memory or a user imposed limit.
-		 */
+	if (this->buffer_size >= len)
+		return result;
 
-		if (this->max_line_length == 0) {
-			if (new_len < this->buffer_size + 10) {
-				/* make sure we don't realloc too often */
-				new_len = this->buffer_size + 10;
-			}
-			/* leave space for terminator */
-			new_buffer = realloc(this->buffer, new_len + 1);
+	/*
+	 * What we do depends on whether we are limited by
+	 * memory or a user imposed limit.
+	 */
+	if (this->max_line_length == 0) {
+		/* make sure we don't realloc too often */
+		if (new_len < this->buffer_size + 10)
+			new_len = this->buffer_size + 10;
+		/* leave space for terminator */
+		new_buffer = realloc(this->buffer, new_len + 1);
+
+		if (NULL == new_buffer) {
+			tinyrl_ding(this);
+			result = BOOL_FALSE;
+		} else {
+			this->buffer_size = new_len;
+			this->line = this->buffer = new_buffer;
+		}
+	} else {
+		if (new_len < this->max_line_length) {
+
+			/* Just reallocate once to the max size */
+			new_buffer = realloc(this->buffer,
+				this->max_line_length);
 
 			if (NULL == new_buffer) {
 				tinyrl_ding(this);
 				result = BOOL_FALSE;
 			} else {
-				this->buffer_size = new_len;
+				this->buffer_size =
+					this->max_line_length - 1;
 				this->line = this->buffer = new_buffer;
 			}
 		} else {
-			if (new_len < this->max_line_length) {
-
-				/* Just reallocate once to the max size */
-				new_buffer =
-				    realloc(this->buffer,
-					    this->max_line_length);
-
-				if (NULL == new_buffer) {
-					tinyrl_ding(this);
-					result = BOOL_FALSE;
-				} else {
-					this->buffer_size =
-					    this->max_line_length - 1;
-					this->line = this->buffer = new_buffer;
-				}
-			} else {
-				tinyrl_ding(this);
-				result = BOOL_FALSE;
-			}
+			tinyrl_ding(this);
+			result = BOOL_FALSE;
 		}
 	}
+
 	return result;
 }
 
@@ -903,7 +890,7 @@ bool_t tinyrl_insert_text(tinyrl_t * this, const char *text)
 {
 	unsigned delta = strlen(text);
 
-	/* 
+	/*
 	 * If the client wants to change the line ensure that the line and buffer
 	 * references are in sync
 	 */
@@ -912,9 +899,8 @@ bool_t tinyrl_insert_text(tinyrl_t * this, const char *text)
 	if ((delta + this->end) > (this->buffer_size)) {
 		/* extend the current buffer */
 		if (BOOL_FALSE ==
-		    tinyrl_extend_line_buffer(this, this->end + delta)) {
+			tinyrl_extend_line_buffer(this, this->end + delta))
 			return BOOL_FALSE;
-		}
 	}
 
 	if (this->point < this->end) {