544 |
544 |
|
545 |
545 |
// move cursor right by printing line content
|
546 |
546 |
while (pos < to) {
|
547 |
|
streamPut(&shell->stream, shell->input.line[pos]);
|
|
547 |
streamPut(&shell->stream, (uint8_t)shell->input.line[pos]);
|
548 |
548 |
++pos;
|
549 |
549 |
}
|
550 |
550 |
|
... | ... | |
568 |
568 |
size_t cnt;
|
569 |
569 |
|
570 |
570 |
for (cnt = 0; from + cnt < to; ++cnt) {
|
571 |
|
streamPut(&shell->stream, shell->input.line[from + cnt]);
|
|
571 |
streamPut(&shell->stream, (uint8_t)shell->input.line[from + cnt]);
|
572 |
572 |
}
|
573 |
573 |
|
574 |
574 |
return cnt;
|
... | ... | |
578 |
578 |
aosDbgCheck(shell != NULL);
|
579 |
579 |
|
580 |
580 |
// check whether input line is already full
|
581 |
|
if (shell->inputdata.lineend + 1 >= shell->input.width) {
|
|
581 |
if (shell->inputdata.lineend + 1 >= shell->input.length) {
|
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.width);
|
|
586 |
memset(shell->input.line, '\0', shell->input.length);
|
587 |
587 |
shell->inputdata.noinput = false;
|
588 |
588 |
}
|
589 |
589 |
// overwrite content
|
... | ... | |
908 |
908 |
charmatch_t mlvl = CHAR_MATCH_NOT;
|
909 |
909 |
_strccmp(fill, cmd->name, shell->config & AOS_SHELL_CONFIG_MATCH_CASE, (n == 0) ? NULL : &n, &mlvl);
|
910 |
910 |
const int cmp = (n < cmatch) ?
|
911 |
|
(n - cmatch) :
|
|
911 |
((int)n - (int)cmatch) :
|
912 |
912 |
(cmd->name[n] != '\0') ?
|
913 |
|
strlen(cmd->name) - n :
|
|
913 |
(int)strlen(cmd->name) - (int)n :
|
914 |
914 |
0;
|
915 |
915 |
// if an exact match was found
|
916 |
|
if (cmatch + cmp == shell->inputdata.cursorpos) {
|
|
916 |
if ((size_t)((int)cmatch + cmp) == shell->inputdata.cursorpos) {
|
917 |
917 |
cmatch = shell->inputdata.cursorpos;
|
918 |
918 |
fill = cmd->name;
|
919 |
919 |
// break the loop only if there are no case mismatches with the input
|
... | ... | |
924 |
924 |
}
|
925 |
925 |
}
|
926 |
926 |
// if a not exact match was found
|
927 |
|
else if (cmatch + cmp > shell->inputdata.cursorpos) {
|
|
927 |
else if ((size_t)((int)cmatch + cmp) > shell->inputdata.cursorpos) {
|
928 |
928 |
// if this is the first one
|
929 |
929 |
if (fill == shell->input.line) {
|
930 |
|
cmatch += cmp;
|
|
930 |
cmatch = (size_t)((int)cmatch + cmp);
|
931 |
931 |
fill = cmd->name;
|
932 |
932 |
}
|
933 |
933 |
// if this is a worse one
|
934 |
934 |
else if ((cmp < 0) || (cmp == 0 && mlvl == CHAR_MATCH_CASE)) {
|
935 |
|
cmatch += cmp;
|
|
935 |
cmatch = (size_t)((int)cmatch + cmp);
|
936 |
936 |
}
|
937 |
937 |
}
|
938 |
938 |
// non matching commands are ignored
|
... | ... | |
945 |
945 |
if (cmatch > shell->inputdata.cursorpos || (cmatch == shell->inputdata.cursorpos && matchlevel == CHAR_MATCH_NCASE)) {
|
946 |
946 |
shell->inputdata.noinput = false;
|
947 |
947 |
// limit auto fill so it will not overflow the line width
|
948 |
|
if (shell->inputdata.lineend + (cmatch - shell->inputdata.cursorpos) > shell->input.width) {
|
949 |
|
cmatch = shell->input.width - shell->inputdata.lineend + shell->inputdata.cursorpos;
|
|
948 |
if (shell->inputdata.lineend + (cmatch - shell->inputdata.cursorpos) > shell->input.length) {
|
|
949 |
cmatch = shell->input.length - shell->inputdata.lineend + shell->inputdata.cursorpos;
|
950 |
950 |
}
|
951 |
951 |
// move trailing memory further in the line
|
952 |
952 |
memmove(&(shell->input.line[cmatch]), &(shell->input.line[shell->inputdata.cursorpos]), shell->inputdata.lineend - shell->inputdata.cursorpos);
|
... | ... | |
982 |
982 |
_strccmp(shell->input.line, cmd->name, true, &i, NULL);
|
983 |
983 |
}
|
984 |
984 |
const int cmp = (i < shell->inputdata.cursorpos) ?
|
985 |
|
(i - shell->inputdata.cursorpos) :
|
|
985 |
(int)(i - shell->inputdata.cursorpos) :
|
986 |
986 |
(cmd->name[i] != '\0') ?
|
987 |
|
strlen(cmd->name) - i :
|
|
987 |
(int)strlen(cmd->name) - (int)i :
|
988 |
988 |
0;
|
989 |
989 |
// if a match was found
|
990 |
990 |
if (cmp > 0) {
|
... | ... | |
1048 |
1048 |
size_t nul_start = 0;
|
1049 |
1049 |
size_t nul_end = 0;
|
1050 |
1050 |
// search line for a NUL byte
|
1051 |
|
while (nul_start < shell->input.width) {
|
|
1051 |
while (nul_start < shell->input.length) {
|
1052 |
1052 |
if (shell->input.line[nul_start] == '\0') {
|
1053 |
1053 |
nul_end = nul_start + 1;
|
1054 |
1054 |
// keep searcjing for a byte that is not NUL
|
1055 |
|
while (nul_end < shell->input.width) {
|
|
1055 |
while (nul_end < shell->input.length) {
|
1056 |
1056 |
if (shell->input.line[nul_end] != '\0') {
|
1057 |
1057 |
// an intermediate NUL sequence was found
|
1058 |
1058 |
memset(&(shell->input.line[nul_start]), ' ', nul_end - nul_start);
|
... | ... | |
1149 |
1149 |
streamPut(&shell->stream, '\n');
|
1150 |
1150 |
// set the number of read bytes and return
|
1151 |
1151 |
if (!shell->inputdata.noinput) {
|
1152 |
|
*n = shell->input.width - shell->inputdata.lineend;
|
|
1152 |
*n = shell->input.length - shell->inputdata.lineend;
|
1153 |
1153 |
// fill the remainder of the line with NUL bytes
|
1154 |
1154 |
memset(&(shell->input.line[shell->inputdata.lineend]), '\0', *n);
|
1155 |
1155 |
// reset static variables
|
... | ... | |
1192 |
1192 |
/**
|
1193 |
1193 |
* @brief Parses the content of the input buffer (line) to separate arguments.
|
1194 |
1194 |
*
|
1195 |
|
* @param[in] shell Pointer to the shell object.
|
|
1195 |
* @param[in] shell Pointer to the shell object.
|
|
1196 |
* @param[out] argbuf Buffer to store argument pointers to.
|
1196 |
1197 |
*
|
1197 |
1198 |
* @return Number of arguments found.
|
1198 |
1199 |
*/
|
1199 |
|
static size_t _parseArguments(aos_shell_t* shell)
|
|
1200 |
static size_t _parseArguments(aos_shell_t* shell, char** argbuf)
|
1200 |
1201 |
{
|
1201 |
1202 |
aosDbgCheck(shell != NULL);
|
|
1203 |
aosDbgCheck(argbuf != NULL);
|
1202 |
1204 |
|
1203 |
1205 |
/*
|
1204 |
1206 |
* States for a very small FSM.
|
... | ... | |
1212 |
1214 |
|
1213 |
1215 |
// local variables
|
1214 |
1216 |
state_t state = START;
|
1215 |
|
size_t arg = 0;
|
|
1217 |
size_t nargs = 0;
|
1216 |
1218 |
|
1217 |
1219 |
// iterate through the line
|
1218 |
|
for (char* c = shell->input.line; c < shell->input.line + shell->input.width; ++c) {
|
|
1220 |
for (char* c = shell->input.line; c < shell->input.line + shell->input.length; ++c) {
|
1219 |
1221 |
// terminate at first NUL byte
|
1220 |
1222 |
if (*c == '\0') {
|
1221 |
1223 |
state = END;
|
... | ... | |
1232 |
1234 |
case START:
|
1233 |
1235 |
case SPACE:
|
1234 |
1236 |
// ignore too many arguments
|
1235 |
|
if (arg < shell->arglistsize) {
|
1236 |
|
shell->arglist[arg] = c;
|
|
1237 |
if (nargs < shell->input.nargs) {
|
|
1238 |
argbuf[nargs] = c;
|
1237 |
1239 |
}
|
1238 |
|
++arg;
|
|
1240 |
++nargs;
|
1239 |
1241 |
break;
|
1240 |
1242 |
case TEXT:
|
1241 |
1243 |
case END:
|
1242 |
|
default:
|
1243 |
1244 |
break;
|
1244 |
1245 |
}
|
1245 |
1246 |
state = TEXT;
|
... | ... | |
1247 |
1248 |
}
|
1248 |
1249 |
|
1249 |
1250 |
// set all remaining argument pointers to NULL
|
1250 |
|
for (size_t a = arg; a < shell->arglistsize; ++a) {
|
1251 |
|
shell->arglist[a] = NULL;
|
|
1251 |
for (size_t a = nargs; a < shell->input.nargs; ++a) {
|
|
1252 |
argbuf[a] = NULL;
|
1252 |
1253 |
}
|
1253 |
1254 |
|
1254 |
|
return arg;
|
|
1255 |
return nargs;
|
1255 |
1256 |
}
|
1256 |
1257 |
|
1257 |
1258 |
/******************************************************************************/
|
... | ... | |
1266 |
1267 |
* @param[in] prompt Prompt line to print (NULL = use default prompt).
|
1267 |
1268 |
* @param[in] line Pointer to the input buffer.
|
1268 |
1269 |
* @param[in] linesize Size of the input buffer.
|
1269 |
|
* @param[in] arglist Pointer to the argument buffer.
|
1270 |
|
* @param[in] arglistsize Size of te argument buffer.
|
|
1270 |
* @param[in] numargs Maximum number of arguments (defines size of internal buffer).
|
1271 |
1271 |
*/
|
1272 |
|
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, size_t numargs)
|
1273 |
1273 |
{
|
1274 |
1274 |
aosDbgCheck(shell != NULL);
|
1275 |
1275 |
aosDbgCheck(oseventsource != NULL);
|
1276 |
1276 |
aosDbgCheck(line != NULL);
|
1277 |
|
aosDbgCheck(arglist != NULL);
|
1278 |
1277 |
|
1279 |
1278 |
// set parameters
|
1280 |
1279 |
shell->thread = NULL;
|
... | ... | |
1286 |
1285 |
shell->execstatus.command = NULL;
|
1287 |
1286 |
shell->execstatus.retval = 0;
|
1288 |
1287 |
shell->input.line = line;
|
1289 |
|
shell->input.width = linesize;
|
|
1288 |
shell->input.length = linesize;
|
1290 |
1289 |
shell->inputdata.lastaction = AOS_SHELL_ACTION_NONE;
|
1291 |
1290 |
memset(shell->inputdata.escseq, '\0', sizeof(shell->inputdata.escseq)*sizeof(shell->inputdata.escseq[0]));
|
1292 |
1291 |
shell->inputdata.cursorpos = 0;
|
1293 |
1292 |
shell->inputdata.lineend = 0;
|
1294 |
1293 |
shell->inputdata.noinput = true;
|
1295 |
|
shell->arglist = arglist;
|
1296 |
|
shell->arglistsize = arglistsize;
|
|
1294 |
shell->input.nargs= numargs;
|
1297 |
1295 |
shell->config = 0x00;
|
1298 |
1296 |
|
1299 |
1297 |
// initialize buffers
|
1300 |
|
memset(shell->input.line, '\0', shell->input.width);
|
1301 |
|
for (size_t a = 0; a < shell->arglistsize; ++a) {
|
1302 |
|
shell->arglist[a] = NULL;
|
1303 |
|
}
|
|
1298 |
memset(shell->input.line, '\0', shell->input.length);
|
1304 |
1299 |
|
1305 |
1300 |
return;
|
1306 |
1301 |
}
|
... | ... | |
1607 |
1602 |
AosShellChannel* channel;
|
1608 |
1603 |
aos_status_t readeval;
|
1609 |
1604 |
size_t nchars = 0;
|
|
1605 |
char* args[((aos_shell_t*)shell)->input.nargs];
|
1610 |
1606 |
size_t nargs = 0;
|
1611 |
1607 |
aos_shellcommand_t* cmd;
|
1612 |
1608 |
|
|
1609 |
// initialize variables
|
|
1610 |
for (size_t arg = 0; arg < ((aos_shell_t*)shell)->input.nargs; ++arg) {
|
|
1611 |
args[arg] = NULL;
|
|
1612 |
}
|
1613 |
1613 |
|
1614 |
1614 |
// register OS related events
|
1615 |
1615 |
chEvtRegisterMask(((aos_shell_t*)shell)->os.eventSource, &(((aos_shell_t*)shell)->os.eventListener), AOS_SHELL_EVENTMASK_OS);
|
... | ... | |
1658 |
1658 |
// read input from channel
|
1659 |
1659 |
readeval = _readChannel((aos_shell_t*)shell, channel, &nchars);
|
1660 |
1660 |
// parse input line to argument list only if the input shall be executed
|
1661 |
|
nargs = (readeval == AOS_SUCCESS && nchars > 0) ? _parseArguments((aos_shell_t*)shell) : 0;
|
|
1661 |
nargs = (readeval == AOS_SUCCESS && nchars > 0) ? _parseArguments((aos_shell_t*)shell, args) : 0;
|
1662 |
1662 |
// check number of arguments
|
1663 |
|
if (nargs > ((aos_shell_t*)shell)->arglistsize) {
|
|
1663 |
if (nargs > ((aos_shell_t*)shell)->input.nargs) {
|
1664 |
1664 |
// error too many arguments
|
1665 |
1665 |
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\ttoo many arguments\n");
|
1666 |
1666 |
} else if (nargs > 0) {
|
1667 |
1667 |
// search command list for arg[0] and execute callback
|
1668 |
1668 |
cmd = ((aos_shell_t*)shell)->commands;
|
1669 |
1669 |
while (cmd != NULL) {
|
1670 |
|
if (strcmp(((aos_shell_t*)shell)->arglist[0], cmd->name) == 0) {
|
|
1670 |
if (strcmp(args[0], cmd->name) == 0) {
|
1671 |
1671 |
((aos_shell_t*)shell)->execstatus.command = cmd;
|
1672 |
1672 |
chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_EXEC);
|
1673 |
|
((aos_shell_t*)shell)->execstatus.retval = cmd->callback((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, nargs, ((aos_shell_t*)shell)->arglist);
|
|
1673 |
((aos_shell_t*)shell)->execstatus.retval = cmd->callback((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, (int)nargs, args);
|
1674 |
1674 |
chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_DONE);
|
1675 |
1675 |
// notify if the command was not successful
|
1676 |
1676 |
if (((aos_shell_t*)shell)->execstatus.retval != 0) {
|
... | ... | |
1683 |
1683 |
|
1684 |
1684 |
// if no matching command was found, print an error
|
1685 |
1685 |
if (cmd == NULL) {
|
1686 |
|
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\tcommand '%s' not found\n", ((aos_shell_t*)shell)->arglist[0]);
|
|
1686 |
chprintf((BaseSequentialStream*)&((aos_shell_t*)shell)->stream, "\tcommand '%s' not found\n", args[0]);
|
1687 |
1687 |
}
|
1688 |
1688 |
}
|
1689 |
1689 |
|