Browse Source

tinyrl: Char processing

Serj Kalichev 3 months ago
parent
commit
080bea63e6
6 changed files with 185 additions and 204 deletions
  1. 2 1
      bin/klish/interactive.c
  2. 4 1
      tinyrl/tinyrl.h
  3. 32 14
      tinyrl/tinyrl/private.h
  4. 145 186
      tinyrl/tinyrl/tinyrl.c
  5. 1 1
      tinyrl/vt100.h
  6. 1 1
      tinyrl/vt100/vt100.c

+ 2 - 1
bin/klish/interactive.c

@@ -80,7 +80,8 @@ static bool_t stdin_cb(faux_eloop_t *eloop, faux_eloop_type_e type,
 {
 	ctx_t *ctx = (ctx_t *)udata;
 
-	ktp_session_cmd(ctx->ktp, "cmd", NULL, BOOL_FALSE);
+	tinyrl_read(ctx->tinyrl);
+//	ktp_session_cmd(ctx->ktp, "cmd", NULL, BOOL_FALSE);
 
 	return BOOL_TRUE;
 }

+ 4 - 1
tinyrl/tinyrl.h

@@ -7,7 +7,9 @@
 
 C_DECL_BEGIN
 
- typedef struct _tinyrl tinyrl_t;
+typedef struct tinyrl_s tinyrl_t;
+
+
 typedef enum {
     /**
      * no possible completions were found
@@ -76,6 +78,7 @@ bool_t tinyrl_hist_save(const tinyrl_t *tinyrl);
 bool_t tinyrl_hist_restore(tinyrl_t *tinyrl);
 void tty_raw_mode(tinyrl_t *tinyrl);
 void tty_restore_mode(tinyrl_t *tinyrl);
+int tinyrl_read(tinyrl_t *tinyrl);
 
 
 

+ 32 - 14
tinyrl/tinyrl/private.h

@@ -32,10 +32,39 @@ bool_t tinyrl_key_clear_screen(tinyrl_t * tinyrl, int key);
 bool_t tinyrl_key_erase_line(tinyrl_t * tinyrl, int key);
 bool_t tinyrl_key_tab(tinyrl_t * tinyrl, int key);
 
+// Tinyrl
+bool_t tinyrl_extend_line(tinyrl_t *tinyrl, size_t len);
+bool_t tinyrl_esc_seq(tinyrl_t *tinyrl, const char *esc_seq);
+
+
+typedef struct line_s {
+	char *str;
+	size_t size; // Size of buffer
+	size_t len; // Length of string
+	off_t pos;
+} line_t;
+
+#define NUM_HANDLERS 256
+
+struct tinyrl_s {
+
+	tinyrl_key_func_t *handlers[NUM_HANDLERS]; // Handlers for pressed keys
+	tinyrl_key_func_t *hotkey_fn; // Handler for non-standard hotkeys
+	hist_t *hist; // History object
+	vt100_t *term; // VT100 terminal object
+	struct termios default_termios; // Saved terminal settings
+	unsigned int width; // Terminal width
+	bool_t utf8; // Is encoding UTF-8 flag. Default is UTF-8
+	line_t line; // Current line
+
+	// Input processing vars. Input is processed char by char so
+	// the current state of processing is necessary.
+	size_t utf8_cont; //  Number of UTF-8 continue bytes left
+	bool_t esc_cont; // Does escape sequence continue
+	char esc_seq[10]; // Current ESC sequence (line doesn't contain it)
+	char *esc_p; // Pointer for unfinished ESC sequence
+
 
-/* define the class member data and virtual methods */
-struct _tinyrl {
-	const char *line;
 	unsigned max_line_length;
 	char *prompt;
 	size_t prompt_size; /* strlen() */
@@ -45,29 +74,18 @@ struct _tinyrl {
 	bool_t done;
 	bool_t completion_over;
 	bool_t completion_error_over;
-	unsigned point;
-	unsigned end;
 	tinyrl_completion_func_t *attempted_completion_function;
 	int state;
 #define RL_STATE_COMPLETING (0x00000001)
 	char *kill_string;
-#define NUM_HANDLERS 256
-	tinyrl_key_func_t *handlers[NUM_HANDLERS];
-	tinyrl_key_func_t *hotkey_fn;
-
-	hist_t *hist; // History object
-	vt100_t *term;
 	void *context;		/* context supplied by caller
 				 * to tinyrl_readline()
 				 */
 	char echo_char;
 	bool_t echo_enabled;
-	struct termios default_termios;
 	char *last_buffer;	/* hold record of the previous
 				buffer for redisplay purposes */
 	unsigned int last_point; /* hold record of the previous
 				cursor position for redisplay purposes */
 	unsigned int last_line_size; /* The length of last_buffer */
-	unsigned int width; /* Last terminal width. For resize */
-	bool_t utf8;		/* Is the encoding UTF-8 */
 };

+ 145 - 186
tinyrl/tinyrl/tinyrl.c

@@ -15,6 +15,8 @@
 
 #include "private.h"
 
+#define LINE_CHUNK 80
+
 
 tinyrl_t *tinyrl_new(FILE *istream, FILE *ostream,
 	const char *hist_fname, size_t hist_stifle)
@@ -26,6 +28,16 @@ tinyrl_t *tinyrl_new(FILE *istream, FILE *ostream,
 	if (!tinyrl)
 		return NULL;
 
+	// Line
+	faux_bzero(&tinyrl->line, sizeof(tinyrl->line));
+	tinyrl_extend_line(tinyrl, LINE_CHUNK);
+
+	// Input processing vars
+	tinyrl->utf8_cont = 0;
+	tinyrl->esc_cont = BOOL_FALSE;
+	tinyrl->esc_seq[0] = '\0';
+	tinyrl->esc_p = tinyrl->esc_seq;
+
 	// Key handlers
 	for (i = 0; i < NUM_HANDLERS; i++) {
 		tinyrl->handlers[i] = tinyrl_key_default;
@@ -45,7 +57,6 @@ tinyrl_t *tinyrl_new(FILE *istream, FILE *ostream,
 	tinyrl->handlers[KEY_HT] = tinyrl_key_tab;
 	tinyrl->handlers[KEY_ETB] = tinyrl_key_backword;
 
-	tinyrl->line = NULL;
 	tinyrl->max_line_length = 0;
 	tinyrl->prompt = NULL;
 	tinyrl->prompt_size = 0;
@@ -53,8 +64,6 @@ tinyrl_t *tinyrl_new(FILE *istream, FILE *ostream,
 	tinyrl->buffer_size = 0;
 	tinyrl->done = BOOL_FALSE;
 	tinyrl->completion_over = BOOL_FALSE;
-	tinyrl->point = 0;
-	tinyrl->end = 0;
 	tinyrl->attempted_completion_function = NULL;
 	tinyrl->hotkey_fn = NULL;
 	tinyrl->state = 0;
@@ -229,111 +238,78 @@ bool_t tinyrl_hist_restore(tinyrl_t *tinyrl)
 }
 
 
-static int process_char(tinyrl_t *tinyrl, unsigned char key)
+static bool_t process_char(tinyrl_t *tinyrl, char key)
 {
-#if 0
-	FILE *istream = vt100_istream(tinyrl->term);
-	char *result = NULL;
-	int lerrno = 0;
-
-	tinyrl->done = BOOL_FALSE;
-	tinyrl->point = 0;
-	tinyrl->end = 0;
-	tinyrl->buffer = lub_string_dup("");
-	tinyrl->buffer_size = strlen(tinyrl->buffer);
-	tinyrl->line = tinyrl->buffer;
-	tinyrl->context = context;
-
-		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 */
-		char *esc_p = esc_seq;
-
 
-			// Begin of ESC sequence
-			if (!esc_cont && (KEY_ESC == key)) {
-				esc_cont = 1; // Start ESC sequence
-				esc_p = esc_seq;
-				continue;
-			}
-			if (esc_cont) {
-				/* Broken sequence */
-				if (esc_p >= (esc_seq + sizeof(esc_seq) - 1)) {
-					esc_cont = 0;
-					continue;
-				}
-				/* Dump the control sequence into sequence buffer
-				   ANSI standard control sequences will end
-				   with a character between 64 - 126 */
-				*esc_p = key & 0xff;
-				esc_p++;
-				/* tinyrl is an ANSI control sequence terminator code */
-				if ((key != '[') && (key > 63)) {
-					*esc_p = '\0';
-					tinyrl_escape_seq(tinyrl, esc_seq);
-					esc_cont = 0;
-					tinyrl_redisplay(tinyrl);
-				}
-				continue;
-			}
+	// Begin of ESC sequence
+	if (!tinyrl->esc_cont && (KEY_ESC == key)) {
+		tinyrl->esc_cont = BOOL_TRUE; // Start ESC sequence
+		tinyrl->esc_p = tinyrl->esc_seq;
+		// Note: Don't put ESC symbol itself to buffer
+		return BOOL_TRUE;
+	}
 
-			/* Call the handler for tinyrl key */
-			if (!tinyrl->handlers[key](tinyrl, key))
-				tinyrl_ding(tinyrl);
-			if (tinyrl->done) /* Some handler set the done flag */
-				continue; /* It will break the loop */
+	// Continue ESC sequence
+	if (tinyrl->esc_cont) {
+		// Broken sequence. Too long
+		if ((tinyrl->esc_p - tinyrl->esc_seq) >= (sizeof(tinyrl->esc_seq) - 1)) {
+			tinyrl->esc_cont = BOOL_FALSE;
+			return BOOL_FALSE;
+		}
+		// Save the curren char to sequence buffer
+		*tinyrl->esc_p = key;
+		tinyrl->esc_p++;
+		// ANSI standard control sequences will end
+		// with a character between 64 - 126
+		if ((key != '[') && (key > 63)) {
+			*tinyrl->esc_p = '\0';
+			tinyrl_esc_seq(tinyrl, tinyrl->esc_seq);
+			tinyrl->esc_cont = BOOL_FALSE;
+			//tinyrl_redisplay(tinyrl);
+		}
+		return BOOL_TRUE;
+	}
 
-			if (tinyrl->utf8) {
-				if (!(UTF8_7BIT_MASK & key)) /* ASCII char */
-					utf8_cont = 0;
-				else if (utf8_cont && (UTF8_10 == (key & UTF8_MASK))) /* Continue byte */
-					utf8_cont--;
-				else if (UTF8_11 == (key & UTF8_MASK)) { /* First byte of multibyte char */
-					/* Find out number of char's bytes */
-					int b = key;
-					utf8_cont = 0;
-					while ((utf8_cont < 6) && (UTF8_10 != (b & UTF8_MASK))) {
-						utf8_cont++;
-						b = b << 1;
-					}
-				}
+	// Call the handler for key
+	// Handler (that has no special meaning) will put new char to line buffer
+	if (!tinyrl->handlers[(unsigned char)key](tinyrl, key))
+		vt100_ding(tinyrl->term);
+//	if (tinyrl->done) // Some handler set the done flag
+//		continue; // It will break the loop
+
+	if (tinyrl->utf8) {
+		 // ASCII char (one byte)
+		if (!(UTF8_7BIT_MASK & key)) {
+			tinyrl->utf8_cont = 0;
+		// First byte of multibyte symbol
+		} else if (UTF8_11 == (key & UTF8_MASK)) {
+			// Find out number of symbol's bytes
+			unsigned int b = (unsigned int)key;
+			tinyrl->utf8_cont = 0;
+			while ((tinyrl->utf8_cont < 6) && (UTF8_10 != (b & UTF8_MASK))) {
+				tinyrl->utf8_cont++;
+				b = b << 1;
 			}
-			/* For non UTF-8 encoding the utf8_cont is always 0.
-			   For UTF-8 it's 0 when one-byte symbol or we get
-			   all bytes for the current multibyte character. */
-			if (!utf8_cont)
-				tinyrl_redisplay(tinyrl);
+		// Continue of multibyte symbol
+		} else if ((tinyrl->utf8_cont > 0) && (UTF8_10 == (key & UTF8_MASK))) {
+			tinyrl->utf8_cont--;
 		}
-		/* If the last character in the line (other than NULL)
-		   is a space remove it. */
-		if (tinyrl->end && tinyrl->line && isspace(tinyrl->line[tinyrl->end - 1]))
-			tinyrl_delete_text(tinyrl, tinyrl->end - 1, tinyrl->end);
-		/* Restores the terminal mode */
-		tty_restore_mode(tinyrl);
-
-	/*
-	 * duplicate the string for return to the client 
-	 * we have to duplicate as we may be referencing a
-	 * history entry or our internal buffer
-	 */
-	result = tinyrl->line ? lub_string_dup(tinyrl->line) : NULL;
+	}
 
-	/* free our internal buffer */
-	free(tinyrl->buffer);
-	tinyrl->buffer = NULL;
+	// For non UTF-8 encoding the utf8_cont is always 0.
+	// For UTF-8 it's 0 when one-byte symbol or we get
+	// all bytes for the current multibyte character
+//	if (!utf8_cont)
+//		tinyrl_redisplay(tinyrl);
 
-	if (!result)
-		errno = lerrno; /* get saved errno */
-	return result;
-#endif
-	return 1;
+	return BOOL_TRUE;
 }
 
 
 int tinyrl_read(tinyrl_t *tinyrl)
 {
 	int rc = 0;
-	unsigned char key = 0;
+	char key = 0;
 	int count = 0;
 
 	assert(tinyrl);
@@ -350,64 +326,103 @@ int tinyrl_read(tinyrl_t *tinyrl)
 }
 
 
-#if 0
-
-/*----------------------------------------------------------------------- */
 /*
-tinyrl is called whenever a line is edited in any way.
-It signals that if we are currently viewing a history line we should transfer it
-to the current buffer
-*/
-static void changed_line(tinyrl_t * tinyrl)
+ * Ensure that buffer has enough space to hold len characters,
+ * possibly reallocating it if necessary. The function returns BOOL_TRUE
+ * if the line is successfully extended, BOOL_FALSE if not.
+ */
+bool_t tinyrl_extend_line(tinyrl_t *tinyrl, size_t len)
 {
-	/* if the current line is not our buffer then make it so */
-	if (tinyrl->line != tinyrl->buffer) {
-		/* replace the current buffer with the new details */
-		free(tinyrl->buffer);
-		tinyrl->line = tinyrl->buffer = lub_string_dup(tinyrl->line);
-		tinyrl->buffer_size = strlen(tinyrl->buffer);
-		assert(tinyrl->line);
+	char *new_buf = NULL;
+	size_t new_size = 0;
+	size_t chunk_num = 0;
+
+	if (tinyrl->line.len >= len)
+		return BOOL_TRUE;
+
+	chunk_num = len / LINE_CHUNK;
+	if ((len % LINE_CHUNK) > 0)
+		chunk_num++;
+	new_size = chunk_num * LINE_CHUNK;
+
+	// First initialization
+	if (tinyrl->line.str == NULL) {
+		tinyrl->line.str = faux_zmalloc(new_size);
+		if (!tinyrl->line.str)
+			return BOOL_FALSE;
+		tinyrl->line.size = new_size;
+		return BOOL_TRUE;
 	}
+
+	new_buf = realloc(tinyrl->line.str, new_size);
+	if (!new_buf)
+		return BOOL_FALSE;
+	tinyrl->line.str = new_buf;
+	tinyrl->line.size = new_size;
+
+	return BOOL_TRUE;
 }
 
 
-static bool_t tinyrl_escape_seq(tinyrl_t *tinyrl, const char *esc_seq)
+bool_t tinyrl_esc_seq(tinyrl_t *tinyrl, const char *esc_seq)
 {
-	int key = 0;
 	bool_t result = BOOL_FALSE;
 
-	switch (tinyrl_vt100_escape_decode(tinyrl->term, esc_seq)) {
-	case tinyrl_vt100_CURSOR_UP:
-		result = tinyrl_key_up(tinyrl, key);
+	switch (vt100_esc_decode(tinyrl->term, esc_seq)) {
+	case VT100_CURSOR_UP:
+		result = tinyrl_key_up(tinyrl, 0);
 		break;
-	case tinyrl_vt100_CURSOR_DOWN:
-		result = tinyrl_key_down(tinyrl, key);
+	case VT100_CURSOR_DOWN:
+		result = tinyrl_key_down(tinyrl, 0);
 		break;
-	case tinyrl_vt100_CURSOR_LEFT:
-		result = tinyrl_key_left(tinyrl, key);
+	case VT100_CURSOR_LEFT:
+		result = tinyrl_key_left(tinyrl, 0);
 		break;
-	case tinyrl_vt100_CURSOR_RIGHT:
-		result = tinyrl_key_right(tinyrl, key);
+	case VT100_CURSOR_RIGHT:
+		result = tinyrl_key_right(tinyrl, 0);
 		break;
-	case tinyrl_vt100_HOME:
-		result = tinyrl_key_start_of_line(tinyrl,key);
+	case VT100_HOME:
+		result = tinyrl_key_start_of_line(tinyrl, 0);
 		break;
-	case tinyrl_vt100_END:
-		result = tinyrl_key_end_of_line(tinyrl,key);
+	case VT100_END:
+		result = tinyrl_key_end_of_line(tinyrl, 0);
 		break;
-	case tinyrl_vt100_DELETE:
-		result = tinyrl_key_delete(tinyrl,key);
+	case VT100_DELETE:
+		result = tinyrl_key_delete(tinyrl, 0);
 		break;
-	case tinyrl_vt100_INSERT:
-	case tinyrl_vt100_PGDOWN:
-	case tinyrl_vt100_PGUP:
-	case tinyrl_vt100_UNKNOWN:
+	case VT100_INSERT:
+	case VT100_PGDOWN:
+	case VT100_PGUP:
+	case VT100_UNKNOWN:
 		break;
 	}
 
 	return result;
 }
 
+
+#if 0
+
+/*----------------------------------------------------------------------- */
+/*
+tinyrl is called whenever a line is edited in any way.
+It signals that if we are currently viewing a history line we should transfer it
+to the current buffer
+*/
+static void changed_line(tinyrl_t * tinyrl)
+{
+	/* if the current line is not our buffer then make it so */
+	if (tinyrl->line != tinyrl->buffer) {
+		/* replace the current buffer with the new details */
+		free(tinyrl->buffer);
+		tinyrl->line = tinyrl->buffer = lub_string_dup(tinyrl->line);
+		tinyrl->buffer_size = strlen(tinyrl->buffer);
+		assert(tinyrl->line);
+	}
+}
+
+
+
 /*-------------------------------------------------------- */
 int tinyrl_printf(const tinyrl_t * tinyrl, const char *fmt, ...)
 {
@@ -732,62 +747,6 @@ char *tinyrl_forceline(tinyrl_t * tinyrl, void *context, const char *line)
 	return internal_readline(tinyrl, context, line);
 }
 
-/*----------------------------------------------------------------------- */
-/*
- * Ensure that buffer has enough space to hold len characters,
- * possibly reallocating it if necessary. The function returns BOOL_TRUE
- * if the line is successfully extended, BOOL_FALSE if not.
- */
-bool_t tinyrl_extend_line_buffer(tinyrl_t * tinyrl, unsigned int len)
-{
-	bool_t result = BOOL_TRUE;
-	char *new_buffer;
-	size_t new_len = len;
-
-	if (tinyrl->buffer_size >= len)
-		return result;
-
-	/*
-	 * What we do depends on whether we are limited by
-	 * memory or a user imposed limit.
-	 */
-	if (tinyrl->max_line_length == 0) {
-		/* make sure we don't realloc too often */
-		if (new_len < tinyrl->buffer_size + 10)
-			new_len = tinyrl->buffer_size + 10;
-		/* leave space for terminator */
-		new_buffer = realloc(tinyrl->buffer, new_len + 1);
-
-		if (!new_buffer) {
-			tinyrl_ding(tinyrl);
-			result = BOOL_FALSE;
-		} else {
-			tinyrl->buffer_size = new_len;
-			tinyrl->line = tinyrl->buffer = new_buffer;
-		}
-	} else {
-		if (new_len < tinyrl->max_line_length) {
-
-			/* Just reallocate once to the max size */
-			new_buffer = realloc(tinyrl->buffer,
-				tinyrl->max_line_length);
-
-			if (!new_buffer) {
-				tinyrl_ding(tinyrl);
-				result = BOOL_FALSE;
-			} else {
-				tinyrl->buffer_size =
-					tinyrl->max_line_length - 1;
-				tinyrl->line = tinyrl->buffer = new_buffer;
-			}
-		} else {
-			tinyrl_ding(tinyrl);
-			result = BOOL_FALSE;
-		}
-	}
-
-	return result;
-}
 
 /*----------------------------------------------------------------------- */
 /*

+ 1 - 1
tinyrl/vt100.h

@@ -85,7 +85,7 @@ int vt100_oflush(const vt100_t *vt100);
 int vt100_ierror(const vt100_t *vt100);
 int vt100_oerror(const vt100_t *vt100);
 int vt100_ieof(const vt100_t *vt100);
-int vt100_getchar(const vt100_t *vt100, unsigned char *c);
+int vt100_getchar(const vt100_t *vt100, char *c);
 vt100_esc_e vt100_esc_decode(const vt100_t *vt100, const char *esc_seq);
 
 void vt100_ding(const vt100_t *vt100);

+ 1 - 1
tinyrl/vt100/vt100.c

@@ -144,7 +144,7 @@ int vt100_vprintf(const vt100_t *vt100, const char *fmt, va_list args)
 }
 
 
-int vt100_getchar(const vt100_t *vt100, unsigned char *c)
+int vt100_getchar(const vt100_t *vt100, char *c)
 {
 	if (!vt100 || !vt100->istream || !c) {
 		errno = ENOENT;