Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
microrl.c
Go to the documentation of this file.
1/*
2 Author: Samoylov Eugene aka Helius (ghelius@gmail.com)
3 BUGS and TODO:
4 -- add echo_off feature
5 -- rewrite history for use more than 256 byte buffer
6*/
7
8#include <string.h>
9#include <ctype.h>
10#include <stdlib.h>
11#include "microrl.h"
12#ifdef _USE_LIBC_STDIO
13#include <stdio.h>
14#endif
15
16//#define DEBUG_MRL
17#ifdef DEBUG_MRL
18#include "ch.h"
19#include "printf.h"
20#include "hal.h"
21
22
23#endif // DEBUG_MRL
24
25
26//#define DBG(...) fprintf(stderr, "\033[33m");fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\033[0m");
27
29
30#ifdef __GNUC__
31#pragma GCC diagnostic push
32#pragma GCC diagnostic ignored "-Wstrict-overflow"
33#endif
34
35
36#ifdef _USE_HISTORY
37
38#ifdef _HISTORY_DEBUG
39//*****************************************************************************
40// print buffer content on screen
41static void print_hist (ring_history_t * pThis)
42{
43 printf ("\n");
44 for (int i = 0; i < _RING_HISTORY_LEN; i++) {
45 if (i == pThis->begin)
46 printf ("b");
47 else
48 printf (" ");
49 }
50 printf ("\n");
51 for (int i = 0; i < _RING_HISTORY_LEN; i++) {
52 if (isalpha(pThis->ring_buf[i]))
53 printf ("%c", pThis->ring_buf[i]);
54 else
55 printf ("%d", pThis->ring_buf[i]);
56 }
57 printf ("\n");
58 for (int i = 0; i < _RING_HISTORY_LEN; i++) {
59 if (i == pThis->end)
60 printf ("e");
61 else
62 printf (" ");
63 }
64 printf ("\n");
65}
66#endif
67
68//*****************************************************************************
69// remove older message from ring buffer
71{
72 int new_pos = pThis->begin + pThis->ring_buf [pThis->begin] + 1;
75
76 pThis->begin = new_pos;
77}
78
79//*****************************************************************************
80// check space for new line, remove older while not space
82{
83 if (pThis->ring_buf [pThis->begin] == 0)
84 return true;
85 if (pThis->end >= pThis->begin) {
86 if (_RING_HISTORY_LEN - pThis->end + pThis->begin - 1 > len)
87 return true;
88 } else {
89 if (pThis->begin - pThis->end - 1> len)
90 return true;
91 }
92 return false;
93}
94
95//*****************************************************************************
96// put line to ring buffer
97static void hist_save_line (ring_history_t * pThis, char * line, int len)
98{
99 if (len > _RING_HISTORY_LEN - 2)
100 return;
101 while (!hist_is_space_for_new (pThis, len)) {
103 }
104 // if it's first line
105 if (pThis->ring_buf [pThis->begin] == 0)
106 pThis->ring_buf [pThis->begin] = len;
107
108 // store line
110 memmove (pThis->ring_buf + pThis->end + 1, line, len);
111 else {
112 int part_len = _RING_HISTORY_LEN-pThis->end-1;
113 memmove (pThis->ring_buf + pThis->end + 1, line, part_len);
114 memmove (pThis->ring_buf, line + part_len, len - part_len);
115 }
116 pThis->ring_buf [pThis->end] = len;
117 pThis->end = pThis->end + len + 1;
118 if (pThis->end >= _RING_HISTORY_LEN)
119 pThis->end -= _RING_HISTORY_LEN;
120 pThis->ring_buf [pThis->end] = 0;
121 pThis->cur = 0;
122#ifdef _HISTORY_DEBUG
124#endif
125}
126
127//*****************************************************************************
128// copy saved line to 'line' and return size of line
129
130
131static int hist_restore_line (ring_history_t * pThis, char * line, int dir)
132{
133 int cnt = 0;
134 // count history record
135 int header = pThis->begin;
136 while (pThis->ring_buf [header] != 0) {
137 header += pThis->ring_buf [header] + 1;
138 if (header >= _RING_HISTORY_LEN)
139 header -= _RING_HISTORY_LEN;
140 cnt++;
141 }
142
143 if (dir == _HIST_UP) {
144 if (cnt >= pThis->cur) {
145 int lheader = pThis->begin;
146 int j = 0;
147 // found record for 'pThis->cur' index
148 while ((pThis->ring_buf [lheader] != 0) && (cnt - j -1 != pThis->cur)) {
149 lheader += pThis->ring_buf [lheader] + 1;
152 j++;
153 }
154 if (pThis->ring_buf[lheader]) {
155 pThis->cur++;
156 // obtain saved line
157 if ((pThis->ring_buf [lheader] + lheader + 1) < _RING_HISTORY_LEN) {
158 // fix from coverity scan
159 /*
160 CID 60358 (#1 of 2): Out-of-bounds read (OVERRUN)30.
161 overrun-local: Overrunning array of 256 bytes at byte offset 256
162 by dereferencing pointer &pThis->ring_buf[lheader] + 1
163 */
164 memmove (line, pThis->ring_buf + lheader + 1, pThis->ring_buf[lheader]);
165 } else {
166 int part0 = _RING_HISTORY_LEN - lheader - 1;
167 memmove (line, pThis->ring_buf + lheader + 1, part0);
168 memmove (line + part0, pThis->ring_buf, pThis->ring_buf[lheader] - part0);
169 }
170 return pThis->ring_buf[lheader];
171 }
172 }
173 } else {
174 if (pThis->cur > 0) {
175 pThis->cur--;
176 int lheader = pThis->begin;
177 int j = 0;
178
179 while ((pThis->ring_buf [lheader] != 0) && (cnt - j != pThis->cur)) {
180 lheader += pThis->ring_buf [lheader] + 1;
183 j++;
184 }
185 if ((pThis->ring_buf [lheader] + lheader +1) < _RING_HISTORY_LEN) {
186 memmove (line, pThis->ring_buf + lheader + 1, pThis->ring_buf[lheader]);
187 } else {
188 int part0 = _RING_HISTORY_LEN - lheader - 1;
189 memmove (line, pThis->ring_buf + lheader + 1, part0);
190 memmove (line + part0, pThis->ring_buf, pThis->ring_buf[lheader] - part0);
191 }
192 return pThis->ring_buf[lheader];
193 }
194 }
195 return 0;
196}
197
198
199#endif
200
201
202//*****************************************************************************
203// split cmdline to tkn array and return nmb of token
204static int split (microrl_t * pThis, int limit)
205{
206 int i = 0;
207 int ind = 0;
208 while (1) {
209 // go to the first whitespace (zerro for us)
210 while ((pThis->cmdline [ind] == '\0') && (ind < limit)) {
211 ind++;
212 }
213 if (!(ind < limit)) return i;
214 pThis->tkn_arr[i++] = pThis->cmdline + ind;
215 if (i >= _COMMAND_TOKEN_NMB) {
216 return -1;
217 }
218 // go to the first NOT whitespace (not zerro for us)
219 while ((pThis->cmdline [ind] != '\0') && (ind < limit)) {
220 ind++;
221 }
222 if (!(ind < limit)) return i;
223 }
224 return i;
225}
226
227
228//*****************************************************************************
229inline static void print_prompt (microrl_t * pThis)
230{
231 pThis->print (pThis->prompt_str);
232}
233
234//*****************************************************************************
235inline static void terminal_backspace (microrl_t * pThis)
236{
237 pThis->print ("\033[D \033[D");
238}
239
240//*****************************************************************************
241inline static void terminal_newline (microrl_t * pThis)
242{
243 pThis->print (ENDL);
244}
245
246#ifndef _USE_LIBC_STDIO
247//*****************************************************************************
248// convert 16 bit value to string
249// 0 value not supported!!! just make empty string
250static void u16bit_to_str (unsigned int nmb, char * buf)
251{
252 char tmp_str [6] = {0,};
253 int i = 0;
254 if (nmb <= 0xFFFF) {
255 while (nmb > 0) {
256 tmp_str[i++] = (nmb % 10) + '0';
257 nmb /=10;
258 }
259 for (int j = 0; j < i; ++j)
260 *(buf++) = tmp_str [i-j-1];
261 }
262 *buf = '\0';
263}
264#endif
265
266
267//*****************************************************************************
268// set cursor at position from begin cmdline (after prompt) + offset
270{
271 char str[16] = {0,};
272#ifdef _USE_LIBC_STDIO
273 if (offset > 0) {
274 snprintf (str, 16, "\033[%dC", offset);
275 } else if (offset < 0) {
276 snprintf (str, 16, "\033[%dD", -(offset));
277 }
278#else
279 strcpy (str, "\033[");
280 if (offset > 0) {
282 strcat (str, "C");
283 } else if (offset < 0) {
284 u16bit_to_str (-(offset), str+2);
285 strcat (str, "D");
286 } else
287 return;
288#endif
289 pThis->print (str);
290}
291
292//*****************************************************************************
294{
295 char str[16];
296#ifdef _USE_LIBC_STDIO
297 snprintf (str, 16, "\033[%dD\033[%dC", \
299
300#else
301 strcpy (str, "\033[");
303 strcat (str, "D\033[");
305 strcat (str, "C");
306#endif
307 pThis->print (str);
308}
309
310//*****************************************************************************
311// print cmdline to screen, replace '\0' to wihitespace
312static void terminal_print_line (microrl_t * pThis, int pos, int cursor)
313{
314 pThis->print ("\033[K"); // delete all from cursor to end
315
316 char nch [] = {0,0};
317 for (int i = pos; i < pThis->cmdlen; i++) {
318 nch [0] = pThis->cmdline [i];
319 if (nch[0] == '\0')
320 nch[0] = ' ';
321 pThis->print (nch);
322 }
323
325 terminal_move_cursor (pThis, cursor);
326}
327
328//*****************************************************************************
329void microrl_init (microrl_t * pThis, void (*print) (const char *))
330{
331 memset(pThis->cmdline, 0, _COMMAND_LINE_LEN);
332#ifdef _USE_HISTORY
333 memset(pThis->ring_hist.ring_buf, 0, _RING_HISTORY_LEN);
334 pThis->ring_hist.begin = 0;
335 pThis->ring_hist.end = 0;
336 pThis->ring_hist.cur = 0;
337#endif
338 pThis->cmdlen =0;
339 pThis->cursor = 0;
340 pThis->execute = NULL;
341 pThis->get_completion = NULL;
342#ifdef _USE_CTLR_C
343 pThis->sigint = NULL;
344#endif
345 pThis->prompt_str = prompt_default;
346 pThis->print = print;
347#ifdef _ENABLE_INIT_PROMPT
349#endif
350}
351
352//*****************************************************************************
354 const char ** (*get_completion)(int, const char* const*))
355{
356 pThis->get_completion = get_completion;
357}
358
359//*****************************************************************************
360void microrl_set_execute_callback (microrl_t * pThis, void (*execute)(int, const char* const*))
361{
362 pThis->execute = execute;
363}
364#ifdef _USE_CTLR_C
365//*****************************************************************************
367{
368 pThis->sigint = sigintf;
369}
370#endif
371
372#ifdef _USE_ESC_SEQ
373static void hist_search (microrl_t * pThis, int dir)
374{
375 int len = hist_restore_line (&pThis->ring_hist, pThis->cmdline, dir);
376 if (len) {
377 pThis->cursor = pThis->cmdlen = len;
379 terminal_print_line (pThis, 0, pThis->cursor);
380 }
381}
382
383//*****************************************************************************
384// handling escape sequences
385static int escape_process (microrl_t * pThis, char ch)
386{
387 static int seq = 0;
388
389 if (ch == '[') {
390 seq = _ESC_BRACKET;
391 } else if (seq == _ESC_BRACKET) {
392 if (ch == 'A') {
393#ifdef _USE_HISTORY
395#endif
396 return 1;
397 } else if (ch == 'B') {
398#ifdef _USE_HISTORY
400#endif
401 return 1;
402 } else if (ch == 'C') {
403 if (pThis->cursor < pThis->cmdlen) {
405 pThis->cursor++;
406 }
407 return 1;
408 } else if (ch == 'D') {
409 if (pThis->cursor > 0) {
411 pThis->cursor--;
412 }
413 return 1;
414 } else if (ch == '7') {
415 seq = _ESC_HOME;
416 return 0;
417 } else if (ch == '8') {
418 seq = _ESC_END;
419 return 0;
420 }
421 } else if (ch == '~') {
422 if (seq == _ESC_HOME) {
424 pThis->cursor = 0;
425 return 1;
426 } else if (seq == _ESC_END) {
427 terminal_move_cursor (pThis, pThis->cmdlen-pThis->cursor);
428 pThis->cursor = pThis->cmdlen;
429 return 1;
430 }
431
432 }
433 return 0;
434}
435#endif
436
437//*****************************************************************************
438// insert len char of text at cursor position
439static int microrl_insert_text (microrl_t * pThis, const char * text, int len)
440{
441#pragma GCC diagnostic push
442#pragma GCC diagnostic ignored "-Wstrict-overflow"
443 if (pThis->cmdlen + len < _COMMAND_LINE_LEN) {
444#pragma GCC diagnostic pop
445 if (pThis->cmdlen != pThis->cursor) {
446 memmove (pThis->cmdline + pThis->cursor + len,
447 pThis->cmdline + pThis->cursor,
448 pThis->cmdlen - pThis->cursor);
449 }
450
451 for (int i = 0; i < len; i++) {
452 pThis->cmdline [pThis->cursor + i] = text [i];
453 if (pThis->cmdline [pThis->cursor + i] == ' ') {
454 pThis->cmdline [pThis->cursor + i] = 0;
455 }
456 }
457 pThis->cursor += len;
458 pThis->cmdlen += len;
459 pThis->cmdline [pThis->cmdlen] = '\0';
460 return true;
461 }
462 return false;
463}
464
465//*****************************************************************************
466// remove one char at cursor
468{
469 if (pThis->cursor > 0) {
471 if ((pThis->cmdlen-pThis->cursor+1) != 0) {
472 memmove (pThis->cmdline + pThis->cursor-1,
473 pThis->cmdline + pThis->cursor,
474 pThis->cmdlen-pThis->cursor+1);
475 }
476 pThis->cursor--;
477 pThis->cmdline [pThis->cmdlen] = '\0';
478 pThis->cmdlen--;
479 }
480}
481
482
483#ifdef _USE_COMPLETE
484
485//*****************************************************************************
486static int common_len (const char ** arr)
487{
488 int len = 0;
489 int i = 1;
490 while (1) {
491 while (arr[i]!=NULL) {
492 if ((arr[i][len] != arr[i-1][len]) ||
493 (arr[i][len] == '\0') ||
494 (arr[i-1][len]=='\0'))
495 return len;
496 len++;
497 }
498 i++;
499 }
500 return 0;
501}
502
503//*****************************************************************************
505{
506 const char ** compl_token;
507
508 if (pThis->get_completion == NULL) // callback was not set
509 return;
510
511 int status = split (pThis, pThis->cursor);
512 if (pThis->cmdline[pThis->cursor-1] == '\0')
513 pThis->tkn_arr[status++] = "";
514 compl_token = pThis->get_completion (status, pThis->tkn_arr);
515 if (compl_token[0] != NULL) {
516 int i = 0;
517 int len;
518
519 if (compl_token[1] == NULL) {
520 len = strlen (compl_token[0]);
521 } else {
522 len = common_len (compl_token);
524 while (compl_token [i] != NULL) {
525 pThis->print (compl_token[i]);
526 pThis->print (" ");
527 i++;
528 }
531 }
532
533 if (len) {
535 len - strlen(pThis->tkn_arr[status-1]));
536 if (compl_token[1] == NULL)
537 microrl_insert_text (pThis, " ", 1);
538 }
540 terminal_print_line (pThis, 0, pThis->cursor);
541 }
542}
543#endif
544
545//*****************************************************************************
547 int status;
548
550#ifdef _USE_HISTORY
551 if (pThis->cmdlen > 0)
552 hist_save_line (&pThis->ring_hist, pThis->cmdline, pThis->cmdlen);
553#endif
554 status = split (pThis, pThis->cmdlen);
555 if (status == -1){
556 // pThis->print ("ERROR: Max token amount exseed\n");
557 pThis->print ("ERROR:too many tokens");
558 pThis->print (ENDL);
559 }
560 if ((status > 0) && (pThis->execute != NULL))
561 pThis->execute (status, pThis->tkn_arr);
563 pThis->cmdlen = 0;
564 pThis->cursor = 0;
565 memset(pThis->cmdline, 0, _COMMAND_LINE_LEN);
566#ifdef _USE_HISTORY
567 pThis->ring_hist.cur = 0;
568#endif
569}
570
571//*****************************************************************************
572#if (defined(_ENDL_CRLF) || defined(_ENDL_LFCR))
573static int tmpch = 0;
574#endif
575
577{
578
579#ifdef _USE_ESC_SEQ
580 static int escape = false;
581
582 if (escape) {
583 if (escape_process(pThis, ch))
584 escape = 0;
585 } else {
586#endif
587 switch (ch) {
588 //-----------------------------------------------------
589#ifdef _ENDL_CR
590 case KEY_CR:
592 break;
593 case KEY_LF:
594 break;
595#elif defined(_ENDL_CRLF)
596 case KEY_CR:
597 tmpch = KEY_CR;
598 break;
599 case KEY_LF:
600 if (tmpch == KEY_CR)
602 break;
603#elif defined(_ENDL_LFCR)
604 case KEY_LF:
605 tmpch = KEY_LF;
606 break;
607 case KEY_CR:
608 if (tmpch == KEY_LF)
610 break;
611#else
612 case KEY_CR:
613 break;
614 case KEY_LF:
616 break;
617#endif
618 //-----------------------------------------------------
619#ifdef _USE_COMPLETE
620 case KEY_HT:
622 break;
623#endif
624 //-----------------------------------------------------
625 case KEY_ESC:
626#ifdef _USE_ESC_SEQ
627 escape = 1;
628#endif
629 break;
630 //-----------------------------------------------------
631 case KEY_NAK: // ^U
632 while (pThis->cursor > 0) {
634 }
635 terminal_print_line (pThis, 0, pThis->cursor);
636 break;
637 //-----------------------------------------------------
638 case KEY_VT: // ^K
639 pThis->print ("\033[K");
640 pThis->cmdlen = pThis->cursor;
641 break;
642 //-----------------------------------------------------
643 case KEY_ENQ: // ^E
644 terminal_move_cursor (pThis, pThis->cmdlen-pThis->cursor);
645 pThis->cursor = pThis->cmdlen;
646 break;
647 //-----------------------------------------------------
648 case KEY_SOH: // ^A
650 pThis->cursor = 0;
651 break;
652 //-----------------------------------------------------
653 case KEY_ACK: // ^F
654 if (pThis->cursor < pThis->cmdlen) {
656 pThis->cursor++;
657 }
658 break;
659 //-----------------------------------------------------
660 case KEY_STX: // ^B
661 if (pThis->cursor) {
663 pThis->cursor--;
664 }
665 break;
666 //-----------------------------------------------------
667 case KEY_DLE: //^P
668#ifdef _USE_HISTORY
670#endif
671 break;
672 //-----------------------------------------------------
673 case KEY_SO: //^N
674#ifdef _USE_HISTORY
676#endif
677 break;
678 //-----------------------------------------------------
679 case KEY_DEL: // Backspace
680 case KEY_BS: // ^U
682 terminal_print_line (pThis, pThis->cursor, pThis->cursor);
683 break;
684#ifdef _USE_CTLR_C
685 case KEY_ETX:
686 if (pThis->sigint != NULL)
687 pThis->sigint();
688 break;
689#endif
690 //-----------------------------------------------------
691 default:
692 if ((ch == ' ') && (pThis->cmdlen == 0))
693 break;
694 if (microrl_insert_text (pThis, (char*)&ch, 1))
695 terminal_print_line (pThis, pThis->cursor-1, pThis->cursor);
696
697 break;
698 }
699#ifdef _USE_ESC_SEQ
700 }
701#endif
702}
703
static uint8_t status
static const float offset[]
uint16_t foo
Definition main_demo5.c:58
#define ENDL
#define _PROMPT_LEN
#define _COMMAND_TOKEN_NMB
#define _RING_HISTORY_LEN
#define _COMMAND_LINE_LEN
#define _PROMPT_DEFAUTL
static void hist_save_line(ring_history_t *pThis, char *line, int len)
Definition microrl.c:97
static int escape_process(microrl_t *pThis, char ch)
Definition microrl.c:385
void new_line_handler(microrl_t *pThis)
Definition microrl.c:546
static int hist_is_space_for_new(ring_history_t *pThis, int len)
Definition microrl.c:81
static int split(microrl_t *pThis, int limit)
Definition microrl.c:204
void microrl_set_complete_callback(microrl_t *pThis, const char **(*get_completion)(int, const char *const *))
Definition microrl.c:353
void microrl_init(microrl_t *pThis, void(*print)(const char *))
Definition microrl.c:329
static void print_prompt(microrl_t *pThis)
Definition microrl.c:229
static void hist_erase_older(ring_history_t *pThis)
Definition microrl.c:70
static void microrl_backspace(microrl_t *pThis)
Definition microrl.c:467
char * prompt_default
Definition microrl.c:28
static void terminal_backspace(microrl_t *pThis)
Definition microrl.c:235
static void hist_search(microrl_t *pThis, int dir)
Definition microrl.c:373
static int common_len(const char **arr)
Definition microrl.c:486
static void terminal_reset_cursor(microrl_t *pThis)
Definition microrl.c:293
static void microrl_get_complite(microrl_t *pThis)
Definition microrl.c:504
static int hist_restore_line(ring_history_t *pThis, char *line, int dir)
Definition microrl.c:131
static void terminal_print_line(microrl_t *pThis, int pos, int cursor)
Definition microrl.c:312
void microrl_insert_char(microrl_t *pThis, int ch)
Definition microrl.c:576
static void terminal_newline(microrl_t *pThis)
Definition microrl.c:241
static int microrl_insert_text(microrl_t *pThis, const char *text, int len)
Definition microrl.c:439
static void terminal_move_cursor(microrl_t *pThis, int offset)
Definition microrl.c:269
void microrl_set_sigint_callback(microrl_t *pThis, void(*sigintf)(void))
Definition microrl.c:366
void microrl_set_execute_callback(microrl_t *pThis, void(*execute)(int, const char *const *))
Definition microrl.c:360
static void u16bit_to_str(unsigned int nmb, char *buf)
Definition microrl.c:250
#define KEY_NAK
^U Negative acknowledge
Definition microrl.h:31
#define KEY_DLE
^P Data link escape
Definition microrl.h:26
#define _ESC_HOME
Definition microrl.h:50
#define KEY_SO
^N Shift Out, alternate character set
Definition microrl.h:24
#define KEY_ENQ
^E Enquiry, goes with ACK; old HP flow control
Definition microrl.h:15
#define _ESC_BRACKET
Definition microrl.h:49
#define KEY_ETX
^C End of text
Definition microrl.h:13
#define KEY_VT
^K Vertical tab
Definition microrl.h:21
#define _ESC_END
Definition microrl.h:51
#define KEY_BS
^H Backspace, works on HP terminals/computers
Definition microrl.h:18
#define KEY_ESC
^[ Escape, next character is not echoed
Definition microrl.h:37
#define KEY_STX
^B Start of text, maintenance mode on HP console
Definition microrl.h:12
#define KEY_ACK
^F Acknowledge, clears ENQ logon hand
Definition microrl.h:16
#define KEY_SOH
^A Start of heading, = console interrupt
Definition microrl.h:11
#define _HIST_UP
Definition microrl.h:46
#define KEY_CR
^M Carriage Return
Definition microrl.h:23
#define KEY_DEL
Delete (not a real control character...)
Definition microrl.h:43
#define KEY_HT
^I Horizontal tab, move to next tab stop
Definition microrl.h:19
#define _HIST_DOWN
Definition microrl.h:47
#define KEY_LF
^J Line Feed
Definition microrl.h:20
static int seq
Definition nps_ivy.c:32
Mini printf-like functionality.
static const float dir[]