mirror of
https://github.com/taigrr/arduinolibs
synced 2025-01-18 04:33:12 -08:00
More compact representation of command history
This commit is contained in:
parent
fcf875f9fd
commit
07af69c612
@ -120,13 +120,13 @@
|
|||||||
* the underlying I/O stream.
|
* the underlying I/O stream.
|
||||||
*/
|
*/
|
||||||
Shell::Shell()
|
Shell::Shell()
|
||||||
: maxHistory(0)
|
: curStart(0)
|
||||||
, curStart(0)
|
|
||||||
, curLen(0)
|
, curLen(0)
|
||||||
, curMax(sizeof(buffer))
|
, curMax(sizeof(buffer))
|
||||||
, history(0)
|
, history(0)
|
||||||
, historyWrite(0)
|
, historyWrite(0)
|
||||||
, historyPosn(0)
|
, historyRead(0)
|
||||||
|
, historySize(0)
|
||||||
, prom("$ ")
|
, prom("$ ")
|
||||||
, isClient(false)
|
, isClient(false)
|
||||||
, lineMode(LINEMODE_NORMAL | LINEMODE_ECHO)
|
, lineMode(LINEMODE_NORMAL | LINEMODE_ECHO)
|
||||||
@ -165,6 +165,11 @@ Shell::~Shell()
|
|||||||
* shell.begin(Serial);
|
* shell.begin(Serial);
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
|
* The \a maxHistory parameter indicates the number of commands of
|
||||||
|
* maximum length that can be stored in the history. If the actual
|
||||||
|
* entered commands are shorter, then more commands can be stored in
|
||||||
|
* the history.
|
||||||
|
*
|
||||||
* \sa end(), setPrompt()
|
* \sa end(), setPrompt()
|
||||||
*/
|
*/
|
||||||
bool Shell::begin(Stream &stream, size_t maxHistory, Terminal::Mode mode)
|
bool Shell::begin(Stream &stream, size_t maxHistory, Terminal::Mode mode)
|
||||||
@ -192,6 +197,11 @@ bool Shell::begin(Stream &stream, size_t maxHistory, Terminal::Mode mode)
|
|||||||
* builtin "exit" command to forcibly stop the TCP connection rather
|
* builtin "exit" command to forcibly stop the TCP connection rather
|
||||||
* than returning to the login prompt.
|
* than returning to the login prompt.
|
||||||
*
|
*
|
||||||
|
* The \a maxHistory parameter indicates the number of commands of
|
||||||
|
* maximum length that can be stored in the history. If the actual
|
||||||
|
* entered commands are shorter, then more commands can be stored in
|
||||||
|
* the history.
|
||||||
|
*
|
||||||
* \sa end(), setPrompt()
|
* \sa end(), setPrompt()
|
||||||
*/
|
*/
|
||||||
bool Shell::begin(Client &client, size_t maxHistory, Terminal::Mode mode)
|
bool Shell::begin(Client &client, size_t maxHistory, Terminal::Mode mode)
|
||||||
@ -212,14 +222,15 @@ bool Shell::beginShell(Stream &stream, size_t maxHistory, Terminal::Mode mode)
|
|||||||
|
|
||||||
// Create the history buffer.
|
// Create the history buffer.
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
this->maxHistory = maxHistory;
|
|
||||||
delete [] history;
|
delete [] history;
|
||||||
|
historySize = sizeof(buffer) * maxHistory;
|
||||||
if (maxHistory) {
|
if (maxHistory) {
|
||||||
history = new char [sizeof(buffer) * maxHistory];
|
history = new char [historySize];
|
||||||
if (history) {
|
if (history) {
|
||||||
memset(history, 0, sizeof(buffer) * maxHistory);
|
memset(history, 0, historySize);
|
||||||
} else {
|
} else {
|
||||||
this->maxHistory = 0;
|
maxHistory = 0;
|
||||||
|
historySize = 0;
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -231,7 +242,7 @@ bool Shell::beginShell(Stream &stream, size_t maxHistory, Terminal::Mode mode)
|
|||||||
curLen = 0;
|
curLen = 0;
|
||||||
curMax = sizeof(buffer);
|
curMax = sizeof(buffer);
|
||||||
historyWrite = 0;
|
historyWrite = 0;
|
||||||
historyPosn = 0;
|
historyRead = 0;
|
||||||
|
|
||||||
// Begins the login session.
|
// Begins the login session.
|
||||||
beginSession();
|
beginSession();
|
||||||
@ -251,13 +262,13 @@ void Shell::end()
|
|||||||
Terminal::end();
|
Terminal::end();
|
||||||
clearHistory();
|
clearHistory();
|
||||||
delete [] history;
|
delete [] history;
|
||||||
maxHistory = 0;
|
|
||||||
curStart = 0;
|
curStart = 0;
|
||||||
curLen = 0;
|
curLen = 0;
|
||||||
curMax = sizeof(buffer);
|
curMax = sizeof(buffer);
|
||||||
history = 0;
|
history = 0;
|
||||||
historyWrite = 0;
|
historyWrite = 0;
|
||||||
historyPosn = 0;
|
historyRead = 0;
|
||||||
|
historySize = 0;
|
||||||
isClient = false;
|
isClient = false;
|
||||||
lineMode = LINEMODE_NORMAL | LINEMODE_ECHO;
|
lineMode = LINEMODE_NORMAL | LINEMODE_ECHO;
|
||||||
}
|
}
|
||||||
@ -334,18 +345,16 @@ void Shell::loop()
|
|||||||
case KEY_UP_ARROW:
|
case KEY_UP_ARROW:
|
||||||
// Go back one item in the command history.
|
// Go back one item in the command history.
|
||||||
if ((lineMode & LINEMODE_NORMAL) != 0 &&
|
if ((lineMode & LINEMODE_NORMAL) != 0 &&
|
||||||
history && historyPosn < maxHistory) {
|
history && historyRead > 0) {
|
||||||
++historyPosn;
|
changeHistory(true);
|
||||||
changeHistory();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_DOWN_ARROW:
|
case KEY_DOWN_ARROW:
|
||||||
// Go forward one item in the command history.
|
// Go forward one item in the command history.
|
||||||
if ((lineMode & LINEMODE_NORMAL) != 0 &&
|
if ((lineMode & LINEMODE_NORMAL) != 0 &&
|
||||||
history && historyPosn > 0) {
|
history && historyRead < historyWrite) {
|
||||||
--historyPosn;
|
changeHistory(false);
|
||||||
changeHistory();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -582,22 +591,45 @@ void Shell::execute()
|
|||||||
// If we have a history stack and the new command is different from
|
// If we have a history stack and the new command is different from
|
||||||
// the previous command, then copy the command into the stack.
|
// the previous command, then copy the command into the stack.
|
||||||
if (history && curLen > curStart) {
|
if (history && curLen > curStart) {
|
||||||
char *hist = history + sizeof(buffer) * historyWrite;
|
char *prevCmd;
|
||||||
if (strcmp(hist, buffer) != 0) {
|
bool newCmd = true;
|
||||||
historyWrite = (historyWrite + 1) % maxHistory;
|
if (historyWrite > 0) {
|
||||||
hist = history + sizeof(buffer) * historyWrite;
|
prevCmd = (char *)memrchr(history, '\0', historyWrite - 1);
|
||||||
strcpy(hist, buffer + curStart);
|
if (prevCmd)
|
||||||
|
++prevCmd;
|
||||||
|
else
|
||||||
|
prevCmd = history;
|
||||||
|
if (strcmp(prevCmd, buffer + curStart) == 0)
|
||||||
|
newCmd = false;
|
||||||
|
}
|
||||||
|
if (newCmd) {
|
||||||
|
size_t len = curLen - curStart;
|
||||||
|
while ((len + 1) > (historySize - historyWrite)) {
|
||||||
|
// History stack is full. Pop older entries to get some room.
|
||||||
|
prevCmd = (char *)memchr(history, '\0', historyWrite);
|
||||||
|
if (prevCmd) {
|
||||||
|
size_t histLen = historyWrite - ((prevCmd + 1) - history);
|
||||||
|
memmove(history, prevCmd + 1, histLen);
|
||||||
|
historyWrite = histLen;
|
||||||
|
} else {
|
||||||
|
historyWrite = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(history + historyWrite, buffer + curStart, len);
|
||||||
|
historyWrite += len;
|
||||||
|
history[historyWrite++] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the history read position to the top of the stack.
|
// Reset the history read position to the top of the stack.
|
||||||
historyPosn = 0;
|
historyRead = historyWrite;
|
||||||
|
|
||||||
// Break the command up into arguments and populate the argument array.
|
// Break the command up into arguments and populate the argument array.
|
||||||
ShellArguments argv(buffer + curStart, curLen - curStart);
|
ShellArguments argv(buffer + curStart, curLen - curStart);
|
||||||
|
|
||||||
// Clear the line buffer.
|
// Clear the line buffer.
|
||||||
curLen = 0;
|
curLen = curStart;
|
||||||
|
|
||||||
// Execute the command.
|
// Execute the command.
|
||||||
if (argv.count() > 0) {
|
if (argv.count() > 0) {
|
||||||
@ -709,36 +741,34 @@ void Shell::clearCharacters(size_t len)
|
|||||||
/**
|
/**
|
||||||
* \brief Changes the current command to reflect a different position
|
* \brief Changes the current command to reflect a different position
|
||||||
* in the history stack.
|
* in the history stack.
|
||||||
|
*
|
||||||
|
* \param up Set to true to go up in the history, false to go down.
|
||||||
*/
|
*/
|
||||||
void Shell::changeHistory()
|
void Shell::changeHistory(bool up)
|
||||||
{
|
{
|
||||||
// Replace the command with the historyPosn item from the stack.
|
char *cmd;
|
||||||
// A historyPosn of 1 is the top of the history stack and a
|
if (up) {
|
||||||
// historyPosn of maxHistory is the bottom of the history stack.
|
cmd = (char *)memrchr(history, '\0', historyRead - 1);
|
||||||
// A historyPosn of 0 means that the down arrow has navigated
|
if (cmd)
|
||||||
// off the history stack, so clear the command only.
|
historyRead = (size_t)(cmd - history + 1);
|
||||||
if (historyPosn) {
|
else
|
||||||
size_t posn = (historyWrite + maxHistory - (historyPosn - 1)) % maxHistory;
|
historyRead = 0;
|
||||||
char *hist = history + sizeof(buffer) * posn;
|
|
||||||
if (*hist != '\0') {
|
|
||||||
// Copy the line from the history into the command buffer.
|
|
||||||
clearCharacters(curLen);
|
|
||||||
curLen = strlen(hist);
|
|
||||||
if (curLen > (curMax - curStart))
|
|
||||||
curLen = curMax - curStart;
|
|
||||||
memcpy(buffer + curStart, hist, curLen);
|
|
||||||
if (lineMode & LINEMODE_ECHO)
|
|
||||||
write((uint8_t *)hist, curLen);
|
|
||||||
curLen += curStart;
|
|
||||||
} else {
|
|
||||||
// We've gone too far - the history is still smaller
|
|
||||||
// than maxHistory in size. So reset the position and
|
|
||||||
// don't go any further.
|
|
||||||
--historyPosn;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// We've navigated off the history stack.
|
cmd = (char *)memchr(history + historyRead, '\0', historyWrite - historyRead);
|
||||||
clearCharacters(curLen);
|
if (cmd)
|
||||||
|
historyRead = (size_t)(cmd - history + 1);
|
||||||
|
else
|
||||||
|
historyRead = historyWrite;
|
||||||
|
}
|
||||||
|
clearCharacters(curLen);
|
||||||
|
if (historyRead < historyWrite) {
|
||||||
|
cmd = history + historyRead;
|
||||||
|
curLen = strlen(cmd);
|
||||||
|
if (curLen > (curMax - curStart))
|
||||||
|
curLen = curMax - curStart;
|
||||||
|
memcpy(buffer + curStart, cmd, curLen);
|
||||||
|
write((uint8_t *)cmd, curLen);
|
||||||
|
curLen += curStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -751,10 +781,9 @@ void Shell::changeHistory()
|
|||||||
void Shell::clearHistory()
|
void Shell::clearHistory()
|
||||||
{
|
{
|
||||||
if (history)
|
if (history)
|
||||||
memset(history, 0, sizeof(buffer) * maxHistory);
|
memset(history, 0, historySize);
|
||||||
historyPosn = 0;
|
historyRead = 0;
|
||||||
historyWrite = 0;
|
historyWrite = 0;
|
||||||
clearCharacters(curLen);
|
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,13 +86,13 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
char buffer[SHELL_MAX_CMD_LEN];
|
char buffer[SHELL_MAX_CMD_LEN];
|
||||||
size_t maxHistory;
|
|
||||||
size_t curStart;
|
size_t curStart;
|
||||||
size_t curLen;
|
size_t curLen;
|
||||||
size_t curMax;
|
size_t curMax;
|
||||||
char *history;
|
char *history;
|
||||||
size_t historyWrite;
|
size_t historyWrite;
|
||||||
size_t historyPosn;
|
size_t historyRead;
|
||||||
|
size_t historySize;
|
||||||
const char *prom;
|
const char *prom;
|
||||||
bool isClient;
|
bool isClient;
|
||||||
uint8_t lineMode;
|
uint8_t lineMode;
|
||||||
@ -106,7 +106,7 @@ private:
|
|||||||
bool execute(const ShellArguments &argv);
|
bool execute(const ShellArguments &argv);
|
||||||
void executeBuiltin(const char *cmd);
|
void executeBuiltin(const char *cmd);
|
||||||
void clearCharacters(size_t len);
|
void clearCharacters(size_t len);
|
||||||
void changeHistory();
|
void changeHistory(bool up);
|
||||||
void clearHistory();
|
void clearHistory();
|
||||||
|
|
||||||
friend class LoginShell;
|
friend class LoginShell;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user