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 |
|