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     Error       error = kErrorNone;
112     uint64_t    value = 0;
113     const char *cur   = aString;
114     bool        isHex = false;
115 
116     enum : uint64_t
117     {
118         kMaxHexBeforeOverflow = (0xffffffffffffffffULL / 16),
119         kMaxDecBeforeOverflow = (0xffffffffffffffffULL / 10),
120     };
121 
122     VerifyOrExit(aString != nullptr, error = kErrorInvalidArgs);
123 
124     if (cur[0] == '0' && (cur[1] == 'x' || cur[1] == 'X'))
125     {
126         cur += 2;
127         isHex = true;
128     }
129 
130     do
131     {
132         uint8_t  digit;
133         uint64_t newValue;
134 
135         SuccessOrExit(error = isHex ? ParseHexDigit(*cur, digit) : ParseDigit(*cur, digit));
136         VerifyOrExit(value <= (isHex ? kMaxHexBeforeOverflow : kMaxDecBeforeOverflow), error = kErrorInvalidArgs);
137         value    = isHex ? (value << 4) : (value * 10);
138         newValue = value + digit;
139         VerifyOrExit(newValue >= value, error = kErrorInvalidArgs);
140         value = newValue;
141         cur++;
142     } while (*cur != '\0');
143 
144     aUint64 = value;
145 
146 exit:
147     return error;
148 }
149 
ParseInt(const char * aString,IntType & aInt)150 template <typename IntType> Error ParseInt(const char *aString, IntType &aInt)
151 {
152     Error   error;
153     int32_t value;
154 
155     SuccessOrExit(error = ParseAsInt32(aString, value));
156 
157     VerifyOrExit((NumericLimits<IntType>::kMin <= value) && (value <= NumericLimits<IntType>::kMax),
158                  error = kErrorInvalidArgs);
159     aInt = static_cast<IntType>(value);
160 
161 exit:
162     return error;
163 }
164 
ParseAsInt8(const char * aString,int8_t & aInt8)165 Error ParseAsInt8(const char *aString, int8_t &aInt8) { return ParseInt<int8_t>(aString, aInt8); }
166 
ParseAsInt16(const char * aString,int16_t & aInt16)167 Error ParseAsInt16(const char *aString, int16_t &aInt16) { return ParseInt<int16_t>(aString, aInt16); }
168 
ParseAsInt32(const char * aString,int32_t & aInt32)169 Error ParseAsInt32(const char *aString, int32_t &aInt32)
170 {
171     Error    error;
172     uint64_t value;
173     bool     isNegative = false;
174 
175     VerifyOrExit(aString != nullptr, error = kErrorInvalidArgs);
176 
177     if (*aString == '-')
178     {
179         aString++;
180         isNegative = true;
181     }
182     else if (*aString == '+')
183     {
184         aString++;
185     }
186 
187     SuccessOrExit(error = ParseAsUint64(aString, value));
188     VerifyOrExit(value <= (isNegative ? static_cast<uint64_t>(-static_cast<int64_t>(NumericLimits<int32_t>::kMin))
189                                       : static_cast<uint64_t>(NumericLimits<int32_t>::kMax)),
190                  error = kErrorInvalidArgs);
191     aInt32 = static_cast<int32_t>(isNegative ? -static_cast<int64_t>(value) : static_cast<int64_t>(value));
192 
193 exit:
194     return error;
195 }
196 
ParseAsBool(const char * aString,bool & aBool)197 Error ParseAsBool(const char *aString, bool &aBool)
198 {
199     Error    error;
200     uint32_t value;
201 
202     SuccessOrExit(error = ParseAsUint32(aString, value));
203     aBool = (value != 0);
204 
205 exit:
206     return error;
207 }
208 #if OPENTHREAD_FTD || OPENTHREAD_MTD
209 
ParseAsIp6Address(const char * aString,otIp6Address & aAddress)210 Error ParseAsIp6Address(const char *aString, otIp6Address &aAddress)
211 {
212     return (aString != nullptr) ? otIp6AddressFromString(aString, &aAddress) : kErrorInvalidArgs;
213 }
214 
ParseAsIp4Address(const char * aString,otIp4Address & aAddress)215 Error ParseAsIp4Address(const char *aString, otIp4Address &aAddress)
216 {
217     return (aString != nullptr) ? otIp4AddressFromString(aString, &aAddress) : kErrorInvalidArgs;
218 }
219 
ParseAsIp6Prefix(const char * aString,otIp6Prefix & aPrefix)220 Error ParseAsIp6Prefix(const char *aString, otIp6Prefix &aPrefix)
221 {
222     return (aString != nullptr) ? otIp6PrefixFromString(aString, &aPrefix) : kErrorInvalidArgs;
223 }
224 #endif // #if OPENTHREAD_FTD || OPENTHREAD_MTD
225 
226 enum HexStringParseMode
227 {
228     kModeExactSize,    // Parse hex string expecting an exact size (number of bytes when parsed).
229     kModeUpToSize,     // Parse hex string expecting less than or equal a given size.
230     kModeAllowPartial, // Allow parsing of partial segments.
231 };
232 
ParseHexString(const char * & aString,uint16_t & aSize,uint8_t * aBuffer,HexStringParseMode aMode)233 static Error ParseHexString(const char *&aString, uint16_t &aSize, uint8_t *aBuffer, HexStringParseMode aMode)
234 {
235     Error  error      = kErrorNone;
236     size_t parsedSize = 0;
237     size_t stringLength;
238     size_t expectedSize;
239     bool   skipFirstDigit;
240 
241     VerifyOrExit(aString != nullptr, error = kErrorInvalidArgs);
242 
243     stringLength = strlen(aString);
244     expectedSize = (stringLength + 1) / 2;
245 
246     switch (aMode)
247     {
248     case kModeExactSize:
249         VerifyOrExit(expectedSize == aSize, error = kErrorInvalidArgs);
250         break;
251     case kModeUpToSize:
252         VerifyOrExit(expectedSize <= aSize, error = kErrorInvalidArgs);
253         break;
254     case kModeAllowPartial:
255         break;
256     }
257 
258     // If number of chars in hex string is odd, we skip parsing
259     // the first digit.
260 
261     skipFirstDigit = ((stringLength & 1) != 0);
262 
263     while (parsedSize < expectedSize)
264     {
265         uint8_t digit;
266 
267         if ((aMode == kModeAllowPartial) && (parsedSize == aSize))
268         {
269             // If partial parse mode is allowed, stop once we read the
270             // requested size.
271             ExitNow(error = kErrorPending);
272         }
273 
274         if (skipFirstDigit)
275         {
276             *aBuffer       = 0;
277             skipFirstDigit = false;
278         }
279         else
280         {
281             SuccessOrExit(error = ParseHexDigit(*aString, digit));
282             aString++;
283             *aBuffer = static_cast<uint8_t>(digit << 4);
284         }
285 
286         SuccessOrExit(error = ParseHexDigit(*aString, digit));
287         aString++;
288         *aBuffer |= digit;
289 
290         aBuffer++;
291         parsedSize++;
292     }
293 
294     aSize = static_cast<uint16_t>(parsedSize);
295 
296 exit:
297     return error;
298 }
299 
ParseAsHexString(const char * aString,uint8_t * aBuffer,uint16_t aSize)300 Error ParseAsHexString(const char *aString, uint8_t *aBuffer, uint16_t aSize)
301 {
302     return ParseHexString(aString, aSize, aBuffer, kModeExactSize);
303 }
304 
ParseAsHexString(const char * aString,uint16_t & aSize,uint8_t * aBuffer)305 Error ParseAsHexString(const char *aString, uint16_t &aSize, uint8_t *aBuffer)
306 {
307     return ParseHexString(aString, aSize, aBuffer, kModeUpToSize);
308 }
309 
ParseAsHexStringSegment(const char * & aString,uint16_t & aSize,uint8_t * aBuffer)310 Error ParseAsHexStringSegment(const char *&aString, uint16_t &aSize, uint8_t *aBuffer)
311 {
312     return ParseHexString(aString, aSize, aBuffer, kModeAllowPartial);
313 }
314 
315 //---------------------------------------------------------------------------------------------------------------------
316 // Arg class
317 
GetLength(void) const318 uint16_t Arg::GetLength(void) const { return IsEmpty() ? 0 : static_cast<uint16_t>(strlen(mString)); }
319 
operator ==(const char * aString) const320 bool Arg::operator==(const char *aString) const { return !IsEmpty() && StringMatch(mString, aString); }
321 
CopyArgsToStringArray(Arg aArgs[],char * aStrings[])322 void Arg::CopyArgsToStringArray(Arg aArgs[], char *aStrings[])
323 {
324     for (uint8_t i = 0; !aArgs[i].IsEmpty(); i++)
325     {
326         aStrings[i] = aArgs[i].GetCString();
327     }
328 }
329 
GetArgsLength(Arg aArgs[])330 uint8_t Arg::GetArgsLength(Arg aArgs[])
331 {
332     uint8_t length = 0;
333 
334     while (!aArgs[length].IsEmpty())
335     {
336         length++;
337     }
338 
339     return length;
340 }
341 
342 } // namespace CmdLineParser
343 } // namespace Utils
344 } // namespace ot
345