• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2021, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file contains definitions for the CLI output.
32  */
33 
34 #ifndef CLI_OUTPUT_HPP_
35 #define CLI_OUTPUT_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <stdarg.h>
40 
41 #include <openthread/cli.h>
42 
43 #include "cli_config.h"
44 
45 #include "common/binary_search.hpp"
46 #include "common/num_utils.hpp"
47 #include "common/string.hpp"
48 #include "common/type_traits.hpp"
49 #include "utils/parse_cmdline.hpp"
50 
51 namespace ot {
52 namespace Cli {
53 
54 /**
55  * Represents a ID number value associated with a CLI command string.
56  *
57  */
58 typedef uint64_t CommandId;
59 
60 /**
61  * This `constexpr` function converts a CLI command string to its associated `CommandId` value.
62  *
63  * @param[in] aString   The CLI command string.
64  *
65  * @returns The associated `CommandId` with @p aString.
66  *
67  */
Cmd(const char * aString)68 constexpr static CommandId Cmd(const char *aString)
69 {
70     return (aString[0] == '\0') ? 0 : (static_cast<uint8_t>(aString[0]) + Cmd(aString + 1) * 255u);
71 }
72 
73 class Utils;
74 
75 /**
76  * Implements the basic output functions.
77  *
78  */
79 class OutputImplementer
80 {
81     friend class Utils;
82 
83 public:
84     /**
85      * Initializes the `OutputImplementer` object.
86      *
87      * @param[in] aCallback           A pointer to an `otCliOutputCallback` to deliver strings to the CLI console.
88      * @param[in] aCallbackContext    An arbitrary context to pass in when invoking @p aCallback.
89      *
90      */
91     OutputImplementer(otCliOutputCallback aCallback, void *aCallbackContext);
92 
93 #if OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE
SetEmittingCommandOutput(bool aEmittingOutput)94     void SetEmittingCommandOutput(bool aEmittingOutput) { mEmittingCommandOutput = aEmittingOutput; }
95 #else
SetEmittingCommandOutput(bool)96     void SetEmittingCommandOutput(bool) {}
97 #endif
98 
99 private:
100     static constexpr uint16_t kInputOutputLogStringSize = OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_LOG_STRING_SIZE;
101 
102     void OutputV(const char *aFormat, va_list aArguments);
103 
104     otCliOutputCallback mCallback;
105     void               *mCallbackContext;
106 #if OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE
107     char     mOutputString[kInputOutputLogStringSize];
108     uint16_t mOutputLength;
109     bool     mEmittingCommandOutput;
110 #endif
111 };
112 
113 /**
114  * Provides CLI helper methods.
115  *
116  */
117 class Utils
118 {
119 public:
120     typedef ot::Utils::CmdLineParser::Arg Arg; ///< An argument
121 
122     /**
123      * Represent a CLI command table entry, mapping a command with `aName` to a handler method.
124      *
125      * @tparam Cli    The CLI module type.
126      *
127      */
128     template <typename Cli> struct CommandEntry
129     {
130         typedef otError (Cli::*Handler)(Arg aArgs[]); ///< The handler method pointer type.
131 
132         /**
133          * Compares the entry's name with a given name.
134          *
135          * @param aName    The name string to compare with.
136          *
137          * @return zero means perfect match, positive (> 0) indicates @p aName is larger than entry's name, and
138          *         negative (< 0) indicates @p aName is smaller than entry's name.
139          *
140          */
Compareot::Cli::Utils::CommandEntry141         int Compare(const char *aName) const { return strcmp(aName, mName); }
142 
143         /**
144          * This `constexpr` method compares two entries to check if they are in order.
145          *
146          * @param[in] aFirst     The first entry.
147          * @param[in] aSecond    The second entry.
148          *
149          * @retval TRUE  if @p aFirst and @p aSecond are in order, i.e. `aFirst < aSecond`.
150          * @retval FALSE if @p aFirst and @p aSecond are not in order, i.e. `aFirst >= aSecond`.
151          *
152          */
AreInOrderot::Cli::Utils::CommandEntry153         constexpr static bool AreInOrder(const CommandEntry &aFirst, const CommandEntry &aSecond)
154         {
155             return AreStringsInOrder(aFirst.mName, aSecond.mName);
156         }
157 
158         const char *mName;    ///< The command name.
159         Handler     mHandler; ///< The handler method pointer.
160     };
161 
162     static const char kUnknownString[]; // Constant string "unknown".
163 
164     /**
165      * This template static method converts an enumeration value to a string using a table array.
166      *
167      * @tparam EnumType       The `enum` type.
168      * @tparam kLength        The table array length (number of entries in the array).
169      *
170      * @param[in] aEnum       The enumeration value to convert (MUST be of `EnumType`).
171      * @param[in] aTable      A reference to the array of strings of length @p kLength. `aTable[e]` is the string
172      *                        representation of enumeration value `e`.
173      * @param[in] aNotFound   The string to return if the @p aEnum is not in the @p aTable.
174      *
175      * @returns The string representation of @p aEnum from @p aTable, or @p aNotFound if it is not in the table.
176      *
177      */
178     template <typename EnumType, uint16_t kLength>
Stringify(EnumType aEnum,const char * const (& aTable)[kLength],const char * aNotFound=kUnknownString)179     static const char *Stringify(EnumType aEnum,
180                                  const char *const (&aTable)[kLength],
181                                  const char *aNotFound = kUnknownString)
182     {
183         return (static_cast<uint16_t>(aEnum) < kLength) ? aTable[static_cast<uint16_t>(aEnum)] : aNotFound;
184     }
185 
186     /**
187      * Initializes the `Output` object.
188      *
189      * @param[in] aInstance           A pointer to OpenThread instance.
190      * @param[in] aImplementer        An `OutputImplementer`.
191      *
192      */
Utils(otInstance * aInstance,OutputImplementer & aImplementer)193     Utils(otInstance *aInstance, OutputImplementer &aImplementer)
194         : mInstance(aInstance)
195         , mImplementer(aImplementer)
196     {
197     }
198 
199     /**
200      * Returns the pointer to OpenThread instance.
201      *
202      * @returns The pointer to the OpenThread instance.
203      *
204      */
GetInstancePtr(void)205     otInstance *GetInstancePtr(void) { return mInstance; }
206 
207     /**
208      * Represents a buffer which is used when converting a `uint64` value to string in decimal format.
209      *
210      */
211     struct Uint64StringBuffer
212     {
213         static constexpr uint16_t kSize = 21; ///< Size of a buffer
214 
215         char mChars[kSize]; ///< Char array (do not access the array directly).
216     };
217 
218     /**
219      * Converts a `uint64_t` value to a decimal format string.
220      *
221      * @param[in] aUint64  The `uint64_t` value to convert.
222      * @param[in] aBuffer  A buffer to allocate the string from.
223      *
224      * @returns A pointer to the start of the string (null-terminated) representation of @p aUint64.
225      *
226      */
227     static const char *Uint64ToString(uint64_t aUint64, Uint64StringBuffer &aBuffer);
228 
229     /**
230      * Delivers a formatted output string to the CLI console.
231      *
232      * @param[in]  aFormat  A pointer to the format string.
233      * @param[in]  ...      A variable list of arguments to format.
234      *
235      */
236     void OutputFormat(const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(2, 3);
237 
238     /**
239      * Delivers a formatted output string to the CLI console (to which it prepends a given number
240      * indentation space chars).
241      *
242      * @param[in]  aIndentSize   Number of indentation space chars to prepend to the string.
243      * @param[in]  aFormat       A pointer to the format string.
244      * @param[in]  ...           A variable list of arguments to format.
245      *
246      */
247     void OutputFormat(uint8_t aIndentSize, const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(3, 4);
248 
249     /**
250      * Delivers a formatted output string to the CLI console (to which it also appends newline "\r\n").
251      *
252      * @param[in]  aFormat  A pointer to the format string.
253      * @param[in]  ...      A variable list of arguments to format.
254      *
255      */
256     void OutputLine(const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(2, 3);
257 
258     /**
259      * Delivers a formatted output string to the CLI console (to which it prepends a given number
260      * indentation space chars and appends newline "\r\n").
261      *
262      * @param[in]  aIndentSize   Number of indentation space chars to prepend to the string.
263      * @param[in]  aFormat       A pointer to the format string.
264      * @param[in]  ...           A variable list of arguments to format.
265      *
266      */
267     void OutputLine(uint8_t aIndentSize, const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(3, 4);
268 
269     /**
270      * Delivered newline "\r\n" to the CLI console.
271      *
272      */
273     void OutputNewLine(void);
274 
275     /**
276      * Outputs a given number of space chars to the CLI console.
277      *
278      * @param[in] aCount  Number of space chars to output.
279      *
280      */
281     void OutputSpaces(uint8_t aCount);
282 
283     /**
284      * Outputs a number of bytes to the CLI console as a hex string.
285      *
286      * @param[in]  aBytes   A pointer to data which should be printed.
287      * @param[in]  aLength  @p aBytes length.
288      *
289      */
290     void OutputBytes(const uint8_t *aBytes, uint16_t aLength);
291 
292     /**
293      * Outputs a number of bytes to the CLI console as a hex string and at the end it also outputs newline
294      * "\r\n".
295      *
296      * @param[in]  aBytes   A pointer to data which should be printed.
297      * @param[in]  aLength  @p aBytes length.
298      *
299      */
300     void OutputBytesLine(const uint8_t *aBytes, uint16_t aLength);
301 
302     /**
303      * Outputs a number of bytes to the CLI console as a hex string.
304      *
305      * @tparam kBytesLength   The length of @p aBytes array.
306      *
307      * @param[in]  aBytes     A array of @p kBytesLength bytes which should be printed.
308      *
309      */
OutputBytes(const uint8_t (& aBytes)[kBytesLength])310     template <uint8_t kBytesLength> void OutputBytes(const uint8_t (&aBytes)[kBytesLength])
311     {
312         OutputBytes(aBytes, kBytesLength);
313     }
314 
315     /**
316      * Outputs a number of bytes to the CLI console as a hex string and at the end it also outputs newline
317      * "\r\n".
318      *
319      * @tparam kBytesLength   The length of @p aBytes array.
320      *
321      * @param[in]  aBytes     A array of @p kBytesLength bytes which should be printed.
322      *
323      */
OutputBytesLine(const uint8_t (& aBytes)[kBytesLength])324     template <uint8_t kBytesLength> void OutputBytesLine(const uint8_t (&aBytes)[kBytesLength])
325     {
326         OutputBytesLine(aBytes, kBytesLength);
327     }
328 
329     /**
330      * Outputs an Extended MAC Address to the CLI console.
331      *
332      * param[in] aExtAddress  The Extended MAC Address to output.
333      *
334      */
OutputExtAddress(const otExtAddress & aExtAddress)335     void OutputExtAddress(const otExtAddress &aExtAddress) { OutputBytes(aExtAddress.m8); }
336 
337     /**
338      * Outputs an Extended MAC Address to the CLI console and at the end it also outputs newline "\r\n".
339      *
340      * param[in] aExtAddress  The Extended MAC Address to output.
341      *
342      */
OutputExtAddressLine(const otExtAddress & aExtAddress)343     void OutputExtAddressLine(const otExtAddress &aExtAddress) { OutputBytesLine(aExtAddress.m8); }
344 
345     /**
346      * Outputs a `uint64_t` value in decimal format.
347      *
348      * @param[in] aUint64   The `uint64_t` value to output.
349      *
350      */
351     void OutputUint64(uint64_t aUint64);
352 
353     /**
354      * Outputs a `uint64_t` value in decimal format and at the end it also outputs newline "\r\n".
355      *
356      * @param[in] aUint64   The `uint64_t` value to output.
357      *
358      */
359     void OutputUint64Line(uint64_t aUint64);
360 
361     /**
362      * Outputs "Enabled" or "Disabled" status to the CLI console (it also appends newline "\r\n").
363      *
364      * @param[in] aEnabled  A boolean indicating the status. TRUE outputs "Enabled", FALSE outputs "Disabled".
365      *
366      */
367     void OutputEnabledDisabledStatus(bool aEnabled);
368 
369 #if OPENTHREAD_FTD || OPENTHREAD_MTD
370 
371     /**
372      * Outputs an IPv6 address to the CLI console.
373      *
374      * @param[in]  aAddress  A reference to the IPv6 address.
375      *
376      */
377     void OutputIp6Address(const otIp6Address &aAddress);
378 
379     /**
380      * Outputs an IPv6 address to the CLI console and at the end it also outputs newline "\r\n".
381      *
382      * @param[in]  aAddress  A reference to the IPv6 address.
383      *
384      */
385     void OutputIp6AddressLine(const otIp6Address &aAddress);
386 
387     /**
388      * Outputs an IPv6 prefix to the CLI console.
389      *
390      * @param[in]  aPrefix  A reference to the IPv6 prefix.
391      *
392      */
393     void OutputIp6Prefix(const otIp6Prefix &aPrefix);
394 
395     /**
396      * Outputs an IPv6 prefix to the CLI console and at the end it also outputs newline "\r\n".
397      *
398      * @param[in]  aPrefix  A reference to the IPv6 prefix.
399      *
400      */
401     void OutputIp6PrefixLine(const otIp6Prefix &aPrefix);
402 
403     /**
404      * Outputs an IPv6 network prefix to the CLI console.
405      *
406      * @param[in]  aPrefix  A reference to the IPv6 network prefix.
407      *
408      */
409     void OutputIp6Prefix(const otIp6NetworkPrefix &aPrefix);
410 
411     /**
412      * Outputs an IPv6 network prefix to the CLI console and at the end it also outputs newline "\r\n".
413      *
414      * @param[in]  aPrefix  A reference to the IPv6 network prefix.
415      *
416      */
417     void OutputIp6PrefixLine(const otIp6NetworkPrefix &aPrefix);
418 
419     /**
420      * Outputs an IPv6 socket address to the CLI console.
421      *
422      * @param[in] aSockAddr   A reference to the IPv6 socket address.
423      *
424      */
425     void OutputSockAddr(const otSockAddr &aSockAddr);
426 
427     /**
428      * Outputs an IPv6 socket address to the CLI console and at the end it also outputs newline "\r\n".
429      *
430      * @param[in] aSockAddr   A reference to the IPv6 socket address.
431      *
432      */
433     void OutputSockAddrLine(const otSockAddr &aSockAddr);
434 
435     /**
436      * Outputs DNS TXT data to the CLI console.
437      *
438      * @param[in] aTxtData        A pointer to a buffer containing the DNS TXT data.
439      * @param[in] aTxtDataLength  The length of @p aTxtData (in bytes).
440      *
441      */
442     void OutputDnsTxtData(const uint8_t *aTxtData, uint16_t aTxtDataLength);
443 
444     /**
445      * Represents a buffer which is used when converting an encoded rate value to percentage string.
446      *
447      */
448     struct PercentageStringBuffer
449     {
450         static constexpr uint16_t kSize = 7; ///< Size of a buffer
451 
452         char mChars[kSize]; ///< Char array (do not access the array directly).
453     };
454 
455     /**
456      * Converts an encoded value to a percentage representation.
457      *
458      * The encoded @p aValue is assumed to be linearly scaled such that `0` maps to 0% and `0xffff` maps to 100%.
459      *
460      * The resulting string provides two decimal accuracy, e.g., "100.00", "0.00", "75.37".
461      *
462      * @param[in] aValue   The encoded percentage value to convert.
463      * @param[in] aBuffer  A buffer to allocate the string from.
464      *
465      * @returns A pointer to the start of the string (null-terminated) representation of @p aValue.
466      *
467      */
468     static const char *PercentageToString(uint16_t aValue, PercentageStringBuffer &aBuffer);
469 
470 #endif // OPENTHREAD_FTD || OPENTHREAD_MTD
471 
472     /**
473      * Outputs a table header to the CLI console.
474      *
475      * An example of the table header format:
476      *
477      *    | Title1    | Title2 |Title3| Title4               |
478      *    +-----------+--------+------+----------------------+
479      *
480      * The titles are left adjusted (extra white space is added at beginning if the column is width enough). The widths
481      * are specified as the number chars between two `|` chars (excluding the char `|` itself).
482      *
483      * @tparam kTableNumColumns   The number columns in the table.
484      *
485      * @param[in] aTitles   An array specifying the table column titles.
486      * @param[in] aWidths   An array specifying the table column widths (in number of chars).
487      *
488      */
489     template <uint8_t kTableNumColumns>
OutputTableHeader(const char * const (& aTitles)[kTableNumColumns],const uint8_t (& aWidths)[kTableNumColumns])490     void OutputTableHeader(const char *const (&aTitles)[kTableNumColumns], const uint8_t (&aWidths)[kTableNumColumns])
491     {
492         OutputTableHeader(kTableNumColumns, &aTitles[0], &aWidths[0]);
493     }
494 
495     /**
496      * Outputs a table separator to the CLI console.
497      *
498      * An example of the table separator:
499      *
500      *    +-----------+--------+------+----------------------+
501      *
502      * The widths are specified as number chars between two `+` chars (excluding the char `+` itself).
503      *
504      * @tparam kTableNumColumns   The number columns in the table.
505      *
506      * @param[in] aWidths   An array specifying the table column widths (in number of chars).
507      *
508      */
OutputTableSeparator(const uint8_t (& aWidths)[kTableNumColumns])509     template <uint8_t kTableNumColumns> void OutputTableSeparator(const uint8_t (&aWidths)[kTableNumColumns])
510     {
511         OutputTableSeparator(kTableNumColumns, &aWidths[0]);
512     }
513 
514     /**
515      * Outputs the list of commands from a given command table.
516      *
517      * @tparam Cli      The CLI module type.
518      * @tparam kLength  The length of command table array.
519      *
520      * @param[in] aCommandTable   The command table array.
521      *
522      */
OutputCommandTable(const CommandEntry<Cli> (& aCommandTable)[kLength])523     template <typename Cli, uint16_t kLength> void OutputCommandTable(const CommandEntry<Cli> (&aCommandTable)[kLength])
524     {
525         for (const CommandEntry<Cli> &entry : aCommandTable)
526         {
527             OutputLine("%s", entry.mName);
528         }
529     }
530 
531     /**
532      * Clears (sets to zero) all bytes of a given object.
533      *
534      * @tparam ObjectType    The object type.
535      *
536      * @param[in] aObject    A reference to the object of type `ObjectType` to clear all its bytes.
537      *
538      */
ClearAllBytes(ObjectType & aObject)539     template <typename ObjectType> static void ClearAllBytes(ObjectType &aObject)
540     {
541         static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
542 
543         memset(reinterpret_cast<void *>(&aObject), 0, sizeof(ObjectType));
544     }
545 
546     // Definitions of handlers to process Get/Set/Enable/Disable.
547     template <typename ValueType> using GetHandler         = ValueType (&)(otInstance *);
548     template <typename ValueType> using SetHandler         = void (&)(otInstance *, ValueType);
549     template <typename ValueType> using SetHandlerFailable = otError (&)(otInstance *, ValueType);
550     using IsEnabledHandler                                 = bool (&)(otInstance *);
551     using SetEnabledHandler                                = void (&)(otInstance *, bool);
552     using SetEnabledHandlerFailable                        = otError (&)(otInstance *, bool);
553 
554     // Returns format string to output a `ValueType` (e.g., "%u" for `uint16_t`).
555     template <typename ValueType> static constexpr const char *FormatStringFor(void);
556 
557     /**
558      * Checks a given argument string against "enable" or "disable" commands.
559      *
560      * @param[in]  aArg     The argument string to parse.
561      * @param[out] aEnable  Boolean variable to return outcome on success.
562      *                      Set to TRUE for "enable" command, and FALSE for "disable" command.
563      *
564      * @retval OT_ERROR_NONE             Successfully parsed the @p aString and updated @p aEnable.
565      * @retval OT_ERROR_INVALID_COMMAND  The @p aString is not "enable" or "disable" command.
566      *
567      */
568     static otError ParseEnableOrDisable(const Arg &aArg, bool &aEnable);
569 
570     // General template implementation.
571     // Specializations for `uint32_t` and `int32_t` are added at the end.
ProcessGet(Arg aArgs[],GetHandler<ValueType> aGetHandler)572     template <typename ValueType> otError ProcessGet(Arg aArgs[], GetHandler<ValueType> aGetHandler)
573     {
574         static_assert(
575             TypeTraits::IsSame<ValueType, uint8_t>::kValue || TypeTraits::IsSame<ValueType, uint16_t>::kValue ||
576                 TypeTraits::IsSame<ValueType, int8_t>::kValue || TypeTraits::IsSame<ValueType, int16_t>::kValue ||
577                 TypeTraits::IsSame<ValueType, const char *>::kValue,
578             "ValueType must be an  8, 16 `int` or `uint` type, or a `const char *`");
579 
580         otError error = OT_ERROR_NONE;
581 
582         VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
583         OutputLine(FormatStringFor<ValueType>(), aGetHandler(GetInstancePtr()));
584 
585     exit:
586         return error;
587     }
588 
ProcessSet(Arg aArgs[],SetHandler<ValueType> aSetHandler)589     template <typename ValueType> otError ProcessSet(Arg aArgs[], SetHandler<ValueType> aSetHandler)
590     {
591         otError   error;
592         ValueType value;
593 
594         SuccessOrExit(error = aArgs[0].ParseAs<ValueType>(value));
595         VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
596 
597         aSetHandler(GetInstancePtr(), value);
598 
599     exit:
600         return error;
601     }
602 
ProcessSet(Arg aArgs[],SetHandlerFailable<ValueType> aSetHandler)603     template <typename ValueType> otError ProcessSet(Arg aArgs[], SetHandlerFailable<ValueType> aSetHandler)
604     {
605         otError   error;
606         ValueType value;
607 
608         SuccessOrExit(error = aArgs[0].ParseAs<ValueType>(value));
609         VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
610 
611         error = aSetHandler(GetInstancePtr(), value);
612 
613     exit:
614         return error;
615     }
616 
617     template <typename ValueType>
ProcessGetSet(Arg aArgs[],GetHandler<ValueType> aGetHandler,SetHandler<ValueType> aSetHandler)618     otError ProcessGetSet(Arg aArgs[], GetHandler<ValueType> aGetHandler, SetHandler<ValueType> aSetHandler)
619     {
620         otError error = ProcessGet(aArgs, aGetHandler);
621 
622         VerifyOrExit(error != OT_ERROR_NONE);
623         error = ProcessSet(aArgs, aSetHandler);
624 
625     exit:
626         return error;
627     }
628 
629     template <typename ValueType>
ProcessGetSet(Arg aArgs[],GetHandler<ValueType> aGetHandler,SetHandlerFailable<ValueType> aSetHandler)630     otError ProcessGetSet(Arg aArgs[], GetHandler<ValueType> aGetHandler, SetHandlerFailable<ValueType> aSetHandler)
631     {
632         otError error = ProcessGet(aArgs, aGetHandler);
633 
634         VerifyOrExit(error != OT_ERROR_NONE);
635         error = ProcessSet(aArgs, aSetHandler);
636 
637     exit:
638         return error;
639     }
640 
641     otError ProcessEnableDisable(Arg aArgs[], SetEnabledHandler aSetEnabledHandler);
642     otError ProcessEnableDisable(Arg aArgs[], SetEnabledHandlerFailable aSetEnabledHandler);
643     otError ProcessEnableDisable(Arg aArgs[], IsEnabledHandler aIsEnabledHandler, SetEnabledHandler aSetEnabledHandler);
644     otError ProcessEnableDisable(Arg                       aArgs[],
645                                  IsEnabledHandler          aIsEnabledHandler,
646                                  SetEnabledHandlerFailable aSetEnabledHandler);
647 
648 protected:
649     void OutputFormatV(const char *aFormat, va_list aArguments);
650 
651 #if OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE
652     void LogInput(const Arg *aArgs);
653 #else
LogInput(const Arg *)654     void LogInput(const Arg *) {}
655 #endif
656 
657 private:
658     static constexpr uint16_t kInputOutputLogStringSize = OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_LOG_STRING_SIZE;
659 
660     void OutputTableHeader(uint8_t aNumColumns, const char *const aTitles[], const uint8_t aWidths[]);
661     void OutputTableSeparator(uint8_t aNumColumns, const uint8_t aWidths[]);
662 
663     otInstance        *mInstance;
664     OutputImplementer &mImplementer;
665 };
666 
667 // Specializations of `FormatStringFor<ValueType>()`
668 
FormatStringFor(void)669 template <> inline constexpr const char *Utils::FormatStringFor<uint8_t>(void) { return "%u"; }
670 
FormatStringFor(void)671 template <> inline constexpr const char *Utils::FormatStringFor<uint16_t>(void) { return "%u"; }
672 
FormatStringFor(void)673 template <> inline constexpr const char *Utils::FormatStringFor<uint32_t>(void) { return "%lu"; }
674 
FormatStringFor(void)675 template <> inline constexpr const char *Utils::FormatStringFor<int8_t>(void) { return "%d"; }
676 
FormatStringFor(void)677 template <> inline constexpr const char *Utils::FormatStringFor<int16_t>(void) { return "%d"; }
678 
FormatStringFor(void)679 template <> inline constexpr const char *Utils::FormatStringFor<int32_t>(void) { return "%ld"; }
680 
FormatStringFor(void)681 template <> inline constexpr const char *Utils::FormatStringFor<const char *>(void) { return "%s"; }
682 
683 // Specialization of ProcessGet<> for `uint32_t` and `int32_t`
684 
ProcessGet(Arg aArgs[],GetHandler<uint32_t> aGetHandler)685 template <> inline otError Utils::ProcessGet<uint32_t>(Arg aArgs[], GetHandler<uint32_t> aGetHandler)
686 {
687     otError error = OT_ERROR_NONE;
688 
689     VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
690     OutputLine(FormatStringFor<uint32_t>(), ToUlong(aGetHandler(GetInstancePtr())));
691 
692 exit:
693     return error;
694 }
695 
ProcessGet(Arg aArgs[],GetHandler<int32_t> aGetHandler)696 template <> inline otError Utils::ProcessGet<int32_t>(Arg aArgs[], GetHandler<int32_t> aGetHandler)
697 {
698     otError error = OT_ERROR_NONE;
699 
700     VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
701     OutputLine(FormatStringFor<int32_t>(), static_cast<long int>(aGetHandler(GetInstancePtr())));
702 
703 exit:
704     return error;
705 }
706 
707 } // namespace Cli
708 } // namespace ot
709 
710 #endif // CLI_OUTPUT_HPP_
711