diff --git a/Android.mk b/Android.mk
index 79c5c98a5..7a925ac36 100644
--- a/Android.mk
+++ b/Android.mk
@@ -168,6 +168,7 @@ LOCAL_SRC_FILES := \
src/core/utils/missing_strlcpy.c \
src/core/utils/missing_strlcat.c \
src/core/utils/missing_strnlen.c \
+ src/core/utils/parse_cmdline.cpp \
src/core/utils/slaac_address.cpp \
src/diag/diag_process.cpp \
src/diag/openthread-diag.cpp \
diff --git a/etc/visual-studio/libopenthread-cli-windows.vcxproj b/etc/visual-studio/libopenthread-cli-windows.vcxproj
index f36e63ac7..db367ff02 100644
--- a/etc/visual-studio/libopenthread-cli-windows.vcxproj
+++ b/etc/visual-studio/libopenthread-cli-windows.vcxproj
@@ -61,6 +61,8 @@
+
+
diff --git a/etc/visual-studio/libopenthread.vcxproj b/etc/visual-studio/libopenthread.vcxproj
index c845381a9..e4603df29 100644
--- a/etc/visual-studio/libopenthread.vcxproj
+++ b/etc/visual-studio/libopenthread.vcxproj
@@ -148,6 +148,7 @@
+
@@ -238,6 +239,7 @@
+
diff --git a/etc/visual-studio/libopenthread.vcxproj.filters b/etc/visual-studio/libopenthread.vcxproj.filters
index d7efac078..fdbebd734 100644
--- a/etc/visual-studio/libopenthread.vcxproj.filters
+++ b/etc/visual-studio/libopenthread.vcxproj.filters
@@ -327,6 +327,9 @@
Source Files\utils
+
+ Source Files\utils
+
Source Files\utils
@@ -593,6 +596,9 @@
Header Files\utils
+
+ Header Files\utils
+
Header Files\utils
diff --git a/etc/visual-studio/libopenthread_k.vcxproj b/etc/visual-studio/libopenthread_k.vcxproj
index 7ef558d67..0e54e2b07 100644
--- a/etc/visual-studio/libopenthread_k.vcxproj
+++ b/etc/visual-studio/libopenthread_k.vcxproj
@@ -157,6 +157,7 @@
+
@@ -272,6 +273,7 @@
+
diff --git a/etc/visual-studio/libopenthread_k.vcxproj.filters b/etc/visual-studio/libopenthread_k.vcxproj.filters
index 85ca29a7a..8d1b8a615 100644
--- a/etc/visual-studio/libopenthread_k.vcxproj.filters
+++ b/etc/visual-studio/libopenthread_k.vcxproj.filters
@@ -327,6 +327,9 @@
Source Files\utils
+
+ Source Files\utils
+
Source Files\utils
@@ -590,6 +593,9 @@
Header Files\utils
+
+ Header Files\utils
+
Header Files\utils
diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp
index 74e20e40f..c6d6136c7 100644
--- a/src/cli/cli.cpp
+++ b/src/cli/cli.cpp
@@ -39,6 +39,7 @@
#include
#include
+#include "utils/parse_cmdline.hpp"
#include "utils/wrap_string.h"
#include
@@ -3477,33 +3478,19 @@ void Interpreter::ProcessDiag(int argc, char *argv[])
void Interpreter::ProcessLine(char *aBuf, uint16_t aBufLength, Server &aServer)
{
- char * argv[kMaxArgs];
+ char * argv[kMaxArgs] = {NULL};
char * cmd;
uint8_t argc = 0, i = 0;
mServer = &aServer;
- VerifyOrExit(aBuf != NULL);
+ VerifyOrExit(aBuf != NULL && strnlen(aBuf, aBufLength + 1) <= aBufLength);
- for (; *aBuf == ' '; aBuf++, aBufLength--)
- ;
+ VerifyOrExit(Utils::CmdLineParser::ParseCmd(aBuf, argc, argv, kMaxArgs) == OT_ERROR_NONE,
+ mServer->OutputFormat("Error: too many args (max %d)\r\n", kMaxArgs));
+ VerifyOrExit(argc >= 1, mServer->OutputFormat("Error: no given command.\r\n"));
- for (cmd = aBuf + 1; (cmd < aBuf + aBufLength) && (cmd != NULL); ++cmd)
- {
- VerifyOrExit(argc < kMaxArgs, mServer->OutputFormat("Error: too many args (max %d)\r\n", kMaxArgs));
-
- if (*cmd == ' ' || *cmd == '\r' || *cmd == '\n')
- {
- *cmd = '\0';
- }
-
- if (*(cmd - 1) == '\0' && *cmd != ' ')
- {
- argv[argc++] = cmd;
- }
- }
-
- cmd = aBuf;
+ cmd = argv[0];
#if OPENTHREAD_ENABLE_DIAG
VerifyOrExit(
@@ -3515,7 +3502,7 @@ void Interpreter::ProcessLine(char *aBuf, uint16_t aBufLength, Server &aServer)
{
if (strcmp(cmd, sCommands[i].mName) == 0)
{
- (this->*sCommands[i].mCommand)(argc, argv);
+ (this->*sCommands[i].mCommand)(argc - 1, &argv[1]);
break;
}
}
@@ -3528,7 +3515,7 @@ void Interpreter::ProcessLine(char *aBuf, uint16_t aBufLength, Server &aServer)
{
if (strcmp(cmd, mUserCommands[i].mName) == 0)
{
- mUserCommands[i].mCommand(argc, argv);
+ mUserCommands[i].mCommand(argc - 1, &argv[1]);
break;
}
}
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 785ed2d6e..51266cda0 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -213,6 +213,7 @@ SOURCES_COMMON = \
utils/missing_strlcat.c \
utils/missing_strlcpy.c \
utils/missing_strnlen.c \
+ utils/parse_cmdline.cpp \
utils/slaac_address.cpp \
$(NULL)
@@ -233,6 +234,7 @@ libopenthread_radio_a_SOURCES = \
utils/missing_strlcat.c \
utils/missing_strlcpy.c \
utils/missing_strnlen.c \
+ utils/parse_cmdline.cpp \
$(NULL)
libopenthread_mtd_a_SOURCES = \
@@ -346,6 +348,7 @@ HEADERS_COMMON = \
utils/child_supervision.hpp \
utils/heap.hpp \
utils/jam_detector.hpp \
+ utils/parse_cmdline.hpp \
utils/slaac_address.hpp \
utils/wrap_stdbool.h \
utils/wrap_stdint.h \
diff --git a/src/core/utils/parse_cmdline.cpp b/src/core/utils/parse_cmdline.cpp
new file mode 100644
index 000000000..9da77ee9f
--- /dev/null
+++ b/src/core/utils/parse_cmdline.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file implements the command line parser.
+ */
+
+#include "parse_cmdline.hpp"
+
+#include "common/code_utils.hpp"
+
+namespace ot {
+namespace Utils {
+
+static bool IsSpaceOrNewLine(char aChar)
+{
+ return (aChar == ' ') || (aChar == '\t') || (aChar == '\r') || (aChar == '\n');
+}
+
+otError CmdLineParser::ParseCmd(char *aString, uint8_t &aArgc, char *aArgv[], uint8_t aArgcMax)
+{
+ otError error = OT_ERROR_NONE;
+ char * cmd;
+
+ aArgc = 0;
+
+ for (cmd = aString; IsSpaceOrNewLine(*cmd) && *cmd; cmd++)
+ ;
+
+ if (*cmd)
+ {
+ aArgv[aArgc++] = cmd++; // the first argument
+ }
+
+ for (; *cmd; cmd++)
+ {
+ if (IsSpaceOrNewLine(*cmd))
+ {
+ *cmd = '\0';
+ }
+ else if (*(cmd - 1) == '\0')
+ {
+ VerifyOrExit(aArgc < aArgcMax, error = OT_ERROR_INVALID_ARGS);
+ aArgv[aArgc++] = cmd;
+ }
+ }
+
+exit:
+ return error;
+}
+
+} // namespace Utils
+} // namespace ot
diff --git a/src/core/utils/parse_cmdline.hpp b/src/core/utils/parse_cmdline.hpp
new file mode 100644
index 000000000..f2ec0025c
--- /dev/null
+++ b/src/core/utils/parse_cmdline.hpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes definitions for command line parser.
+ */
+
+#ifndef PARSE_CMD_LINE_HPP_
+#define PARSE_CMD_LINE_HPP_
+
+#include
+#include
+
+namespace ot {
+namespace Utils {
+
+/**
+ * @addtogroup utils-parse-cmd-line
+ *
+ * @brief
+ * This module includes definitions for command line parser.
+ *
+ * @{
+ */
+
+/**
+ * This class implements the command line parser.
+ *
+ */
+class CmdLineParser
+{
+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.
+ *
+ * @param[in] aString A NULL-terminated input string.
+ * @param[out] aArgc The argument counter of the command line.
+ * @param[out] aArgv The argument vector of the command line.
+ * @param[in] aArgcMax The maximum argument counter.
+ *
+ */
+ static otError ParseCmd(char *aString, uint8_t &aArgc, char *aArgv[], uint8_t aArgcMax);
+};
+
+/**
+ * @}
+ */
+
+} // namespace Utils
+} // namespace ot
+
+#endif // PARSE_CMD_LINE_HPP_
diff --git a/src/diag/openthread-diag.cpp b/src/diag/openthread-diag.cpp
index 13f4fdaf0..762054731 100644
--- a/src/diag/openthread-diag.cpp
+++ b/src/diag/openthread-diag.cpp
@@ -35,6 +35,7 @@
#include
#include
+#include "utils/parse_cmdline.hpp"
#include "utils/wrap_string.h"
#include
@@ -54,16 +55,6 @@ void otDiagProcessCmd(int aArgCount, char *aArgVector[], char *aOutput, size_t a
Diag::ProcessCmd(aArgCount, aArgVector, aOutput, aOutputMaxLen);
}
-static bool IsSpace(char aChar)
-{
- return (aChar == ' ') || (aChar == '\t');
-}
-
-static bool IsNullOrNewline(char aChar)
-{
- return (aChar == 0) || (aChar == '\n') || (aChar == '\r');
-}
-
void otDiagProcessCmdLine(const char *aInput, char *aOutput, size_t aOutputMaxLen)
{
enum
@@ -75,34 +66,12 @@ void otDiagProcessCmdLine(const char *aInput, char *aOutput, size_t aOutputMaxLe
otError error = OT_ERROR_NONE;
char buffer[kMaxCommandBuffer];
char *argVector[kMaxArgs];
- int argCount = 0;
- char *bufPtr = &buffer[0];
- uint16_t bufLen = sizeof(buffer);
+ uint8_t argCount = 0;
- while (!IsNullOrNewline(*aInput))
- {
- while (IsSpace(*aInput))
- {
- aInput++;
- }
+ VerifyOrExit(strnlen(aInput, kMaxCommandBuffer) < kMaxCommandBuffer, error = OT_ERROR_NO_BUFS);
- argVector[argCount] = bufPtr;
-
- while (!IsSpace(*aInput) && !IsNullOrNewline(*aInput))
- {
- *bufPtr++ = *aInput++;
- VerifyOrExit(--bufLen > 0, error = OT_ERROR_NO_BUFS);
- }
-
- if (argVector[argCount] != bufPtr)
- {
- *bufPtr++ = 0;
- VerifyOrExit(--bufLen > 0, error = OT_ERROR_NO_BUFS);
-
- argCount++;
- VerifyOrExit(argCount < kMaxArgs, error = OT_ERROR_INVALID_ARGS);
- }
- }
+ strcpy(buffer, aInput);
+ error = ot::Utils::CmdLineParser::ParseCmd(buffer, argCount, argVector, kMaxArgs);
exit:
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
index f388e5502..109b61caa 100644
--- a/tests/unit/Makefile.am
+++ b/tests/unit/Makefile.am
@@ -228,7 +228,8 @@ test_toolchain_LDADD = $(COMMON_LDADD)
test_toolchain_SOURCES = test_platform.cpp test_toolchain.cpp test_toolchain_c.c
if OPENTHREAD_ENABLE_DIAG
-test_diag_LDADD = $(top_builddir)/src/diag/libopenthread-diag.a
+test_diag_LDADD = $(top_builddir)/src/diag/libopenthread-diag.a \
+ $(COMMON_LDADD)
test_diag_SOURCES = test_diag.cpp
if OPENTHREAD_ENABLE_POSIX_APP
test_diag_LDADD += $(top_builddir)/src/posix/platform/libopenthread-posix.a \