Browse Source

Machine oriented protocol

Serj Kalichev 3 years ago
parent
commit
b19c902842

+ 6 - 0
clish/shell.h

@@ -222,6 +222,12 @@ int clish_shell__set_udata(clish_shell_t *instance,
 /* Access functions */
 int clish_shell_prepare(clish_shell_t *instance);
 
+/* Machine/Human oriented protocol */
+bool_t clish_shell_is_machine_interface(const clish_shell_t *shell);
+void clish_shell_set_machine_interface(clish_shell_t *shell);
+void clish_shell_set_human_interface(clish_shell_t *shell);
+void clish_shell_machine_retval(clish_shell_t *shell, int retval);
+
 /*
  * Non shell specific functions.
  * Start and Stop XML parser engine.

+ 1 - 0
clish/shell/private.h

@@ -78,6 +78,7 @@ struct clish_shell_s {
 
 	/* Boolean flags */
 	bool_t interactive; /* Is shell interactive. */
+	bool_t machine_interface; /* Machine oriented interface with special protocol */
 	bool_t log; /* If command logging is enabled */
 	int log_facility; /* Syslog facility */
 	bool_t dryrun; /* Is this a dry-running */

+ 18 - 0
clish/shell/shell_execute.c

@@ -86,6 +86,21 @@ static void clish_shell_unlock(int lock_fd)
 	close(lock_fd);
 }
 
+/*----------------------------------------------------------- */
+// Prints return value in a case of machine oriented protocol
+void clish_shell_machine_retval(clish_shell_t *shell, int retval)
+{
+	assert(shell);
+	if (!shell)
+		return;
+
+	if (!clish_shell_is_machine_interface(shell))
+		return;
+
+	printf("\033[%dR\n", retval);
+	fflush(stdout);
+}
+
 /*----------------------------------------------------------- */
 int clish_shell_execute(clish_context_t *context, char **out)
 {
@@ -152,6 +167,9 @@ int clish_shell_execute(clish_context_t *context, char **out)
 			free(space);
 	}
 
+	// Machine oriented protocol outputs return value
+	clish_shell_machine_retval(this, result);
+
 	/* Unlock the lockfile */
 	if (lock_fd != -1)
 		clish_shell_unlock(lock_fd);

+ 33 - 0
clish/shell/shell_misc.c

@@ -8,3 +8,36 @@
 #include "private.h"
 
 CLISH_GET_STR(shell, overview);
+
+bool_t clish_shell_is_machine_interface(const clish_shell_t *shell)
+{
+	assert(shell);
+	if (!shell)
+		return BOOL_FALSE;
+
+	return shell->machine_interface;
+}
+
+
+void clish_shell_set_machine_interface(clish_shell_t *shell)
+{
+	assert(shell);
+	if (!shell)
+		return;
+
+	shell->machine_interface = BOOL_TRUE;
+	if (shell->tinyrl)
+		tinyrl_set_machine_interface(shell->tinyrl);
+}
+
+
+void clish_shell_set_human_interface(clish_shell_t *shell)
+{
+	assert(shell);
+	if (!shell)
+		return;
+
+	shell->machine_interface = BOOL_FALSE;
+	if (shell->tinyrl)
+		tinyrl_set_human_interface(shell->tinyrl);
+}

+ 1 - 0
clish/shell/shell_new.c

@@ -66,6 +66,7 @@ static void clish_shell_init(clish_shell_t * this,
 	this->client = NULL;
 	this->lockfile = lub_string_dup(CLISH_LOCK_PATH);
 	this->default_shebang = lub_string_dup("/bin/sh");
+	this->machine_interface = BOOL_FALSE; /* Human oriented protocol by default. */
 	this->interactive = BOOL_TRUE; /* The interactive shell by default. */
 	this->log = BOOL_FALSE; /* Disable logging by default */
 	this->log_facility = LOG_LOCAL0; /* LOCAL0 for compatibility */

+ 3 - 0
clish/shell/shell_tinyrl.c

@@ -310,6 +310,9 @@ static bool_t clish_shell_tinyrl_key_enter(tinyrl_t *this, int key)
 			fprintf(stderr, "Syntax error on line %s:%u \"%s\": "
 			"%s\n", fname, shell->current_file->line, line, errmsg);
 		}
+		// Wrong line must return bad retval for machine oriented proto
+		// Let retval=2 means wrong command
+		clish_shell_machine_retval(shell, 2);
 	}
 
 	tinyrl_done(this);

+ 6 - 0
clish/shell/shell_var.c

@@ -112,6 +112,12 @@ static char *find_context_var(const char *name, clish_context_t *this)
 		else
 			result = strdup("0");
 
+	} else if (!lub_string_nocasecmp(name, "_machine_interface")) {
+		if (clish_shell_is_machine_interface(this->shell))
+			result = strdup("1");
+		else
+			result = strdup("0");
+
 	} else if (!lub_string_nocasecmp(name, "_pid")) {
 		char tmp[10];
 		snprintf(tmp, sizeof(tmp), "%u", getpid());

+ 2 - 0
plugins/clish/builtin_init.c

@@ -30,6 +30,8 @@ CLISH_PLUGIN_INIT(clish)
 	clish_plugin_add_psym(plugin, clish_wdog, "clish_wdog");
 	clish_plugin_add_psym(plugin, clish_macros, "clish_macros");
 	clish_plugin_add_osym(plugin, clish_script, "clish_script");
+	clish_plugin_add_psym(plugin, clish_machine_interface, "clish_machine_interface");
+	clish_plugin_add_psym(plugin, clish_human_interface, "clish_human_interface");
 
 	clish_shell = clish_shell; /* Happy compiler */
 

+ 2 - 0
plugins/clish/private.h

@@ -21,3 +21,5 @@ CLISH_PLUGIN_SYM(clish_nop);
 CLISH_PLUGIN_SYM(clish_wdog);
 CLISH_PLUGIN_OSYM(clish_script);
 CLISH_PLUGIN_SYM(clish_macros);
+CLISH_PLUGIN_SYM(clish_machine_interface);
+CLISH_PLUGIN_SYM(clish_human_interface);

+ 25 - 0
plugins/clish/sym_misc.c

@@ -221,4 +221,29 @@ CLISH_PLUGIN_SYM(clish_macros)
 	return 0;
 }
 
+/*----------------------------------------------------------- */
+CLISH_PLUGIN_SYM(clish_machine_interface)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	clish_shell_set_machine_interface(this);
+
+	script = script; /* Happy compiler */
+	out = out; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */
+CLISH_PLUGIN_SYM(clish_human_interface)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	clish_shell_set_human_interface(this);
+
+	script = script; /* Happy compiler */
+	out = out; /* Happy compiler */
+
+	return 0;
+}
+
+
 /*----------------------------------------------------------- */

+ 1 - 0
tinyrl/private.h

@@ -44,4 +44,5 @@ struct _tinyrl {
 	unsigned int last_line_size; /* The length of last_buffer */
 	unsigned int last_width; /* Last terminal width. For resize */
 	bool_t utf8;		/* Is the encoding UTF-8 */
+	bool_t machine_interface; /* Mashine/Human interface flag */
 };

+ 69 - 9
tinyrl/tinyrl.c

@@ -652,6 +652,7 @@ static void tinyrl_init(tinyrl_t * this, FILE * istream, FILE * ostream,
 	this->last_point = 0;
 	this->last_line_size = 0;
 	this->utf8 = BOOL_FALSE;
+	this->machine_interface = BOOL_FALSE;
 
 	/* create the vt100 terminal */
 	this->term = tinyrl_vt100_new(NULL, ostream);
@@ -739,9 +740,20 @@ static void tinyrl_internal_position(const tinyrl_t *this, int prompt_len,
 /* Jump to first free line after current multiline input   */
 void tinyrl_multi_crlf(const tinyrl_t * this)
 {
-	unsigned int line_size = strlen(this->last_buffer);
-	unsigned int line_len = utf8_nsyms(this, this->last_buffer, line_size);
-	unsigned int count = utf8_nsyms(this, this->last_buffer, this->last_point);
+	unsigned int line_size = 0;
+	unsigned int line_len = 0;
+	unsigned int count = 0;
+
+	assert(this);
+	if (!this)
+		return;
+
+	if (tinyrl_is_machine_interface(this))
+		return;
+
+	line_size = strlen(this->last_buffer);
+	line_len = utf8_nsyms(this, this->last_buffer, line_size);
+	count = utf8_nsyms(this, this->last_buffer, this->last_point);
 
 	tinyrl_internal_position(this, this->prompt_len + line_len,
 		- (line_len - count), this->last_width);
@@ -752,11 +764,20 @@ void tinyrl_multi_crlf(const tinyrl_t * this)
 /*----------------------------------------------------------------------- */
 void tinyrl_redisplay(tinyrl_t * this)
 {
-	unsigned int line_size = strlen(this->line);
-	unsigned int line_len = utf8_nsyms(this, this->line, line_size);
-	unsigned int width = tinyrl_vt100__get_width(this->term);
-	unsigned int count, eq_chars = 0;
-	int cols;
+	unsigned int line_size = 0;
+	unsigned int line_len = 0;
+	unsigned int width = 0;
+	unsigned int count = 0;
+	unsigned int eq_chars = 0;
+	int cols = 0;
+
+	// Don't redisplay for non-interactive machine interface
+	if (tinyrl_is_machine_interface(this))
+		return;
+
+	line_size = strlen(this->line);
+	line_len = utf8_nsyms(this, this->line, line_size);
+	width = tinyrl_vt100__get_width(this->term);
 
 	/* Prepare print position */
 	if (this->last_buffer && (width == this->last_width)) {
@@ -862,7 +883,7 @@ static char *internal_readline(tinyrl_t * this,
 	this->context = context;
 
 	/* Interactive session */
-	if (this->isatty && !str) {
+	if (tinyrl__get_isatty(this) && !str) {
 		unsigned int utf8_cont = 0; /* UTF-8 continue bytes */
 		unsigned int esc_cont = 0; /* Escape sequence continues */
 		char esc_seq[10]; /* Buffer for ESC sequence */
@@ -1516,6 +1537,16 @@ void tinyrl__set_istream(tinyrl_t * this, FILE * istream)
 /*-------------------------------------------------------- */
 bool_t tinyrl__get_isatty(const tinyrl_t * this)
 {
+	assert(this);
+	if (!this)
+		return BOOL_FALSE;
+
+	// The machine interface can be forced. It means the interaction is not
+	// interactive and stdin/stdout considered as not terminal but just as
+	// a stream. So return fake value.
+	if (tinyrl_is_machine_interface(this))
+		return BOOL_FALSE;
+
 	return this->isatty;
 }
 
@@ -1654,4 +1685,33 @@ void tinyrl__stifle_history(tinyrl_t *this, unsigned int stifle)
 {
 	tinyrl_history_stifle(this->history, stifle);
 }
+
+/*--------------------------------------------------------- */
+void tinyrl_set_machine_interface(tinyrl_t *this)
+{
+	assert(this);
+	if (!this)
+		return;
+
+	this->machine_interface = BOOL_TRUE;
+}
+
+/*--------------------------------------------------------- */
+void tinyrl_set_human_interface(tinyrl_t *this)
+{
+	assert(this);
+	if (!this)
+		return;
+
+	this->machine_interface = BOOL_FALSE;
+}
+
 /*--------------------------------------------------------- */
+bool_t tinyrl_is_machine_interface(const tinyrl_t *this)
+{
+	assert(this);
+	if (!this)
+		return BOOL_FALSE;
+
+	return this->machine_interface;
+}

+ 3 - 0
tinyrl/tinyrl.h

@@ -223,6 +223,9 @@ extern unsigned tinyrl__get_height(const tinyrl_t *instance);
 extern int tinyrl__save_history(const tinyrl_t *instance, const char *fname);
 extern int tinyrl__restore_history(tinyrl_t *instance, const char *fname);
 extern void tinyrl__stifle_history(tinyrl_t *instance, unsigned int stifle);
+extern void tinyrl_set_machine_interface(tinyrl_t *instance);
+extern void tinyrl_set_human_interface(tinyrl_t *instance);
+bool_t tinyrl_is_machine_interface(const tinyrl_t *instance);
 
 _END_C_DECL
 #endif				/* _tinyrl_tinyrl_h */