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