• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2018, 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 defines OpenThread String class.
32  */
33 
34 #ifndef STRING_HPP_
35 #define STRING_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <stdarg.h>
40 #include <stdint.h>
41 #include <stdio.h>
42 
43 #include "common/binary_search.hpp"
44 #include "common/code_utils.hpp"
45 #include "common/error.hpp"
46 
47 namespace ot {
48 
49 /**
50  * @addtogroup core-string
51  *
52  * @brief
53  *   This module includes definitions for OpenThread String class.
54  *
55  * @{
56  *
57  */
58 
59 /**
60  * This enumeration represents comparison mode when matching strings.
61  *
62  */
63 enum StringMatchMode : uint8_t
64 {
65     kStringExactMatch,           ///< Exact match of characters.
66     kStringCaseInsensitiveMatch, ///< Case insensitive match (uppercase and lowercase characters are treated as equal).
67 };
68 
69 static constexpr char kNullChar = '\0'; ///< null character.
70 
71 /**
72  * This function returns the number of characters that precede the terminating null character.
73  *
74  * @param[in] aString      A pointer to the string.
75  * @param[in] aMaxLength   The maximum length in bytes.
76  *
77  * @returns The number of characters that precede the terminating null character or @p aMaxLength, whichever is
78  *          smaller.
79  *
80  */
81 uint16_t StringLength(const char *aString, uint16_t aMaxLength);
82 
83 /**
84  * This function finds the first occurrence of a given character in a null-terminated string.
85  *
86  * @param[in] aString     A pointer to the string.
87  * @param[in] aChar       A char to search for in the string.
88  *
89  * @returns The pointer to first occurrence of the @p aChar in @p aString, or `nullptr` if cannot be found.
90  *
91  */
92 const char *StringFind(const char *aString, char aChar);
93 
94 /**
95  * This function finds the first occurrence of a given sub-string in a null-terminated string.
96  *
97  * @param[in] aString     A pointer to the string.
98  * @param[in] aSubString  A sub-string to search for.
99  * @param[in] aMode       The string comparison mode, exact match or case insensitive match.
100  *
101  * @returns The pointer to first match of the @p aSubString in @p aString (using comparison @p aMode), or `nullptr` if
102  *          cannot be found.
103  *
104  */
105 const char *StringFind(const char *aString, const char *aSubString, StringMatchMode aMode = kStringExactMatch);
106 
107 /**
108  * This function checks whether a null-terminated string starts with a given prefix string.
109  *
110  * @param[in] aString         A pointer to the string.
111  * @param[in] aPrefixString   A prefix string.
112  * @param[in] aMode           The string comparison mode, exact match or case insensitive match.
113  *
114  * @retval TRUE   If @p aString starts with @p aPrefixString.
115  * @retval FALSE  If @p aString does not start with @p aPrefixString.
116  *
117  */
118 bool StringStartsWith(const char *aString, const char *aPrefixString, StringMatchMode aMode = kStringExactMatch);
119 
120 /**
121  * This function checks whether a null-terminated string ends with a given character.
122  *
123  * @param[in] aString  A pointer to the string.
124  * @param[in] aChar    A char to check.
125  *
126  * @retval TRUE   If @p aString ends with character @p aChar.
127  * @retval FALSE  If @p aString does not end with character @p aChar.
128  *
129  */
130 bool StringEndsWith(const char *aString, char aChar);
131 
132 /**
133  * This function checks whether a null-terminated string ends with a given sub-string.
134  *
135  * @param[in] aString      A pointer to the string.
136  * @param[in] aSubString   A sub-string to check against.
137  * @param[in] aMode        The string comparison mode, exact match or case insensitive match.
138  *
139  * @retval TRUE   If @p aString ends with sub-string @p aSubString.
140  * @retval FALSE  If @p aString does not end with sub-string @p aSubString.
141  *
142  */
143 bool StringEndsWith(const char *aString, const char *aSubString, StringMatchMode aMode = kStringExactMatch);
144 
145 /**
146  * This method checks whether or not two null-terminated strings match.
147  *
148  * @param[in] aFirstString   A pointer to the first string.
149  * @param[in] aSecondString  A pointer to the second string.
150  * @param[in] aMode          The string comparison mode, exact match or case insensitive match.
151  *
152  * @retval TRUE   If @p aFirstString matches @p aSecondString using match mode @p aMode.
153  * @retval FALSE  If @p aFirstString does not match @p aSecondString using match mode @p aMode.
154  *
155  */
156 bool StringMatch(const char *aFirstString, const char *aSecondString, StringMatchMode aMode = kStringExactMatch);
157 
158 /**
159  * This function converts all uppercase letter characters in a given string to lowercase.
160  *
161  * @param[in,out] aString   A pointer to the string to convert.
162  *
163  */
164 void StringConvertToLowercase(char *aString);
165 
166 /**
167  * This function converts all lowercase letter characters in a given string to uppercase.
168  *
169  * @param[in,out] aString   A pointer to the string to convert.
170  *
171  */
172 void StringConvertToUppercase(char *aString);
173 
174 /**
175  * This function converts an uppercase letter character to lowercase.
176  *
177  * If @p aChar is uppercase letter it is converted lowercase. Otherwise, it remains unchanged.
178  *
179  * @param[in] aChar   The character to convert
180  *
181  * @returns The character converted to lowercase.
182  *
183  */
184 char ToLowercase(char aChar);
185 
186 /**
187  * This function converts a lowercase letter character to uppercase.
188  *
189  * If @p aChar is lowercase letter it is converted uppercase. Otherwise, it remains unchanged.
190  *
191  * @param[in] aChar   The character to convert
192  *
193  * @returns The character converted to uppercase.
194  *
195  */
196 char ToUppercase(char aChar);
197 
198 /**
199  * This function coverts a boolean to "yes" or "no" string.
200  *
201  * @param[in] aBool  A boolean value to convert.
202  *
203  * @returns The converted string representation of @p aBool ("yes" for TRUE and "no" for FALSE).
204  *
205  */
206 const char *ToYesNo(bool aBool);
207 
208 /**
209  * This function validates whether a given byte sequence (string) follows UTF-8 encoding.
210  * Control characters are not allowed.
211  *
212  * @param[in]  aString  A null-terminated byte sequence.
213  *
214  * @retval TRUE   The sequence is a valid UTF-8 string.
215  * @retval FALSE  The sequence is not a valid UTF-8 string.
216  *
217  */
218 bool IsValidUtf8String(const char *aString);
219 
220 /**
221  * This function validates whether a given byte sequence (string) follows UTF-8 encoding.
222  * Control characters are not allowed.
223  *
224  * @param[in]  aString  A byte sequence.
225  * @param[in]  aLength  Length of the sequence.
226  *
227  * @retval TRUE   The sequence is a valid UTF-8 string.
228  * @retval FALSE  The sequence is not a valid UTF-8 string.
229  *
230  */
231 bool IsValidUtf8String(const char *aString, size_t aLength);
232 
233 /**
234  * This `constexpr` function checks whether two given C strings are in order (alphabetical order).
235  *
236  * This is intended for use from `static_assert`, e.g., checking if a lookup table entries are sorted. It is not
237  * recommended to use this function in other situations as it uses recursion so that it can be `constexpr`.
238  *
239  * @param[in] aFirst    The first string.
240  * @param[in] aSecond   The second string.
241  *
242  * @retval TRUE  If first string is strictly before second string (alphabetical order).
243  * @retval FALSE If first string is not strictly before second string (alphabetical order).
244  *
245  */
AreStringsInOrder(const char * aFirst,const char * aSecond)246 inline constexpr bool AreStringsInOrder(const char *aFirst, const char *aSecond)
247 {
248     return (*aFirst < *aSecond)
249                ? true
250                : ((*aFirst > *aSecond) || (*aFirst == '\0') ? false : AreStringsInOrder(aFirst + 1, aSecond + 1));
251 }
252 
253 /**
254  * This class implements writing to a string buffer.
255  *
256  */
257 class StringWriter
258 {
259 public:
260     /**
261      * This constructor initializes the object as cleared on the provided buffer.
262      *
263      * @param[in] aBuffer  A pointer to the char buffer to write into.
264      * @param[in] aSize    The size of @p aBuffer.
265      *
266      */
267     StringWriter(char *aBuffer, uint16_t aSize);
268 
269     /**
270      * This method clears the string writer.
271      *
272      * @returns The string writer.
273      *
274      */
275     StringWriter &Clear(void);
276 
277     /**
278      * This method returns whether the output is truncated.
279      *
280      * @note If the output is truncated, the buffer is still null-terminated.
281      *
282      * @retval  true    The output is truncated.
283      * @retval  false   The output is not truncated.
284      *
285      */
IsTruncated(void) const286     bool IsTruncated(void) const { return mLength >= mSize; }
287 
288     /**
289      * This method gets the length of the wanted string.
290      *
291      * Similar to `strlen()` the length does not include the null character at the end of the string.
292      *
293      * @returns The string length.
294      *
295      */
GetLength(void) const296     uint16_t GetLength(void) const { return mLength; }
297 
298     /**
299      * This method returns the size (number of chars) in the buffer.
300      *
301      * @returns The size of the buffer.
302      *
303      */
GetSize(void) const304     uint16_t GetSize(void) const { return mSize; }
305 
306     /**
307      * This method appends `printf()` style formatted data to the buffer.
308      *
309      * @param[in] aFormat    A pointer to the format string.
310      * @param[in] ...        Arguments for the format specification.
311      *
312      * @returns The string writer.
313      *
314      */
315     StringWriter &Append(const char *aFormat, ...);
316 
317     /**
318      * This method appends `printf()` style formatted data to the buffer.
319      *
320      * @param[in] aFormat    A pointer to the format string.
321      * @param[in] aArgs      Arguments for the format specification (as `va_list`).
322      *
323      * @returns The string writer.
324      *
325      */
326     StringWriter &AppendVarArgs(const char *aFormat, va_list aArgs);
327 
328     /**
329      * This method appends an array of bytes in hex representation (using "%02x" style) to the buffer.
330      *
331      * @param[in] aBytes    A pointer to buffer containing the bytes to append.
332      * @param[in] aLength   The length of @p aBytes buffer (in bytes).
333      *
334      * @returns The string writer.
335      *
336      */
337     StringWriter &AppendHexBytes(const uint8_t *aBytes, uint16_t aLength);
338 
339     /**
340      * This method converts all uppercase letter characters in the string to lowercase.
341      *
342      */
ConvertToLowercase(void)343     void ConvertToLowercase(void) { StringConvertToLowercase(mBuffer); }
344 
345     /**
346      * This method converts all lowercase letter characters in the string to uppercase.
347      *
348      */
ConvertToUppercase(void)349     void ConvertToUppercase(void) { StringConvertToUppercase(mBuffer); }
350 
351 private:
352     char *         mBuffer;
353     uint16_t       mLength;
354     const uint16_t mSize;
355 };
356 
357 /**
358  * This class defines a fixed-size string.
359  *
360  */
361 template <uint16_t kSize> class String : public StringWriter
362 {
363     static_assert(kSize > 0, "String buffer cannot be empty.");
364 
365 public:
366     /**
367      * This constructor initializes the string as empty.
368      *
369      */
String(void)370     String(void)
371         : StringWriter(mBuffer, sizeof(mBuffer))
372     {
373     }
374 
375     /**
376      * This method returns the string as a null-terminated C string.
377      *
378      * @returns The null-terminated C string.
379      *
380      */
AsCString(void) const381     const char *AsCString(void) const { return mBuffer; }
382 
383 private:
384     char mBuffer[kSize];
385 };
386 
387 /**
388  * This class provides helper methods to convert from a set of `uint16_t` values (e.g., a non-sequential `enum`) to
389  * string using binary search in a lookup table.
390  *
391  */
392 class Stringify : public BinarySearch
393 {
394 public:
395     /**
396      * This class represents a entry in the lookup table.
397      *
398      */
399     class Entry
400     {
401         friend class BinarySearch;
402 
403     public:
404         uint16_t    mKey;    ///< The key value.
405         const char *mString; ///< The associated string.
406 
407     private:
Compare(uint16_t aKey) const408         int Compare(uint16_t aKey) const { return (aKey == mKey) ? 0 : ((aKey > mKey) ? 1 : -1); }
409 
AreInOrder(const Entry & aFirst,const Entry & aSecond)410         constexpr static bool AreInOrder(const Entry &aFirst, const Entry &aSecond)
411         {
412             return aFirst.mKey < aSecond.mKey;
413         }
414     };
415 
416     /**
417      * This static method looks up a key in a given sorted table array (using binary search) and return the associated
418      * strings with the key.
419      *
420      * @note This method requires the array to be sorted, otherwise its behavior is undefined.
421      *
422      * @tparam kLength     The array length (number of entries in the array).
423      *
424      * @param[in] aKey       The key to search for within the table.
425      * @param[in] aTable     A reference to an array of `kLength` entries.
426      * @param[in] aNotFound  A C string to return if @p aKey was not found in the table.
427      *
428      * @returns The associated string with @p aKey in @p aTable if found, or @p aNotFound otherwise.
429      *
430      */
431     template <uint16_t kLength>
Lookup(uint16_t aKey,const Entry (& aTable)[kLength],const char * aNotFound="unknown")432     static const char *Lookup(uint16_t aKey, const Entry (&aTable)[kLength], const char *aNotFound = "unknown")
433     {
434         const Entry *entry = BinarySearch::Find(aKey, aTable);
435 
436         return (entry != nullptr) ? entry->mString : aNotFound;
437     }
438 
439     Stringify(void) = delete;
440 };
441 
442 /**
443  * @}
444  *
445  */
446 
447 } // namespace ot
448 
449 #endif // STRING_HPP_
450