From 621effa74ac159927fc4277f17ee21f00624232c Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Tue, 12 Dec 2017 14:32:56 -0800 Subject: [PATCH 01/14] Remove trailing whitespace on lines The trailing whitespace gets removed by editing steps I have done for other changes, so I wanted to commit this change by itself first to avoid making the other changes less clear. --- src/microrl.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/microrl.c b/src/microrl.c index 5bf1962..83043c8 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -28,21 +28,21 @@ static void print_hist (ring_history_t * pThis) for (int i = 0; i < _RING_HISTORY_LEN; i++) { if (i == pThis->begin) printf ("b"); - else + else printf (" "); } printf ("\n"); for (int i = 0; i < _RING_HISTORY_LEN; i++) { if (isalpha(pThis->ring_buf[i])) printf ("%c", pThis->ring_buf[i]); - else + else printf ("%d", pThis->ring_buf[i]); } printf ("\n"); for (int i = 0; i < _RING_HISTORY_LEN; i++) { if (i == pThis->end) printf ("e"); - else + else printf (" "); } printf ("\n"); @@ -56,7 +56,7 @@ static void hist_erase_older (ring_history_t * pThis) int new_pos = pThis->begin + pThis->ring_buf [pThis->begin] + 1; if (new_pos >= _RING_HISTORY_LEN) new_pos = new_pos - _RING_HISTORY_LEN; - + pThis->begin = new_pos; } @@ -86,9 +86,9 @@ static void hist_save_line (ring_history_t * pThis, char * line, int len) hist_erase_older (pThis); } // if it's first line - if (pThis->ring_buf [pThis->begin] == 0) + if (pThis->ring_buf [pThis->begin] == 0) pThis->ring_buf [pThis->begin] = len; - + // store line if (len < _RING_HISTORY_LEN-pThis->end-1) memcpy (pThis->ring_buf + pThis->end + 1, line, len); @@ -113,12 +113,12 @@ static void hist_save_line (ring_history_t * pThis, char * line, int len) static int hist_restore_line (ring_history_t * pThis, char * line, int dir) { int cnt = 0; - // count history record + // count history record int header = pThis->begin; while (pThis->ring_buf [header] != 0) { header += pThis->ring_buf [header] + 1; if (header >= _RING_HISTORY_LEN) - header -= _RING_HISTORY_LEN; + header -= _RING_HISTORY_LEN; cnt++; } @@ -256,13 +256,13 @@ static char *u16bit_to_str (unsigned int nmb, char * buf) static void terminal_move_cursor (microrl_t * pThis, int offset) { char str[16] = {0,}; -#ifdef _USE_LIBC_STDIO +#ifdef _USE_LIBC_STDIO if (offset > 0) { snprintf (str, 16, "\033[%dC", offset); } else if (offset < 0) { snprintf (str, 16, "\033[%dD", -(offset)); } -#else +#else char *endstr; strcpy (str, "\033["); if (offset > 0) { @@ -273,7 +273,7 @@ static void terminal_move_cursor (microrl_t * pThis, int offset) strcpy (endstr, "D"); } else return; -#endif +#endif pThis->print (str); } @@ -297,7 +297,7 @@ static void terminal_reset_cursor (microrl_t * pThis) } //***************************************************************************** -// print cmdline to screen, replace '\0' to wihitespace +// print cmdline to screen, replace '\0' to wihitespace static void terminal_print_line (microrl_t * pThis, int pos, int cursor) { pThis->print ("\033[K"); // delete all from cursor to end @@ -310,13 +310,13 @@ static void terminal_print_line (microrl_t * pThis, int pos, int cursor) nch[0] = ' '; pThis->print (nch); } - + terminal_reset_cursor (pThis); terminal_move_cursor (pThis, cursor); } //***************************************************************************** -void microrl_init (microrl_t * pThis, void (*print) (const char *)) +void microrl_init (microrl_t * pThis, void (*print) (const char *)) { memset(pThis->cmdline, 0, _COMMAND_LINE_LEN); #ifdef _USE_HISTORY @@ -408,7 +408,7 @@ static int escape_process (microrl_t * pThis, char ch) } else if (ch == '8') { pThis->escape_seq = _ESC_END; return 0; - } + } } else if (ch == '~') { if (pThis->escape_seq == _ESC_HOME) { terminal_reset_cursor (pThis); @@ -490,14 +490,14 @@ static int common_len (char ** arr) } //***************************************************************************** -static void microrl_get_complite (microrl_t * pThis) +static void microrl_get_complite (microrl_t * pThis) { char const * tkn_arr[_COMMAND_TOKEN_NMB]; - char ** compl_token; - + char ** compl_token; + if (pThis->get_completion == NULL) // callback was not set return; - + int status = split (pThis, pThis->cursor, tkn_arr); if (pThis->cmdline[pThis->cursor-1] == '\0') tkn_arr[status++] = ""; @@ -519,16 +519,16 @@ static void microrl_get_complite (microrl_t * pThis) terminal_newline (pThis); print_prompt (pThis); } - + if (len) { - microrl_insert_text (pThis, compl_token[0] + strlen(tkn_arr[status-1]), + microrl_insert_text (pThis, compl_token[0] + strlen(tkn_arr[status-1]), len - strlen(tkn_arr[status-1])); - if (compl_token[1] == NULL) + if (compl_token[1] == NULL) microrl_insert_text (pThis, " ", 1); } terminal_reset_cursor (pThis); terminal_print_line (pThis, 0, pThis->cursor); - } + } } #endif @@ -686,7 +686,7 @@ void microrl_insert_char (microrl_t * pThis, int ch) break; if (microrl_insert_text (pThis, (char*)&ch, 1)) terminal_print_line (pThis, pThis->cursor-1, pThis->cursor); - + break; } #ifdef _USE_ESC_SEQ From 114e3c0416cce06caf4773e2c06d392d6ecf8f0e Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Tue, 12 Dec 2017 14:45:56 -0800 Subject: [PATCH 02/14] Fix the inverted sense of a pair of comments about whitespace --- src/microrl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/microrl.c b/src/microrl.c index 83043c8..2343f0a 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -191,7 +191,7 @@ static int split (microrl_t * pThis, int limit, char const ** tkn_arr) int i = 0; int ind = 0; while (1) { - // go to the first whitespace (zerro for us) + // go to the first NOT whitespace (zerro for us) while ((pThis->cmdline [ind] == '\0') && (ind < limit)) { ind++; } @@ -200,7 +200,7 @@ static int split (microrl_t * pThis, int limit, char const ** tkn_arr) if (i >= _COMMAND_TOKEN_NMB) { return -1; } - // go to the first NOT whitespace (not zerro for us) + // go to the first whitespace (not zerro for us) while ((pThis->cmdline [ind] != '\0') && (ind < limit)) { ind++; } From 174e73aa1f53aed4801af177ec2f7c0404f612f5 Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Tue, 12 Dec 2017 14:49:08 -0800 Subject: [PATCH 03/14] Fix the inverted sense of a pair of comments about whitespace [2nd part] --- src/microrl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/microrl.c b/src/microrl.c index 2343f0a..9f76a08 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -191,7 +191,7 @@ static int split (microrl_t * pThis, int limit, char const ** tkn_arr) int i = 0; int ind = 0; while (1) { - // go to the first NOT whitespace (zerro for us) + // go to the first NOT whitespace (not zerro for us) while ((pThis->cmdline [ind] == '\0') && (ind < limit)) { ind++; } @@ -200,7 +200,7 @@ static int split (microrl_t * pThis, int limit, char const ** tkn_arr) if (i >= _COMMAND_TOKEN_NMB) { return -1; } - // go to the first whitespace (not zerro for us) + // go to the first whitespace (zerro for us) while ((pThis->cmdline [ind] != '\0') && (ind < limit)) { ind++; } From 4efa948a584bbf46c563d203d30e40a3fccb5db6 Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Tue, 12 Dec 2017 21:41:20 -0800 Subject: [PATCH 04/14] Correct the comment for the KEY_BS character --- src/microrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/microrl.c b/src/microrl.c index 9f76a08..f28cfcd 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -662,7 +662,7 @@ void microrl_insert_char (microrl_t * pThis, int ch) break; //----------------------------------------------------- case KEY_DEL: // Backspace - case KEY_BS: // ^U + case KEY_BS: // ^H microrl_backspace (pThis); terminal_print_line (pThis, pThis->cursor, pThis->cursor); break; From 0c622ff629c83c2feb6289689754c218e4b4ff9a Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Tue, 12 Dec 2017 21:44:47 -0800 Subject: [PATCH 05/14] Implement Ctrl-D as delete-character-forward --- src/microrl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/microrl.c b/src/microrl.c index f28cfcd..d4ec2c6 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -464,6 +464,16 @@ static void microrl_backspace (microrl_t * pThis) } } +//***************************************************************************** +// remove one char forward at cursor +static void microrl_delete (microrl_t * pThis) +{ + memmove (pThis->cmdline + pThis->cursor, + pThis->cmdline + pThis->cursor+1, + pThis->cmdlen-pThis->cursor+1); + pThis->cmdline [pThis->cmdlen] = '\0'; + pThis->cmdlen--; +} #ifdef _USE_COMPLETE @@ -667,6 +677,11 @@ void microrl_insert_char (microrl_t * pThis, int ch) terminal_print_line (pThis, pThis->cursor, pThis->cursor); break; //----------------------------------------------------- + case KEY_EOT: // ^D + microrl_delete (pThis); + terminal_print_line (pThis, pThis->cursor, pThis->cursor); + break; + //----------------------------------------------------- case KEY_DC2: // ^R terminal_newline (pThis); print_prompt (pThis); From 369f1b48dbfa981f20cdc7b5c550b15ee3b4bc1b Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Tue, 12 Dec 2017 21:47:37 -0800 Subject: [PATCH 06/14] Add note about Ctrl+D feature (delete character forward) --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 4bf02dc..c458d3a 100644 --- a/README +++ b/README @@ -17,6 +17,7 @@ Microrl library is designed to help implement command line interface in small an - Ctrl+A (like HOME) - Ctrl+E (like END) - Ctrl+H (like backspace) + - Ctrl+D (delete one character forward) - Ctrl+B (like cursor arrow left) - Ctrl+F (like cursor arrow right) - Ctrl+P (like cursor arrow up) From 9fadb3daa4171906ed72b162ad2f7b441aee75fe Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Tue, 12 Dec 2017 21:53:13 -0800 Subject: [PATCH 07/14] Don't do completion if command split to tokens fails --- src/microrl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/microrl.c b/src/microrl.c index d4ec2c6..d54c3d3 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -509,6 +509,8 @@ static void microrl_get_complite (microrl_t * pThis) return; int status = split (pThis, pThis->cursor, tkn_arr); + if (status < 0) + return; if (pThis->cmdline[pThis->cursor-1] == '\0') tkn_arr[status++] = ""; compl_token = pThis->get_completion (status, tkn_arr); From d33cfb0726c213b93fd39188731555ceba1f8740 Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Wed, 13 Dec 2017 00:08:11 -0800 Subject: [PATCH 08/14] Add optional quoting to allow command args to include spaces --- README | 3 ++ src/config.h | 13 +++++++++ src/microrl.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/microrl.h | 11 ++++++++ 4 files changed, 101 insertions(+), 2 deletions(-) diff --git a/README b/README index c458d3a..ecf6901 100644 --- a/README +++ b/README @@ -31,6 +31,9 @@ Microrl library is designed to help implement command line interface in small an ** completion - via completion callback + ** quoting (optional) + - Use single or double quotes around a command argument that needs to include space characters. + 3. SRC STRUCTURE diff --git a/src/config.h b/src/config.h index 6c9ddde..ef8c899 100644 --- a/src/config.h +++ b/src/config.h @@ -41,6 +41,19 @@ NULL to callback ptr and do not use it, but for memory saving tune, if you are not going to use it - disable this define.*/ #define _USE_COMPLETE +/*Define it, if you want to allow quoting command arguments to include spaces. +Depends upon _QUOTED_TOKEN_NMB parameter */ +#define _USE_QUOTING + +/* +Quoted token number, define max number of tokens allowed to be quoted. If the +number of quoted tokens typed in the command line exceeds this value, then +prints message about it and the command line is not parsed and 'execute' +callback is not called. +Quoting protects whitespace, for example 2 quoted tokens: +"IRin> set wifi 'Home Net' 'this is a secret'" */ +#define _QUOTED_TOKEN_NMB 2 + /*Define it, if you wanna use history. It s work's like bash history, and set stored value to cmdline, if UP and DOWN key pressed. Using history add memory consuming, depends from _RING_HISTORY_LEN parametr */ diff --git a/src/microrl.c b/src/microrl.c index d54c3d3..933a808 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -184,27 +184,92 @@ static int hist_restore_line (ring_history_t * pThis, char * line, int dir) +#ifdef _USE_QUOTING +//***************************************************************************** +// restore end quote marks in cmdline +static void restore (microrl_t * pThis) +{ + int iq; + for (iq = 0; iq < _QUOTED_TOKEN_NMB; ++iq) { + if (pThis->quotes[iq].end == 0) + break; + *pThis->quotes[iq].end = *pThis->quotes[iq].begin; + pThis->quotes[iq].begin = 0; + pThis->quotes[iq].end = 0; + } +} +#endif + //***************************************************************************** // split cmdline to tkn array and return nmb of token static int split (microrl_t * pThis, int limit, char const ** tkn_arr) { int i = 0; int ind = 0; +#ifdef _USE_QUOTING + int iq = 0; + char quote = 0; + for (iq = 0; iq < _QUOTED_TOKEN_NMB; ++iq) { + pThis->quotes[iq].begin = 0; + pThis->quotes[iq].end = 0; + } + iq = 0; +#endif while (1) { // go to the first NOT whitespace (not zerro for us) while ((pThis->cmdline [ind] == '\0') && (ind < limit)) { ind++; } if (!(ind < limit)) return i; +#ifdef _USE_QUOTING + if (pThis->cmdline [ind] == '\'' || pThis->cmdline [ind] == '"') { + if (iq >= _QUOTED_TOKEN_NMB) { + restore (pThis); + return -1; + } + quote = pThis->cmdline [ind]; + pThis->quotes[iq].begin = pThis->cmdline + ind; + ind++; + } +#endif tkn_arr[i++] = pThis->cmdline + ind; if (i >= _COMMAND_TOKEN_NMB) { +#ifdef _USE_QUOTING + restore (pThis); +#endif return -1; } // go to the first whitespace (zerro for us) - while ((pThis->cmdline [ind] != '\0') && (ind < limit)) { + while (ind < limit) { + if (pThis->cmdline [ind] == '\0') { +#ifdef _USE_QUOTING + if (!quote) +#endif + break; +#ifdef _USE_QUOTING + pThis->cmdline [ind] = ' '; + } else if (pThis->cmdline [ind] == quote) { + if (pThis->cmdline [ind + 1] != '\0') { + restore (pThis); + return -1; + } + quote = 0; + pThis->quotes[iq++].end = pThis->cmdline + ind; + pThis->cmdline [ind++] = '\0'; + break; +#endif + } ind++; } - if (!(ind < limit)) return i; + if (!(ind < limit)) { +#ifdef _USE_QUOTING + if (quote) { + restore (pThis); + return -1; + } +#endif + return i; + } } return i; } @@ -514,6 +579,9 @@ static void microrl_get_complite (microrl_t * pThis) if (pThis->cmdline[pThis->cursor-1] == '\0') tkn_arr[status++] = ""; compl_token = pThis->get_completion (status, tkn_arr); +#ifdef _USE_QUOTING + restore (pThis); +#endif if (compl_token[0] != NULL) { int i = 0; int len; @@ -557,7 +625,11 @@ void new_line_handler(microrl_t * pThis){ status = split (pThis, pThis->cmdlen, tkn_arr); if (status == -1){ // pThis->print ("ERROR: Max token amount exseed\n"); +#ifdef _USE_QUOTING + pThis->print ("ERROR:too many tokens or invalid quoting"); +#else pThis->print ("ERROR:too many tokens"); +#endif pThis->print (ENDL); } if ((status > 0) && (pThis->execute != NULL)) diff --git a/src/microrl.h b/src/microrl.h index 3831afe..9547967 100644 --- a/src/microrl.h +++ b/src/microrl.h @@ -63,6 +63,14 @@ typedef struct { } ring_history_t; #endif +#ifdef _USE_QUOTING +// quoted token struct, point to begin and end marks +typedef struct { + char * begin; + char * end; +} quoted_token_t; +#endif + // microrl struct, contain internal library data typedef struct { #ifdef _USE_ESC_SEQ @@ -79,6 +87,9 @@ typedef struct { char cmdline [_COMMAND_LINE_LEN]; // cmdline buffer int cmdlen; // last position in command line int cursor; // input cursor +#ifdef _USE_QUOTING + quoted_token_t quotes[_QUOTED_TOKEN_NMB];// pointers to quoted tokens +#endif int (*execute) (int argc, const char * const * argv ); // ptr to 'execute' callback char ** (*get_completion) (int argc, const char * const * argv ); // ptr to 'completion' callback void (*print) (const char *); // ptr to 'print' callback From ee1be4399649e9ff8385ff56dc78e45bf91f9b87 Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Thu, 14 Dec 2017 00:14:45 -0800 Subject: [PATCH 09/14] Make microrl_init more complete and more compact Instead of separate memset calls and assignments to initialize various members of the microrl_t struct to zero, just clear the entire struct first and then set the nonzero values. --- src/microrl.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/microrl.c b/src/microrl.c index 933a808..b2eeaf7 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -383,20 +383,7 @@ static void terminal_print_line (microrl_t * pThis, int pos, int cursor) //***************************************************************************** void microrl_init (microrl_t * pThis, void (*print) (const char *)) { - memset(pThis->cmdline, 0, _COMMAND_LINE_LEN); -#ifdef _USE_HISTORY - memset(pThis->ring_hist.ring_buf, 0, _RING_HISTORY_LEN); - pThis->ring_hist.begin = 0; - pThis->ring_hist.end = 0; - pThis->ring_hist.cur = 0; -#endif - pThis->cmdlen =0; - pThis->cursor = 0; - pThis->execute = NULL; - pThis->get_completion = NULL; -#ifdef _USE_CTLR_C - pThis->sigint = NULL; -#endif + memset(pThis, 0, sizeof(microrl_t)); pThis->prompt_str = prompt_default; pThis->print = print; #ifdef _ENABLE_INIT_PROMPT From 7334fbd5a49e517458399cb9ac0c718c806bc4ab Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Thu, 14 Dec 2017 15:14:04 -0800 Subject: [PATCH 10/14] Adapt microrl for embedding in C++ programs 1. Add a 'void* userdata' member to microrl_t that can be used by applications to store a C++ object pointer or other context info. 2. Pass the pointer to microrl_t in all callbacks so that the operations can be specific to a particular instance of microrl. 3. Enclose the definitions in microrl.h in a conditional 'extern "C"' block to allow those definitions to be referenced from C++ files. --- src/microrl.c | 40 ++++++++++++++++++++-------------------- src/microrl.h | 25 +++++++++++++++++-------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/microrl.c b/src/microrl.c index b2eeaf7..ae3adda 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -278,19 +278,19 @@ static int split (microrl_t * pThis, int limit, char const ** tkn_arr) //***************************************************************************** inline static void print_prompt (microrl_t * pThis) { - pThis->print (pThis->prompt_str); + pThis->print (pThis, pThis->prompt_str); } //***************************************************************************** inline static void terminal_backspace (microrl_t * pThis) { - pThis->print ("\033[D \033[D"); + pThis->print (pThis, "\033[D \033[D"); } //***************************************************************************** inline static void terminal_newline (microrl_t * pThis) { - pThis->print (ENDL); + pThis->print (pThis, ENDL); } #ifndef _USE_LIBC_STDIO @@ -339,7 +339,7 @@ static void terminal_move_cursor (microrl_t * pThis, int offset) } else return; #endif - pThis->print (str); + pThis->print (pThis, str); } //***************************************************************************** @@ -358,14 +358,14 @@ static void terminal_reset_cursor (microrl_t * pThis) endstr = u16bit_to_str (_PROMPT_LEN, endstr); strcpy (endstr, "C"); #endif - pThis->print (str); + pThis->print (pThis, str); } //***************************************************************************** // print cmdline to screen, replace '\0' to wihitespace static void terminal_print_line (microrl_t * pThis, int pos, int cursor) { - pThis->print ("\033[K"); // delete all from cursor to end + pThis->print (pThis, "\033[K"); // delete all from cursor to end char nch [] = {0,0}; int i; @@ -373,7 +373,7 @@ static void terminal_print_line (microrl_t * pThis, int pos, int cursor) nch [0] = pThis->cmdline [i]; if (nch[0] == '\0') nch[0] = ' '; - pThis->print (nch); + pThis->print (pThis, nch); } terminal_reset_cursor (pThis); @@ -381,7 +381,7 @@ static void terminal_print_line (microrl_t * pThis, int pos, int cursor) } //***************************************************************************** -void microrl_init (microrl_t * pThis, void (*print) (const char *)) +void microrl_init (microrl_t * pThis, void (*print) (microrl_t*, const char *)) { memset(pThis, 0, sizeof(microrl_t)); pThis->prompt_str = prompt_default; @@ -392,19 +392,19 @@ void microrl_init (microrl_t * pThis, void (*print) (const char *)) } //***************************************************************************** -void microrl_set_complete_callback (microrl_t * pThis, char ** (*get_completion)(int, const char* const*)) +void microrl_set_complete_callback (microrl_t * pThis, char ** (*get_completion)(microrl_t*, int, const char* const*)) { pThis->get_completion = get_completion; } //***************************************************************************** -void microrl_set_execute_callback (microrl_t * pThis, int (*execute)(int, const char* const*)) +void microrl_set_execute_callback (microrl_t * pThis, int (*execute)(microrl_t*, int, const char* const*)) { pThis->execute = execute; } #ifdef _USE_CTLR_C //***************************************************************************** -void microrl_set_sigint_callback (microrl_t * pThis, void (*sigintf)(void)) +void microrl_set_sigint_callback (microrl_t * pThis, void (*sigintf)(microrl_t*)) { pThis->sigint = sigintf; } @@ -565,7 +565,7 @@ static void microrl_get_complite (microrl_t * pThis) return; if (pThis->cmdline[pThis->cursor-1] == '\0') tkn_arr[status++] = ""; - compl_token = pThis->get_completion (status, tkn_arr); + compl_token = pThis->get_completion (pThis, status, tkn_arr); #ifdef _USE_QUOTING restore (pThis); #endif @@ -579,8 +579,8 @@ static void microrl_get_complite (microrl_t * pThis) len = common_len (compl_token); terminal_newline (pThis); while (compl_token [i] != NULL) { - pThis->print (compl_token[i]); - pThis->print (" "); + pThis->print (pThis, compl_token[i]); + pThis->print (pThis, " "); i++; } terminal_newline (pThis); @@ -613,14 +613,14 @@ void new_line_handler(microrl_t * pThis){ if (status == -1){ // pThis->print ("ERROR: Max token amount exseed\n"); #ifdef _USE_QUOTING - pThis->print ("ERROR:too many tokens or invalid quoting"); + pThis->print (pThis, "ERROR:too many tokens or invalid quoting"); #else - pThis->print ("ERROR:too many tokens"); + pThis->print (pThis, "ERROR:too many tokens"); #endif - pThis->print (ENDL); + pThis->print (pThis, ENDL); } if ((status > 0) && (pThis->execute != NULL)) - pThis->execute (status, tkn_arr); + pThis->execute (pThis, status, tkn_arr); print_prompt (pThis); pThis->cmdlen = 0; pThis->cursor = 0; @@ -692,7 +692,7 @@ void microrl_insert_char (microrl_t * pThis, int ch) break; //----------------------------------------------------- case KEY_VT: // ^K - pThis->print ("\033[K"); + pThis->print (pThis,"\033[K"); pThis->cmdlen = pThis->cursor; break; //----------------------------------------------------- @@ -753,7 +753,7 @@ void microrl_insert_char (microrl_t * pThis, int ch) #ifdef _USE_CTLR_C case KEY_ETX: if (pThis->sigint != NULL) - pThis->sigint(); + pThis->sigint(pThis); break; #endif //----------------------------------------------------- diff --git a/src/microrl.h b/src/microrl.h index 9547967..a0ccde1 100644 --- a/src/microrl.h +++ b/src/microrl.h @@ -1,6 +1,10 @@ #ifndef _MICRORL_H_ #define _MICRORL_H_ +#ifdef __cplusplus +extern "C" { +#endif + #include "config.h" #define true 1 @@ -90,16 +94,17 @@ typedef struct { #ifdef _USE_QUOTING quoted_token_t quotes[_QUOTED_TOKEN_NMB];// pointers to quoted tokens #endif - int (*execute) (int argc, const char * const * argv ); // ptr to 'execute' callback - char ** (*get_completion) (int argc, const char * const * argv ); // ptr to 'completion' callback - void (*print) (const char *); // ptr to 'print' callback + int (*execute) (microrl_t* pThis, int argc, const char * const * argv ); // ptr to 'execute' callback + char ** (*get_completion) (microrl_t* pThis, int argc, const char * const * argv ); // ptr to 'completion' callback + void (*print) (microrl_t* pThis, const char *); // ptr to 'print' callback #ifdef _USE_CTLR_C - void (*sigint) (void); + void (*sigint) (microrl_t* pThis); #endif + void* userdata; // Generic user data storage } microrl_t; // init internal data, calls once at start up -void microrl_init (microrl_t * pThis, void (*print)(const char*)); +void microrl_init (microrl_t * pThis, void (*print)(microrl_t* pThis, const char*)); // set echo mode (true/false), using for disabling echo for password input // echo mode will enabled after user press Enter. @@ -111,18 +116,22 @@ void microrl_set_echo (int); // must return NULL-terminated string, contain complite variant splitted by 'Whitespace' // If complite token found, it's must contain only one token to be complitted // Empty string if complite not found, and multiple string if there are some token -void microrl_set_complete_callback (microrl_t * pThis, char ** (*get_completion)(int, const char* const*)); +void microrl_set_complete_callback (microrl_t * pThis, char ** (*get_completion)(microrl_t*, int, const char* const*)); // pointer to callback func, that called when user press 'Enter' // execute func param: argc - argument count, argv - pointer array to token string -void microrl_set_execute_callback (microrl_t * pThis, int (*execute)(int, const char* const*)); +void microrl_set_execute_callback (microrl_t * pThis, int (*execute)(microrl_t*, int, const char* const*)); // set callback for Ctrl+C terminal signal #ifdef _USE_CTLR_C -void microrl_set_sigint_callback (microrl_t * pThis, void (*sigintf)(void)); +void microrl_set_sigint_callback (microrl_t * pThis, void (*sigintf)(microrl_t*)); #endif // insert char to cmdline (for example call in usart RX interrupt) void microrl_insert_char (microrl_t * pThis, int ch); +#ifdef __cplusplus +} +#endif + #endif From 58abf1f5ab1d3ab17df91cf71dfe84f41acdc017 Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Thu, 14 Dec 2017 15:42:00 -0800 Subject: [PATCH 11/14] Define microrl_t type before struct to allow references inside This is a change that was missed in copying over to this repository in the previous commit 7334fbd5a49e517458399cb9ac0c718c806bc4ab. --- src/microrl.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/microrl.h b/src/microrl.h index a0ccde1..3620080 100644 --- a/src/microrl.h +++ b/src/microrl.h @@ -76,7 +76,9 @@ typedef struct { #endif // microrl struct, contain internal library data -typedef struct { +typedef struct microrl microrl_t; + +struct microrl { #ifdef _USE_ESC_SEQ char escape_seq; char escape; @@ -101,7 +103,7 @@ typedef struct { void (*sigint) (microrl_t* pThis); #endif void* userdata; // Generic user data storage -} microrl_t; +}; // init internal data, calls once at start up void microrl_init (microrl_t * pThis, void (*print)(microrl_t* pThis, const char*)); From 7c0d061f9e181776a3cc36341ead61502092ea30 Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Thu, 14 Dec 2017 16:10:23 -0800 Subject: [PATCH 12/14] Adapt the example programs to API changes Change the example code to include the microrl_t pointer as the first argument of all the callbacks as was added to the microrl library in commit 7334fbd5a49e517458399cb9ac0c718c806bc4ab. Note: The changes in avr_misc have not been tested since I don't have a build environment. --- examples/avr_misc/avr_misc.c | 62 ++++++++++++++++---------------- examples/example_misc.h | 8 ++--- examples/unix_misc/unix_misc.c | 64 +++++++++++++++++----------------- 3 files changed, 67 insertions(+), 67 deletions(-) diff --git a/examples/avr_misc/avr_misc.c b/examples/avr_misc/avr_misc.c index d8cce94..50eeb21 100644 --- a/examples/avr_misc/avr_misc.c +++ b/examples/avr_misc/avr_misc.c @@ -50,7 +50,7 @@ void init (void) //} //***************************************************************************** -void print (const char * str) +void print (void * pThis, const char * str) { int i = 0; while (str [i] != 0) { @@ -67,24 +67,24 @@ char get_char (void) } //***************************************************************************** -void print_help (void) +void print_help (void * pThis, void) { - print ("Use TAB key for completion\n\rCommand:\n\r"); - print ("\tclear - clear screen\n\r"); - print ("\tset_port port pin - set 1 port[pin] value, support only 'port_b' and 'port_d'\n\r"); - print ("\tclear_port port pin - set 0 port[pin] value, support only 'port_b' and 'port_d'\n\r"); + print (pThis, "Use TAB key for completion\n\rCommand:\n\r"); + print (pThis, "\tclear - clear screen\n\r"); + print (pThis, "\tset_port port pin - set 1 port[pin] value, support only 'port_b' and 'port_d'\n\r"); + print (pThis, "\tclear_port port pin - set 0 port[pin] value, support only 'port_b' and 'port_d'\n\r"); } //***************************************************************************** -void set_port_val (unsigned char * port, int pin, int val) +void set_port_val (void * pThis, unsigned char * port, int pin, int val) { if ((*port == PORTD) && (pin < 2) && (pin > 7)) { - print ("only 2..7 pin avialable for PORTD\n\r"); + print (pThis, "only 2..7 pin avialable for PORTD\n\r"); return; } if ((*port == PORTB) && (pin > 5)) { - print ("only 0..5 pin avialable for PORTB\n\r"); + print (pThis, "only 0..5 pin avialable for PORTB\n\r"); return; } @@ -98,21 +98,21 @@ void set_port_val (unsigned char * port, int pin, int val) //***************************************************************************** // execute callback for microrl library // do what you want here, but don't write to argv!!! read only!! -int execute (int argc, const char * const * argv) +int execute (void * pThis, int argc, const char * const * argv) { int i = 0; // just iterate through argv word and compare it with your commands while (i < argc) { if (strcmp (argv[i], _CMD_HELP) == 0) { - print ("microrl v"); - print (MICRORL_LIB_VER); - print (" library AVR DEMO v"); - print (_AVR_DEMO_VER); + print (pThis, "microrl v"); + print (pThis, MICRORL_LIB_VER); + print (pThis, " library AVR DEMO v"); + print (pThis, _AVR_DEMO_VER); print("\n\r"); - print_help (); // print help + print_help (pThis); // print help } else if (strcmp (argv[i], _CMD_CLEAR) == 0) { - print ("\033[2J"); // ESC seq for clear entire screen - print ("\033[H"); // ESC seq for move cursor at left-top corner + print (pThis, "\033[2J"); // ESC seq for clear entire screen + print (pThis, "\033[H"); // ESC seq for move cursor at left-top corner } else if ((strcmp (argv[i], _CMD_SET) == 0) || (strcmp (argv[i], _CMD_CLR) == 0)) { if (++i < argc) { @@ -124,29 +124,29 @@ int execute (int argc, const char * const * argv) } else if (strcmp (argv[i], _SCMD_PB) == 0) { port = (unsigned char *)&PORTB; } else { - print ("only '"); - print (_SCMD_PB); - print ("' and '"); - print (_SCMD_PD); - print ("' support\n\r"); + print (pThis, "only '"); + print (pThis, _SCMD_PB); + print (pThis, "' and '"); + print (pThis, _SCMD_PD); + print (pThis, "' support\n\r"); return 1; } if (++i < argc) { pin = atoi (argv[i]); - set_port_val (port, pin, val); + set_port_val (pThis, port, pin, val); return 0; } else { - print ("specify pin number, use Tab\n\r"); + print (pThis, "specify pin number, use Tab\n\r"); return 1; } } else { - print ("specify port, use Tab\n\r"); + print (pThis, "specify port, use Tab\n\r"); return 1; } } else { - print ("command: '"); - print ((char*)argv[i]); - print ("' Not found.\n\r"); + print (pThis, "command: '"); + print (pThis, (char*)argv[i]); + print (pThis, "' Not found.\n\r"); } i++; } @@ -156,7 +156,7 @@ int execute (int argc, const char * const * argv) #ifdef _USE_COMPLETE //***************************************************************************** // completion callback for microrl library -char ** complet (int argc, const char * const * argv) +char ** complet (void * pThis, int argc, const char * const * argv) { int j = 0; @@ -196,7 +196,7 @@ char ** complet (int argc, const char * const * argv) #endif //***************************************************************************** -void sigint (void) +void sigint (void * pThis) { - print ("^C catched!\n\r"); + print (pThis, "^C catched!\n\r"); } diff --git a/examples/example_misc.h b/examples/example_misc.h index d3f98e5..2e797b7 100644 --- a/examples/example_misc.h +++ b/examples/example_misc.h @@ -10,18 +10,18 @@ for AVR, linux PC or ARM void init (void); // print to stream callback -void print (const char * str); +void print (void * pThis, const char * str); // get_char from stream char get_char (void); // execute callback -int execute (int argc, const char * const * argv); +int execute (void * pThis, int argc, const char * const * argv); // completion callback -char ** complet (int argc, const char * const * argv); +char ** complet (void * pThis, int argc, const char * const * argv); // ctrl+c callback -void sigint (void); +void sigint (void * pThis, void); #endif diff --git a/examples/unix_misc/unix_misc.c b/examples/unix_misc/unix_misc.c index cfa7ff1..494f3c4 100644 --- a/examples/unix_misc/unix_misc.c +++ b/examples/unix_misc/unix_misc.c @@ -13,7 +13,7 @@ void init (void){ //***************************************************************************** // print callback for microrl library -void print (const char * str) +void print (void * pThis, const char * str) { fprintf (stdout, "%s", str); } @@ -64,66 +64,66 @@ int val; //***************************************************************************** -void print_help () +void print_help (void * pThis) { - print ("Use TAB key for completion\n\rCommand:\n\r"); - print ("\tversion {microrl | demo} - print version of microrl lib or version of this demo src\n\r"); - print ("\thelp - this message\n\r"); - print ("\tclear - clear screen\n\r"); - print ("\tlist - list all commands in tree\n\r"); - print ("\tname [string] - print 'name' value if no 'string', set name value to 'string' if 'string' present\n\r"); - print ("\tlisp - dummy command for demonstation auto-completion, while inputed 'l+'\n\r"); + print (pThis, "Use TAB key for completion\n\rCommand:\n\r"); + print (pThis, "\tversion {microrl | demo} - print version of microrl lib or version of this demo src\n\r"); + print (pThis, "\thelp - this message\n\r"); + print (pThis, "\tclear - clear screen\n\r"); + print (pThis, "\tlist - list all commands in tree\n\r"); + print (pThis, "\tname [string] - print 'name' value if no 'string', set name value to 'string' if 'string' present\n\r"); + print (pThis, "\tlisp - dummy command for demonstation auto-completion, while inputed 'l+'\n\r"); } //***************************************************************************** // execute callback for microrl library // do what you want here, but don't write to argv!!! read only!! -int execute (int argc, const char * const * argv) +int execute (void * pThis, int argc, const char * const * argv) { int i = 0; // just iterate through argv word and compare it with your commands while (i < argc) { if (strcmp (argv[i], _CMD_HELP) == 0) { - print ("microrl library based shell v 1.0\n\r"); - print_help (); // print help + print (pThis, "microrl library based shell v 1.0\n\r"); + print_help (pThis); // print help } else if (strcmp (argv[i], _CMD_NAME) == 0) { if ((++i) < argc) { // if value preset if (strlen (argv[i]) < _NAME_LEN) { strcpy (name, argv[i]); } else { - print ("name value too long!\n\r"); + print (pThis, "name value too long!\n\r"); } } else { - print (name); - print ("\n\r"); + print (pThis, name); + print (pThis, "\n\r"); } } else if (strcmp (argv[i], _CMD_VER) == 0) { if (++i < argc) { if (strcmp (argv[i], _SCMD_DEMO) == 0) { - print ("demo v 1.0\n\r"); + print (pThis, "demo v 1.0\n\r"); } else if (strcmp (argv[i], _SCMD_MRL) == 0) { - print ("microrl v 1.2\n\r"); + print (pThis, "microrl v 1.2\n\r"); } else { - print ((char*)argv[i]); - print (" wrong argument, see help\n\r"); + print (pThis, (char*)argv[i]); + print (pThis, " wrong argument, see help\n\r"); } } else { - print ("version needs 1 parametr, see help\n\r"); + print (pThis, "version needs 1 parametr, see help\n\r"); } } else if (strcmp (argv[i], _CMD_CLEAR) == 0) { - print ("\033[2J"); // ESC seq for clear entire screen - print ("\033[H"); // ESC seq for move cursor at left-top corner + print (pThis, "\033[2J"); // ESC seq for clear entire screen + print (pThis, "\033[H"); // ESC seq for move cursor at left-top corner } else if (strcmp (argv[i], _CMD_LIST) == 0) { - print ("available command:\n");// print all command per line + print (pThis, "available command:\n");// print all command per line for (int i = 0; i < _NUM_OF_CMD; i++) { - print ("\t"); - print (keyworld[i]); - print ("\n\r"); + print (pThis, "\t"); + print (pThis, keyworld[i]); + print (pThis, "\n\r"); } } else { - print ("command: '"); - print ((char*)argv[i]); - print ("' Not found.\n\r"); + print (pThis, "command: '"); + print (pThis, (char*)argv[i]); + print (pThis, "' Not found.\n\r"); } i++; } @@ -133,7 +133,7 @@ int execute (int argc, const char * const * argv) #ifdef _USE_COMPLETE //***************************************************************************** // completion callback for microrl library -char ** complet (int argc, const char * const * argv) +char ** complet (void * pThis, int argc, const char * const * argv) { int j = 0; @@ -172,7 +172,7 @@ char ** complet (int argc, const char * const * argv) #endif //***************************************************************************** -void sigint (void) +void sigint (void * pThis) { - print ("^C catched!\n\r"); + print (pThis, "^C catched!\n\r"); } From 0babf34aa5bbcc49f3275a95d692b8278177cacf Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Fri, 15 Dec 2017 14:56:18 -0800 Subject: [PATCH 13/14] Bugfix: check for cmdlen > 0 omitted from microrl_delete Typing multiple Ctrl-D while on an empty command line would crash. This was missed in merging changes from another repository. --- src/microrl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/microrl.c b/src/microrl.c index ae3adda..6cead57 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -520,11 +520,13 @@ static void microrl_backspace (microrl_t * pThis) // remove one char forward at cursor static void microrl_delete (microrl_t * pThis) { - memmove (pThis->cmdline + pThis->cursor, - pThis->cmdline + pThis->cursor+1, - pThis->cmdlen-pThis->cursor+1); + if (pThis->cmdlen > 0) { + memmove (pThis->cmdline + pThis->cursor, + pThis->cmdline + pThis->cursor+1, + pThis->cmdlen-pThis->cursor+1); pThis->cmdline [pThis->cmdlen] = '\0'; pThis->cmdlen--; + } } #ifdef _USE_COMPLETE From 15fde9bdf336ae7e8a89c23d07fa4096cdcb7098 Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Fri, 15 Dec 2017 23:00:44 -0800 Subject: [PATCH 14/14] Reduce and consolidate print operations When used over a network connection, each print() call in microrl may be transmitted as a separate packet, so the many small print operations make output slow. This commit optimizes some common cases to avoid unnecessary prints and combines others into a buffer to be printed together. - When adding characters to the end of a command, now just the single character is output. This avoids cursor jumping. Similarly, when backspacing at the end of the line, just the simple sequence back-one, space, back-one is sufficient. - The biggest number of back-to-back print operations occurred in terminal_print_line() where each character was printed separately. Now the characters are packed into a temporary buffer first so they can be printed in one or a few operations, depending upon the command length and buffer size. Positioning sequences are also consolidated into the buffer. - Some calls to terminal_reset_cursor() that were changed to call terminal_move_cursor() instead since the latter outputs fewer characters and avoids extra jumping of the cursor on slow lines. The code to reset the cursor position was then incorporated into terminal_print_line() where those positioning operations can be consolidated into a print buffer. Since the reset is not always necessary, an argument controls whether it is done. - A new define _USE_CARRIAGE_RETURN controls using a carriate return to reposition the cursor to the left margin rather than moving left by a large number. This takes fewer characters. This optimization can be turned off if the terminal simulates receiving a linefeed when it receives the carriage return. - In terminal_print_line(), the delete-to-end-of-line escape sequence is moved to be output after all of the command text. This avoids a flash of the text going away and then being repainted. - The code to create repositioning sequences was extracted into a separate function generate_move_cursor() so it can be shared between terminal_move_cursor() and terminal_print_line(). - After reorganizing the code to generate repositioning strings there was only one call to u16bit_to_str(), so it was merged inline. - strcpy() calls of just a few characters are replaced by depositing the characters individually. This removes a dependency and may use fewer instructions. - To allow ^U to backspace across all of the characters to the left of the curso in one motion, microrl_backspace() now takes a parameter for the number of spaces to move rather than always moving one. --- src/config.h | 18 ++++- src/microrl.c | 190 ++++++++++++++++++++++++++------------------------ 2 files changed, 112 insertions(+), 96 deletions(-) diff --git a/src/config.h b/src/config.h index ef8c899..b9238be 100644 --- a/src/config.h +++ b/src/config.h @@ -67,19 +67,31 @@ but memory using more effective. We not prefer dinamic memory allocation for small and embedded devices. Overhead is 2 char on each saved line*/ #define _RING_HISTORY_LEN 64 +/* +Size of the buffer used for piecemeal printing of part or all of the command +line. Allocated on the stack. Must be at least 16. */ +#define _PRINT_BUFFER_LEN 40 + /* Enable Handling terminal ESC sequence. If disabling, then cursor arrow, HOME, END will not work, use Ctrl+A(B,F,P,N,A,E,H,K,U,C) see README, but decrease code memory.*/ #define _USE_ESC_SEQ /* -Use snprintf from you standard complier library, but it gives some overhead. -If not defined, use my own u16int_to_str variant, it's save about 800 byte of code size -on AVR (avr-gcc build). +Use sprintf from you standard complier library, but it gives some overhead. +If not defined, use my own number conversion code, it's save about 800 byte of +code size on AVR (avr-gcc build). Try to build with and without, and compare total code size for tune library. */ #define _USE_LIBC_STDIO +/* +Use a single carriage return character to move the cursor to the left margin +rather than moving left by a large number. This reduces the number of +characters sent to the terminal, but should be left undefined if the terminal +will also simulate a linefeed when it receives the carriage return. */ +#define _USE_CARRIAGE_RETURN + /* Enable 'interrupt signal' callback, if user press Ctrl+C */ #define _USE_CTLR_C diff --git a/src/microrl.c b/src/microrl.c index 6cead57..9422265 100644 --- a/src/microrl.c +++ b/src/microrl.c @@ -293,91 +293,87 @@ inline static void terminal_newline (microrl_t * pThis) pThis->print (pThis, ENDL); } -#ifndef _USE_LIBC_STDIO //***************************************************************************** -// convert 16 bit value to string -// 0 value not supported!!! just make empty string -// Returns pointer to a buffer tail -static char *u16bit_to_str (unsigned int nmb, char * buf) +// set cursor at current position + offset (positive or negative). +// the provided buffer must be at least 7 bytes long. +static char* generate_move_cursor (char* str, int offset) { - char tmp_str [6] = {0,}; + char c = 'C'; + if (offset > 999) + offset = 999; + if (offset < -999) + offset = -999; + if (offset < 0) { + offset = -offset; + c = 'D'; + } else if (offset == 0) { + *str = '\0'; + return str; + } + +#ifdef _USE_LIBC_STDIO + str += sprintf (str, "\033[%d%c", offset, c); +#else + *str++ = '\033'; + *str++ = '['; + char tmp_str [4] = {0,}; int i = 0, j; - if (nmb <= 0xFFFF) { - while (nmb > 0) { - tmp_str[i++] = (nmb % 10) + '0'; - nmb /=10; - } - for (j = 0; j < i; ++j) - *(buf++) = tmp_str [i-j-1]; + while (offset > 0) { + tmp_str[i++] = (offset % 10) + '0'; + offset /=10; } - *buf = '\0'; - return buf; -} + for (j = 0; j < i; ++j) + *str++ = tmp_str [i-j-1]; + *str++ = c; + *str = '\0'; #endif - + return str; +} //***************************************************************************** -// set cursor at position from begin cmdline (after prompt) + offset +// set cursor at current position + offset (positive or negative) static void terminal_move_cursor (microrl_t * pThis, int offset) { char str[16] = {0,}; -#ifdef _USE_LIBC_STDIO - if (offset > 0) { - snprintf (str, 16, "\033[%dC", offset); - } else if (offset < 0) { - snprintf (str, 16, "\033[%dD", -(offset)); + if (offset != 0) { + generate_move_cursor (str, offset); + pThis->print (pThis, str); } -#else - char *endstr; - strcpy (str, "\033["); - if (offset > 0) { - endstr = u16bit_to_str (offset, str+2); - strcpy (endstr, "C"); - } else if (offset < 0) { - endstr = u16bit_to_str (-(offset), str+2); - strcpy (endstr, "D"); - } else - return; -#endif - pThis->print (pThis, str); } //***************************************************************************** -static void terminal_reset_cursor (microrl_t * pThis) +// print cmdline to screen, replace '\0' to whitespace +static void terminal_print_line (microrl_t * pThis, int pos, int reset) { - char str[16]; -#ifdef _USE_LIBC_STDIO - snprintf (str, 16, "\033[%dD\033[%dC", \ - _COMMAND_LINE_LEN + _PROMPT_LEN + 2, _PROMPT_LEN); - + char str[_PRINT_BUFFER_LEN]; + char *j = str; + if (reset) { +#ifdef _USE_CARRIAGE_RETURN + *j++ = '\r'; + j = generate_move_cursor(j, _PROMPT_LEN + pos); #else - char *endstr; - strcpy (str, "\033["); - endstr = u16bit_to_str ( _COMMAND_LINE_LEN + _PROMPT_LEN + 2,str+2); - strcpy (endstr, "D\033["); endstr += 3; - endstr = u16bit_to_str (_PROMPT_LEN, endstr); - strcpy (endstr, "C"); + j = generate_move_cursor(j, -(_COMMAND_LINE_LEN + _PROMPT_LEN + 2)); + j = generate_move_cursor(j, _PROMPT_LEN + pos); #endif - pThis->print (pThis, str); -} - -//***************************************************************************** -// print cmdline to screen, replace '\0' to wihitespace -static void terminal_print_line (microrl_t * pThis, int pos, int cursor) -{ - pThis->print (pThis, "\033[K"); // delete all from cursor to end - - char nch [] = {0,0}; - int i; - for (i = pos; i < pThis->cmdlen; i++) { - nch [0] = pThis->cmdline [i]; - if (nch[0] == '\0') - nch[0] = ' '; - pThis->print (pThis, nch); } - - terminal_reset_cursor (pThis); - terminal_move_cursor (pThis, cursor); + for (int i = pos; i < pThis->cmdlen; i++) { + *j++ = (pThis->cmdline [i] == '\0') ? ' ' : pThis->cmdline [i]; + if (j-str == sizeof(str)-1) { + *j = '\0'; + pThis->print (pThis, str); + j = str; + } + } + if (j - str + 3+6+1 > _PRINT_BUFFER_LEN) { + *j = '\0'; + pThis->print (pThis, str); + j = str; + } + *j++ = '\033'; // delete all past end of text + *j++ = '['; + *j++ = 'K'; + generate_move_cursor (j, pThis->cursor - pThis->cmdlen); + pThis->print (pThis, str); } //***************************************************************************** @@ -417,8 +413,7 @@ static void hist_search (microrl_t * pThis, int dir) if (len >= 0) { pThis->cmdline[len] = '\0'; pThis->cursor = pThis->cmdlen = len; - terminal_reset_cursor (pThis); - terminal_print_line (pThis, 0, pThis->cursor); + terminal_print_line (pThis, 0, 1); } } #endif @@ -463,7 +458,7 @@ static int escape_process (microrl_t * pThis, char ch) } } else if (ch == '~') { if (pThis->escape_seq == _ESC_HOME) { - terminal_reset_cursor (pThis); + terminal_move_cursor (pThis, -pThis->cursor); pThis->cursor = 0; return 1; } else if (pThis->escape_seq == _ESC_END) { @@ -502,17 +497,16 @@ static int microrl_insert_text (microrl_t * pThis, char * text, int len) } //***************************************************************************** -// remove one char at cursor -static void microrl_backspace (microrl_t * pThis) +// remove len chars backwards at cursor +static void microrl_backspace (microrl_t * pThis, int len) { - if (pThis->cursor > 0) { - terminal_backspace (pThis); - memmove (pThis->cmdline + pThis->cursor-1, + if (pThis->cursor >= len) { + memmove (pThis->cmdline + pThis->cursor-len, pThis->cmdline + pThis->cursor, - pThis->cmdlen-pThis->cursor+1); - pThis->cursor--; + pThis->cmdlen-pThis->cursor+len); + pThis->cursor -= len; pThis->cmdline [pThis->cmdlen] = '\0'; - pThis->cmdlen--; + pThis->cmdlen -= len; } } @@ -574,6 +568,7 @@ static void microrl_get_complite (microrl_t * pThis) if (compl_token[0] != NULL) { int i = 0; int len; + int pos = pThis->cursor; if (compl_token[1] == NULL) { len = strlen (compl_token[0]); @@ -587,6 +582,7 @@ static void microrl_get_complite (microrl_t * pThis) } terminal_newline (pThis); print_prompt (pThis); + pos = 0; } if (len) { @@ -595,8 +591,7 @@ static void microrl_get_complite (microrl_t * pThis) if (compl_token[1] == NULL) microrl_insert_text (pThis, " ", 1); } - terminal_reset_cursor (pThis); - terminal_print_line (pThis, 0, pThis->cursor); + terminal_print_line (pThis, pos, 0); } } #endif @@ -687,10 +682,9 @@ void microrl_insert_char (microrl_t * pThis, int ch) break; //----------------------------------------------------- case KEY_NAK: // ^U - while (pThis->cursor > 0) { - microrl_backspace (pThis); - } - terminal_print_line (pThis, 0, pThis->cursor); + if (pThis->cursor > 0) + microrl_backspace (pThis, pThis->cursor); + terminal_print_line (pThis, 0, 1); break; //----------------------------------------------------- case KEY_VT: // ^K @@ -704,7 +698,7 @@ void microrl_insert_char (microrl_t * pThis, int ch) break; //----------------------------------------------------- case KEY_SOH: // ^A - terminal_reset_cursor (pThis); + terminal_move_cursor (pThis, -pThis->cursor); pThis->cursor = 0; break; //----------------------------------------------------- @@ -736,20 +730,24 @@ void microrl_insert_char (microrl_t * pThis, int ch) //----------------------------------------------------- case KEY_DEL: // Backspace case KEY_BS: // ^H - microrl_backspace (pThis); - terminal_print_line (pThis, pThis->cursor, pThis->cursor); + if (pThis->cursor > 0) { + microrl_backspace (pThis, 1); + if (pThis->cursor == pThis->cmdlen) + terminal_backspace (pThis); + else + terminal_print_line (pThis, pThis->cursor, 1); + } break; //----------------------------------------------------- case KEY_EOT: // ^D microrl_delete (pThis); - terminal_print_line (pThis, pThis->cursor, pThis->cursor); + terminal_print_line (pThis, pThis->cursor, 0); break; //----------------------------------------------------- case KEY_DC2: // ^R terminal_newline (pThis); print_prompt (pThis); - terminal_reset_cursor (pThis); - terminal_print_line (pThis, 0, pThis->cursor); + terminal_print_line (pThis, 0, 0); break; //----------------------------------------------------- #ifdef _USE_CTLR_C @@ -762,9 +760,15 @@ void microrl_insert_char (microrl_t * pThis, int ch) default: if (((ch == ' ') && (pThis->cmdlen == 0)) || IS_CONTROL_CHAR(ch)) break; - if (microrl_insert_text (pThis, (char*)&ch, 1)) - terminal_print_line (pThis, pThis->cursor-1, pThis->cursor); - + if (microrl_insert_text (pThis, (char*)&ch, 1)) { + if (pThis->cursor == pThis->cmdlen) { + char nch [] = {0,0}; + nch[0] = ch; + pThis->print (pThis, nch); + } else { + terminal_print_line (pThis, pThis->cursor-1, 0); + } + } break; } #ifdef _USE_ESC_SEQ