Revision c18a848e
| core/src/aos_shell.c | ||
|---|---|---|
| 578 | 578 |
aosDbgCheck(shell != NULL); |
| 579 | 579 |
|
| 580 | 580 |
// check whether input line is already full |
| 581 |
if (shell->inputdata.lineend + 1 >= shell->input.length) {
|
|
| 581 |
if (shell->inputdata.lineend + 1 >= shell->input.size) {
|
|
| 582 | 582 |
return 0; |
| 583 | 583 |
} else {
|
| 584 | 584 |
// clear old line content on first input |
| 585 | 585 |
if (shell->inputdata.noinput) {
|
| 586 |
memset(shell->input.line, '\0', shell->input.length);
|
|
| 586 |
memset(shell->input.line, '\0', shell->input.size);
|
|
| 587 | 587 |
shell->inputdata.noinput = false; |
| 588 | 588 |
} |
| 589 | 589 |
// overwrite content |
| ... | ... | |
| 716 | 716 |
* |
| 717 | 717 |
* @param[in] shell Pointer to the shell object. |
| 718 | 718 |
* @param[in] channel The channel to read from. |
| 719 |
* @param[out] n Optional pointer to a variable to store the number of read characters to.
|
|
| 719 |
* @param[out] exec Optional pointer to a flag, which indicates, whether a command shall be executed.
|
|
| 720 | 720 |
* |
| 721 |
* @return Indicator, whether the read character(s) indicated, that a command shall be executed.
|
|
| 721 |
* @return Number of read characters.
|
|
| 722 | 722 |
*/ |
| 723 |
static bool _readChannel(aos_shell_t* shell, AosShellChannel* channel, size_t* n)
|
|
| 723 |
static int _readChannel(aos_shell_t* shell, AosShellChannel* channel, bool* execute)
|
|
| 724 | 724 |
{
|
| 725 | 725 |
aosDbgCheck(shell != NULL); |
| 726 | 726 |
aosDbgCheck(channel != NULL); |
| ... | ... | |
| 729 | 729 |
aos_shellaction_t action = AOS_SHELL_ACTION_NONE; |
| 730 | 730 |
char c; |
| 731 | 731 |
special_key_t key; |
| 732 |
|
|
| 733 |
// initialize output variables |
|
| 734 |
if (n) {
|
|
| 735 |
*n = 0; |
|
| 736 |
} |
|
| 732 |
int nchars = 0; |
|
| 733 |
bool exec = false; |
|
| 737 | 734 |
|
| 738 | 735 |
// read character by character from the channel |
| 739 | 736 |
while (chnReadTimeout(channel, (uint8_t*)&c, 1, TIME_IMMEDIATE)) {
|
| 740 | 737 |
key = KEY_UNKNOWN; |
| 741 | 738 |
|
| 739 |
// drop any input after an execution request was detected |
|
| 740 |
if (exec) {
|
|
| 741 |
continue; |
|
| 742 |
} |
|
| 743 |
|
|
| 744 |
// incremet character counter |
|
| 745 |
++nchars; |
|
| 746 |
|
|
| 742 | 747 |
// parse escape sequence |
| 743 | 748 |
if (strlen(shell->inputdata.escseq) > 0) {
|
| 744 | 749 |
shell->inputdata.escseq[strlen(shell->inputdata.escseq)] = c; |
| ... | ... | |
| 946 | 951 |
if (cmatch > shell->inputdata.cursorpos || (cmatch == shell->inputdata.cursorpos && matchlevel == CHAR_MATCH_NCASE)) {
|
| 947 | 952 |
shell->inputdata.noinput = false; |
| 948 | 953 |
// limit auto fill so it will not overflow the line width |
| 949 |
if (shell->inputdata.lineend + (cmatch - shell->inputdata.cursorpos) > shell->input.length) {
|
|
| 950 |
cmatch = shell->input.length - shell->inputdata.lineend + shell->inputdata.cursorpos;
|
|
| 954 |
if (shell->inputdata.lineend + (cmatch - shell->inputdata.cursorpos) > shell->input.size) {
|
|
| 955 |
cmatch = shell->input.size - shell->inputdata.lineend + shell->inputdata.cursorpos;
|
|
| 951 | 956 |
} |
| 952 | 957 |
// move trailing memory further in the line |
| 953 | 958 |
memmove(&(shell->input.line[cmatch]), &(shell->input.line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos); |
| ... | ... | |
| 1049 | 1054 |
size_t nul_start = 0; |
| 1050 | 1055 |
size_t nul_end = 0; |
| 1051 | 1056 |
// search line for a NUL byte |
| 1052 |
while (nul_start < shell->input.length) {
|
|
| 1057 |
while (nul_start < shell->input.size) {
|
|
| 1053 | 1058 |
if (shell->input.line[nul_start] == '\0') {
|
| 1054 | 1059 |
nul_end = nul_start + 1; |
| 1055 | 1060 |
// keep searcjing for a byte that is not NUL |
| 1056 |
while (nul_end < shell->input.length) {
|
|
| 1061 |
while (nul_end < shell->input.size) {
|
|
| 1057 | 1062 |
if (shell->input.line[nul_end] != '\0') {
|
| 1058 | 1063 |
// an intermediate NUL sequence was found |
| 1059 | 1064 |
memset(&(shell->input.line[nul_start]), ' ', nul_end - nul_start); |
| ... | ... | |
| 1148 | 1153 |
case AOS_SHELL_ACTION_EXECUTE: |
| 1149 | 1154 |
{
|
| 1150 | 1155 |
streamPut(&shell->stream, '\n'); |
| 1151 |
// set the number of read bytes and return
|
|
| 1156 |
// if there was some input
|
|
| 1152 | 1157 |
if (!shell->inputdata.noinput) {
|
| 1153 |
if (n) {
|
|
| 1154 |
*n = shell->input.length - shell->inputdata.lineend; |
|
| 1155 |
} |
|
| 1156 | 1158 |
// fill the remainder of the line with NUL bytes |
| 1157 |
memset(&(shell->input.line[shell->inputdata.lineend]), '\0', (shell->input.length - shell->inputdata.lineend));
|
|
| 1159 |
memset(&(shell->input.line[shell->inputdata.lineend]), '\0', shell->input.size - shell->inputdata.lineend);
|
|
| 1158 | 1160 |
} |
| 1159 |
return true; |
|
| 1161 |
// set the execution flag |
|
| 1162 |
exec = true; |
|
| 1163 |
break; |
|
| 1160 | 1164 |
} |
| 1161 | 1165 |
|
| 1162 | 1166 |
case AOS_SHELL_ACTION_ESCSTART: |
| ... | ... | |
| 1186 | 1190 |
shell->inputdata.lastaction = action; |
| 1187 | 1191 |
} /* end of while */ |
| 1188 | 1192 |
|
| 1189 |
// no more data could be read from the channel |
|
| 1190 |
return false; |
|
| 1193 |
// set the execution output flag |
|
| 1194 |
if (execute) {
|
|
| 1195 |
*execute = exec; |
|
| 1196 |
} |
|
| 1197 |
|
|
| 1198 |
return nchars; |
|
| 1191 | 1199 |
} |
| 1192 | 1200 |
|
| 1193 | 1201 |
/** |
| ... | ... | |
| 1218 | 1226 |
size_t nargs = 0; |
| 1219 | 1227 |
|
| 1220 | 1228 |
// iterate through the line |
| 1221 |
for (char* c = shell->input.line; c < shell->input.line + shell->input.length; ++c) {
|
|
| 1229 |
for (char* c = shell->input.line; c < shell->input.line + shell->input.size; ++c) {
|
|
| 1222 | 1230 |
// terminate at first NUL byte |
| 1223 | 1231 |
if (*c == '\0') {
|
| 1224 | 1232 |
state = END; |
| ... | ... | |
| 1601 | 1609 |
eventmask_t eventmask; |
| 1602 | 1610 |
eventflags_t eventflags; |
| 1603 | 1611 |
AosShellChannel* channel; |
| 1604 |
aos_status_t readeval;
|
|
| 1612 |
bool execute;
|
|
| 1605 | 1613 |
char* args[((aos_shell_t*)shell)->input.nargs]; |
| 1606 | 1614 |
size_t nargs = 0; |
| 1607 | 1615 |
aos_shellcommand_t* cmd; |
| ... | ... | |
| 1654 | 1662 |
while (channel != NULL) {
|
| 1655 | 1663 |
eventflags = chEvtGetAndClearFlags(&channel->listener); |
| 1656 | 1664 |
// if there is new input and a command shall be executed |
| 1657 |
if ((eventflags & CHN_INPUT_AVAILABLE) && _readChannel((aos_shell_t*)shell, channel, NULL)) {
|
|
| 1658 |
// parse input line to argument list |
|
| 1659 |
nargs = _parseArguments((aos_shell_t*)shell, args); |
|
| 1660 |
// check number of arguments |
|
| 1661 |
if (nargs > ((aos_shell_t*)shell)->input.nargs) {
|
|
| 1662 |
// error too many arguments |
|
| 1663 |
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\ttoo many arguments\n"); |
|
| 1664 |
} else if (nargs > 0) {
|
|
| 1665 |
// search command list for arg[0] and execute callback |
|
| 1666 |
cmd = ((aos_shell_t*)shell)->commands; |
|
| 1667 |
while (cmd != NULL) {
|
|
| 1668 |
if (strcmp(args[0], cmd->name) == 0) {
|
|
| 1669 |
((aos_shell_t*)shell)->execstatus.command = cmd; |
|
| 1670 |
chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_EXEC); |
|
| 1671 |
((aos_shell_t*)shell)->execstatus.retval = cmd->callback((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, (int)nargs, args); |
|
| 1672 |
chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_DONE); |
|
| 1673 |
// notify if the command was not successful |
|
| 1674 |
if (((aos_shell_t*)shell)->execstatus.retval != 0) {
|
|
| 1675 |
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "command returned exit status %d\n", ((aos_shell_t*)shell)->execstatus.retval); |
|
| 1665 |
if (eventflags & CHN_INPUT_AVAILABLE) {
|
|
| 1666 |
_readChannel((aos_shell_t*)shell, channel, &execute); |
|
| 1667 |
// an execution request was detected |
|
| 1668 |
if (execute && !((aos_shell_t*)shell)->inputdata.noinput) {
|
|
| 1669 |
// parse input line to argument list |
|
| 1670 |
nargs = _parseArguments((aos_shell_t*)shell, args); |
|
| 1671 |
// check number of arguments |
|
| 1672 |
if (nargs > ((aos_shell_t*)shell)->input.nargs) {
|
|
| 1673 |
// error too many arguments |
|
| 1674 |
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\ttoo many arguments\n"); |
|
| 1675 |
} else if (nargs > 0) {
|
|
| 1676 |
// search command list for arg[0] and execute callback |
|
| 1677 |
cmd = ((aos_shell_t*)shell)->commands; |
|
| 1678 |
while (cmd != NULL) {
|
|
| 1679 |
if (strcmp(args[0], cmd->name) == 0) {
|
|
| 1680 |
((aos_shell_t*)shell)->execstatus.command = cmd; |
|
| 1681 |
chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_EXEC); |
|
| 1682 |
((aos_shell_t*)shell)->execstatus.retval = cmd->callback((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, (int)nargs, args); |
|
| 1683 |
chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_DONE); |
|
| 1684 |
// notify if the command was not successful |
|
| 1685 |
if (((aos_shell_t*)shell)->execstatus.retval != 0) {
|
|
| 1686 |
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "command returned exit status %d\n", ((aos_shell_t*)shell)->execstatus.retval); |
|
| 1687 |
} |
|
| 1688 |
break; |
|
| 1676 | 1689 |
} |
| 1677 |
break; |
|
| 1678 |
} |
|
| 1679 |
cmd = cmd->next; |
|
| 1680 |
} /* end of while */ |
|
| 1690 |
cmd = cmd->next; |
|
| 1691 |
} /* end of while */ |
|
| 1681 | 1692 |
|
| 1682 |
// if no matching command was found, print an error |
|
| 1683 |
if (cmd == NULL) {
|
|
| 1684 |
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\tcommand '%s' not found\n", args[0]); |
|
| 1693 |
// if no matching command was found, print an error |
|
| 1694 |
if (cmd == NULL) {
|
|
| 1695 |
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\tcommand '%s' not found\n", args[0]); |
|
| 1696 |
} |
|
| 1685 | 1697 |
} |
| 1686 | 1698 |
} |
| 1687 | 1699 |
|
| 1688 |
// reset some internal variables and eprint a new prompt
|
|
| 1689 |
if (readeval == AOS_SUCCESS && !chThdShouldTerminateX()) {
|
|
| 1700 |
// reset some internal variables and print a new prompt |
|
| 1701 |
if (execute && !chThdShouldTerminateX()) {
|
|
| 1690 | 1702 |
((aos_shell_t*)shell)->inputdata.cursorpos = 0; |
| 1691 | 1703 |
((aos_shell_t*)shell)->inputdata.lineend = 0; |
| 1692 | 1704 |
((aos_shell_t*)shell)->inputdata.noinput = true; |
Also available in: Unified diff