• 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 implements the command line parser.
32  */
33 
34 #include "parse_cmdline.hpp"
35 
36 #include <string.h>
37 
38 #include "common/code_utils.hpp"
39 #include "common/numeric_limits.hpp"
40 #include "common/string.hpp"
41 #include "net/ip6_address.hpp"
42 
43 namespace ot {
44 namespace Utils {
45 namespace CmdLineParser {
46 
IsSeparator(char aChar)47 static bool IsSeparator(char aChar) { return (aChar == ' ') || (aChar == '\t') || (aChar == '\r') || (aChar == '\n'); }
48 
IsEscapable(char aChar)49 static bool IsEscapable(char aChar) { return IsSeparator(aChar) || (aChar == '\\'); }
50 
ParseCmd(char * aCommandString,Arg aArgs[],uint8_t aArgsMaxLength)51 Error ParseCmd(char *aCommandString, Arg aArgs[], uint8_t aArgsMaxLength)
52 {
53     Error   error = kErrorNone;
54     uint8_t index = 0;
55     char   *cmd;
56 
57     for (cmd = aCommandString; *cmd; cmd++)
58     {
59         if ((*cmd == '\\') && IsEscapable(*(cmd + 1)))
60         {
61             // include the null terminator: strlen(cmd) = strlen(cmd + 1) + 1
62             memmove(cmd, cmd + 1, strlen(cmd));
63         }
64         else if (IsSeparator(*cmd))
65         {
66             *cmd = '\0';
67         }
68 
69         if ((*cmd != '\0') && ((index == 0) || (*(cmd - 1) == '\0')))
70         {
71             if (index == aArgsMaxLength - 1)
72             {
73                 error = kErrorInvalidArgs;
74                 break;
75             }
76 
77             aArgs[index++].SetCString(cmd);
78         }
79     }
80 
81     while (index < aArgsMaxLength)
82     {
83         aArgs[index++].Clear();
84     }
85 
86     return error;
87 }
88 
ParseUint(const char * aString,UintType & aUint)89 template <typename UintType> Error ParseUint(const char *aString, UintType &aUint)
90 {
91     Error    error;
92     uint64_t value;
93 
94     SuccessOrExit(error = ParseAsUint64(aString, value));
95 
96     VerifyOrExit(value <= NumericLimits<UintType>::kMax, error = kErrorInvalidArgs);
97     aUint = static_cast<UintType>(value);
98 
99 exit:
100     return error;
101 }
102 
ParseAsUint8(const char * aString,uint8_t & aUint8)103 Error ParseAsUint8(const char *aString, uint8_t &aUint8) { return ParseUint<uint8_t>(aString, aUint8); }
104 
ParseAsUint16(const char * aString,uint16_t & aUint16)105 Error ParseAsUint16(const char *aString, uint16_t &aUint16) { return ParseUint<uint16_t>(aString, aUint16); }
106 
ParseAsUint32(const char * aString,uint32_t & aUint32)107 Error ParseAsUint32(const char *aString, uint32_t &aUint32) { return ParseUint<uint32_t>(aString, aUint32); }
108 
ParseAsUint64(const char * aString,uint64_t & aUint64)109 Error ParseAsUint64(const char *aString, uint64_t &aUint64)
110 {
111     static constexpr uint64_t kMaxHexBeforeOverflow = (0xffffffffffffffffULL / 16);
112     static constexpr uint64_t kMaxDecBeforeOverflow = (0xffffffffffffffffULL / 10);
113 
114     Error       error = kErrorNone;
115     uint64_t    value = 0;
116     const char *cur   = aString;
117     bool        isHex = false;
118 
119     VerifyOrExit(aString != nullptr, error = kErrorInvalidArgs);
120 
121     if (cur[0] == '0' && (cur[1] == 'x' || cur[1] == 'X'))
122     {
123         cur += 2;
124         isHex = true;
125     }
126 
127     do
128     {
129         uint8_t  digit;
130         uint64_t newValue;
131 
132         SuccessOrExit(error = isHex ? ParseHexDigit(*cur, digit) : ParseDigit(*cur, digit));
133         VerifyOrExit(value <= (isHex ? kMaxHexBeforeOverflow : kMaxDecBeforeOverflow), error = kErrorInvalidArgs);
134         value    = isHex ? (value << 4) : (value * 10);
135         newValue = value + digit;
136         VerifyOrExit(newValue >= value, error = kErrorInvalidArgs);
137         value = newValue;
138         cur++;
139     } while (*cur != '\0');
140 
141     aUint64 = value;
142 
143 exit:
144     return error;
145 }
146 
ParseInt(const char * aString,IntType & aInt)147 template <typename IntType> Error ParseInt(const char *aString, IntType &aInt)
148 {
149     Error   error;
150     int32_t value;
151 
152     SuccessOrExit(error = ParseAsInt32(aString, value));
153 
154     VerifyOrExit((NumericLimits<IntType>::kMin <= value) && (value <= NumericLimits<IntType>::kMax),
155                  error = kErrorInvalidArgs);
156     aInt = static_cast<IntType>(value);
157 
158 exit:
159     return error;
160 }
161 
ParseAsInt8(const char * aString,int8_t & aInt8)162 Error ParseAsInt8(const char *aString, int8_t &aInt8) { return ParseInt<int8_t>(aString, aInt8); }
163 
ParseAsInt16(const char * aString,int16_t & aInt16)164 Error ParseAsInt16(const char *aString, int16_t &aInt16) { return ParseInt<int16_t>(aString, aInt16); }
165 
ParseAsInt32(const char * aString,int32_t & aInt32)166 Error ParseAsInt32(const char *aString, int32_t &aInt32)
167 {
168     Error    error;
169     uint64_t value;
170     bool     isNegative = false;
171 
172     VerifyOrExit(aString != nullptr, error = kErrorInvalidArgs);
173 
174     if (*aString == '-')
175     {
176         aString++;
177         isNegative = true;
178     }
179     else if (*aString == '+')
180     {
181         aString++;
182     }
183 
184     SuccessOrExit(error = ParseAsUint64(aString, value));
185     VerifyOrExit(value <= (isNegative ? static_cast<uint64_t>(-static_cast<int64_t>(NumericLimits<int32_t>::kMin))
186                                       : static_cast<uint64_t>(NumericLimits<int32_t>::kMax)),
187                  error = kErrorInvalidArgs);
188     aInt32 = static_cast<int32_t>(isNegative ? -static_cast<int64_t>(value) : static_cast<int64_t>(value));
189 
190 exit:
191     return error;
192 }
193 
ParseAsBool(const char * aString,bool & aBool)194 Error ParseAsBool(const char *aString, bool &aBool)
195 {
196     Error    error;
197     uint32_t value;
198 
199     SuccessOrExit(error = ParseAsUint32(aString, value));
200     aBool = (value != 0);
201 
202 exit:
203     return error;
204 }
205 #if OPENTHREAD_FTD || OPENTHREAD_MTD
206 
ParseAsIp6Address(const char * aString,otIp6Address & aAddress)207 Error ParseAsIp6Address(const char *aString, otIp6Address &aAddress)
208 {
209     return (aString != nullptr) ? otIp6AddressFromString(aString, &aAddress) : kErrorInvalidArgs;
210 }
211 
ParseAsIp4Address(const char * aString,otIp4Address & aAddress)212 Error ParseAsIp4Address(const char *aString, otIp4Address &aAddress)
213 {
214     return (aString != nullptr) ? otIp4AddressFromString(aString, &aAddress) : kErrorInvalidArgs;
215 }
216 
ParseAsIp6Prefix(const char * aString,otIp6Prefix & aPrefix)217 Error ParseAsIp6Prefix(const char *aString, otIp6Prefix &aPrefix)
218 {
219     return (aString != nullptr) ? otIp6PrefixFromString(aString, &aPrefix) : kErrorInvalidArgs;
220 }
221 #endif // #if OPENTHREAD_FTD || OPENTHREAD_MTD
222 
223 enum HexStringParseMode
224 {
225     kModeExactSize,    // Parse hex string expecting an exact size (number of bytes when parsed).
226     kModeUpToSize,     // Parse hex string expecting less than or equal a given size.
227     kModeAllowPartial, // Allow parsing of partial segments.
228 };
229 
ParseHexString(const char * & aString,uint16_t & aSize,uint8_t * aBuffer,HexStringParseMode aMode)230 static Error ParseHexString(const char *&aString, uint16_t &aSize, uint8_t *aBuffer, HexStringParseMode aMode)
231 {
232     Error  error      = kErrorNone;
233     size_t parsedSize = 0;
234     size_t stringLength;
235     size_t expectedSize;
236     bool   skipFirstDigit;
237 
238     VerifyOrExit(aString != nullptr, error = kErrorInvalidArgs);
239 
240     stringLength = strlen(aString);
241     expectedSize = (stringLength + 1) / 2;
242 
243     switch (aMode)
244     {
245     case kModeExactSize:
246         VerifyOrExit(expectedSize == aSize, error = kErrorInvalidArgs);
247         break;
248     case kModeUpToSize:
249         VerifyOrExit(expectedSize <= aSize, error = kErrorInvalidArgs);
250         break;
251     case kModeAllowPartial:
252         break;
253     }
254 
255     // If number of chars in hex string is odd, we skip parsing
256     // the first digit.
257 
258     skipFirstDigit = ((stringLength & 1) != 0);
259 
260     while (parsedSize < expectedSize)
261     {
262         uint8_t digit;
263 
264         if ((aMode == kModeAllowPartial) && (parsedSize == aSize))
265         {
266             // If partial parse mode is allowed, stop once we read the
267             // requested size.
268             ExitNow(error = kErrorPending);
269         }
270 
271         if (skipFirstDigit)
272         {
273             *aBuffer       = 0;
274             skipFirstDigit = false;
275         }
276         else
277         {
278             SuccessOrExit(error = ParseHexDigit(*aString, digit));
279             aString++;
280             *aBuffer = static_cast<uint8_t>(digit << 4);
281         }
282 
283         SuccessOrExit(error = ParseHexDigit(*aString, digit));
284         aString++;
285         *aBuffer |= digit;
286 
287         aBuffer++;
288         parsedSize++;
289     }
290 
291     aSize = static_cast<uint16_t>(parsedSize);
292 
293 exit:
294     return error;
295 }
296 
ParseAsHexString(const char * aString,uint8_t * aBuffer,uint16_t aSize)297 Error ParseAsHexString(const char *aString, uint8_t *aBuffer, uint16_t aSize)
298 {
299     return ParseHexString(aString, aSize, aBuffer, kModeExactSize);
300 }
301 
ParseAsHexString(const char * aString,uint16_t & aSize,uint8_t * aBuffer)302 Error ParseAsHexString(const char *aString, uint16_t &aSize, uint8_t *aBuffer)
303 {
304     return ParseHexString(aString, aSize, aBuffer, kModeUpToSize);
305 }
306 
ParseAsHexStringSegment(const char * & aString,uint16_t & aSize,uint8_t * aBuffer)307 Error ParseAsHexStringSegment(const char *&aString, uint16_t &aSize, uint8_t *aBuffer)
308 {
309     return ParseHexString(aString, aSize, aBuffer, kModeAllowPartial);
310 }
311 
312 //---------------------------------------------------------------------------------------------------------------------
313 // Arg class
314 
GetLength(void) const315 uint16_t Arg::GetLength(void) const { return IsEmpty() ? 0 : static_cast<uint16_t>(strlen(mString)); }
316 
operator ==(const char * aString) const317 bool Arg::operator==(const char *aString) const { return !IsEmpty() && StringMatch(mString, aString); }
318 
CopyArgsToStringArray(Arg aArgs[],char * aStrings[])319 void Arg::CopyArgsToStringArray(Arg aArgs[], char *aStrings[])
320 {
321     for (uint8_t i = 0; !aArgs[i].IsEmpty(); i++)
322     {
323         aStrings[i] = aArgs[i].GetCString();
324     }
325 }
326 
GetArgsLength(Arg aArgs[])327 uint8_t Arg::GetArgsLength(Arg aArgs[])
328 {
329     uint8_t length = 0;
330 
331     while (!aArgs[length].IsEmpty())
332     {
333         length++;
334     }
335 
336     return length;
337 }
338 
339 } // namespace CmdLineParser
340 } // namespace Utils
341 } // namespace ot
342