Revision cc33217b core/src/aos_shell.c
core/src/aos_shell.c | ||
---|---|---|
94 | 94 |
* @brief Enumerator of special keyboard keys. |
95 | 95 |
*/ |
96 | 96 |
typedef enum special_key { |
97 |
KEY_UNKNOWN, /**< any/unknow key */ |
|
98 |
KEY_AMBIGUOUS, /**< key is ambiguous */ |
|
99 |
KEY_TAB, /**< tabulator key */ |
|
100 |
KEY_ESCAPE, /**< escape key */ |
|
101 |
KEY_BACKSPACE, /**< backspace key */ |
|
102 |
KEY_INSERT, /**< insert key */ |
|
103 |
KEY_DELETE, /**< delete key */ |
|
104 |
KEY_HOME, /**< home key */ |
|
105 |
KEY_END, /**< end key */ |
|
106 |
KEY_PAGE_UP, /**< page up key */ |
|
107 |
KEY_PAGE_DOWN, /**< page down key */ |
|
108 |
KEY_ARROW_UP, /**< arrow up key */ |
|
109 |
KEY_ARROW_DOWN, /**< arrow down key */ |
|
110 |
KEY_ARROW_LEFT, /**< arrow left key */ |
|
111 |
KEY_ARROW_RIGHT, /**< arrow right key */ |
|
97 |
KEY_UNKNOWN, /**< any/unknow key */ |
|
98 |
KEY_AMBIGUOUS, /**< key is ambiguous */ |
|
99 |
KEY_TAB, /**< tabulator key */ |
|
100 |
KEY_ESCAPE, /**< escape key */ |
|
101 |
KEY_BACKSPACE, /**< backspace key */ |
|
102 |
KEY_INSERT, /**< insert key */ |
|
103 |
KEY_DELETE, /**< delete key */ |
|
104 |
KEY_HOME, /**< home key */ |
|
105 |
KEY_END, /**< end key */ |
|
106 |
KEY_PAGE_UP, /**< page up key */ |
|
107 |
KEY_PAGE_DOWN, /**< page down key */ |
|
108 |
KEY_ARROW_UP, /**< arrow up key */ |
|
109 |
KEY_ARROW_DOWN, /**< arrow down key */ |
|
110 |
KEY_ARROW_LEFT, /**< arrow left key */ |
|
111 |
KEY_ARROW_RIGHT, /**< arrow right key */ |
|
112 |
KEY_CTRL_ARROW_UP, /**< CTRL + arrow up key */ |
|
113 |
KEY_CTRL_ARROW_DOWN, /**< CTRL + arrow down key */ |
|
114 |
KEY_CTRL_ARROW_LEFT, /**< CTRL + arrow left key */ |
|
115 |
KEY_CTRL_ARROW_RIGHT, /**< CTRL + arrow right key */ |
|
112 | 116 |
} special_key_t; |
113 | 117 |
|
114 | 118 |
/** |
... | ... | |
367 | 371 |
static special_key_t _interpreteEscapeSequence(const char seq[]) |
368 | 372 |
{ |
369 | 373 |
// local variables |
374 |
char str[AOS_SHELL_ESCSEQUENCE_LENGTH]; |
|
375 |
unsigned long strl = 0; |
|
376 |
const unsigned long seql = strlen(seq); |
|
370 | 377 |
bool ambiguous = false; |
371 |
int cmp = 0; |
|
372 | 378 |
|
373 | 379 |
// TAB |
374 | 380 |
/* not supported yet; use "\x09" instead */ |
... | ... | |
377 | 383 |
/* not supported yet; use "\x08" instead */ |
378 | 384 |
|
379 | 385 |
// ESCAPE |
380 |
cmp = strcmp(seq, "\x1B"); |
|
381 |
if (cmp == 0) { |
|
386 |
strncpy(str, "\x1B", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
387 |
strl = strlen(str); |
|
388 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
382 | 389 |
return KEY_ESCAPE; |
383 |
} else { |
|
384 |
ambiguous |= (cmp < 0);
|
|
390 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) {
|
|
391 |
ambiguous = true;
|
|
385 | 392 |
} |
386 | 393 |
|
387 | 394 |
// INSERT |
388 |
cmp = strcmp(seq, "\x1B\x5B\x32\x7E"); |
|
389 |
if (cmp == 0) { |
|
395 |
strncpy(str, "\x1B\x5B\x32\x7E", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
396 |
strl = strlen(str); |
|
397 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
390 | 398 |
return KEY_INSERT; |
391 |
} else { |
|
392 |
ambiguous |= (cmp < 0);
|
|
399 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) {
|
|
400 |
ambiguous = true;
|
|
393 | 401 |
} |
394 | 402 |
|
395 | 403 |
// DELETE |
396 |
cmp = strcmp(seq, "\x1B\x5B\x33\x7E"); |
|
397 |
if (cmp == 0) { |
|
404 |
strncpy(str, "\x1B\x5B\x33\x7E", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
405 |
strl = strlen(str); |
|
406 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
398 | 407 |
return KEY_DELETE; |
399 |
} else { |
|
400 |
ambiguous |= (cmp < 0);
|
|
408 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) {
|
|
409 |
ambiguous = true;
|
|
401 | 410 |
} |
402 | 411 |
|
403 | 412 |
// HOME |
404 |
cmp = strcmp(seq, "\x1B\x5B\x48"); |
|
405 |
if (cmp == 0) { |
|
413 |
strncpy(str, "\x1B\x5B\x48", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
414 |
strl = strlen(str); |
|
415 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
406 | 416 |
return KEY_HOME; |
407 |
} else { |
|
408 |
ambiguous |= (cmp < 0);
|
|
417 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) {
|
|
418 |
ambiguous = true;
|
|
409 | 419 |
} |
410 | 420 |
|
411 | 421 |
// END |
412 |
cmp = strcmp(seq, "\x1B\x5B\x46"); |
|
413 |
if (cmp == 0) { |
|
422 |
strncpy(str, "\x1B\x5B\x46", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
423 |
strl = strlen(str); |
|
424 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
414 | 425 |
return KEY_END; |
415 |
} else { |
|
416 |
ambiguous |= (cmp < 0);
|
|
426 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) {
|
|
427 |
ambiguous = true;
|
|
417 | 428 |
} |
418 | 429 |
|
419 | 430 |
// PAGE UP |
420 |
cmp = strcmp(seq, "\x1B\x5B\x35\x7E"); |
|
421 |
if (cmp == 0) { |
|
431 |
strncpy(str, "\x1B\x5B\x35\x7E", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
432 |
strl = strlen(str); |
|
433 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
422 | 434 |
return KEY_PAGE_UP; |
423 |
} else { |
|
424 |
ambiguous |= (cmp < 0);
|
|
435 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) {
|
|
436 |
ambiguous = true;
|
|
425 | 437 |
} |
426 | 438 |
|
427 | 439 |
// PAGE DOWN |
428 |
cmp = strcmp(seq, "\x1B\x5B\x36\x7E"); |
|
429 |
if (cmp == 0) { |
|
440 |
strncpy(str, "\x1B\x5B\x36\x7E", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
441 |
strl = strlen(str); |
|
442 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
430 | 443 |
return KEY_PAGE_DOWN; |
431 |
} else { |
|
432 |
ambiguous |= (cmp < 0);
|
|
444 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) {
|
|
445 |
ambiguous = true;
|
|
433 | 446 |
} |
434 | 447 |
|
435 | 448 |
// ARROW UP |
436 |
cmp = strcmp(seq, "\x1B\x5B\x41"); |
|
437 |
if (cmp == 0) { |
|
449 |
strncpy(str, "\x1B\x5B\x41", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
450 |
strl = strlen(str); |
|
451 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
438 | 452 |
return KEY_ARROW_UP; |
439 |
} else { |
|
440 |
ambiguous |= (cmp < 0);
|
|
453 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) {
|
|
454 |
ambiguous = true;
|
|
441 | 455 |
} |
442 | 456 |
|
443 | 457 |
// ARROW DOWN |
444 |
cmp = strcmp(seq, "\x1B\x5B\x42"); |
|
445 |
if (cmp == 0) { |
|
458 |
strncpy(str, "\x1B\x5B\x42", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
459 |
strl = strlen(str); |
|
460 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
446 | 461 |
return KEY_ARROW_DOWN; |
447 |
} else { |
|
448 |
ambiguous |= (cmp < 0);
|
|
462 |
} else if (seql < strl && strncmp(seq, str, seql) == 0) {
|
|
463 |
ambiguous = true;
|
|
449 | 464 |
} |
450 | 465 |
|
451 | 466 |
// ARROW LEFT |
452 |
cmp = strcmp(seq, "\x1B\x5B\x44"); |
|
453 |
if (cmp == 0) { |
|
467 |
strncpy(str, "\x1B\x5B\x44", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
468 |
strl = strlen(str); |
|
469 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
454 | 470 |
return KEY_ARROW_LEFT; |
455 |
} else { |
|
456 |
ambiguous |= (cmp < 0);
|
|
471 |
} else if (seql < strl && strncmp(seq, str, seql) == 0) {
|
|
472 |
ambiguous = true;
|
|
457 | 473 |
} |
458 | 474 |
|
459 | 475 |
// ARROW RIGHT |
460 |
cmp = strcmp(seq, "\x1B\x5B\x43"); |
|
461 |
if (cmp == 0) { |
|
476 |
strncpy(str, "\x1B\x5B\x43", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
477 |
strl = strlen(str); |
|
478 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
462 | 479 |
return KEY_ARROW_RIGHT; |
463 |
} else { |
|
464 |
ambiguous |= (cmp < 0); |
|
480 |
} else if (seql < strl && strncmp(seq, str, seql) == 0) { |
|
481 |
ambiguous = true; |
|
482 |
} |
|
483 |
|
|
484 |
// CTRL + ARROW UP |
|
485 |
strncpy(str, "\x1B\x5B\x31\x3B\x35\x41", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
486 |
strl = strlen(str); |
|
487 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
488 |
return KEY_CTRL_ARROW_UP; |
|
489 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) { |
|
490 |
ambiguous = true; |
|
491 |
} |
|
492 |
|
|
493 |
// CTRL + ARROW DOWN |
|
494 |
strncpy(str, "\x1B\x5B\x31\x3B\x35\x42", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
495 |
strl = strlen(str); |
|
496 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
497 |
return KEY_CTRL_ARROW_DOWN; |
|
498 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) { |
|
499 |
ambiguous = true; |
|
500 |
} |
|
501 |
|
|
502 |
// CTRL + ARROW LEFT |
|
503 |
strncpy(str, "\x1B\x5B\x31\x3B\x35\x44", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
504 |
strl = strlen(str); |
|
505 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
506 |
return KEY_CTRL_ARROW_LEFT; |
|
507 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) { |
|
508 |
ambiguous = true; |
|
509 |
} |
|
510 |
|
|
511 |
// CTRL + ARROW RIGHT |
|
512 |
strncpy(str, "\x1B\x5B\x31\x3B\x35\x43", AOS_SHELL_ESCSEQUENCE_LENGTH); |
|
513 |
strl = strlen(str); |
|
514 |
if (seql == strl && strncmp(seq, str, seql) == 0) { |
|
515 |
return KEY_CTRL_ARROW_RIGHT; |
|
516 |
} else if(seql < strl && strncmp(seq, str, seql) == 0) { |
|
517 |
ambiguous = true; |
|
465 | 518 |
} |
466 | 519 |
|
467 | 520 |
return ambiguous ? KEY_AMBIGUOUS : KEY_UNKNOWN; |
... | ... | |
491 | 544 |
|
492 | 545 |
// move cursor right by printing line content |
493 | 546 |
while (pos < to) { |
494 |
streamPut(&shell->stream, shell->line[pos]); |
|
547 |
streamPut(&shell->stream, shell->input.line[pos]);
|
|
495 | 548 |
++pos; |
496 | 549 |
} |
497 | 550 |
|
... | ... | |
515 | 568 |
size_t cnt; |
516 | 569 |
|
517 | 570 |
for (cnt = 0; from + cnt < to; ++cnt) { |
518 |
streamPut(&shell->stream, shell->line[from + cnt]); |
|
571 |
streamPut(&shell->stream, shell->input.line[from + cnt]);
|
|
519 | 572 |
} |
520 | 573 |
|
521 | 574 |
return cnt; |
522 | 575 |
} |
523 | 576 |
|
577 |
static int _readChar(aos_shell_t* shell, const char c) { |
|
578 |
aosDbgCheck(shell != NULL); |
|
579 |
|
|
580 |
// check whether input line is already full |
|
581 |
if (shell->inputdata.lineend + 1 >= shell->input.width) { |
|
582 |
return 0; |
|
583 |
} else { |
|
584 |
// clear old line content on first input |
|
585 |
if (shell->inputdata.noinput) { |
|
586 |
memset(shell->input.line, '\0', shell->input.width); |
|
587 |
shell->inputdata.noinput = false; |
|
588 |
} |
|
589 |
// overwrite content |
|
590 |
if (shell->config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) { |
|
591 |
shell->input.line[shell->inputdata.cursorpos] = c; |
|
592 |
++shell->inputdata.cursorpos; |
|
593 |
shell->inputdata.lineend = (shell->inputdata.cursorpos > shell->inputdata.lineend) ? shell->inputdata.cursorpos : shell->inputdata.lineend; |
|
594 |
streamPut(&shell->stream, (uint8_t)c); |
|
595 |
} |
|
596 |
// insert character |
|
597 |
else { |
|
598 |
memmove(&(shell->input.line[shell->inputdata.cursorpos+1]), &(shell->input.line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos); |
|
599 |
shell->input.line[shell->inputdata.cursorpos] = c; |
|
600 |
++shell->inputdata.lineend; |
|
601 |
_printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend); |
|
602 |
++shell->inputdata.cursorpos; |
|
603 |
_moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos); |
|
604 |
} |
|
605 |
return 1; |
|
606 |
} |
|
607 |
} |
|
608 |
|
|
524 | 609 |
/** |
525 | 610 |
* @brief Compare two characters. |
526 | 611 |
* |
... | ... | |
654 | 739 |
key = KEY_UNKNOWN; |
655 | 740 |
|
656 | 741 |
// parse escape sequence |
657 |
if (shell->inputdata.escp > 0) { |
|
658 |
shell->inputdata.escseq[shell->inputdata.escp] = c; |
|
659 |
++shell->inputdata.escp; |
|
742 |
if (strlen(shell->inputdata.escseq) > 0) { |
|
743 |
shell->inputdata.escseq[strlen(shell->inputdata.escseq)] = c; |
|
660 | 744 |
key = _interpreteEscapeSequence(shell->inputdata.escseq); |
661 |
if (key == KEY_AMBIGUOUS) {
|
|
662 |
// read next byte to resolve ambiguity
|
|
663 |
continue;
|
|
664 |
} else {
|
|
665 |
/*
|
|
666 |
* If the escape sequence could either be parsed sucessfully
|
|
667 |
* or there is no match (KEY_UNKNOWN),
|
|
668 |
* reset the sequence variable and interprete key/character
|
|
669 |
*/
|
|
670 |
shell->inputdata.escp = 0;
|
|
671 |
memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0]));
|
|
745 |
switch (key) {
|
|
746 |
case KEY_AMBIGUOUS:
|
|
747 |
// read next byte to resolve ambiguity
|
|
748 |
continue;
|
|
749 |
case KEY_UNKNOWN:
|
|
750 |
// do nothing here, but handle the unknown sequence below
|
|
751 |
break;
|
|
752 |
default:
|
|
753 |
// reset the sequence variable and buffer
|
|
754 |
memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0]));
|
|
755 |
break;
|
|
672 | 756 |
} |
673 | 757 |
} |
674 | 758 |
|
... | ... | |
678 | 762 |
action = AOS_SHELL_ACTION_NONE; |
679 | 763 |
|
680 | 764 |
// printable character |
681 |
if (key == KEY_UNKNOWN && c >= '\x20' && c <= '\x7E') { |
|
765 |
if (key == KEY_UNKNOWN && strlen(shell->inputdata.escseq) == 0 && c >= '\x20' && c <= '\x7E') {
|
|
682 | 766 |
action = AOS_SHELL_ACTION_READCHAR; |
683 | 767 |
} |
684 | 768 |
|
... | ... | |
716 | 800 |
} |
717 | 801 |
} |
718 | 802 |
|
719 |
// 'page up' of 'arrow up' key
|
|
720 |
else if (key == KEY_PAGE_UP || key == KEY_ARROW_UP) { |
|
803 |
// 'page up' key or CTRL + 'arrow up' key combination
|
|
804 |
else if (key == KEY_PAGE_UP || key == KEY_CTRL_ARROW_UP) {
|
|
721 | 805 |
// ignore if there was some input |
722 | 806 |
if (shell->inputdata.noinput) { |
723 | 807 |
action = AOS_SHELL_ACTION_RECALLLAST; |
724 | 808 |
} |
725 | 809 |
} |
726 | 810 |
|
727 |
// 'page down' key, 'arrow done' key, 'end of test' character or 'end of transmission' character
|
|
728 |
else if (key == KEY_PAGE_DOWN || key == KEY_ARROW_DOWN || c == '\x03' || c == '\x03') { |
|
811 |
// 'page down' key, 'arrow down' key, 'end of test' character or 'end of transmission' character, or CTRL + 'arrow down' key combination
|
|
812 |
else if (key == KEY_PAGE_DOWN || key == KEY_ARROW_DOWN || c == '\x03' || c == '\x03' || key == KEY_CTRL_ARROW_DOWN) {
|
|
729 | 813 |
// ignore if line is empty |
730 | 814 |
if (shell->inputdata.lineend > 0) { |
731 | 815 |
action = AOS_SHELL_ACTION_CLEAR; |
... | ... | |
758 | 842 |
|
759 | 843 |
// 'arrow right' key |
760 | 844 |
else if (key == KEY_ARROW_RIGHT) { |
761 |
// irgnore if cursor is very right
|
|
845 |
// ignore if cursor is very right |
|
762 | 846 |
if (shell->inputdata.cursorpos < shell->inputdata.lineend) { |
763 | 847 |
action = AOS_SHELL_ACTION_CURSORRIGHT; |
764 | 848 |
} |
765 | 849 |
} |
766 | 850 |
|
851 |
// CTRL + 'arrow left' key combination |
|
852 |
else if (key == KEY_CTRL_ARROW_LEFT) { |
|
853 |
// ignore if cursor is very left |
|
854 |
if (shell->inputdata.cursorpos > 0) { |
|
855 |
action = AOS_SHELL_ACTION_CURSORWORDLEFT; |
|
856 |
} |
|
857 |
} |
|
858 |
|
|
859 |
// CTRL + 'arrow right' key combination |
|
860 |
else if (key == KEY_CTRL_ARROW_RIGHT) { |
|
861 |
// ignore if cursor is very right |
|
862 |
if (shell->inputdata.cursorpos < shell->inputdata.lineend) { |
|
863 |
action = AOS_SHELL_ACTION_CURSORWORDRIGHT; |
|
864 |
} |
|
865 |
} |
|
866 |
|
|
767 | 867 |
// carriage return ('\r') or line feed ('\n') character |
768 | 868 |
else if (c == '\x0D' || c == '\x0A') { |
769 | 869 |
action = AOS_SHELL_ACTION_EXECUTE; |
... | ... | |
773 | 873 |
else if (key == KEY_ESCAPE || c == '\x1B') { |
774 | 874 |
action = AOS_SHELL_ACTION_ESCSTART; |
775 | 875 |
} |
876 |
|
|
877 |
// unknown escape sequence |
|
878 |
else if (key == KEY_UNKNOWN && strlen(shell->inputdata.escseq) > 0) { |
|
879 |
action = AOS_SHELL_ACTION_PRINTUNKNOWNSEQUENCE; |
|
880 |
} |
|
776 | 881 |
} |
777 | 882 |
|
778 | 883 |
/* handle function */ |
779 | 884 |
switch (action) { |
780 | 885 |
case AOS_SHELL_ACTION_READCHAR: |
781 | 886 |
{ |
782 |
// line is full
|
|
783 |
if (shell->inputdata.lineend + 1 >= shell->linesize) {
|
|
887 |
if (_readChar(shell, c) == 0) {
|
|
888 |
// line is full
|
|
784 | 889 |
_moveCursor(shell, shell->inputdata.cursorpos, shell->inputdata.lineend); |
785 | 890 |
chprintf((BaseSequentialStream*)&shell->stream, "\n\tmaximum line width reached\n"); |
786 | 891 |
_printPrompt(shell); |
787 | 892 |
_printLine(shell, 0, shell->inputdata.lineend); |
788 | 893 |
_moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos); |
789 | 894 |
} |
790 |
// read character |
|
791 |
else { |
|
792 |
// clear old line content on first input |
|
793 |
if (shell->inputdata.noinput) { |
|
794 |
memset(shell->line, '\0', shell->linesize); |
|
795 |
shell->inputdata.noinput = false; |
|
796 |
} |
|
797 |
// overwrite content |
|
798 |
if (shell->config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) { |
|
799 |
shell->line[shell->inputdata.cursorpos] = c; |
|
800 |
++shell->inputdata.cursorpos; |
|
801 |
shell->inputdata.lineend = (shell->inputdata.cursorpos > shell->inputdata.lineend) ? shell->inputdata.cursorpos : shell->inputdata.lineend; |
|
802 |
streamPut(&shell->stream, (uint8_t)c); |
|
803 |
} |
|
804 |
// insert character |
|
805 |
else { |
|
806 |
memmove(&(shell->line[shell->inputdata.cursorpos+1]), &(shell->line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos); |
|
807 |
shell->line[shell->inputdata.cursorpos] = c; |
|
808 |
++shell->inputdata.lineend; |
|
809 |
_printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend); |
|
810 |
++shell->inputdata.cursorpos; |
|
811 |
_moveCursor(shell, shell->inputdata.lineend, shell->inputdata.cursorpos); |
|
812 |
} |
|
813 |
} |
|
814 | 895 |
break; |
815 | 896 |
} |
816 | 897 |
|
817 | 898 |
case AOS_SHELL_ACTION_AUTOFILL: |
818 | 899 |
{ |
819 |
const char* fill = shell->line; |
|
900 |
const char* fill = shell->input.line;
|
|
820 | 901 |
size_t cmatch = shell->inputdata.cursorpos; |
821 | 902 |
charmatch_t matchlevel = CHAR_MATCH_NOT; |
822 | 903 |
size_t n; |
... | ... | |
837 | 918 |
fill = cmd->name; |
838 | 919 |
// break the loop only if there are no case mismatches with the input |
839 | 920 |
n = shell->inputdata.cursorpos; |
840 |
_strccmp(fill, shell->line, false, &n, &mlvl); |
|
921 |
_strccmp(fill, shell->input.line, false, &n, &mlvl);
|
|
841 | 922 |
if (mlvl == CHAR_MATCH_CASE) { |
842 | 923 |
break; |
843 | 924 |
} |
... | ... | |
845 | 926 |
// if a not exact match was found |
846 | 927 |
else if (cmatch + cmp > shell->inputdata.cursorpos) { |
847 | 928 |
// if this is the first one |
848 |
if (fill == shell->line) { |
|
929 |
if (fill == shell->input.line) {
|
|
849 | 930 |
cmatch += cmp; |
850 | 931 |
fill = cmd->name; |
851 | 932 |
} |
... | ... | |
859 | 940 |
} |
860 | 941 |
// evaluate if there are case mismatches |
861 | 942 |
n = cmatch; |
862 |
_strccmp(shell->line, fill, shell->config & AOS_SHELL_CONFIG_MATCH_CASE, &n, &matchlevel); |
|
943 |
_strccmp(shell->input.line, fill, shell->config & AOS_SHELL_CONFIG_MATCH_CASE, &n, &matchlevel);
|
|
863 | 944 |
// print the auto fill if any |
864 | 945 |
if (cmatch > shell->inputdata.cursorpos || (cmatch == shell->inputdata.cursorpos && matchlevel == CHAR_MATCH_NCASE)) { |
865 | 946 |
shell->inputdata.noinput = false; |
866 | 947 |
// limit auto fill so it will not overflow the line width |
867 |
if (shell->inputdata.lineend + (cmatch - shell->inputdata.cursorpos) > shell->linesize) {
|
|
868 |
cmatch = shell->linesize - shell->inputdata.lineend + shell->inputdata.cursorpos;
|
|
948 |
if (shell->inputdata.lineend + (cmatch - shell->inputdata.cursorpos) > shell->input.width) {
|
|
949 |
cmatch = shell->input.width - shell->inputdata.lineend + shell->inputdata.cursorpos;
|
|
869 | 950 |
} |
870 | 951 |
// move trailing memory further in the line |
871 |
memmove(&(shell->line[cmatch]), &(shell->line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos);
|
|
952 |
memmove(&(shell->input.line[cmatch]), &(shell->input.line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos);
|
|
872 | 953 |
shell->inputdata.lineend += cmatch - shell->inputdata.cursorpos; |
873 | 954 |
// if there was no incorrect case when matching |
874 | 955 |
if (matchlevel == CHAR_MATCH_CASE) { |
875 | 956 |
// insert fill command name to line |
876 |
memcpy(&(shell->line[shell->inputdata.cursorpos]), &(fill[shell->inputdata.cursorpos]), cmatch - shell->inputdata.cursorpos); |
|
957 |
memcpy(&(shell->input.line[shell->inputdata.cursorpos]), &(fill[shell->inputdata.cursorpos]), cmatch - shell->inputdata.cursorpos);
|
|
877 | 958 |
// print the output |
878 | 959 |
_printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend); |
879 | 960 |
} else { |
880 | 961 |
// overwrite line with fill command name |
881 |
memcpy(shell->line, fill, cmatch); |
|
962 |
memcpy(shell->input.line, fill, cmatch);
|
|
882 | 963 |
// reprint the whole line |
883 | 964 |
_moveCursor(shell, shell->inputdata.cursorpos, 0); |
884 | 965 |
_printLine(shell, 0, shell->inputdata.lineend); |
... | ... | |
898 | 979 |
// compare line content with command, excpet if cursorpos=0 |
899 | 980 |
size_t i = shell->inputdata.cursorpos; |
900 | 981 |
if (shell->inputdata.cursorpos > 0) { |
901 |
_strccmp(shell->line, cmd->name, true, &i, NULL); |
|
982 |
_strccmp(shell->input.line, cmd->name, true, &i, NULL);
|
|
902 | 983 |
} |
903 | 984 |
const int cmp = (i < shell->inputdata.cursorpos) ? |
904 | 985 |
(i - shell->inputdata.cursorpos) : |
... | ... | |
940 | 1021 |
case AOS_SHELL_ACTION_DELETEFORWARD: |
941 | 1022 |
{ |
942 | 1023 |
--shell->inputdata.lineend; |
943 |
memmove(&(shell->line[shell->inputdata.cursorpos]), &(shell->line[shell->inputdata.cursorpos+1]), shell->inputdata.lineend - shell->inputdata.cursorpos);
|
|
1024 |
memmove(&(shell->input.line[shell->inputdata.cursorpos]), &(shell->input.line[shell->inputdata.cursorpos+1]), shell->inputdata.lineend - shell->inputdata.cursorpos);
|
|
944 | 1025 |
_printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend); |
945 | 1026 |
streamPut(&shell->stream, ' '); |
946 | 1027 |
_moveCursor(shell, shell->inputdata.lineend + 1, shell->inputdata.cursorpos); |
... | ... | |
950 | 1031 |
case AOS_SHELL_ACTION_DELETEBACKWARD: |
951 | 1032 |
{ |
952 | 1033 |
--shell->inputdata.cursorpos; |
953 |
memmove(&(shell->line[shell->inputdata.cursorpos]), &(shell->line[shell->inputdata.cursorpos+1]), shell->inputdata.lineend - shell->inputdata.cursorpos);
|
|
1034 |
memmove(&(shell->input.line[shell->inputdata.cursorpos]), &(shell->input.line[shell->inputdata.cursorpos+1]), shell->inputdata.lineend - shell->inputdata.cursorpos);
|
|
954 | 1035 |
--shell->inputdata.lineend; |
955 |
shell->line[shell->inputdata.lineend] = '\0'; |
|
1036 |
shell->input.line[shell->inputdata.lineend] = '\0';
|
|
956 | 1037 |
_moveCursor(shell, shell->inputdata.cursorpos + 1, shell->inputdata.cursorpos); |
957 | 1038 |
_printLine(shell, shell->inputdata.cursorpos, shell->inputdata.lineend); |
958 | 1039 |
streamPut(&shell->stream, ' '); |
... | ... | |
967 | 1048 |
size_t nul_start = 0; |
968 | 1049 |
size_t nul_end = 0; |
969 | 1050 |
// search line for a NUL byte |
970 |
while (nul_start < shell->linesize) {
|
|
971 |
if (shell->line[nul_start] == '\0') { |
|
1051 |
while (nul_start < shell->input.width) {
|
|
1052 |
if (shell->input.line[nul_start] == '\0') {
|
|
972 | 1053 |
nul_end = nul_start + 1; |
973 | 1054 |
// keep searcjing for a byte that is not NUL |
974 |
while (nul_end < shell->linesize) {
|
|
975 |
if (shell->line[nul_end] != '\0') { |
|
1055 |
while (nul_end < shell->input.width) {
|
|
1056 |
if (shell->input.line[nul_end] != '\0') {
|
|
976 | 1057 |
// an intermediate NUL sequence was found |
977 |
memset(&(shell->line[nul_start]), ' ', nul_end - nul_start); |
|
1058 |
memset(&(shell->input.line[nul_start]), ' ', nul_end - nul_start);
|
|
978 | 1059 |
shell->inputdata.lineend = nul_end + 1; |
979 | 1060 |
break; |
980 | 1061 |
} else { |
... | ... | |
1035 | 1116 |
break; |
1036 | 1117 |
} |
1037 | 1118 |
|
1119 |
case AOS_SHELL_ACTION_CURSORWORDLEFT: |
|
1120 |
{ |
|
1121 |
size_t cpos = shell->inputdata.cursorpos; |
|
1122 |
while (cpos > 0 && shell->input.line[cpos-1] == ' ') { |
|
1123 |
--cpos; |
|
1124 |
} |
|
1125 |
while (cpos > 0 && shell->input.line[cpos-1] != ' ') { |
|
1126 |
--cpos; |
|
1127 |
} |
|
1128 |
_moveCursor(shell, shell->inputdata.cursorpos, cpos); |
|
1129 |
shell->inputdata.cursorpos = cpos; |
|
1130 |
break; |
|
1131 |
} |
|
1132 |
|
|
1133 |
case AOS_SHELL_ACTION_CURSORWORDRIGHT: |
|
1134 |
{ |
|
1135 |
size_t cpos = shell->inputdata.cursorpos; |
|
1136 |
while (cpos < shell->inputdata.lineend && shell->input.line[cpos] != ' ') { |
|
1137 |
++cpos; |
|
1138 |
} |
|
1139 |
while (cpos < shell->inputdata.lineend && shell->input.line[cpos] == ' ') { |
|
1140 |
++cpos; |
|
1141 |
} |
|
1142 |
_moveCursor(shell, shell->inputdata.cursorpos, cpos); |
|
1143 |
shell->inputdata.cursorpos = cpos; |
|
1144 |
break; |
|
1145 |
} |
|
1146 |
|
|
1038 | 1147 |
case AOS_SHELL_ACTION_EXECUTE: |
1039 | 1148 |
{ |
1040 | 1149 |
streamPut(&shell->stream, '\n'); |
1041 | 1150 |
// set the number of read bytes and return |
1042 | 1151 |
if (!shell->inputdata.noinput) { |
1043 |
*n = shell->linesize - shell->inputdata.lineend;
|
|
1152 |
*n = shell->input.width - shell->inputdata.lineend;
|
|
1044 | 1153 |
// fill the remainder of the line with NUL bytes |
1045 |
memset(&(shell->line[shell->inputdata.lineend]), '\0', *n); |
|
1154 |
memset(&(shell->input.line[shell->inputdata.lineend]), '\0', *n);
|
|
1046 | 1155 |
// reset static variables |
1047 | 1156 |
shell->inputdata.noinput = true; |
1048 | 1157 |
} |
... | ... | |
1052 | 1161 |
case AOS_SHELL_ACTION_ESCSTART: |
1053 | 1162 |
{ |
1054 | 1163 |
shell->inputdata.escseq[0] = c; |
1055 |
++shell->inputdata.escp; |
|
1164 |
break; |
|
1165 |
} |
|
1166 |
|
|
1167 |
case AOS_SHELL_ACTION_PRINTUNKNOWNSEQUENCE: |
|
1168 |
{ |
|
1169 |
size_t seqc = 1; // element 0 would be unprintible ESC character |
|
1170 |
while (shell->inputdata.escseq[seqc] != '\0') { |
|
1171 |
_readChar(shell, shell->inputdata.escseq[seqc]); |
|
1172 |
++seqc; |
|
1173 |
} |
|
1174 |
memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0])); |
|
1056 | 1175 |
break; |
1057 | 1176 |
} |
1058 | 1177 |
|
1059 | 1178 |
case AOS_SHELL_ACTION_NONE: |
1060 |
default: |
|
1061 | 1179 |
{ |
1062 | 1180 |
// do nothing (ignore input) and read next byte |
1063 | 1181 |
continue; |
... | ... | |
1097 | 1215 |
size_t arg = 0; |
1098 | 1216 |
|
1099 | 1217 |
// iterate through the line |
1100 |
for (char* c = shell->line; c < shell->line + shell->linesize; ++c) {
|
|
1218 |
for (char* c = shell->input.line; c < shell->input.line + shell->input.width; ++c) {
|
|
1101 | 1219 |
// terminate at first NUL byte |
1102 | 1220 |
if (*c == '\0') { |
1103 | 1221 |
state = END; |
... | ... | |
1151 | 1269 |
* @param[in] arglist Pointer to the argument buffer. |
1152 | 1270 |
* @param[in] arglistsize Size of te argument buffer. |
1153 | 1271 |
*/ |
1154 |
void aosShellInit(aos_shell_t* shell, event_source_t* oseventsource, const char* prompt, char* line, size_t linesize, char** arglist, size_t arglistsize)
|
|
1272 |
void aosShellInit(aos_shell_t* shell, event_source_t* oseventsource, const char* prompt, char* line, size_t linesize, char** arglist, size_t arglistsize) |
|
1155 | 1273 |
{ |
1156 | 1274 |
aosDbgCheck(shell != NULL); |
1157 | 1275 |
aosDbgCheck(oseventsource != NULL); |
... | ... | |
1167 | 1285 |
shell->commands = NULL; |
1168 | 1286 |
shell->execstatus.command = NULL; |
1169 | 1287 |
shell->execstatus.retval = 0; |
1170 |
shell->line = line; |
|
1171 |
shell->linesize = linesize;
|
|
1288 |
shell->input.line = line;
|
|
1289 |
shell->input.width = linesize;
|
|
1172 | 1290 |
shell->inputdata.lastaction = AOS_SHELL_ACTION_NONE; |
1173 |
shell->inputdata.escp = 0; |
|
1174 | 1291 |
memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0])); |
1175 | 1292 |
shell->inputdata.cursorpos = 0; |
1176 | 1293 |
shell->inputdata.lineend = 0; |
... | ... | |
1179 | 1296 |
shell->arglistsize = arglistsize; |
1180 | 1297 |
shell->config = 0x00; |
1181 | 1298 |
|
1182 |
// initialize arrays
|
|
1183 |
memset(shell->line, '\0', shell->linesize);
|
|
1299 |
// initialize buffers
|
|
1300 |
memset(shell->input.line, '\0', shell->input.width);
|
|
1184 | 1301 |
for (size_t a = 0; a < shell->arglistsize; ++a) { |
1185 | 1302 |
shell->arglist[a] = NULL; |
1186 | 1303 |
} |
... | ... | |
1566 | 1683 |
|
1567 | 1684 |
// if no matching command was found, print an error |
1568 | 1685 |
if (cmd == NULL) { |
1569 |
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "%s: command not found\n", ((aos_shell_t*)shell)->arglist[0]);
|
|
1686 |
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\tcommand '%s' not found\n", ((aos_shell_t*)shell)->arglist[0]);
|
|
1570 | 1687 |
} |
1571 | 1688 |
} |
1572 | 1689 |
|
Also available in: Unified diff