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