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