• 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 util functions.
32  */
33 
34 #ifndef CLI_UTILS_HPP_
35 #define CLI_UTILS_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <stdarg.h>
40 
41 #include <openthread/border_router.h>
42 #include <openthread/border_routing.h>
43 #include <openthread/cli.h>
44 #include <openthread/joiner.h>
45 #include <openthread/thread.h>
46 
47 #include "cli_config.h"
48 
49 #include "common/binary_search.hpp"
50 #include "common/num_utils.hpp"
51 #include "common/string.hpp"
52 #include "common/type_traits.hpp"
53 #include "utils/parse_cmdline.hpp"
54 
55 namespace ot {
56 namespace Cli {
57 
58 /**
59  * Represents a ID number value associated with a CLI command string.
60  */
61 typedef uint64_t CommandId;
62 
63 /**
64  * This `constexpr` function converts a CLI command string to its associated `CommandId` value.
65  *
66  * @param[in] aString   The CLI command string.
67  *
68  * @returns The associated `CommandId` with @p aString.
69  */
Cmd(const char * aString)70 constexpr static CommandId Cmd(const char *aString)
71 {
72     return (aString[0] == '\0') ? 0 : (static_cast<uint8_t>(aString[0]) + Cmd(aString + 1) * 255u);
73 }
74 
75 class Utils;
76 
77 /**
78  * Implements the basic output functions.
79  */
80 class OutputImplementer
81 {
82     friend class Utils;
83 
84 public:
85     /**
86      * Initializes the `OutputImplementer` object.
87      *
88      * @param[in] aCallback           A pointer to an `otCliOutputCallback` to deliver strings to the CLI console.
89      * @param[in] aCallbackContext    An arbitrary context to pass in when invoking @p aCallback.
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 class Utils
117 {
118 public:
119     typedef ot::Utils::CmdLineParser::Arg Arg; ///< An argument
120 
121     /**
122      * Represent a CLI command table entry, mapping a command with `aName` to a handler method.
123      *
124      * @tparam Cli    The CLI module type.
125      */
126     template <typename Cli> struct CommandEntry
127     {
128         typedef otError (Cli::*Handler)(Arg aArgs[]); ///< The handler method pointer type.
129 
130         /**
131          * Compares the entry's name with a given name.
132          *
133          * @param aName    The name string to compare with.
134          *
135          * @return zero means perfect match, positive (> 0) indicates @p aName is larger than entry's name, and
136          *         negative (< 0) indicates @p aName is smaller than entry's name.
137          */
Compareot::Cli::Utils::CommandEntry138         int Compare(const char *aName) const { return strcmp(aName, mName); }
139 
140         /**
141          * This `constexpr` method compares two entries to check if they are in order.
142          *
143          * @param[in] aFirst     The first entry.
144          * @param[in] aSecond    The second entry.
145          *
146          * @retval TRUE  if @p aFirst and @p aSecond are in order, i.e. `aFirst < aSecond`.
147          * @retval FALSE if @p aFirst and @p aSecond are not in order, i.e. `aFirst >= aSecond`.
148          */
AreInOrderot::Cli::Utils::CommandEntry149         constexpr static bool AreInOrder(const CommandEntry &aFirst, const CommandEntry &aSecond)
150         {
151             return AreStringsInOrder(aFirst.mName, aSecond.mName);
152         }
153 
154         const char *mName;    ///< The command name.
155         Handler     mHandler; ///< The handler method pointer.
156     };
157 
158     static const char kUnknownString[]; // Constant string "unknown".
159 
160     /**
161      * This template static method converts an enumeration value to a string using a table array.
162      *
163      * @tparam EnumType       The `enum` type.
164      * @tparam kLength        The table array length (number of entries in the array).
165      *
166      * @param[in] aEnum       The enumeration value to convert (MUST be of `EnumType`).
167      * @param[in] aTable      A reference to the array of strings of length @p kLength. `aTable[e]` is the string
168      *                        representation of enumeration value `e`.
169      * @param[in] aNotFound   The string to return if the @p aEnum is not in the @p aTable.
170      *
171      * @returns The string representation of @p aEnum from @p aTable, or @p aNotFound if it is not in the table.
172      */
173     template <typename EnumType, uint16_t kLength>
Stringify(EnumType aEnum,const char * const (& aTable)[kLength],const char * aNotFound=kUnknownString)174     static const char *Stringify(EnumType aEnum,
175                                  const char *const (&aTable)[kLength],
176                                  const char *aNotFound = kUnknownString)
177     {
178         return (static_cast<uint16_t>(aEnum) < kLength) ? aTable[static_cast<uint16_t>(aEnum)] : aNotFound;
179     }
180 
181     /**
182      * Initializes the `Utils` object.
183      *
184      * @param[in] aInstance           A pointer to OpenThread instance.
185      * @param[in] aImplementer        An `OutputImplementer`.
186      */
Utils(otInstance * aInstance,OutputImplementer & aImplementer)187     Utils(otInstance *aInstance, OutputImplementer &aImplementer)
188         : mInstance(aInstance)
189         , mImplementer(aImplementer)
190     {
191     }
192 
193     /**
194      * Returns the pointer to OpenThread instance.
195      *
196      * @returns The pointer to the OpenThread instance.
197      */
GetInstancePtr(void)198     otInstance *GetInstancePtr(void) { return mInstance; }
199 
200     /**
201      * Represents a buffer which is used when converting a `uint64` value to string in decimal format.
202      */
203     struct Uint64StringBuffer
204     {
205         static constexpr uint16_t kSize = 21; ///< Size of a buffer
206 
207         char mChars[kSize]; ///< Char array (do not access the array directly).
208     };
209 
210     /**
211      * Converts a `uint64_t` value to a decimal format string.
212      *
213      * @param[in] aUint64  The `uint64_t` value to convert.
214      * @param[in] aBuffer  A buffer to allocate the string from.
215      *
216      * @returns A pointer to the start of the string (null-terminated) representation of @p aUint64.
217      */
218     static const char *Uint64ToString(uint64_t aUint64, Uint64StringBuffer &aBuffer);
219 
220     /**
221      * Delivers a formatted output string to the CLI console.
222      *
223      * @param[in]  aFormat  A pointer to the format string.
224      * @param[in]  ...      A variable list of arguments to format.
225      */
226     void OutputFormat(const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(2, 3);
227 
228     /**
229      * Delivers a formatted output string to the CLI console (to which it prepends a given number
230      * indentation space chars).
231      *
232      * @param[in]  aIndentSize   Number of indentation space chars to prepend to the string.
233      * @param[in]  aFormat       A pointer to the format string.
234      * @param[in]  ...           A variable list of arguments to format.
235      */
236     void OutputFormat(uint8_t aIndentSize, const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(3, 4);
237 
238     /**
239      * Delivers a formatted output string to the CLI console (to which it also appends newline "\r\n").
240      *
241      * @param[in]  aFormat  A pointer to the format string.
242      * @param[in]  ...      A variable list of arguments to format.
243      */
244     void OutputLine(const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(2, 3);
245 
246     /**
247      * Delivers a formatted output string to the CLI console (to which it prepends a given number
248      * indentation space chars and appends newline "\r\n").
249      *
250      * @param[in]  aIndentSize   Number of indentation space chars to prepend to the string.
251      * @param[in]  aFormat       A pointer to the format string.
252      * @param[in]  ...           A variable list of arguments to format.
253      */
254     void OutputLine(uint8_t aIndentSize, const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(3, 4);
255 
256     /**
257      * Delivered newline "\r\n" to the CLI console.
258      */
259     void OutputNewLine(void);
260 
261     /**
262      * Outputs a given number of space chars to the CLI console.
263      *
264      * @param[in] aCount  Number of space chars to output.
265      */
266     void OutputSpaces(uint8_t aCount);
267 
268     /**
269      * Outputs a number of bytes to the CLI console as a hex string.
270      *
271      * @param[in]  aBytes   A pointer to data which should be printed.
272      * @param[in]  aLength  @p aBytes length.
273      */
274     void OutputBytes(const uint8_t *aBytes, uint16_t aLength);
275 
276     /**
277      * Outputs a number of bytes to the CLI console as a hex string and at the end it also outputs newline
278      * "\r\n".
279      *
280      * @param[in]  aBytes   A pointer to data which should be printed.
281      * @param[in]  aLength  @p aBytes length.
282      */
283     void OutputBytesLine(const uint8_t *aBytes, uint16_t aLength);
284 
285     /**
286      * Outputs a number of bytes to the CLI console as a hex string.
287      *
288      * @tparam kBytesLength   The length of @p aBytes array.
289      *
290      * @param[in]  aBytes     A array of @p kBytesLength bytes which should be printed.
291      */
OutputBytes(const uint8_t (& aBytes)[kBytesLength])292     template <uint8_t kBytesLength> void OutputBytes(const uint8_t (&aBytes)[kBytesLength])
293     {
294         OutputBytes(aBytes, kBytesLength);
295     }
296 
297     /**
298      * Outputs a number of bytes to the CLI console as a hex string and at the end it also outputs newline
299      * "\r\n".
300      *
301      * @tparam kBytesLength   The length of @p aBytes array.
302      *
303      * @param[in]  aBytes     A array of @p kBytesLength bytes which should be printed.
304      */
OutputBytesLine(const uint8_t (& aBytes)[kBytesLength])305     template <uint8_t kBytesLength> void OutputBytesLine(const uint8_t (&aBytes)[kBytesLength])
306     {
307         OutputBytesLine(aBytes, kBytesLength);
308     }
309 
310     /**
311      * Outputs an Extended MAC Address to the CLI console.
312      *
313      * param[in] aExtAddress  The Extended MAC Address to output.
314      */
OutputExtAddress(const otExtAddress & aExtAddress)315     void OutputExtAddress(const otExtAddress &aExtAddress) { OutputBytes(aExtAddress.m8); }
316 
317     /**
318      * Outputs an Extended MAC Address to the CLI console and at the end it also outputs newline "\r\n".
319      *
320      * param[in] aExtAddress  The Extended MAC Address to output.
321      */
OutputExtAddressLine(const otExtAddress & aExtAddress)322     void OutputExtAddressLine(const otExtAddress &aExtAddress) { OutputBytesLine(aExtAddress.m8); }
323 
324     /**
325      * Outputs a `uint64_t` value in decimal format.
326      *
327      * @param[in] aUint64   The `uint64_t` value to output.
328      */
329     void OutputUint64(uint64_t aUint64);
330 
331     /**
332      * Outputs a `uint64_t` value in decimal format and at the end it also outputs newline "\r\n".
333      *
334      * @param[in] aUint64   The `uint64_t` value to output.
335      */
336     void OutputUint64Line(uint64_t aUint64);
337 
338     /**
339      * Outputs "Enabled" or "Disabled" status to the CLI console (it also appends newline "\r\n").
340      *
341      * @param[in] aEnabled  A boolean indicating the status. TRUE outputs "Enabled", FALSE outputs "Disabled".
342      */
343     void OutputEnabledDisabledStatus(bool aEnabled);
344 
345 #if OPENTHREAD_FTD || OPENTHREAD_MTD
346 
347     /**
348      * Outputs an IPv6 address to the CLI console.
349      *
350      * @param[in]  aAddress  A reference to the IPv6 address.
351      */
352     void OutputIp6Address(const otIp6Address &aAddress);
353 
354     /**
355      * Outputs an IPv6 address to the CLI console and at the end it also outputs newline "\r\n".
356      *
357      * @param[in]  aAddress  A reference to the IPv6 address.
358      */
359     void OutputIp6AddressLine(const otIp6Address &aAddress);
360 
361     /**
362      * Outputs an IPv6 prefix to the CLI console.
363      *
364      * @param[in]  aPrefix  A reference to the IPv6 prefix.
365      */
366     void OutputIp6Prefix(const otIp6Prefix &aPrefix);
367 
368     /**
369      * Outputs an IPv6 prefix to the CLI console and at the end it also outputs newline "\r\n".
370      *
371      * @param[in]  aPrefix  A reference to the IPv6 prefix.
372      */
373     void OutputIp6PrefixLine(const otIp6Prefix &aPrefix);
374 
375     /**
376      * Outputs an IPv6 network prefix to the CLI console.
377      *
378      * @param[in]  aPrefix  A reference to the IPv6 network prefix.
379      */
380     void OutputIp6Prefix(const otIp6NetworkPrefix &aPrefix);
381 
382     /**
383      * Outputs an IPv6 network prefix to the CLI console and at the end it also outputs newline "\r\n".
384      *
385      * @param[in]  aPrefix  A reference to the IPv6 network prefix.
386      */
387     void OutputIp6PrefixLine(const otIp6NetworkPrefix &aPrefix);
388 
389     /**
390      * Outputs an IPv6 socket address to the CLI console.
391      *
392      * @param[in] aSockAddr   A reference to the IPv6 socket address.
393      */
394     void OutputSockAddr(const otSockAddr &aSockAddr);
395 
396     /**
397      * Outputs an IPv6 socket address to the CLI console and at the end it also outputs newline "\r\n".
398      *
399      * @param[in] aSockAddr   A reference to the IPv6 socket address.
400      */
401     void OutputSockAddrLine(const otSockAddr &aSockAddr);
402 
403     /**
404      * Outputs DNS TXT data to the CLI console.
405      *
406      * @param[in] aTxtData        A pointer to a buffer containing the DNS TXT data.
407      * @param[in] aTxtDataLength  The length of @p aTxtData (in bytes).
408      */
409     void OutputDnsTxtData(const uint8_t *aTxtData, uint16_t aTxtDataLength);
410 
411     /**
412      * Represents a buffer which is used when converting an encoded rate value to percentage string.
413      */
414     struct PercentageStringBuffer
415     {
416         static constexpr uint16_t kSize = 7; ///< Size of a buffer
417 
418         char mChars[kSize]; ///< Char array (do not access the array directly).
419     };
420 
421     /**
422      * Converts an encoded value to a percentage representation.
423      *
424      * The encoded @p aValue is assumed to be linearly scaled such that `0` maps to 0% and `0xffff` maps to 100%.
425      *
426      * The resulting string provides two decimal accuracy, e.g., "100.00", "0.00", "75.37".
427      *
428      * @param[in] aValue   The encoded percentage value to convert.
429      * @param[in] aBuffer  A buffer to allocate the string from.
430      *
431      * @returns A pointer to the start of the string (null-terminated) representation of @p aValue.
432      */
433     static const char *PercentageToString(uint16_t aValue, PercentageStringBuffer &aBuffer);
434 
435 #endif // OPENTHREAD_FTD || OPENTHREAD_MTD
436 
437     /**
438      * Outputs a table header to the CLI console.
439      *
440      * An example of the table header format:
441      *
442      *    | Title1    | Title2 |Title3| Title4               |
443      *    +-----------+--------+------+----------------------+
444      *
445      * The titles are left adjusted (extra white space is added at beginning if the column is width enough). The widths
446      * are specified as the number chars between two `|` chars (excluding the char `|` itself).
447      *
448      * @tparam kTableNumColumns   The number columns in the table.
449      *
450      * @param[in] aTitles   An array specifying the table column titles.
451      * @param[in] aWidths   An array specifying the table column widths (in number of chars).
452      */
453     template <uint8_t kTableNumColumns>
OutputTableHeader(const char * const (& aTitles)[kTableNumColumns],const uint8_t (& aWidths)[kTableNumColumns])454     void OutputTableHeader(const char *const (&aTitles)[kTableNumColumns], const uint8_t (&aWidths)[kTableNumColumns])
455     {
456         OutputTableHeader(kTableNumColumns, &aTitles[0], &aWidths[0]);
457     }
458 
459     /**
460      * Outputs a table separator to the CLI console.
461      *
462      * An example of the table separator:
463      *
464      *    +-----------+--------+------+----------------------+
465      *
466      * The widths are specified as number chars between two `+` chars (excluding the char `+` itself).
467      *
468      * @tparam kTableNumColumns   The number columns in the table.
469      *
470      * @param[in] aWidths   An array specifying the table column widths (in number of chars).
471      */
OutputTableSeparator(const uint8_t (& aWidths)[kTableNumColumns])472     template <uint8_t kTableNumColumns> void OutputTableSeparator(const uint8_t (&aWidths)[kTableNumColumns])
473     {
474         OutputTableSeparator(kTableNumColumns, &aWidths[0]);
475     }
476 
477     /**
478      * Outputs the list of commands from a given command table.
479      *
480      * @tparam Cli      The CLI module type.
481      * @tparam kLength  The length of command table array.
482      *
483      * @param[in] aCommandTable   The command table array.
484      */
OutputCommandTable(const CommandEntry<Cli> (& aCommandTable)[kLength])485     template <typename Cli, uint16_t kLength> void OutputCommandTable(const CommandEntry<Cli> (&aCommandTable)[kLength])
486     {
487         for (const CommandEntry<Cli> &entry : aCommandTable)
488         {
489             OutputLine("%s", entry.mName);
490         }
491     }
492 
493     /**
494      * Clears (sets to zero) all bytes of a given object.
495      *
496      * @tparam ObjectType    The object type.
497      *
498      * @param[in] aObject    A reference to the object of type `ObjectType` to clear all its bytes.
499      */
ClearAllBytes(ObjectType & aObject)500     template <typename ObjectType> static void ClearAllBytes(ObjectType &aObject)
501     {
502         static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
503 
504         memset(reinterpret_cast<void *>(&aObject), 0, sizeof(ObjectType));
505     }
506 
507     // Definitions of handlers to process Get/Set/Enable/Disable.
508     template <typename ValueType> using GetHandler         = ValueType (&)(otInstance *);
509     template <typename ValueType> using SetHandler         = void (&)(otInstance *, ValueType);
510     template <typename ValueType> using SetHandlerFailable = otError (&)(otInstance *, ValueType);
511     using IsEnabledHandler                                 = bool (&)(otInstance *);
512     using SetEnabledHandler                                = void (&)(otInstance *, bool);
513     using SetEnabledHandlerFailable                        = otError (&)(otInstance *, bool);
514 
515     // Returns format string to output a `ValueType` (e.g., "%u" for `uint16_t`).
516     template <typename ValueType> static constexpr const char *FormatStringFor(void);
517 
518     /**
519      * Checks a given argument string against "enable" or "disable" commands.
520      *
521      * @param[in]  aArg     The argument string to parse.
522      * @param[out] aEnable  Boolean variable to return outcome on success.
523      *                      Set to TRUE for "enable" command, and FALSE for "disable" command.
524      *
525      * @retval OT_ERROR_NONE             Successfully parsed the @p aString and updated @p aEnable.
526      * @retval OT_ERROR_INVALID_COMMAND  The @p aString is not "enable" or "disable" command.
527      */
528     static otError ParseEnableOrDisable(const Arg &aArg, bool &aEnable);
529 
530     // General template implementation.
531     // Specializations for `uint32_t` and `int32_t` are added at the end.
ProcessGet(Arg aArgs[],GetHandler<ValueType> aGetHandler)532     template <typename ValueType> otError ProcessGet(Arg aArgs[], GetHandler<ValueType> aGetHandler)
533     {
534         static_assert(
535             TypeTraits::IsSame<ValueType, uint8_t>::kValue || TypeTraits::IsSame<ValueType, uint16_t>::kValue ||
536                 TypeTraits::IsSame<ValueType, int8_t>::kValue || TypeTraits::IsSame<ValueType, int16_t>::kValue ||
537                 TypeTraits::IsSame<ValueType, const char *>::kValue,
538             "ValueType must be an  8, 16 `int` or `uint` type, or a `const char *`");
539 
540         otError error = OT_ERROR_NONE;
541 
542         VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
543         OutputLine(FormatStringFor<ValueType>(), aGetHandler(GetInstancePtr()));
544 
545     exit:
546         return error;
547     }
548 
ProcessSet(Arg aArgs[],SetHandler<ValueType> aSetHandler)549     template <typename ValueType> otError ProcessSet(Arg aArgs[], SetHandler<ValueType> aSetHandler)
550     {
551         otError   error;
552         ValueType value;
553 
554         SuccessOrExit(error = aArgs[0].ParseAs<ValueType>(value));
555         VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
556 
557         aSetHandler(GetInstancePtr(), value);
558 
559     exit:
560         return error;
561     }
562 
ProcessSet(Arg aArgs[],SetHandlerFailable<ValueType> aSetHandler)563     template <typename ValueType> otError ProcessSet(Arg aArgs[], SetHandlerFailable<ValueType> aSetHandler)
564     {
565         otError   error;
566         ValueType value;
567 
568         SuccessOrExit(error = aArgs[0].ParseAs<ValueType>(value));
569         VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
570 
571         error = aSetHandler(GetInstancePtr(), value);
572 
573     exit:
574         return error;
575     }
576 
577     template <typename ValueType>
ProcessGetSet(Arg aArgs[],GetHandler<ValueType> aGetHandler,SetHandler<ValueType> aSetHandler)578     otError ProcessGetSet(Arg aArgs[], GetHandler<ValueType> aGetHandler, SetHandler<ValueType> aSetHandler)
579     {
580         otError error = ProcessGet(aArgs, aGetHandler);
581 
582         VerifyOrExit(error != OT_ERROR_NONE);
583         error = ProcessSet(aArgs, aSetHandler);
584 
585     exit:
586         return error;
587     }
588 
589     template <typename ValueType>
ProcessGetSet(Arg aArgs[],GetHandler<ValueType> aGetHandler,SetHandlerFailable<ValueType> aSetHandler)590     otError ProcessGetSet(Arg aArgs[], GetHandler<ValueType> aGetHandler, SetHandlerFailable<ValueType> aSetHandler)
591     {
592         otError error = ProcessGet(aArgs, aGetHandler);
593 
594         VerifyOrExit(error != OT_ERROR_NONE);
595         error = ProcessSet(aArgs, aSetHandler);
596 
597     exit:
598         return error;
599     }
600 
601     otError ProcessEnableDisable(Arg aArgs[], SetEnabledHandler aSetEnabledHandler);
602     otError ProcessEnableDisable(Arg aArgs[], SetEnabledHandlerFailable aSetEnabledHandler);
603     otError ProcessEnableDisable(Arg aArgs[], IsEnabledHandler aIsEnabledHandler, SetEnabledHandler aSetEnabledHandler);
604     otError ProcessEnableDisable(Arg                       aArgs[],
605                                  IsEnabledHandler          aIsEnabledHandler,
606                                  SetEnabledHandlerFailable aSetEnabledHandler);
607 
608     /**
609      * Parses a given argument string as a route preference comparing it against  "high", "med", or
610      * "low".
611      *
612      * @param[in]  aArg          The argument string to parse.
613      * @param[out] aPreference   Reference to a `otRoutePreference` to return the parsed preference.
614      *
615      * @retval OT_ERROR_NONE             Successfully parsed @p aArg and updated @p aPreference.
616      * @retval OT_ERROR_INVALID_ARG      @p aArg is not a valid preference string "high", "med", or "low".
617      */
618     static otError ParsePreference(const Arg &aArg, otRoutePreference &aPreference);
619 
620     /**
621      * Converts a route preference value to human-readable string.
622      *
623      * @param[in] aPreference   The preference value to convert (`OT_ROUTE_PREFERENCE_*` values).
624      *
625      * @returns A string representation @p aPreference.
626      */
627     static const char *PreferenceToString(signed int aPreference);
628 
629     /**
630      * Parses the argument as an IP address.
631      *
632      * If the argument string is an IPv4 address, this method will try to synthesize an IPv6 address using preferred
633      * NAT64 prefix in the network data.
634      *
635      * @param[in]  aInstance       A pointer to OpenThread instance.
636      * @param[in]  aArg            The argument string to parse.
637      * @param[out] aAddress        A reference to an `otIp6Address` to output the parsed IPv6 address.
638      * @param[out] aSynthesized    Whether @p aAddress is synthesized from an IPv4 address.
639      *
640      * @retval OT_ERROR_NONE           The argument was parsed successfully.
641      * @retval OT_ERROR_INVALID_ARGS   The argument is empty or does not contain a valid IP address.
642      * @retval OT_ERROR_INVALID_STATE  No valid NAT64 prefix in the network data.
643      */
644     static otError ParseToIp6Address(otInstance   *aInstance,
645                                      const Arg    &aArg,
646                                      otIp6Address &aAddress,
647                                      bool         &aSynthesized);
648 
649     /**
650      * Parses the argument as a Joiner Discerner.
651      *
652      * @param[in]  aArg            The argument string to parse.
653      * @param[out] aDiscerner      A reference to an `otJoinerDiscerner` to output the parsed discerner
654      *
655      * @retval OT_ERROR_NONE           The argument was parsed successfully.
656      * @retval OT_ERROR_INVALID_ARGS   The argument is empty or does not contain a valid joiner discerner.
657      */
658     static otError ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner);
659 
660 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
661     /**
662      * Parses the argument as a Border Router configuration.
663      *
664      * @param[in]  aArg            The argument string to parse.
665      * @param[out] aConfig         A reference to an `otBorderRouterConfig` to output the configuration.
666      *
667      * @retval OT_ERROR_NONE           The argument was parsed successfully.
668      * @retval OT_ERROR_INVALID_ARGS   The argument is empty or does not contain a valid configuration.
669      */
670     static otError ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig);
671 
672     /**
673      * Parses the argument as a External Route configuration.
674      *
675      * @param[in]  aArg            The argument string to parse.
676      * @param[out] aConfig         A reference to an `otExternalRouteConfig` to output the configuration.
677      *
678      * @retval OT_ERROR_NONE           The argument was parsed successfully.
679      * @retval OT_ERROR_INVALID_ARGS   The argument is empty or does not contain a valid configuration.
680      */
681     static otError ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig);
682 #endif
683 
684     static constexpr uint8_t kLinkModeStringSize = sizeof("rdn"); ///< Size of string buffer for a MLE Link Mode.
685 
686     /**
687      * Converts a given MLE Link Mode to flag string.
688      *
689      * The characters 'r', 'd', and 'n' are respectively used for `mRxOnWhenIdle`, `mDeviceType` and `mNetworkData`
690      * flags. If all flags are `false`, then "-" is returned.
691      *
692      * @param[in]  aLinkMode       The MLE Link Mode to convert.
693      * @param[out] aStringBuffer   A reference to an string array to place the string.
694      *
695      * @returns A pointer @p aStringBuffer which contains the converted string.
696      */
697     static const char *LinkModeToString(const otLinkModeConfig &aLinkMode, char (&aStringBuffer)[kLinkModeStringSize]);
698 
699     /**
700      * Converts an IPv6 address origin `OT_ADDRESS_ORIGIN_*` value to human-readable string.
701      *
702      * @param[in] aOrigin   The IPv6 address origin to convert.
703      *
704      * @returns A human-readable string representation of @p aOrigin.
705      */
706     static const char *AddressOriginToString(uint8_t aOrigin);
707 
708 protected:
709     void OutputFormatV(const char *aFormat, va_list aArguments);
710 
711 #if OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE
712     void LogInput(const Arg *aArgs);
713 #else
LogInput(const Arg *)714     void LogInput(const Arg *) {}
715 #endif
716 
717 private:
718     static constexpr uint16_t kInputOutputLogStringSize = OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_LOG_STRING_SIZE;
719 
720     void OutputTableHeader(uint8_t aNumColumns, const char *const aTitles[], const uint8_t aWidths[]);
721     void OutputTableSeparator(uint8_t aNumColumns, const uint8_t aWidths[]);
722 
723     otInstance        *mInstance;
724     OutputImplementer &mImplementer;
725 };
726 
727 // Specializations of `FormatStringFor<ValueType>()`
728 
FormatStringFor(void)729 template <> inline constexpr const char *Utils::FormatStringFor<uint8_t>(void) { return "%u"; }
730 
FormatStringFor(void)731 template <> inline constexpr const char *Utils::FormatStringFor<uint16_t>(void) { return "%u"; }
732 
FormatStringFor(void)733 template <> inline constexpr const char *Utils::FormatStringFor<uint32_t>(void) { return "%lu"; }
734 
FormatStringFor(void)735 template <> inline constexpr const char *Utils::FormatStringFor<int8_t>(void) { return "%d"; }
736 
FormatStringFor(void)737 template <> inline constexpr const char *Utils::FormatStringFor<int16_t>(void) { return "%d"; }
738 
FormatStringFor(void)739 template <> inline constexpr const char *Utils::FormatStringFor<int32_t>(void) { return "%ld"; }
740 
FormatStringFor(void)741 template <> inline constexpr const char *Utils::FormatStringFor<const char *>(void) { return "%s"; }
742 
743 // Specialization of ProcessGet<> for `uint32_t` and `int32_t`
744 
ProcessGet(Arg aArgs[],GetHandler<uint32_t> aGetHandler)745 template <> inline otError Utils::ProcessGet<uint32_t>(Arg aArgs[], GetHandler<uint32_t> aGetHandler)
746 {
747     otError error = OT_ERROR_NONE;
748 
749     VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
750     OutputLine(FormatStringFor<uint32_t>(), ToUlong(aGetHandler(GetInstancePtr())));
751 
752 exit:
753     return error;
754 }
755 
ProcessGet(Arg aArgs[],GetHandler<int32_t> aGetHandler)756 template <> inline otError Utils::ProcessGet<int32_t>(Arg aArgs[], GetHandler<int32_t> aGetHandler)
757 {
758     otError error = OT_ERROR_NONE;
759 
760     VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
761     OutputLine(FormatStringFor<int32_t>(), static_cast<long int>(aGetHandler(GetInstancePtr())));
762 
763 exit:
764     return error;
765 }
766 
767 } // namespace Cli
768 } // namespace ot
769 
770 #endif // CLI_UTILS_HPP_
771