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