| /* |
| * Copyright (c) 2021, 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 contains definitions for the CLI output. |
| */ |
| |
| #ifndef CLI_OUTPUT_HPP_ |
| #define CLI_OUTPUT_HPP_ |
| |
| #include "openthread-core-config.h" |
| |
| #include <stdarg.h> |
| |
| #include <openthread/cli.h> |
| |
| #include "cli_config.h" |
| |
| #include "common/binary_search.hpp" |
| #include "common/string.hpp" |
| #include "utils/parse_cmdline.hpp" |
| |
| namespace ot { |
| namespace Cli { |
| |
| /** |
| * This type represents a ID number value associated with a CLI command string. |
| * |
| */ |
| typedef uint64_t CommandId; |
| |
| /** |
| * This `constexpr` function converts a CLI command string to its associated `CommandId` value. |
| * |
| * @param[in] aString The CLI command string. |
| * |
| * @returns The associated `CommandId` with @p aString. |
| * |
| */ |
| constexpr static CommandId Cmd(const char *aString) |
| { |
| return (aString[0] == '\0') ? 0 : (static_cast<uint8_t>(aString[0]) + Cmd(aString + 1) * 255u); |
| } |
| |
| /** |
| * This class is the base class for `Output` and `OutputWrapper` providing common helper methods. |
| * |
| */ |
| class OutputBase |
| { |
| public: |
| typedef Utils::CmdLineParser::Arg Arg; ///< An argument |
| |
| /** |
| * This structure represent a CLI command table entry, mapping a command with `aName` to a handler method. |
| * |
| * @tparam Cli The CLI module type. |
| * |
| */ |
| template <typename Cli> struct CommandEntry |
| { |
| typedef otError (Cli::*Handler)(Arg aArgs[]); ///< The handler method pointer type. |
| |
| /** |
| * This method compares the entry's name with a given name. |
| * |
| * @param aName The name string to compare with. |
| * |
| * @return zero means perfect match, positive (> 0) indicates @p aName is larger than entry's name, and |
| * negative (< 0) indicates @p aName is smaller than entry's name. |
| * |
| */ |
| int Compare(const char *aName) const { return strcmp(aName, mName); } |
| |
| /** |
| * This `constexpr` method compares two entries to check if they are in order. |
| * |
| * @param[in] aFirst The first entry. |
| * @param[in] aSecond The second entry. |
| * |
| * @retval TRUE if @p aFirst and @p aSecond are in order, i.e. `aFirst < aSecond`. |
| * @retval FALSE if @p aFirst and @p aSecond are not in order, i.e. `aFirst >= aSecond`. |
| * |
| */ |
| constexpr static bool AreInOrder(const CommandEntry &aFirst, const CommandEntry &aSecond) |
| { |
| return AreStringsInOrder(aFirst.mName, aSecond.mName); |
| } |
| |
| const char *mName; ///< The command name. |
| Handler mHandler; ///< The handler method pointer. |
| }; |
| |
| static const char kUnknownString[]; // Constant string "unknown". |
| |
| /** |
| * This template static method converts an enumeration value to a string using a table array. |
| * |
| * @tparam EnumType The `enum` type. |
| * @tparam kLength The table array length (number of entries in the array). |
| * |
| * @param[in] aEnum The enumeration value to convert (MUST be of `EnumType`). |
| * @param[in] aTable A reference to the array of strings of length @p kLength. `aTable[e]` is the string |
| * representation of enumeration value `e`. |
| * @param[in] aNotFound The string to return if the @p aEnum is not in the @p aTable. |
| * |
| * @returns The string representation of @p aEnum from @p aTable, or @p aNotFound if it is not in the table. |
| * |
| */ |
| template <typename EnumType, uint16_t kLength> |
| static const char *Stringify(EnumType aEnum, |
| const char *const (&aTable)[kLength], |
| const char *aNotFound = kUnknownString) |
| { |
| return (static_cast<uint16_t>(aEnum) < kLength) ? aTable[static_cast<uint16_t>(aEnum)] : aNotFound; |
| } |
| |
| protected: |
| OutputBase(void) = default; |
| }; |
| |
| /** |
| * This class provides CLI output helper methods. |
| * |
| */ |
| class Output : public OutputBase |
| { |
| public: |
| /** |
| * This constructor initializes the `Output` object. |
| * |
| * @param[in] aInstance A pointer to OpenThread instance. |
| * @param[in] aCallback A pointer to an `otCliOutputCallback` to deliver strings to the CLI console. |
| * @param[in] aCallbackContext An arbitrary context to pass in when invoking @p aCallback. |
| * |
| */ |
| Output(otInstance *aInstance, otCliOutputCallback aCallback, void *aCallbackContext); |
| |
| /** |
| * This method returns the pointer to OpenThread instance. |
| * |
| * @returns The pointer to the OpenThread instance. |
| * |
| */ |
| otInstance *GetInstancePtr(void) { return mInstance; } |
| |
| /** |
| * This method delivers a formatted output string to the CLI console. |
| * |
| * @param[in] aFormat A pointer to the format string. |
| * @param[in] ... A variable list of arguments to format. |
| * |
| */ |
| void OutputFormat(const char *aFormat, ...); |
| |
| /** |
| * This method delivers a formatted output string to the CLI console (to which it prepends a given number |
| * indentation space chars). |
| * |
| * @param[in] aIndentSize Number of indentation space chars to prepend to the string. |
| * @param[in] aFormat A pointer to the format string. |
| * @param[in] ... A variable list of arguments to format. |
| * |
| */ |
| void OutputFormat(uint8_t aIndentSize, const char *aFormat, ...); |
| |
| /** |
| * This method delivers a formatted output string to the CLI console (to which it also appends newline "\r\n"). |
| * |
| * @param[in] aFormat A pointer to the format string. |
| * @param[in] ... A variable list of arguments to format. |
| * |
| */ |
| void OutputLine(const char *aFormat, ...); |
| |
| /** |
| * This method delivers a formatted output string to the CLI console (to which it prepends a given number |
| * indentation space chars and appends newline "\r\n"). |
| * |
| * @param[in] aIndentSize Number of indentation space chars to prepend to the string. |
| * @param[in] aFormat A pointer to the format string. |
| * @param[in] ... A variable list of arguments to format. |
| * |
| */ |
| void OutputLine(uint8_t aIndentSize, const char *aFormat, ...); |
| |
| /** |
| * This method outputs a given number of space chars to the CLI console. |
| * |
| * @param[in] aCount Number of space chars to output. |
| * |
| */ |
| void OutputSpaces(uint8_t aCount); |
| |
| /** |
| * This method outputs a number of bytes to the CLI console as a hex string. |
| * |
| * @param[in] aBytes A pointer to data which should be printed. |
| * @param[in] aLength @p aBytes length. |
| * |
| */ |
| void OutputBytes(const uint8_t *aBytes, uint16_t aLength); |
| |
| /** |
| * This method outputs a number of bytes to the CLI console as a hex string and at the end it also outputs newline |
| * "\r\n". |
| * |
| * @param[in] aBytes A pointer to data which should be printed. |
| * @param[in] aLength @p aBytes length. |
| * |
| */ |
| void OutputBytesLine(const uint8_t *aBytes, uint16_t aLength); |
| |
| /** |
| * This method outputs a number of bytes to the CLI console as a hex string. |
| * |
| * @tparam kBytesLength The length of @p aBytes array. |
| * |
| * @param[in] aBytes A array of @p kBytesLength bytes which should be printed. |
| * |
| */ |
| template <uint8_t kBytesLength> void OutputBytes(const uint8_t (&aBytes)[kBytesLength]) |
| { |
| OutputBytes(aBytes, kBytesLength); |
| } |
| |
| /** |
| * This method outputs a number of bytes to the CLI console as a hex string and at the end it also outputs newline |
| * "\r\n". |
| * |
| * @tparam kBytesLength The length of @p aBytes array. |
| * |
| * @param[in] aBytes A array of @p kBytesLength bytes which should be printed. |
| * |
| */ |
| template <uint8_t kBytesLength> void OutputBytesLine(const uint8_t (&aBytes)[kBytesLength]) |
| { |
| OutputBytesLine(aBytes, kBytesLength); |
| } |
| |
| /** |
| * This method outputs an Extended MAC Address to the CLI console. |
| * |
| * param[in] aExtAddress The Extended MAC Address to output. |
| * |
| */ |
| void OutputExtAddress(const otExtAddress &aExtAddress) { OutputBytes(aExtAddress.m8); } |
| |
| /** |
| * This method outputs an Extended MAC Address to the CLI console and at the end it also outputs newline "\r\n". |
| * |
| * param[in] aExtAddress The Extended MAC Address to output. |
| * |
| */ |
| void OutputExtAddressLine(const otExtAddress &aExtAddress) { OutputBytesLine(aExtAddress.m8); } |
| |
| /** |
| * This method outputs "Enabled" or "Disabled" status to the CLI console (it also appends newline "\r\n"). |
| * |
| * @param[in] aEnabled A boolean indicating the status. TRUE outputs "Enabled", FALSE outputs "Disabled". |
| * |
| */ |
| void OutputEnabledDisabledStatus(bool aEnabled); |
| |
| #if OPENTHREAD_FTD || OPENTHREAD_MTD |
| |
| /** |
| * This method outputs an IPv6 address to the CLI console. |
| * |
| * @param[in] aAddress A reference to the IPv6 address. |
| * |
| */ |
| void OutputIp6Address(const otIp6Address &aAddress); |
| |
| /** |
| * This method outputs an IPv6 address to the CLI console and at the end it also outputs newline "\r\n". |
| * |
| * @param[in] aAddress A reference to the IPv6 address. |
| * |
| */ |
| void OutputIp6AddressLine(const otIp6Address &aAddress); |
| |
| /** |
| * This method outputs an IPv6 prefix to the CLI console. |
| * |
| * @param[in] aPrefix A reference to the IPv6 prefix. |
| * |
| */ |
| void OutputIp6Prefix(const otIp6Prefix &aPrefix); |
| |
| /** |
| * This method outputs an IPv6 prefix to the CLI console and at the end it also outputs newline "\r\n". |
| * |
| * @param[in] aPrefix A reference to the IPv6 prefix. |
| * |
| */ |
| void OutputIp6PrefixLine(const otIp6Prefix &aPrefix); |
| |
| /** |
| * This method outputs an IPv6 network prefix to the CLI console. |
| * |
| * @param[in] aPrefix A reference to the IPv6 network prefix. |
| * |
| */ |
| void OutputIp6Prefix(const otIp6NetworkPrefix &aPrefix); |
| |
| /** |
| * This method outputs an IPv6 network prefix to the CLI console and at the end it also outputs newline "\r\n". |
| * |
| * @param[in] aPrefix A reference to the IPv6 network prefix. |
| * |
| */ |
| void OutputIp6PrefixLine(const otIp6NetworkPrefix &aPrefix); |
| |
| /** |
| * This method outputs an IPv6 socket address to the CLI console. |
| * |
| * @param[in] aSockAddr A reference to the IPv6 socket address. |
| * |
| */ |
| void OutputSockAddr(const otSockAddr &aSockAddr); |
| |
| /** |
| * This method outputs an IPv6 socket address to the CLI console and at the end it also outputs newline "\r\n". |
| * |
| * @param[in] aSockAddr A reference to the IPv6 socket address. |
| * |
| */ |
| void OutputSockAddrLine(const otSockAddr &aSockAddr); |
| |
| /** |
| * This method outputs DNS TXT data to the CLI console. |
| * |
| * @param[in] aTxtData A pointer to a buffer containing the DNS TXT data. |
| * @param[in] aTxtDataLength The length of @p aTxtData (in bytes). |
| * |
| */ |
| void OutputDnsTxtData(const uint8_t *aTxtData, uint16_t aTxtDataLength); |
| |
| #endif // OPENTHREAD_FTD || OPENTHREAD_MTD |
| |
| /** |
| * This method outputs a table header to the CLI console. |
| * |
| * An example of the table header format: |
| * |
| * | Title1 | Title2 |Title3| Title4 | |
| * +-----------+--------+------+----------------------+ |
| * |
| * The titles are left adjusted (extra white space is added at beginning if the column is width enough). The widths |
| * are specified as the number chars between two `|` chars (excluding the char `|` itself). |
| * |
| * @tparam kTableNumColumns The number columns in the table. |
| * |
| * @param[in] aTitles An array specifying the table column titles. |
| * @param[in] aWidths An array specifying the table column widths (in number of chars). |
| * |
| */ |
| template <uint8_t kTableNumColumns> |
| void OutputTableHeader(const char *const (&aTitles)[kTableNumColumns], const uint8_t (&aWidths)[kTableNumColumns]) |
| { |
| OutputTableHeader(kTableNumColumns, &aTitles[0], &aWidths[0]); |
| } |
| |
| /** |
| * This method outputs a table separator to the CLI console. |
| * |
| * An example of the table separator: |
| * |
| * +-----------+--------+------+----------------------+ |
| * |
| * The widths are specified as number chars between two `+` chars (excluding the char `+` itself). |
| * |
| * @tparam kTableNumColumns The number columns in the table. |
| * |
| * @param[in] aWidths An array specifying the table column widths (in number of chars). |
| * |
| */ |
| template <uint8_t kTableNumColumns> void OutputTableSeparator(const uint8_t (&aWidths)[kTableNumColumns]) |
| { |
| OutputTableSeparator(kTableNumColumns, &aWidths[0]); |
| } |
| |
| /** |
| * This method outputs the list of commands from a given command table. |
| * |
| * @tparam Cli The CLI module type. |
| * @tparam kLength The length of command table array. |
| * |
| * @param[in] aCommandTable The command table array. |
| * |
| */ |
| template <typename Cli, uint16_t kLength> void OutputCommandTable(const CommandEntry<Cli> (&aCommandTable)[kLength]) |
| { |
| for (const CommandEntry<Cli> &entry : aCommandTable) |
| { |
| OutputLine("%s", entry.mName); |
| } |
| } |
| |
| protected: |
| void OutputFormatV(const char *aFormat, va_list aArguments); |
| |
| #if OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE |
| void LogInput(const Arg *aArgs); |
| void SetEmittingCommandOutput(bool aEmittingOutput) { mEmittingCommandOutput = aEmittingOutput; } |
| #else |
| void LogInput(const Arg *) {} |
| void SetEmittingCommandOutput(bool) {} |
| #endif |
| |
| private: |
| static constexpr uint16_t kInputOutputLogStringSize = OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_LOG_STRING_SIZE; |
| |
| void OutputTableHeader(uint8_t aNumColumns, const char *const aTitles[], const uint8_t aWidths[]); |
| void OutputTableSeparator(uint8_t aNumColumns, const uint8_t aWidths[]); |
| |
| otInstance * mInstance; |
| otCliOutputCallback mCallback; |
| void * mCallbackContext; |
| #if OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE |
| char mOutputString[kInputOutputLogStringSize]; |
| uint16_t mOutputLength; |
| bool mEmittingCommandOutput; |
| #endif |
| }; |
| |
| class OutputWrapper : public OutputBase |
| { |
| protected: |
| explicit OutputWrapper(Output &aOutput) |
| : mOutput(aOutput) |
| { |
| } |
| |
| otInstance *GetInstancePtr(void) { return mOutput.GetInstancePtr(); } |
| |
| template <typename... Args> void OutputFormat(const char *aFormat, Args... aArgs) |
| { |
| mOutput.OutputFormat(aFormat, aArgs...); |
| } |
| |
| template <typename... Args> void OutputFormat(uint8_t aIndentSize, const char *aFormat, Args... aArgs) |
| { |
| mOutput.OutputFormat(aIndentSize, aFormat, aArgs...); |
| } |
| |
| template <typename... Args> void OutputLine(const char *aFormat, Args... aArgs) |
| { |
| return mOutput.OutputLine(aFormat, aArgs...); |
| } |
| |
| template <typename... Args> void OutputLine(uint8_t aIndentSize, const char *aFormat, Args... aArgs) |
| { |
| return mOutput.OutputLine(aIndentSize, aFormat, aArgs...); |
| } |
| |
| template <uint8_t kBytesLength> void OutputBytes(const uint8_t (&aBytes)[kBytesLength]) |
| { |
| mOutput.OutputBytes(aBytes, kBytesLength); |
| } |
| |
| template <uint8_t kBytesLength> void OutputBytesLine(const uint8_t (&aBytes)[kBytesLength]) |
| { |
| mOutput.OutputBytesLine(aBytes, kBytesLength); |
| } |
| |
| void OutputSpaces(uint8_t aCount) { return mOutput.OutputSpaces(aCount); } |
| void OutputBytes(const uint8_t *aBytes, uint16_t aLength) { return mOutput.OutputBytes(aBytes, aLength); } |
| void OutputBytesLine(const uint8_t *aBytes, uint16_t aLength) { return mOutput.OutputBytesLine(aBytes, aLength); } |
| void OutputExtAddress(const otExtAddress &aExtAddress) { mOutput.OutputExtAddress(aExtAddress); } |
| void OutputExtAddressLine(const otExtAddress &aExtAddress) { mOutput.OutputExtAddressLine(aExtAddress); } |
| void OutputEnabledDisabledStatus(bool aEnabled) { mOutput.OutputEnabledDisabledStatus(aEnabled); } |
| |
| #if OPENTHREAD_FTD || OPENTHREAD_MTD |
| void OutputIp6Address(const otIp6Address &aAddress) { mOutput.OutputIp6Address(aAddress); } |
| void OutputIp6AddressLine(const otIp6Address &aAddress) { mOutput.OutputIp6AddressLine(aAddress); } |
| void OutputIp6Prefix(const otIp6Prefix &aPrefix) { mOutput.OutputIp6Prefix(aPrefix); } |
| void OutputIp6PrefixLine(const otIp6Prefix &aPrefix) { mOutput.OutputIp6PrefixLine(aPrefix); } |
| void OutputIp6Prefix(const otIp6NetworkPrefix &aPrefix) { mOutput.OutputIp6Prefix(aPrefix); } |
| void OutputIp6PrefixLine(const otIp6NetworkPrefix &aPrefix) { mOutput.OutputIp6PrefixLine(aPrefix); } |
| void OutputSockAddr(const otSockAddr &aSockAddr) { mOutput.OutputSockAddr(aSockAddr); } |
| void OutputSockAddrLine(const otSockAddr &aSockAddr) { mOutput.OutputSockAddrLine(aSockAddr); } |
| void OutputDnsTxtData(const uint8_t *aTxtData, uint16_t aTxtDataLength) |
| { |
| mOutput.OutputDnsTxtData(aTxtData, aTxtDataLength); |
| } |
| #endif |
| |
| template <uint8_t kTableNumColumns> |
| void OutputTableHeader(const char *const (&aTitles)[kTableNumColumns], const uint8_t (&aWidths)[kTableNumColumns]) |
| { |
| mOutput.OutputTableHeader(aTitles, aWidths); |
| } |
| |
| template <uint8_t kTableNumColumns> void OutputTableSeparator(const uint8_t (&aWidths)[kTableNumColumns]) |
| { |
| mOutput.OutputTableSeparator(aWidths); |
| } |
| |
| template <typename Cli, uint16_t kLength> void OutputCommandTable(const CommandEntry<Cli> (&aCommandTable)[kLength]) |
| { |
| mOutput.OutputCommandTable(aCommandTable); |
| } |
| |
| private: |
| Output &mOutput; |
| }; |
| |
| } // namespace Cli |
| } // namespace ot |
| |
| #endif // CLI_OUTPUT_HPP_ |