[cli] allow to escape separators (#4608)

This commit is contained in:
Eduardo Montoya
2020-03-02 08:48:31 -08:00
committed by GitHub
parent f4775fe13a
commit 15f6808206
5 changed files with 74 additions and 18 deletions
+21
View File
@@ -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)
+17 -12
View File
@@ -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;
+2 -1
View File
@@ -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.
+17 -3
View File
@@ -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')
+17 -2
View File
@@ -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 '