/* * 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 #include #include namespace ot { namespace Utils { namespace CmdLineParser { /** * @addtogroup utils-parse-cmd-line * * @brief * This module includes definitions for command line parser. * * @{ */ /** * This function parses a string as a `uint8_t` value. * * The number in string is parsed as decimal or hex format (if contains `0x` or `0X` prefix). * * @param[in] aString The string to parse. * @param[out] aUint8 A reference to an `uint8_t` variable to output the parsed value. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid number (e.g., value out of range). * */ otError ParseAsUint8(const char *aString, uint8_t &aUint8); /** * This function parses a string as a `uint16_t` value. * * The number in string is parsed as decimal or hex format (if contains `0x` or `0X` prefix). * * @param[in] aString The string to parse. * @param[out] aUint16 A reference to an `uint16_t` variable to output the parsed value. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid number (e.g., value out of range). * */ otError ParseAsUint16(const char *aString, uint16_t &aUint16); /** * This function parses a string as a `uint32_t` value. * * The number in string is parsed as decimal or hex format (if contains `0x` or `0X` prefix). * * @param[in] aString The string to parse. * @param[out] aUint32 A reference to an `uint32_t` variable to output the parsed value. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid number (e.g., value out of range). * */ otError ParseAsUint32(const char *aString, uint32_t &aUint32); /** * This function parses a string as a `uint64_t` value. * * The number in string is parsed as decimal or hex format (if contains `0x` or `0X` prefix). * * @param[in] aString The string to parse. * @param[out] aUint64 A reference to an `uint64_t` variable to output the parsed value. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid number (e.g., value out of range). * */ otError ParseAsUint64(const char *aString, uint64_t &aUint64); /** * This function parses a string as a `int8_t` value. * * The number in string is parsed as decimal or hex format (if contains `0x` or `0X` prefix). The string can start with * `+`/`-` sign. * * @param[in] aString The string to parse. * @param[out] aInt8 A reference to an `int8_t` variable to output the parsed value. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid number (e.g., value out of range). * */ otError ParseAsInt8(const char *aString, int8_t &aInt8); /** * This function parses a string as a `int16_t` value. * * The number in string is parsed as decimal or hex format (if contains `0x` or `0X` prefix). The string can start with * `+`/`-` sign. * * @param[in] aString The string to parse. * @param[out] aInt16 A reference to an `int16_t` variable to output the parsed value. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid number (e.g., value out of range). * */ otError ParseAsInt16(const char *aString, int16_t &aInt16); /** * This function parses a string as a `int32_t` value. * * The number in string is parsed as decimal or hex format (if contains `0x` or `0X` prefix). The string can start with * `+`/`-` sign. * * @param[in] aString The string to parse. * @param[out] aInt32 A reference to an `int32_t` variable to output the parsed value. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid number (e.g., value out of range). * */ otError ParseAsInt32(const char *aString, int32_t &aInt32); /** * This function parses a string as a `bool` value. * * Zero value is treated as `false`, non-zero value as `true`. * * @param[in] aString The string to parse. * @param[out] aBool A reference to a `bool` variable to output the parsed value. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid number. * */ otError ParseAsBool(const char *aString, bool &aBool); #if OPENTHREAD_FTD || OPENTHREAD_MTD /** * This function parses a string as an IPv6 address. * * * @param[in] aString The string to parse. * @param[out] aAddress A reference to an `otIp6Address` to output the parsed IPv6 address. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid IPv6 address. * */ otError ParseAsIp6Address(const char *aString, otIp6Address &aAddress); /** * This function parses a string as an IPv6 prefix. * * The string is parsed as `{IPv6Address}/{PrefixLength}`. * * @param[in] aString The string to parse. * @param[out] aPrefix A reference to an `otIp6Prefix` to output the parsed IPv6 prefix. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain a valid IPv6 prefix. * */ otError ParseAsIp6Prefix(const char *aString, otIp6Prefix &aPrefix); #endif // OPENTHREAD_FTD || OPENTHREAD_MTD /** * This function parses a hex string into a byte array of fixed expected size. * * This function returns `kErrorNone` only when the hex string contains exactly @p aSize bytes (after parsing). If * there are fewer or more bytes in hex string that @p aSize, the parsed bytes (up to @p aSize) are copied into the * `aBuffer` and `kErrorInvalidArgs` is returned. * * This function correctly handles hex strings with even or odd length. For example, "AABBCCDD" (with even length) is * parsed as {0xaa, 0xbb, 0xcc, 0xdd} and "123" (with odd length) is parsed as {0x01, 0x23}. * * @param[in] aString The string to parse. * @param[out] aBuffer A pointer to a buffer to output the parsed byte sequence. * @param[in] aSize The expected size of byte sequence (number of bytes after parsing). * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid hex bytes and/or not @p aSize bytes. * */ otError ParseAsHexString(const char *aString, uint8_t *aBuffer, uint16_t aSize); /** * This template function parses a hex string into a a given fixed size array. * * This function returns `kErrorNone` only when the hex string contains exactly @p kBufferSize bytes (after parsing). * If there are fewer or more bytes in hex string that @p kBufferSize, the parsed bytes (up to @p kBufferSize) are * copied into the `aBuffer` and `kErrorInvalidArgs` is returned. * * This function correctly handles hex strings with even or odd length. For example, "AABBCCDD" (with even length) is * parsed as {0xaa, 0xbb, 0xcc, 0xdd} and "123" (with odd length) is parsed as {0x01, 0x23}. * * @tparam kBufferSize The byte array size (number of bytes). * * @param[in] aString The string to parse. * @param[out] aBuffer A reference to a byte array to output the parsed byte sequence. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid hex bytes and/or not @p aSize bytes. * */ template static otError ParseAsHexString(const char *aString, uint8_t (&aBuffer)[kBufferSize]) { return ParseAsHexString(aString, aBuffer, kBufferSize); } /** * This function parses a hex string into a byte array. * * This function verifies that the parsed hex string bytes fit in @p aBuffer with its given @p aSize. * * This function correctly handles hex strings with even or odd length. For example, "AABBCCDD" (with even length) is * parsed as {0xaa, 0xbb, 0xcc, 0xdd} and "123" (with odd length) is parsed as {0x01, 0x23}. * * @param[in] aString The string to parse. * @param[in,out] aSize On entry indicates the number of bytes in @p aBuffer (max size of @p aBuffer). * On exit provides number of bytes parsed and copied into @p aBuffer. * @param[out] aBuffer A pointer to a buffer to output the parsed byte sequence. * * @retval kErrorNone The string was parsed successfully. * @retval kErrorInvalidArgs The string does not contain valid format or too many bytes. * */ otError ParseAsHexString(const char *aString, uint16_t &aSize, uint8_t *aBuffer); /** * This function parses a segment of a hex string up to a given size. * * This function allows a longer hex string to be parsed and read in smaller segments into a given buffer. If the * entire hex string bytes can fit in the given @p aBuffer with its @p aSize, they are copied into @p aBuffer and * function returns `kErrorNone`. Otherwise, @p aSize bytes are read and copied and function returns `kErrorPending` * to indicate that there are more bytes to parse. The @p aString is also updated to skip over the parsed segment. * * This function correctly handles hex strings with even or odd length. For example, "AABBCCDD" (with even length) is * parsed as {0xaa, 0xbb, 0xcc, 0xdd} and "123" (with odd length) is parsed as {0x01, 0x23}. * * @param[in,out] aString A reference to string to parse. On successful parse, updated to skip parsed digits. * @param[in,out] aSize On entry indicates the segment size (number of bytes in @p aBuffer). * On exit provides number of bytes parsed and copied into @p aBuffer. * @param[out] aBuffer A pointer to a buffer to output the parsed byte sequence. * * @retval kErrorNone The string was parsed successfully to the end of string. * @retval kErrorPedning The string segment was parsed successfully, but there are additional bytes remaining * to be parsed. * @retval kErrorInvalidArgs The string does not contain valid format hex digits. * */ otError ParseAsHexStringSegment(const char *&aString, uint16_t &aSize, uint8_t *aBuffer); /** * This class represents a single argument from an argument list. * */ class Arg { public: /** * This method clears the argument. * */ void Clear(void) { mString = nullptr; } /** * This method indicates whether or not the argument is empty (i.e., reached the end of argument list). * * @retval TRUE The argument is empty. * @retval FALSE The argument is not empty. * */ bool IsEmpty(void) const { return (mString == nullptr); } /** * This method returns the length (number of characters) in the argument C string. * * @returns The argument string length if argument is not empty, zero otherwise. * */ uint16_t GetLength(void) const; /** * This method gets the argument as a C string. * * @returns A pointer to the argument as a C string, or `nullptr` if argument is empty. * */ const char *GetCString(void) const { return mString; } /** * This method gets the argument as C string. * * @returns A pointer to the argument as a C string, or `nullptr` if argument is empty. * */ char *GetCString(void) { return mString; } /** * This method sets the argument with a given C string. * * @param[in] aString A pointer to the new C string. * */ void SetCString(char *aString) { mString = aString; } /** * This method overload the operator `==` to evaluate whether the argument is equal to a given C string. * * If the argument is empty (`IsEmpty()` is `true`) then comparing it using operator `==` with any C string will * return false. * * @param[in] aString The C string to compare with (MUST not be `nullptr`). * * @retval TRUE If the argument is not empty and is equal to @p aString. * @retval FALSE If the argument is not equal to @p aString, or if the argument is empty. * */ bool operator==(const char *aString) const; /** * This method overload the operator `!=` to evaluate whether the argument is unequal to a given C string. * * @param[in] aString The C string to compare with (MUST not be `nullptr`). * * @retval TRUE If the argument is not equal to @p aString, or if the argument is empty. * @retval FALSE If the argument is not empty and equal to @p aString. * */ bool operator!=(const char *aString) const { return !(*this == aString); } /** * This method parses the argument as a `uint8_t` value. * * The number is parsed as decimal or hex format (if contains `0x` or `0X` prefix). * * @param[out] aUint8 A reference to an `uint8_t` variable to output the parsed value. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid number (e.g., value out of range). * */ otError ParseAsUint8(uint8_t &aUint8) const { return CmdLineParser::ParseAsUint8(mString, aUint8); } /** * This method parses the argument as a `uint16_t` value. * * The number is parsed as decimal or hex format (if contains `0x` or `0X` prefix). * * @param[out] aUint16 A reference to an `uint16_t` variable to output the parsed value. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid number (e.g., value out of range). * */ otError ParseAsUint16(uint16_t &aUint16) const { return CmdLineParser::ParseAsUint16(mString, aUint16); } /** * This method parses the argument as a `uint32_t` value. * * The number is parsed as decimal or hex format (if contains `0x` or `0X` prefix). * * @param[out] aUint32 A reference to an `uint32_t` variable to output the parsed value. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid number (e.g., value out of range). * */ otError ParseAsUint32(uint32_t &aUint32) const { return CmdLineParser::ParseAsUint32(mString, aUint32); } /** * This method parses the argument as a `uint64_t` value. * * The number is parsed as decimal or hex format (if contains `0x` or `0X` prefix). * * @param[out] aUint64 A reference to an `uint64_t` variable to output the parsed value. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid number (e.g., value out of range). * */ otError ParseAsUint64(uint64_t &aUint64) const { return CmdLineParser::ParseAsUint64(mString, aUint64); } /** * This method parses the argument as a `int8_t` value. * * The number is parsed as decimal or hex format (if contains `0x` or `0X` prefix). The string can start with * `+`/`-` sign. * * @param[out] aInt8 A reference to an `int8_t` variable to output the parsed value. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid number (e.g., value out of range). * */ otError ParseAsInt8(int8_t &aInt8) const { return CmdLineParser::ParseAsInt8(mString, aInt8); } /** * This method parses the argument as a `int16_t` value. * * The number is parsed as decimal or hex format (if contains `0x` or `0X` prefix). The string can start with * `+`/`-` sign. * * @param[out] aInt16 A reference to an `int16_t` variable to output the parsed value. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid number (e.g., value out of range). * */ otError ParseAsInt16(int16_t &aInt16) const { return CmdLineParser::ParseAsInt16(mString, aInt16); } /** * This method parses the argument as a `int32_t` value. * * The number is parsed as decimal or hex format (if contains `0x` or `0X` prefix). The string can start with * `+`/`-` sign. * * @param[out] aInt32 A reference to an `int32_t` variable to output the parsed value. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid number (e.g., value out of range). * */ otError ParseAsInt32(int32_t &aInt32) const { return CmdLineParser::ParseAsInt32(mString, aInt32); } /** * This method parses the argument as a `bool` value. * * Zero value is treated as `false`, non-zero value as `true`. * * @param[out] aBool A reference to a `bool` variable to output the parsed value. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid number. * */ otError ParseAsBool(bool &aBool) const { return CmdLineParser::ParseAsBool(mString, aBool); } #if OPENTHREAD_FTD || OPENTHREAD_MTD /** * This method parses the argument as an IPv6 address. * * @param[out] aAddress A reference to an `otIp6Address` to output the parsed IPv6 address. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid IPv6 address. * */ otError ParseAsIp6Address(otIp6Address &aAddress) const { return CmdLineParser::ParseAsIp6Address(mString, aAddress); } /** * This method parses the argument as an IPv6 prefix. * * The string is parsed as `{IPv6Address}/{PrefixLength}`. * * @param[out] aPrefix A reference to an `otIp6Prefix` to output the parsed IPv6 prefix. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain a valid IPv6 prefix. * */ otError ParseAsIp6Prefix(otIp6Prefix &aPrefix) const { return CmdLineParser::ParseAsIp6Prefix(mString, aPrefix); } #endif // OPENTHREAD_FTD || OPENTHREAD_MTD /** * This template method parses the argument as a specified value type. * * @tparam Type The value type. * * @param[out] aValue A reference to output the parsed value. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain a valid value. * */ template otError ParseAs(Type &aValue) const; /** * This method parses the argument as a hex string into a byte array of fixed expected size. * * This method returns `kErrorNone` only when the hex string contains exactly @p aSize bytes (after parsing). If * there are fewer or more bytes in hex string that @p aSize, the parsed bytes (up to @p aSize) are copied into the * `aBuffer` and `kErrorInvalidArgs` is returned. * * @param[out] aBuffer A pointer to a buffer to output the parsed byte sequence. * @param[in] aSize The expected size of byte sequence (number of bytes after parsing). * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid hex bytes and/or not @p aSize bytes. * */ otError ParseAsHexString(uint8_t *aBuffer, uint16_t aSize) const { return CmdLineParser::ParseAsHexString(mString, aBuffer, aSize); } /** * This template method parses the argument as a hex string into a a given fixed size array. * * This method returns `kErrorNone` only when the hex string contains exactly @p kBufferSize bytes (after parsing). * If there are fewer or more bytes in hex string that @p kBufferSize, the parsed bytes (up to @p kBufferSize) are * copied into the `aBuffer` and `kErrorInvalidArgs` is returned. * * @tparam kBufferSize The byte array size (number of bytes). * * @param[out] aBuffer A reference to a byte array to output the parsed byte sequence. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument is empty or does not contain valid hex bytes and/or not @p aSize bytes. * */ template otError ParseAsHexString(uint8_t (&aBuffer)[kBufferSize]) { return ParseAsHexString(aBuffer, kBufferSize); } /** * This method parses the argument as a hex string into a byte array. * * This method verifies that the parsed hex string bytes fit in @p aBuffer with its given @p aSize. * * @param[in,out] aSize On entry indicates the number of bytes in @p aBuffer (max size of @p aBuffer). * On exit provides number of bytes parsed and copied into @p aBuffer. * @param[out] aBuffer A pointer to a buffer to output the parsed byte sequence. * * @retval kErrorNone The argument was parsed successfully. * @retval kErrorInvalidArgs The argument does not contain valid format or too many bytes. * */ otError ParseAsHexString(uint16_t &aSize, uint8_t *aBuffer) { return CmdLineParser::ParseAsHexString(mString, aSize, aBuffer); } /** * This static method copies the argument string pointers from an `Arg` array to a C string array. * * @note this method only copies the string pointer value (i.e., `GetString()` pointer) from `aArgs` array to the * @p aStrings array (the content of strings are not copied). * * @param[in] aArgs An `Arg` array. * @param[out] aStrings An `char *` array to populate with the argument string pointers. The @p aString array * MUST contain at least same number of entries as in @p aArgs array. * */ static void CopyArgsToStringArray(Arg aArgs[], char *aStrings[]); /** * This static method returns the length of argument array, i.e. number of consecutive non-empty arguments. * * @param[in] aArgs An `Arg` array. * * @returns Number of non-empty arguments in the array. * */ static uint8_t GetArgsLength(Arg aArgs[]); private: char *mString; }; /** * This function parses a given command line string and breaks it into an argument list. * * This function may change the input @p aCommandString, it will put a '\0' by the end of each argument, and @p aArgs * will point to the arguments in the input @p aCommandString. Backslash ('\') can be used to escape separators * (' ', '\t', '\r', '\n') and the backslash itself. * * As the arguments are parsed, the @p aArgs array entries are populated. Any remaining @p aArgs entries in the array * will be cleared and marked as empty. So the number of arguments can be determined by going through @p aArgs array * entries till we get to an empty `Arg` (i.e., `Arg::IsEmpty()` returns `true). * * This function ensures that the last entry in @p aArgs array is always used to indicate the end (always marked as * empty), so the @p aArgs array should have one more entry than the desired max number of arguments. * * @param[in] aCommandString A null-terminated input string. * @param[out] aArgs The argument array. * @param[in] aArgsMaxLength The max length of @p aArgs array. * * @retval OT_ERROR_NONE The command line parsed successfully and @p aArgs array is populated. * @retval OT_ERROR_INVALID_ARGS Too many arguments in @p aCommandString and could not fit in @p aArgs array. * */ otError ParseCmd(char *aCommandString, Arg aArgs[], uint8_t aArgsMaxLength); template inline otError ParseCmd(char *aCommandString, Arg (&aArgs)[kLength]) { return ParseCmd(aCommandString, aArgs, kLength); } //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Specializations of `Arg::ParseAs()` method. template <> inline otError Arg::ParseAs(uint8_t &aValue) const { return ParseAsUint8(aValue); } template <> inline otError Arg::ParseAs(uint16_t &aValue) const { return ParseAsUint16(aValue); } template <> inline otError Arg::ParseAs(uint32_t &aValue) const { return ParseAsUint32(aValue); } template <> inline otError Arg::ParseAs(uint64_t &aValue) const { return ParseAsUint64(aValue); } template <> inline otError Arg::ParseAs(bool &aValue) const { return ParseAsBool(aValue); } template <> inline otError Arg::ParseAs(int8_t &aValue) const { return ParseAsInt8(aValue); } template <> inline otError Arg::ParseAs(int16_t &aValue) const { return ParseAsInt16(aValue); } template <> inline otError Arg::ParseAs(int32_t &aValue) const { return ParseAsInt32(aValue); } #if OPENTHREAD_FTD || OPENTHREAD_MTD template <> inline otError Arg::ParseAs(otIp6Address &aValue) const { return ParseAsIp6Address(aValue); } template <> inline otError Arg::ParseAs(otIp6Prefix &aValue) const { return ParseAsIp6Prefix(aValue); } #endif /** * @} */ } // namespace CmdLineParser } // namespace Utils } // namespace ot #endif // PARSE_CMD_LINE_HPP_