mirror of
https://github.com/espressif/openthread.git
synced 2026-09-08 18:20:06 +00:00
[posix] ot-ctl process lines for non-interactive mode (#5134)
This commit enhances ot-ctl to process only after a full line is read in non-interactive mode. This eliminates the complex and error-prone states handling, which still has potential issues (despite of small chance): - If Done\r\n is received in two chunks: Done\r and \n, the original implementation won't output \n - If Error 7: InvalidArgs is received in two chunks: Error and 7: InvalidArgs, the original implementation won't output 7: InvalidArgs
This commit is contained in:
+41
-127
@@ -59,6 +59,15 @@
|
||||
|
||||
#include "platform-posix.h"
|
||||
|
||||
enum
|
||||
{
|
||||
kLineBufferSize = 256,
|
||||
};
|
||||
|
||||
static_assert(kLineBufferSize >= sizeof("> "), "kLineBufferSize is too small");
|
||||
static_assert(kLineBufferSize >= sizeof("Done\r\n"), "kLineBufferSize is too small");
|
||||
static_assert(kLineBufferSize >= sizeof("Error "), "kLineBufferSize is too small");
|
||||
|
||||
static int sSessionFd = -1;
|
||||
|
||||
#if OPENTHREAD_USE_READLINE
|
||||
@@ -77,97 +86,6 @@ static void InputCallback(char *aLine)
|
||||
}
|
||||
#endif // OPENTHREAD_USE_READLINE
|
||||
|
||||
static bool FindPrompt(int &aState, char aChar)
|
||||
{
|
||||
switch (aChar)
|
||||
{
|
||||
case '>':
|
||||
aState = aState == 0 ? 1 : -1;
|
||||
break;
|
||||
case ' ':
|
||||
aState = aState == 1 ? 2 : -1;
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
aState = 0;
|
||||
break;
|
||||
default:
|
||||
aState = -1;
|
||||
}
|
||||
|
||||
return aState == 2;
|
||||
}
|
||||
|
||||
static bool FindDone(int &aDoneState, char aNowCharacter)
|
||||
{
|
||||
switch (aNowCharacter)
|
||||
{
|
||||
case 'D':
|
||||
aDoneState = aDoneState == 0 ? 1 : -1;
|
||||
break;
|
||||
case 'o':
|
||||
aDoneState = aDoneState == 1 ? 2 : -1;
|
||||
break;
|
||||
case 'n':
|
||||
aDoneState = aDoneState == 2 ? 3 : -1;
|
||||
break;
|
||||
case 'e':
|
||||
aDoneState = aDoneState == 3 ? 4 : -1;
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
if (aDoneState == 4)
|
||||
{
|
||||
aDoneState = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
aDoneState = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
aDoneState = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return aDoneState == 5;
|
||||
}
|
||||
|
||||
static bool FindError(int &aErrorState, char aNowCharacter)
|
||||
{
|
||||
switch (aNowCharacter)
|
||||
{
|
||||
case 'E':
|
||||
aErrorState = aErrorState == 0 ? 1 : -1;
|
||||
break;
|
||||
case 'r':
|
||||
if (aErrorState == 1 || aErrorState == 2 || aErrorState == 4)
|
||||
{
|
||||
(aErrorState)++;
|
||||
}
|
||||
else
|
||||
{
|
||||
aErrorState = -1;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
aErrorState = aErrorState == 3 ? 4 : -1;
|
||||
break;
|
||||
case ' ':
|
||||
aErrorState = aErrorState == 5 ? 6 : -1;
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
aErrorState = 0;
|
||||
break;
|
||||
default:
|
||||
aErrorState = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return aErrorState == 6;
|
||||
}
|
||||
|
||||
static bool DoWrite(int aFile, const void *aBuffer, size_t aSize)
|
||||
{
|
||||
bool ret = true;
|
||||
@@ -192,12 +110,12 @@ exit:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
bool isInteractive = true;
|
||||
bool isFinished = false;
|
||||
int doneState = 0;
|
||||
int errorState = 0;
|
||||
int promptState = 0;
|
||||
int ret;
|
||||
bool isInteractive = true;
|
||||
bool isFinished = false;
|
||||
char lineBuffer[kLineBufferSize];
|
||||
size_t lineBufferWritePos = 0;
|
||||
bool isBeginOfLine = true;
|
||||
|
||||
sSessionFd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
VerifyOrExit(sSessionFd != -1, perror("socket"); ret = OT_EXIT_FAILURE);
|
||||
@@ -296,43 +214,39 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
ssize_t lineStart = 0;
|
||||
|
||||
for (ssize_t i = 0; i < rval; i++)
|
||||
{
|
||||
int prevPromptState = promptState;
|
||||
char c = buffer[i];
|
||||
|
||||
if (FindPrompt(promptState, buffer[i]))
|
||||
lineBuffer[lineBufferWritePos++] = c;
|
||||
if (c == '\n' || lineBufferWritePos >= sizeof(lineBuffer) - 1)
|
||||
{
|
||||
doneState = 0;
|
||||
errorState = 0;
|
||||
lineStart = i + 1;
|
||||
continue;
|
||||
}
|
||||
else if (prevPromptState == 1 && i == 0)
|
||||
{
|
||||
VerifyOrExit(DoWrite(STDOUT_FILENO, ">", 1), ret = OT_EXIT_FAILURE);
|
||||
}
|
||||
char * line = lineBuffer;
|
||||
size_t len = lineBufferWritePos;
|
||||
|
||||
if (buffer[i] == '\r' || buffer[i] == '\n')
|
||||
{
|
||||
VerifyOrExit(DoWrite(STDOUT_FILENO, buffer + lineStart, static_cast<size_t>(i - lineStart + 1)),
|
||||
ret = OT_EXIT_FAILURE);
|
||||
lineStart = i + 1;
|
||||
}
|
||||
// read one line successfully or line buffer is full
|
||||
line[len] = '\0';
|
||||
|
||||
if (FindDone(doneState, buffer[i]) || FindError(errorState, buffer[i]))
|
||||
{
|
||||
isFinished = true;
|
||||
ret = OT_EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (isBeginOfLine && strncmp("> ", lineBuffer, 2) == 0)
|
||||
{
|
||||
line += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (lineStart < rval && promptState != 1)
|
||||
{
|
||||
assert(promptState != 0 && promptState != 2);
|
||||
VerifyOrExit(DoWrite(STDOUT_FILENO, buffer + lineStart, static_cast<size_t>(rval - lineStart)),
|
||||
ret = OT_EXIT_FAILURE);
|
||||
VerifyOrExit(DoWrite(STDOUT_FILENO, line, len), ret = OT_EXIT_FAILURE);
|
||||
|
||||
if (isBeginOfLine && (strncmp("Done\n", line, 5) == 0 || strncmp("Done\r\n", line, 6) == 0 ||
|
||||
strncmp("Error ", line, 6) == 0))
|
||||
{
|
||||
isFinished = true;
|
||||
ret = OT_EXIT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
// reset for next line
|
||||
lineBufferWritePos = 0;
|
||||
isBeginOfLine = c == '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user