mirror of
https://github.com/espressif/openthread.git
synced 2026-08-10 04:37:47 +00:00
[cli] allow to escape separators (#4608)
This commit is contained in:
@@ -5,6 +5,27 @@ command line interface. Use the CLI to play with OpenThread, which
|
||||
can also be used with additional application code. The
|
||||
OpenThread test scripts use the CLI to execute test cases.
|
||||
|
||||
## Separator and escaping characters
|
||||
|
||||
The whitespace character (`' '`) is used to delimit the command name
|
||||
and the different arguments, together with tab (`'\t'`) and new line
|
||||
characters (`'\r'`, `'\n'`).
|
||||
|
||||
Some arguments might require to accept whitespaces on them. For those
|
||||
cases the backslash character (`'\'`) can be used to escape separators
|
||||
or the backslash itself.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
> networkname Test\ Network
|
||||
Done
|
||||
> networkname
|
||||
Test Network
|
||||
Done
|
||||
>
|
||||
```
|
||||
|
||||
## OpenThread Command List
|
||||
|
||||
* [bufferinfo](#bufferinfo)
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
* This file implements the command line parser.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "parse_cmdline.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
@@ -38,11 +40,16 @@
|
||||
namespace ot {
|
||||
namespace Utils {
|
||||
|
||||
static bool IsSpaceOrNewLine(char aChar)
|
||||
static bool IsSeparator(char aChar)
|
||||
{
|
||||
return (aChar == ' ') || (aChar == '\t') || (aChar == '\r') || (aChar == '\n');
|
||||
}
|
||||
|
||||
static bool IsEscapable(char aChar)
|
||||
{
|
||||
return IsSeparator(aChar) || (aChar == '\\');
|
||||
}
|
||||
|
||||
otError CmdLineParser::ParseCmd(char *aString, uint8_t &aArgc, char *aArgv[], uint8_t aArgcMax)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
@@ -50,21 +57,19 @@ otError CmdLineParser::ParseCmd(char *aString, uint8_t &aArgc, char *aArgv[], ui
|
||||
|
||||
aArgc = 0;
|
||||
|
||||
for (cmd = aString; IsSpaceOrNewLine(*cmd) && *cmd; cmd++)
|
||||
;
|
||||
|
||||
if (*cmd)
|
||||
for (cmd = aString; *cmd; cmd++)
|
||||
{
|
||||
aArgv[aArgc++] = cmd++; // the first argument
|
||||
}
|
||||
|
||||
for (; *cmd; cmd++)
|
||||
{
|
||||
if (IsSpaceOrNewLine(*cmd))
|
||||
if ((*cmd == '\\') && IsEscapable(*(cmd + 1)))
|
||||
{
|
||||
// include the null terminator: strlen(cmd) = strlen(cmd + 1) + 1
|
||||
memmove(cmd, cmd + 1, strlen(cmd));
|
||||
}
|
||||
else if (IsSeparator(*cmd))
|
||||
{
|
||||
*cmd = '\0';
|
||||
}
|
||||
else if (*(cmd - 1) == '\0')
|
||||
|
||||
if ((*cmd != '\0') && ((aArgc == 0) || (*(cmd - 1) == '\0')))
|
||||
{
|
||||
VerifyOrExit(aArgc < aArgcMax, error = OT_ERROR_INVALID_ARGS);
|
||||
aArgv[aArgc++] = cmd;
|
||||
|
||||
@@ -60,7 +60,8 @@ public:
|
||||
* This function parses the command line.
|
||||
*
|
||||
* Note: this method may change the input @p aString, it will put a '\0' by the end of each argument,
|
||||
* and @p aArgv will point to the arguments in the input @p aString.
|
||||
* and @p aArgv will point to the arguments in the input @p aString. Backslash ('\') can be used
|
||||
* to escape separators (' ', '\t', '\r', '\n') and the backslash itself.
|
||||
*
|
||||
* @param[in] aString A NULL-terminated input string.
|
||||
* @param[out] aArgc The argument counter of the command line.
|
||||
|
||||
@@ -446,6 +446,20 @@ class Node:
|
||||
self.send_command(cmd)
|
||||
self._expect('Done')
|
||||
|
||||
def _escape_escapable(self, string):
|
||||
"""Escape CLI escapable characters in the given string.
|
||||
|
||||
Args:
|
||||
string (str): UTF-8 input string.
|
||||
|
||||
Returns:
|
||||
[str]: The modified string with escaped characters.
|
||||
"""
|
||||
escapable_chars = '\\ \t\r\n'
|
||||
for char in escapable_chars:
|
||||
string = string.replace(char, '\\%s' % char)
|
||||
return string
|
||||
|
||||
def get_network_name(self):
|
||||
self.send_command('networkname')
|
||||
while True:
|
||||
@@ -457,7 +471,7 @@ class Node:
|
||||
return network_name
|
||||
|
||||
def set_network_name(self, network_name):
|
||||
cmd = 'networkname %s' % network_name
|
||||
cmd = 'networkname %s' % self._escape_escapable(network_name)
|
||||
self.send_command(cmd)
|
||||
self._expect('Done')
|
||||
|
||||
@@ -969,7 +983,7 @@ class Node:
|
||||
cmd += 'localprefix %s ' % mesh_local
|
||||
|
||||
if network_name is not None:
|
||||
cmd += 'networkname %s ' % network_name
|
||||
cmd += 'networkname %s ' % self._escape_escapable(network_name)
|
||||
|
||||
if binary is not None:
|
||||
cmd += 'binary %s ' % binary
|
||||
@@ -1011,7 +1025,7 @@ class Node:
|
||||
cmd += 'localprefix %s ' % mesh_local
|
||||
|
||||
if network_name is not None:
|
||||
cmd += 'networkname %s ' % network_name
|
||||
cmd += 'networkname %s ' % self._escape_escapable(network_name)
|
||||
|
||||
self.send_command(cmd)
|
||||
self._expect('Done')
|
||||
|
||||
@@ -626,6 +626,20 @@ class OpenThread(IThci):
|
||||
print('%s call getCommissionerSessionId' % self.port)
|
||||
return self.__sendCommand('commissioner sessionid')[0]
|
||||
|
||||
def __escapeEscapable(self, string):
|
||||
"""Escape CLI escapable characters in the given string.
|
||||
|
||||
Args:
|
||||
string (str): UTF-8 input string.
|
||||
|
||||
Returns:
|
||||
[str]: The modified string with escaped characters.
|
||||
"""
|
||||
escapable_chars = '\\ \t\r\n'
|
||||
for char in escapable_chars:
|
||||
string = string.replace(char, '\\%s' % char)
|
||||
return string
|
||||
|
||||
def _connect(self):
|
||||
print('My port is %s' % self.port)
|
||||
if self.port.startswith('COM'):
|
||||
@@ -688,6 +702,7 @@ class OpenThread(IThci):
|
||||
"""
|
||||
print('%s call setNetworkName' % self.port)
|
||||
print(networkName)
|
||||
networkName = self.__escapeEscapable(networkName)
|
||||
try:
|
||||
cmd = 'networkname %s' % networkName
|
||||
datasetCmd = 'dataset networkname %s' % networkName
|
||||
@@ -2393,7 +2408,7 @@ class OpenThread(IThci):
|
||||
|
||||
if sNetworkName is not None:
|
||||
cmd += ' networkname '
|
||||
cmd += str(sNetworkName)
|
||||
cmd += self.__escapeEscapable(str(sNetworkName))
|
||||
|
||||
if xChannel is not None:
|
||||
cmd += ' channel '
|
||||
@@ -2594,7 +2609,7 @@ class OpenThread(IThci):
|
||||
|
||||
if sNetworkName is not None:
|
||||
cmd += ' networkname '
|
||||
cmd += str(sNetworkName)
|
||||
cmd += self.__escapeEscapable(str(sNetworkName))
|
||||
|
||||
if xCommissionerSessionId is not None:
|
||||
cmd += ' binary '
|
||||
|
||||
Reference in New Issue
Block a user