blob: 61e8997a736e13d45092f29b0c1ff599c8efb74a [file] [log] [blame]
/*
* 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_